kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / dev / sound / isa / i386 / sbmidi / sb16_midi.c
1 /*
2  * sound/sb16_midi.c
3  * 
4  * The low level driver for the MPU-401 UART emulation of the SB16.
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  * $FreeBSD: src/sys/i386/isa/sound/sb16_midi.c,v 1.20 1999/12/27 04:37:18 tanimura Exp $
29  * $DragonFly: src/sys/dev/sound/isa/i386/sbmidi/Attic/sb16_midi.c,v 1.3 2003/08/07 21:17:12 dillon Exp $
30  *
31  */
32
33 #include "use_sb.h"
34
35 #include <i386/isa/sound/sound_config.h>
36 #include <i386/isa/sound/sbcard.h>
37
38 #if defined(CONFIG_SB) && defined(CONFIG_SB16) && defined(CONFIG_MIDI)
39
40 #ifdef PC98
41 #define DATAPORT   (sb16midi_base)
42 #define COMDPORT   (sb16midi_base+0x100)
43 #define STATPORT   (sb16midi_base+0x100)
44 #else
45 #define DATAPORT   (sb16midi_base)
46 #define COMDPORT   (sb16midi_base+1)
47 #define STATPORT   (sb16midi_base+1)
48 #endif
49
50 extern sound_os_info *sb_osp;
51
52 #define sb16midi_status()               inb( STATPORT)
53 #define input_avail()           (!(sb16midi_status()&INPUT_AVAIL))
54 #define output_ready()          (!(sb16midi_status()&OUTPUT_READY))
55 #define sb16midi_cmd(cmd)               outb( COMDPORT,  cmd)
56 #define sb16midi_read()         inb( DATAPORT)
57 #define sb16midi_write(byte)    outb( DATAPORT,  byte)
58
59 #define OUTPUT_READY    0x40
60 #define INPUT_AVAIL     0x80
61 #define MPU_ACK         0xFE
62 #define MPU_RESET       0xFF
63 #define UART_MODE_ON    0x3F
64
65 static int      sb16midi_opened = 0;
66 #ifdef PC98
67 static int      sb16midi_base = 0x80d2;
68 #else
69 static int      sb16midi_base = 0x330;
70 #endif
71 static int      sb16midi_detected = 0;
72 static int      my_dev;
73 extern int      sbc_base;
74
75 static int      reset_sb16midi(void);
76 static void     (*midi_input_intr) (int dev, u_char data);
77 static volatile u_char input_byte;
78
79 static void
80 sb16midi_input_loop(void)
81 {
82         while (input_avail()) {
83                 u_char   c = sb16midi_read();
84
85                 if (c == MPU_ACK)
86                         input_byte = c;
87                 else if (sb16midi_opened & OPEN_READ && midi_input_intr)
88                         midi_input_intr(my_dev, c);
89         }
90 }
91
92 void
93 sb16midiintr(int unit)
94 {
95         if (input_avail())
96                 sb16midi_input_loop();
97 }
98
99 static int
100 sb16midi_open(int dev, int mode,
101               void (*input) (int dev, u_char data),
102               void (*output) (int dev)
103 )
104 {
105         if (sb16midi_opened) {
106                 return -(EBUSY);
107         }
108         sb16midi_input_loop();
109
110         midi_input_intr = input;
111         sb16midi_opened = mode;
112
113         return 0;
114 }
115
116 static void
117 sb16midi_close(int dev)
118 {
119         sb16midi_opened = 0;
120 }
121
122 static int
123 sb16midi_out(int dev, u_char midi_byte)
124 {
125         int             timeout;
126         u_long   flags;
127
128         /*
129          * Test for input since pending input seems to block the output.
130          */
131
132         flags = splhigh();
133
134         if (input_avail())
135                 sb16midi_input_loop();
136
137         splx(flags);
138
139         /*
140          * Sometimes it takes about 13000 loops before the output becomes
141          * ready (After reset). Normally it takes just about 10 loops.
142          */
143
144         for (timeout = 30000; timeout > 0 && !output_ready(); timeout--);       /* Wait */
145
146         if (!output_ready()) {
147                 printf("MPU-401: Timeout\n");
148                 return 0;
149         }
150         sb16midi_write(midi_byte);
151         return 1;
152 }
153
154 static int
155 sb16midi_start_read(int dev)
156 {
157         return 0;
158 }
159
160 static int
161 sb16midi_end_read(int dev)
162 {
163         return 0;
164 }
165
166 static int
167 sb16midi_ioctl(int dev, u_int cmd, ioctl_arg arg)
168 {
169         return -(EINVAL);
170 }
171
172 static void
173 sb16midi_kick(int dev)
174 {
175 }
176
177 static int
178 sb16midi_buffer_status(int dev)
179 {
180         return 0;               /* No data in buffers */
181 }
182
183 #define MIDI_SYNTH_NAME "SoundBlaster 16 Midi"
184 #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
185 #include <i386/isa/sound/midi_synth.h>
186
187 static struct midi_operations sb16midi_operations =
188 {
189         {"SoundBlaster 16 Midi", 0, 0, SNDCARD_SB16MIDI},
190         &std_midi_synth,
191         {0},
192         sb16midi_open,
193         sb16midi_close,
194         sb16midi_ioctl,
195         sb16midi_out,
196         sb16midi_start_read,
197         sb16midi_end_read,
198         sb16midi_kick,
199         NULL,
200         sb16midi_buffer_status,
201         NULL
202 };
203
204
205 void
206 attach_sb16midi(struct address_info * hw_config)
207 {
208         int             ok, timeout;
209         u_long   flags;
210
211         sb16midi_base = hw_config->io_base;
212
213         if (!sb16midi_detected)
214                 return;
215
216         flags = splhigh();
217         for (timeout = 30000; timeout < 0 && !output_ready(); timeout--);       /* Wait */
218         input_byte = 0;
219         sb16midi_cmd(UART_MODE_ON);
220
221         ok = 0;
222         for (timeout = 50000; timeout > 0 && !ok; timeout--)
223                 if (input_byte == MPU_ACK)
224                         ok = 1;
225                 else if (input_avail())
226                         if (sb16midi_read() == MPU_ACK)
227                                 ok = 1;
228
229         splx(flags);
230
231         if (num_midis >= MAX_MIDI_DEV) {
232                 printf("Sound: Too many midi devices detected\n");
233                 return;
234         }
235         
236         conf_printf("SoundBlaster MPU-401", hw_config);
237         std_midi_synth.midi_dev = my_dev = num_midis;
238         midi_devs[num_midis++] = &sb16midi_operations;
239         return;
240 }
241
242 static int
243 reset_sb16midi(void)
244 {
245         int             ok, timeout, n;
246
247         /*
248          * Send the RESET command. Try again if no success at the first time.
249          */
250
251         if (inb(STATPORT) == 0xff)
252                 return 0;
253
254         ok = 0;
255
256         /* flags = splhigh(); */
257
258         for (n = 0; n < 2 && !ok; n++) {
259                 for (timeout = 30000; timeout < 0 && !output_ready(); timeout--);       /* Wait */
260                 input_byte = 0;
261                 sb16midi_cmd(MPU_RESET);        /* Send MPU-401 RESET Command */
262
263                 /*
264                  * Wait at least 25 msec. This method is not accurate so
265                  * let's make the loop bit longer. Cannot sleep since this is
266                  * called during boot.
267                  */
268
269                 for (timeout = 50000; timeout > 0 && !ok; timeout--)
270                         if (input_byte == MPU_ACK)      /* Interrupt */
271                                 ok = 1;
272                         else if (input_avail())
273                                 if (sb16midi_read() == MPU_ACK)
274                                         ok = 1;
275
276         }
277
278         sb16midi_opened = 0;
279         if (ok)
280                 sb16midi_input_loop();  /* Flush input before enabling
281                                          * interrupts */
282
283         /* splx(flags); */
284
285         return ok;
286 }
287
288
289 int
290 probe_sb16midi(struct address_info * hw_config)
291 {
292         int             ok = 0;
293         struct address_info *sb_config;
294
295         if (sbc_major < 4)
296                 return 0;       /* Not a SB16 */
297
298         if (!(sb_config = sound_getconf(SNDCARD_SB))) {
299           printf("SB16 Error: Plain SB not configured\n");
300           return 0;
301         }
302
303         sb16midi_base = hw_config->io_base;
304
305         ok = reset_sb16midi();
306
307         sb16midi_detected = ok;
308         return ok;
309 }
310
311 #endif
312