Use M_INTWAIT, not M_NOWAIT. We don't really support fast interrupt
[dragonfly.git] / sys / i386 / isa / sound / mad16_sb_midi.c
1 /*
2  * sound/mad16_sb_midi.c
3  * 
4  * The low level driver for MAD16 SoundBlaster-DS-chip-based MIDI.
5  * 
6  * Copyright by Hannu Savolainen 1993, Aaron Ucko 1995
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_MAD16) && defined(CONFIG_MIDI)
33
34 #define sbc_base mad16_sb_base
35 #include <i386/isa/sound/sb_card.h>
36
37 static int      input_opened = 0;
38 static int      my_dev;
39 static int      mad16_sb_base = 0x220;
40 static int      mad16_sb_irq = 0;
41 static int      mad16_sb_dsp_ok = 0;
42 static sound_os_info *midi_osp;
43
44 int             mad16_sb_midi_mode = NORMAL_MIDI;
45 int             mad16_sb_midi_busy = 0;
46
47 int             mad16_sb_duplex_midi = 0;
48 volatile int    mad16_sb_intr_active = 0;
49
50 void            (*midi_input_intr) (int dev, unsigned char data);
51
52 static void     mad16_sb_midi_init(int model);
53
54 static int
55 mad16_sb_dsp_command(unsigned char val)
56 {
57         int             i;
58         unsigned long   limit;
59
60         limit = get_time() + hz / 10;   /* The timeout is 0.1 secods */
61
62         /*
63          * Note! the i<500000 is an emergency exit. The
64          * mad16_sb_dsp_command() is sometimes called while interrupts are
65          * disabled. This means that the timer is disabled also. However the
66          * timeout situation is a abnormal condition. Normally the DSP should
67          * be ready to accept commands after just couple of loops.
68          */
69
70         for (i = 0; i < 500000 && get_time() < limit; i++) {
71                 if ((inb(DSP_STATUS) & 0x80) == 0) {
72                         outb(DSP_COMMAND, val);
73                         return 1;
74                 }
75         }
76
77         printf("MAD16 (SBP mode): DSP Command(%x) Timeout.\n", val);
78         printf("IRQ conflict???\n");
79         return 0;
80 }
81
82 void
83 mad16_sbintr(int irq)
84 {
85         int             status;
86
87         unsigned long   flags;
88         unsigned char   data;
89
90         status = inb(DSP_DATA_AVAIL);   /* Clear interrupt */
91
92         flags = splhigh();
93
94         data = inb(DSP_READ);
95         if (input_opened)
96                 midi_input_intr(my_dev, data);
97
98         splx(flags);
99 }
100
101 static int
102 mad16_sb_reset_dsp(void)
103 {
104         int             loopc;
105
106         outb(DSP_RESET, 1);
107         DELAY(10);
108         outb(DSP_RESET, 0);
109         DELAY(30);
110
111         for (loopc = 0; loopc < 100 && !(inb(DSP_DATA_AVAIL) & 0x80); loopc++)
112                 DELAY(10);
113                 /* Wait for data available status */
114
115         if (inb(DSP_READ) != 0xAA)
116                 return 0;       /* Sorry */
117
118         return 1;
119 }
120
121 int
122 mad16_sb_dsp_detect(struct address_info * hw_config)
123 {
124         mad16_sb_base = hw_config->io_base;
125         mad16_sb_irq = hw_config->irq;
126         midi_osp = hw_config->osp;
127
128         if (mad16_sb_dsp_ok)
129                 return 0;       /* Already initialized */
130         if (!mad16_sb_reset_dsp())
131                 return 0;
132
133         return 1;               /* Detected */
134 }
135
136 void
137 mad16_sb_dsp_init(struct address_info * hw_config)
138 /*
139  * this function now just verifies the reported version and calls
140  * mad16_sb_midi_init -- everything else is done elsewhere
141  */
142 {
143
144         midi_osp = hw_config->osp;
145         if (snd_set_irq_handler(mad16_sb_irq, mad16_sbintr, midi_osp) < 0) {
146                 printf("MAD16 SB MIDI: IRQ not free\n");
147                 return;
148         }
149
150         conf_printf("MAD16 MIDI (SB mode)", hw_config);
151         mad16_sb_midi_init(2);
152
153         mad16_sb_dsp_ok = 1;
154         return;
155 }
156
157 static int
158 mad16_sb_midi_open(int dev, int mode,
159                    void (*input) (int dev, unsigned char data),
160                    void (*output) (int dev)
161 )
162 {
163
164         if (!mad16_sb_dsp_ok) {
165                 printf("MAD16_SB Error: MIDI hardware not installed\n");
166                 return -(ENXIO);
167         }
168         if (mad16_sb_midi_busy)
169                 return -(EBUSY);
170
171         if (mode != OPEN_WRITE && !mad16_sb_duplex_midi) {
172                 if (num_midis == 1)
173                         printf("MAD16 (SBP mode): Midi input not currently supported\n");
174                 return -(EPERM);
175         }
176         mad16_sb_midi_mode = NORMAL_MIDI;
177         if (mode != OPEN_WRITE) {
178                 if (mad16_sb_intr_active)
179                         return -(EBUSY);
180                 mad16_sb_midi_mode = UART_MIDI;
181         }
182         if (mad16_sb_midi_mode == UART_MIDI) {
183                 mad16_sb_reset_dsp();
184
185                 if (!mad16_sb_dsp_command(0x35))
186                         return -(EIO);  /* Enter the UART mode */
187                 mad16_sb_intr_active = 1;
188
189                 input_opened = 1;
190                 midi_input_intr = input;
191         }
192         mad16_sb_midi_busy = 1;
193
194         return 0;
195 }
196
197 static void
198 mad16_sb_midi_close(int dev)
199 {
200         if (mad16_sb_midi_mode == UART_MIDI) {
201                 mad16_sb_reset_dsp();   /* The only way to kill the UART mode */
202         }
203         mad16_sb_intr_active = 0;
204         mad16_sb_midi_busy = 0;
205         input_opened = 0;
206 }
207
208 static int
209 mad16_sb_midi_out(int dev, unsigned char midi_byte)
210 {
211         unsigned long   flags;
212
213         if (mad16_sb_midi_mode == NORMAL_MIDI) {
214                 flags = splhigh();
215                 if (mad16_sb_dsp_command(0x38))
216                         mad16_sb_dsp_command(midi_byte);
217                 else
218                         printf("MAD16_SB Error: Unable to send a MIDI byte\n");
219                 splx(flags);
220         } else
221                 mad16_sb_dsp_command(midi_byte);        /* UART write */
222
223         return 1;
224 }
225
226 static int
227 mad16_sb_midi_start_read(int dev)
228 {
229         if (mad16_sb_midi_mode != UART_MIDI) {
230                 printf("MAD16 (SBP mode): MIDI input not implemented.\n");
231                 return -(EPERM);
232         }
233         return 0;
234 }
235
236 static int
237 mad16_sb_midi_end_read(int dev)
238 {
239         if (mad16_sb_midi_mode == UART_MIDI) {
240                 mad16_sb_reset_dsp();
241                 mad16_sb_intr_active = 0;
242         }
243         return 0;
244 }
245
246 static int
247 mad16_sb_midi_ioctl(int dev, unsigned cmd, ioctl_arg arg)
248 {
249         return -(EPERM);
250 }
251
252 #define MIDI_SYNTH_NAME "pseudo-SoundBlaster Midi"
253 #define MIDI_SYNTH_CAPS 0
254 #include <i386/isa/sound/midi_synth.h>
255
256 static struct midi_operations mad16_sb_midi_operations =
257 {
258         {"MAD16 (SBP mode)", 0, 0, SNDCARD_MAD16},
259         &std_midi_synth,
260         {0},
261         mad16_sb_midi_open,
262         mad16_sb_midi_close,
263         mad16_sb_midi_ioctl,
264         mad16_sb_midi_out,
265         mad16_sb_midi_start_read,
266         mad16_sb_midi_end_read,
267         NULL,                   /* Kick */
268         NULL,                   /* command */
269         NULL,                   /* buffer_status */
270         NULL
271 };
272
273 static void
274 mad16_sb_midi_init(int model)
275 {
276         if (num_midis >= MAX_MIDI_DEV) {
277                 printf("Sound: Too many midi devices detected\n");
278                 return;
279         }
280         std_midi_synth.midi_dev = num_midis;
281         my_dev = num_midis;
282         midi_devs[num_midis++] = &mad16_sb_midi_operations;
283 }
284
285 #endif