v_midi.c 6.3 KB

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