v_midi.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /*
  2. * sound/oss/v_midi.c
  3. *
  4. * The low level driver for the Sound Blaster DS chips.
  5. *
  6. *
  7. * Copyright (C) by Hannu Savolainen 1993-1996
  8. *
  9. * USS/Lite 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. *
  14. * Changes
  15. * Alan Cox Modularisation, changed memory allocations
  16. * Christoph Hellwig Adapted to module_init/module_exit
  17. *
  18. * Status
  19. * Untested
  20. */
  21. #include <linux/init.h>
  22. #include <linux/module.h>
  23. #include <linux/spinlock.h>
  24. #include "sound_config.h"
  25. #include "v_midi.h"
  26. static vmidi_devc *v_devc[2] = { NULL, NULL};
  27. static int midi1,midi2;
  28. static void *midi_mem = NULL;
  29. /*
  30. * The DSP channel can be used either for input or output. Variable
  31. * 'sb_irq_mode' will be set when the program calls read or write first time
  32. * after open. Current version doesn't support mode changes without closing
  33. * and reopening the device. Support for this feature may be implemented in a
  34. * future version of this driver.
  35. */
  36. static int v_midi_open (int dev, int mode,
  37. void (*input) (int dev, unsigned char data),
  38. void (*output) (int dev)
  39. )
  40. {
  41. vmidi_devc *devc = midi_devs[dev]->devc;
  42. unsigned long flags;
  43. if (devc == NULL)
  44. return -(ENXIO);
  45. spin_lock_irqsave(&devc->lock,flags);
  46. if (devc->opened)
  47. {
  48. spin_unlock_irqrestore(&devc->lock,flags);
  49. return -(EBUSY);
  50. }
  51. devc->opened = 1;
  52. spin_unlock_irqrestore(&devc->lock,flags);
  53. devc->intr_active = 1;
  54. if (mode & OPEN_READ)
  55. {
  56. devc->input_opened = 1;
  57. devc->midi_input_intr = input;
  58. }
  59. return 0;
  60. }
  61. static void v_midi_close (int dev)
  62. {
  63. vmidi_devc *devc = midi_devs[dev]->devc;
  64. unsigned long flags;
  65. if (devc == NULL)
  66. return;
  67. spin_lock_irqsave(&devc->lock,flags);
  68. devc->intr_active = 0;
  69. devc->input_opened = 0;
  70. devc->opened = 0;
  71. spin_unlock_irqrestore(&devc->lock,flags);
  72. }
  73. static int v_midi_out (int dev, unsigned char midi_byte)
  74. {
  75. vmidi_devc *devc = midi_devs[dev]->devc;
  76. vmidi_devc *pdevc;
  77. if (devc == NULL)
  78. return -ENXIO;
  79. pdevc = midi_devs[devc->pair_mididev]->devc;
  80. if (pdevc->input_opened > 0){
  81. if (MIDIbuf_avail(pdevc->my_mididev) > 500)
  82. return 0;
  83. pdevc->midi_input_intr (pdevc->my_mididev, midi_byte);
  84. }
  85. return 1;
  86. }
  87. static inline int v_midi_start_read (int dev)
  88. {
  89. return 0;
  90. }
  91. static int v_midi_end_read (int dev)
  92. {
  93. vmidi_devc *devc = midi_devs[dev]->devc;
  94. if (devc == NULL)
  95. return -ENXIO;
  96. devc->intr_active = 0;
  97. return 0;
  98. }
  99. /* why -EPERM and not -EINVAL?? */
  100. static inline int v_midi_ioctl (int dev, unsigned cmd, void __user *arg)
  101. {
  102. return -EPERM;
  103. }
  104. #define MIDI_SYNTH_NAME "Loopback MIDI"
  105. #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
  106. #include "midi_synth.h"
  107. static struct midi_operations v_midi_operations =
  108. {
  109. .owner = THIS_MODULE,
  110. .info = {"Loopback MIDI Port 1", 0, 0, SNDCARD_VMIDI},
  111. .converter = &std_midi_synth,
  112. .in_info = {0},
  113. .open = v_midi_open,
  114. .close = v_midi_close,
  115. .ioctl = v_midi_ioctl,
  116. .outputc = v_midi_out,
  117. .start_read = v_midi_start_read,
  118. .end_read = v_midi_end_read,
  119. };
  120. static struct midi_operations v_midi_operations2 =
  121. {
  122. .owner = THIS_MODULE,
  123. .info = {"Loopback MIDI Port 2", 0, 0, SNDCARD_VMIDI},
  124. .converter = &std_midi_synth,
  125. .in_info = {0},
  126. .open = v_midi_open,
  127. .close = v_midi_close,
  128. .ioctl = v_midi_ioctl,
  129. .outputc = v_midi_out,
  130. .start_read = v_midi_start_read,
  131. .end_read = v_midi_end_read,
  132. };
  133. /*
  134. * We kmalloc just one of these - it makes life simpler and the code
  135. * cleaner and the memory handling far more efficient
  136. */
  137. struct vmidi_memory
  138. {
  139. /* Must be first */
  140. struct midi_operations m_ops[2];
  141. struct synth_operations s_ops[2];
  142. struct vmidi_devc v_ops[2];
  143. };
  144. static void __init attach_v_midi (struct address_info *hw_config)
  145. {
  146. struct vmidi_memory *m;
  147. /* printk("Attaching v_midi device.....\n"); */
  148. midi1 = sound_alloc_mididev();
  149. if (midi1 == -1)
  150. {
  151. printk(KERN_ERR "v_midi: Too many midi devices detected\n");
  152. return;
  153. }
  154. m = kmalloc(sizeof(struct vmidi_memory), GFP_KERNEL);
  155. if (m == NULL)
  156. {
  157. printk(KERN_WARNING "Loopback MIDI: Failed to allocate memory\n");
  158. sound_unload_mididev(midi1);
  159. return;
  160. }
  161. midi_mem = m;
  162. midi_devs[midi1] = &m->m_ops[0];
  163. midi2 = sound_alloc_mididev();
  164. if (midi2 == -1)
  165. {
  166. printk (KERN_ERR "v_midi: Too many midi devices detected\n");
  167. kfree(m);
  168. sound_unload_mididev(midi1);
  169. return;
  170. }
  171. midi_devs[midi2] = &m->m_ops[1];
  172. /* printk("VMIDI1: %d VMIDI2: %d\n",midi1,midi2); */
  173. /* for MIDI-1 */
  174. v_devc[0] = &m->v_ops[0];
  175. memcpy ((char *) midi_devs[midi1], (char *) &v_midi_operations,
  176. sizeof (struct midi_operations));
  177. v_devc[0]->my_mididev = midi1;
  178. v_devc[0]->pair_mididev = midi2;
  179. v_devc[0]->opened = v_devc[0]->input_opened = 0;
  180. v_devc[0]->intr_active = 0;
  181. v_devc[0]->midi_input_intr = NULL;
  182. spin_lock_init(&v_devc[0]->lock);
  183. midi_devs[midi1]->devc = v_devc[0];
  184. midi_devs[midi1]->converter = &m->s_ops[0];
  185. std_midi_synth.midi_dev = midi1;
  186. memcpy ((char *) midi_devs[midi1]->converter, (char *) &std_midi_synth,
  187. sizeof (struct synth_operations));
  188. midi_devs[midi1]->converter->id = "V_MIDI 1";
  189. /* for MIDI-2 */
  190. v_devc[1] = &m->v_ops[1];
  191. memcpy ((char *) midi_devs[midi2], (char *) &v_midi_operations2,
  192. sizeof (struct midi_operations));
  193. v_devc[1]->my_mididev = midi2;
  194. v_devc[1]->pair_mididev = midi1;
  195. v_devc[1]->opened = v_devc[1]->input_opened = 0;
  196. v_devc[1]->intr_active = 0;
  197. v_devc[1]->midi_input_intr = NULL;
  198. spin_lock_init(&v_devc[1]->lock);
  199. midi_devs[midi2]->devc = v_devc[1];
  200. midi_devs[midi2]->converter = &m->s_ops[1];
  201. std_midi_synth.midi_dev = midi2;
  202. memcpy ((char *) midi_devs[midi2]->converter, (char *) &std_midi_synth,
  203. sizeof (struct synth_operations));
  204. midi_devs[midi2]->converter->id = "V_MIDI 2";
  205. sequencer_init();
  206. /* printk("Attached v_midi device\n"); */
  207. }
  208. static inline int __init probe_v_midi(struct address_info *hw_config)
  209. {
  210. return(1); /* always OK */
  211. }
  212. static void __exit unload_v_midi(struct address_info *hw_config)
  213. {
  214. sound_unload_mididev(midi1);
  215. sound_unload_mididev(midi2);
  216. kfree(midi_mem);
  217. }
  218. static struct address_info cfg; /* dummy */
  219. static int __init init_vmidi(void)
  220. {
  221. printk("MIDI Loopback device driver\n");
  222. if (!probe_v_midi(&cfg))
  223. return -ENODEV;
  224. attach_v_midi(&cfg);
  225. return 0;
  226. }
  227. static void __exit cleanup_vmidi(void)
  228. {
  229. unload_v_midi(&cfg);
  230. }
  231. module_init(init_vmidi);
  232. module_exit(cleanup_vmidi);
  233. MODULE_LICENSE("GPL");