Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / sound / isa / i386 / gus / gus_midi.c
1 /*
2  * sound/gus2_midi.c
3  * 
4  * The low level driver for the GUS Midi Interface.
5  * 
6  * Copyright by Hannu Savolainen 1993
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met: 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer. 2.
12  * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  * 
28  */
29
30 #include <i386/isa/sound/sound_config.h>
31
32 #if defined(CONFIG_GUS) && defined(CONFIG_MIDI)
33 #include <i386/isa/sound/gus_hw.h>
34
35 static int      midi_busy = 0, input_opened = 0;
36 static int      my_dev;
37 static int      output_used = 0;
38 static volatile unsigned char gus_midi_control;
39
40 static void     (*midi_input_intr) (int dev, unsigned char data);
41
42 static unsigned char tmp_queue[256];
43 static volatile int qlen;
44 static volatile unsigned char qhead, qtail;
45 extern int      gus_base, gus_irq, gus_dma;
46 extern sound_os_info *gus_osp;
47
48 #define GUS_MIDI_STATUS()       inb( u_MidiStatus)
49
50 static int
51 gus_midi_open(int dev, int mode,
52               void (*input) (int dev, unsigned char data),
53               void (*output) (int dev)
54 )
55 {
56
57         if (midi_busy) {
58                 printf("GUS: Midi busy\n");
59                 return -(EBUSY);
60         }
61         outb(u_MidiControl, MIDI_RESET);
62         gus_delay();
63
64         gus_midi_control = 0;
65         input_opened = 0;
66
67         if (mode == OPEN_READ || mode == OPEN_READWRITE) {
68                 gus_midi_control |= MIDI_ENABLE_RCV;
69                 input_opened = 1;
70         }
71         if (mode == OPEN_WRITE || mode == OPEN_READWRITE) {
72                 gus_midi_control |= MIDI_ENABLE_XMIT;
73         }
74         outb(u_MidiControl, gus_midi_control);  /* Enable */
75
76         midi_busy = 1;
77         qlen = qhead = qtail = output_used = 0;
78         midi_input_intr = input;
79
80         return 0;
81 }
82
83 static int
84 dump_to_midi(unsigned char midi_byte)
85 {
86         unsigned long   flags;
87         int             ok = 0;
88
89         output_used = 1;
90
91         flags = splhigh();
92
93         if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY) {
94                 ok = 1;
95                 outb(u_MidiData, midi_byte);
96         } else {
97                 /*
98                  * Enable Midi xmit interrupts (again)
99                  */
100                 gus_midi_control |= MIDI_ENABLE_XMIT;
101                 outb(u_MidiControl, gus_midi_control);
102         }
103
104         splx(flags);
105         return ok;
106 }
107
108 static void
109 gus_midi_close(int dev)
110 {
111         /*
112          * Reset FIFO pointers, disable intrs
113          */
114
115         outb(u_MidiControl, MIDI_RESET);
116         midi_busy = 0;
117 }
118
119 static int
120 gus_midi_out(int dev, unsigned char midi_byte)
121 {
122
123         unsigned long   flags;
124
125         /*
126          * Drain the local queue first
127          */
128
129         flags = splhigh();
130
131         while (qlen && dump_to_midi(tmp_queue[qhead])) {
132                 qlen--;
133                 qhead++;
134         }
135
136         splx(flags);
137
138         /*
139          * Output the byte if the local queue is empty.
140          */
141
142         if (!qlen)
143                 if (dump_to_midi(midi_byte))
144                         return 1;       /* OK */
145
146         /*
147          * Put to the local queue
148          */
149
150         if (qlen >= 256)
151                 return 0;       /* Local queue full */
152
153         flags = splhigh();
154
155         tmp_queue[qtail] = midi_byte;
156         qlen++;
157         qtail++;
158
159         splx(flags);
160
161         return 1;
162 }
163
164 static int
165 gus_midi_start_read(int dev)
166 {
167         return 0;
168 }
169
170 static int
171 gus_midi_end_read(int dev)
172 {
173         return 0;
174 }
175
176 static int
177 gus_midi_ioctl(int dev, unsigned cmd, ioctl_arg arg)
178 {
179         return -(EINVAL);
180 }
181
182 static void
183 gus_midi_kick(int dev)
184 {
185 }
186
187 static int
188 gus_midi_buffer_status(int dev)
189 {
190         unsigned long   flags;
191
192         if (!output_used)
193                 return 0;
194
195         flags = splhigh();
196
197         if (qlen && dump_to_midi(tmp_queue[qhead])) {
198                 qlen--;
199                 qhead++;
200         }
201         splx(flags);
202
203         return (qlen > 0) | !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
204 }
205
206 #define MIDI_SYNTH_NAME "Gravis Ultrasound Midi"
207 #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
208 #include <i386/isa/sound/midi_synth.h>
209
210 static struct midi_operations gus_midi_operations =
211 {
212         {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
213         &std_midi_synth,
214         {0},
215         gus_midi_open,
216         gus_midi_close,
217         gus_midi_ioctl,
218         gus_midi_out,
219         gus_midi_start_read,
220         gus_midi_end_read,
221         gus_midi_kick,
222         NULL,                   /* command */
223         gus_midi_buffer_status,
224         NULL
225 };
226
227 void
228 gus_midi_init()
229 {
230         if (num_midis >= MAX_MIDI_DEV) {
231                 printf("Sound: Too many midi devices detected\n");
232                 return;
233         }
234         outb(u_MidiControl, MIDI_RESET);
235
236         std_midi_synth.midi_dev = my_dev = num_midis;
237         midi_devs[num_midis++] = &gus_midi_operations;
238         return;
239 }
240
241 void
242 gus_midi_interrupt(int dummy)
243 {
244         unsigned char   stat, data;
245         unsigned long   flags;
246
247         flags = splhigh();
248
249         stat = GUS_MIDI_STATUS();
250
251         if (stat & MIDI_RCV_FULL) {
252                 data = inb(u_MidiData);
253                 if (input_opened)
254                         midi_input_intr(my_dev, data);
255         }
256         if (stat & MIDI_XMIT_EMPTY) {
257                 while (qlen && dump_to_midi(tmp_queue[qhead])) {
258                         qlen--;
259                         qhead++;
260                 }
261
262                 if (!qlen) {
263                         /*
264                          * Disable Midi output interrupts, since no data in
265                          * the buffer
266                          */
267                         gus_midi_control &= ~MIDI_ENABLE_XMIT;
268                         outb(u_MidiControl, gus_midi_control);
269                 }
270         }
271         splx(flags);
272 }
273
274 #endif