pas2_midi.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * sound/pas2_midi.c
  3.  *
  4.  * The low level driver for the PAS Midi Interface.
  5.  */
  6. /*
  7.  * Copyright (C) by Hannu Savolainen 1993-1997
  8.  *
  9.  * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  10.  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  11.  * for more info.
  12.  *
  13.  * Bartlomiej Zolnierkiewicz : Added __init to pas_init_mixer()
  14.  */
  15. #include <linux/init.h>
  16. #include "sound_config.h"
  17. #include "pas2.h"
  18. static int      midi_busy = 0, input_opened = 0;
  19. static int      my_dev;
  20. int pas2_mididev=-1;
  21. static unsigned char tmp_queue[256];
  22. static volatile int qlen;
  23. static volatile unsigned char qhead, qtail;
  24. static void     (*midi_input_intr) (int dev, unsigned char data);
  25. static int pas_midi_open(int dev, int mode,
  26.       void            (*input) (int dev, unsigned char data),
  27.       void            (*output) (int dev)
  28. )
  29. {
  30. int             err;
  31. unsigned long   flags;
  32. unsigned char   ctrl;
  33. if (midi_busy)
  34. return -EBUSY;
  35. /*
  36.  * Reset input and output FIFO pointers
  37.  */
  38. pas_write(0x20 | 0x40,
  39.   0x178b);
  40. save_flags(flags);
  41. cli();
  42. if ((err = pas_set_intr(0x10)) < 0)
  43. {
  44. restore_flags(flags);
  45. return err;
  46. }
  47. /*
  48.  * Enable input available and output FIFO empty interrupts
  49.  */
  50. ctrl = 0;
  51. input_opened = 0;
  52. midi_input_intr = input;
  53. if (mode == OPEN_READ || mode == OPEN_READWRITE)
  54. {
  55. ctrl |= 0x04; /* Enable input */
  56. input_opened = 1;
  57. }
  58. if (mode == OPEN_WRITE || mode == OPEN_READWRITE)
  59. {
  60. ctrl |= 0x08 | 0x10; /* Enable output */
  61. }
  62. pas_write(ctrl, 0x178b);
  63. /*
  64.  * Acknowledge any pending interrupts
  65.  */
  66. pas_write(0xff, 0x1B88);
  67. restore_flags(flags);
  68. midi_busy = 1;
  69. qlen = qhead = qtail = 0;
  70. return 0;
  71. }
  72. static void pas_midi_close(int dev)
  73. {
  74. /*
  75.  * Reset FIFO pointers, disable intrs
  76.  */
  77. pas_write(0x20 | 0x40, 0x178b);
  78. pas_remove_intr(0x10);
  79. midi_busy = 0;
  80. }
  81. static int dump_to_midi(unsigned char midi_byte)
  82. {
  83. int fifo_space, x;
  84. fifo_space = ((x = pas_read(0x1B89)) >> 4) & 0x0f;
  85. /*
  86.  * The MIDI FIFO space register and it's documentation is nonunderstandable.
  87.  * There seem to be no way to differentiate between buffer full and buffer
  88.  * empty situations. For this reason we don't never write the buffer
  89.  * completely full. In this way we can assume that 0 (or is it 15)
  90.  * means that the buffer is empty.
  91.  */
  92. if (fifo_space < 2 && fifo_space != 0) /* Full (almost) */
  93. return 0; /* Ask upper layers to retry after some time */
  94. pas_write(midi_byte, 0x178A);
  95. return 1;
  96. }
  97. static int pas_midi_out(int dev, unsigned char midi_byte)
  98. {
  99. unsigned long flags;
  100. /*
  101.  * Drain the local queue first
  102.  */
  103. save_flags(flags);
  104. cli();
  105. while (qlen && dump_to_midi(tmp_queue[qhead]))
  106. {
  107. qlen--;
  108. qhead++;
  109. }
  110. restore_flags(flags);
  111. /*
  112.  * Output the byte if the local queue is empty.
  113.  */
  114. if (!qlen)
  115. if (dump_to_midi(midi_byte))
  116. return 1;
  117. /*
  118.  * Put to the local queue
  119.  */
  120. if (qlen >= 256)
  121. return 0; /* Local queue full */
  122. save_flags(flags);
  123. cli();
  124. tmp_queue[qtail] = midi_byte;
  125. qlen++;
  126. qtail++;
  127. restore_flags(flags);
  128. return 1;
  129. }
  130. static int pas_midi_start_read(int dev)
  131. {
  132. return 0;
  133. }
  134. static int pas_midi_end_read(int dev)
  135. {
  136. return 0;
  137. }
  138. static void pas_midi_kick(int dev)
  139. {
  140. }
  141. static int pas_buffer_status(int dev)
  142. {
  143. return qlen;
  144. }
  145. #define MIDI_SYNTH_NAME "Pro Audio Spectrum Midi"
  146. #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
  147. #include "midi_synth.h"
  148. static struct midi_operations pas_midi_operations =
  149. {
  150. owner: THIS_MODULE,
  151. info: {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS},
  152. converter: &std_midi_synth,
  153. in_info: {0},
  154. open: pas_midi_open,
  155. close: pas_midi_close,
  156. outputc: pas_midi_out,
  157. start_read: pas_midi_start_read,
  158. end_read: pas_midi_end_read,
  159. kick: pas_midi_kick,
  160. buffer_status: pas_buffer_status,
  161. };
  162. void __init pas_midi_init(void)
  163. {
  164. int dev = sound_alloc_mididev();
  165. if (dev == -1)
  166. {
  167. printk(KERN_WARNING "pas_midi_init: Too many midi devices detectedn");
  168. return;
  169. }
  170. std_midi_synth.midi_dev = my_dev = dev;
  171. midi_devs[dev] = &pas_midi_operations;
  172. pas2_mididev = dev;
  173. sequencer_init();
  174. }
  175. void pas_midi_interrupt(void)
  176. {
  177. unsigned char   stat;
  178. int             i, incount;
  179. unsigned long   flags;
  180. stat = pas_read(0x1B88);
  181. if (stat & 0x04) /* Input data available */
  182. {
  183. incount = pas_read(0x1B89) & 0x0f; /* Input FIFO size */
  184. if (!incount)
  185. incount = 16;
  186. for (i = 0; i < incount; i++)
  187. if (input_opened)
  188. {
  189. midi_input_intr(my_dev, pas_read(0x178A));
  190. } else
  191. pas_read(0x178A); /* Flush */
  192. }
  193. if (stat & (0x08 | 0x10))
  194. {
  195. save_flags(flags);
  196. cli();
  197. while (qlen && dump_to_midi(tmp_queue[qhead]))
  198. {
  199. qlen--;
  200. qhead++;
  201. }
  202. restore_flags(flags);
  203. }
  204. if (stat & 0x40)
  205. {
  206. printk(KERN_WARNING "MIDI output overrun %x,%xn", pas_read(0x1B89), stat);
  207. }
  208. pas_write(stat, 0x1B88); /* Acknowledge interrupts */
  209. }