1 /*
2 * sound/gus2_midi.c
3 *
4 * The low level driver for the GUS 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 * Changes:
14 * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
15 * Added __init to gus_midi_init()
16 */
17
18 #include <linux/init.h>
19 #include "sound_config.h"
20
21 #include "gus.h"
22 #include "gus_hw.h"
23
24 static int midi_busy = 0, input_opened = 0;
25 static int my_dev;
26 static int output_used = 0;
27 static volatile unsigned char gus_midi_control;
28
29 static void (*midi_input_intr) (int dev, unsigned char data);
30
31 static unsigned char tmp_queue[256];
32 extern int gus_pnp_flag;
33 static volatile int qlen;
34 static volatile unsigned char qhead, qtail;
35 extern int gus_base, gus_irq, gus_dma;
36 extern int *gus_osp;
37
GUS_MIDI_STATUS(void)38 static int GUS_MIDI_STATUS(void)
39 {
40 return inb(u_MidiStatus);
41 }
42
gus_midi_open(int dev,int mode,void (* input)(int dev,unsigned char data),void (* output)(int dev))43 static int gus_midi_open(int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev))
44 {
45 if (midi_busy)
46 {
47 /* printk("GUS: Midi busy\n");*/
48 return -EBUSY;
49 }
50 outb((MIDI_RESET), u_MidiControl);
51 gus_delay();
52
53 gus_midi_control = 0;
54 input_opened = 0;
55
56 if (mode == OPEN_READ || mode == OPEN_READWRITE)
57 if (!gus_pnp_flag)
58 {
59 gus_midi_control |= MIDI_ENABLE_RCV;
60 input_opened = 1;
61 }
62 outb((gus_midi_control), u_MidiControl); /* Enable */
63
64 midi_busy = 1;
65 qlen = qhead = qtail = output_used = 0;
66 midi_input_intr = input;
67
68 return 0;
69 }
70
dump_to_midi(unsigned char midi_byte)71 static int dump_to_midi(unsigned char midi_byte)
72 {
73 unsigned long flags;
74 int ok = 0;
75
76 output_used = 1;
77
78 save_flags(flags);
79 cli();
80
81 if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY)
82 {
83 ok = 1;
84 outb((midi_byte), u_MidiData);
85 }
86 else
87 {
88 /*
89 * Enable Midi xmit interrupts (again)
90 */
91 gus_midi_control |= MIDI_ENABLE_XMIT;
92 outb((gus_midi_control), u_MidiControl);
93 }
94
95 restore_flags(flags);
96 return ok;
97 }
98
gus_midi_close(int dev)99 static void gus_midi_close(int dev)
100 {
101 /*
102 * Reset FIFO pointers, disable intrs
103 */
104
105 outb((MIDI_RESET), u_MidiControl);
106 midi_busy = 0;
107 }
108
gus_midi_out(int dev,unsigned char midi_byte)109 static int gus_midi_out(int dev, unsigned char midi_byte)
110 {
111 unsigned long flags;
112
113 /*
114 * Drain the local queue first
115 */
116
117 save_flags(flags);
118 cli();
119
120 while (qlen && dump_to_midi(tmp_queue[qhead]))
121 {
122 qlen--;
123 qhead++;
124 }
125 restore_flags(flags);
126
127 /*
128 * Output the byte if the local queue is empty.
129 */
130
131 if (!qlen)
132 if (dump_to_midi(midi_byte))
133 return 1; /*
134 * OK
135 */
136
137 /*
138 * Put to the local queue
139 */
140
141 if (qlen >= 256)
142 return 0; /*
143 * Local queue full
144 */
145 save_flags(flags);
146 cli();
147
148 tmp_queue[qtail] = midi_byte;
149 qlen++;
150 qtail++;
151
152 restore_flags(flags);
153 return 1;
154 }
155
gus_midi_start_read(int dev)156 static int gus_midi_start_read(int dev)
157 {
158 return 0;
159 }
160
gus_midi_end_read(int dev)161 static int gus_midi_end_read(int dev)
162 {
163 return 0;
164 }
165
gus_midi_kick(int dev)166 static void gus_midi_kick(int dev)
167 {
168 }
169
gus_midi_buffer_status(int dev)170 static int gus_midi_buffer_status(int dev)
171 {
172 unsigned long flags;
173
174 if (!output_used)
175 return 0;
176
177 save_flags(flags);
178 cli();
179
180 if (qlen && dump_to_midi(tmp_queue[qhead]))
181 {
182 qlen--;
183 qhead++;
184 }
185 restore_flags(flags);
186 return (qlen > 0) || !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
187 }
188
189 #define MIDI_SYNTH_NAME "Gravis Ultrasound Midi"
190 #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
191 #include "midi_synth.h"
192
193 static struct midi_operations gus_midi_operations =
194 {
195 owner: THIS_MODULE,
196 info: {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
197 converter: &std_midi_synth,
198 in_info: {0},
199 open: gus_midi_open,
200 close: gus_midi_close,
201 outputc: gus_midi_out,
202 start_read: gus_midi_start_read,
203 end_read: gus_midi_end_read,
204 kick: gus_midi_kick,
205 buffer_status: gus_midi_buffer_status,
206 };
207
gus_midi_init(struct address_info * hw_config)208 void __init gus_midi_init(struct address_info *hw_config)
209 {
210 int dev = sound_alloc_mididev();
211
212 if (dev == -1)
213 {
214 printk(KERN_INFO "gus_midi: Too many midi devices detected\n");
215 return;
216 }
217 outb((MIDI_RESET), u_MidiControl);
218
219 std_midi_synth.midi_dev = my_dev = dev;
220 hw_config->slots[2] = dev;
221 midi_devs[dev] = &gus_midi_operations;
222 sequencer_init();
223 return;
224 }
225
gus_midi_interrupt(int dummy)226 void gus_midi_interrupt(int dummy)
227 {
228 volatile unsigned char stat, data;
229 unsigned long flags;
230 int timeout = 10;
231
232 save_flags(flags);
233 cli();
234
235 while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY))
236 {
237 if (stat & MIDI_RCV_FULL)
238 {
239 data = inb(u_MidiData);
240 if (input_opened)
241 midi_input_intr(my_dev, data);
242 }
243 if (stat & MIDI_XMIT_EMPTY)
244 {
245 while (qlen && dump_to_midi(tmp_queue[qhead]))
246 {
247 qlen--;
248 qhead++;
249 }
250 if (!qlen)
251 {
252 /*
253 * Disable Midi output interrupts, since no data in the buffer
254 */
255 gus_midi_control &= ~MIDI_ENABLE_XMIT;
256 outb((gus_midi_control), u_MidiControl);
257 outb((gus_midi_control), u_MidiControl);
258 }
259 }
260 }
261 restore_flags(flags);
262 }
263