Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / i386 / isa / sound / maui.c
1 /*
2  * sound/maui.c
3  * 
4  * The low level driver for Turtle Beach Maui and Tropez.
5  * 
6  * Copyright by Hannu Savolainen 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 #define USE_SEQ_MACROS
31 #define USE_SIMPLE_MACROS
32
33 #include <i386/isa/sound/sound_config.h>
34
35
36 #if defined(CONFIG_MAUI)
37
38 static int      maui_base = 0x330;
39
40 static volatile int irq_ok = 0;
41 static sound_os_info *maui_osp;
42
43 #define HOST_DATA_PORT  (maui_base + 2)
44 #define HOST_STAT_PORT  (maui_base + 3)
45 #define HOST_CTRL_PORT  (maui_base + 3)
46
47 #define STAT_TX_INTR    0x40
48 #define STAT_TX_AVAIL   0x20
49 #define STAT_TX_IENA    0x10
50 #define STAT_RX_INTR    0x04
51 #define STAT_RX_AVAIL   0x02
52 #define STAT_RX_IENA    0x01
53
54 static int      (*orig_load_patch) (int dev, int format, snd_rw_buf * addr,
55                                  int offs, int count, int pmgr_flag) = NULL;
56
57 static int
58 maui_read(void)
59 {
60     int             timeout;
61
62     for (timeout = 0; timeout < 1000000; timeout++)
63         if (inb(HOST_STAT_PORT) & STAT_RX_AVAIL)
64             return inb(HOST_DATA_PORT);
65
66     printf("Maui: Receive timeout\n");
67
68     return -1;
69 }
70
71 static int
72 maui_write(u_char data)
73 {
74     int             timeout;
75
76     for (timeout = 0; timeout < 10000000; timeout++) {
77         if (inb(HOST_STAT_PORT) & STAT_TX_AVAIL) {
78             outb(HOST_DATA_PORT, data);
79             return 1;
80         }
81     }
82
83     printf("Maui: Write timeout\n");
84
85     return 0;
86 }
87
88 void
89 mauiintr(int irq)
90 {
91     irq_ok = 1;
92 }
93
94
95 int
96 maui_load_patch(int dev, int format, snd_rw_buf * addr,
97                 int offs, int count, int pmgr_flag)
98 {
99
100     struct sysex_info header;
101     u_long   left, src_offs;
102     int             hdr_size = (u_long) &header.data[0] - (u_long) &header;
103     int             i;
104
105     if (format == SYSEX_PATCH)  /* Handled by midi_synth.c */
106         return orig_load_patch(dev, format, addr, offs, count, pmgr_flag);
107
108     if (format != MAUI_PATCH) {
109         printf("Maui: Unknown patch format\n");
110     }
111     if (count < hdr_size) {
112         printf("Maui error: Patch header too short\n");
113         return -(EINVAL);
114     }
115     count -= hdr_size;
116
117     /*
118      * Copy the header from user space but ignore the first bytes which
119      * have been transferred already.
120      */
121
122     if (uiomove(&((char *) &header)[offs], hdr_size - offs, addr)) {
123         printf("sb: Bad copyin()!\n");
124     };
125
126     if (count < header.len) {
127         printf("Maui warning: Host command record too short (%d<%d)\n",
128                count, (int) header.len);
129         header.len = count;
130     }
131     left = header.len;
132     src_offs = 0;
133
134     for (i = 0; i < left; i++) {
135         u_char   data;
136         uiomove((char *) &(data), 1, addr);
137         if (i == 0 && !(data & 0x80))
138             return -(EINVAL);
139
140         if (maui_write(data) == -1)
141             return -(EIO);
142     }
143
144     if ((i = maui_read()) != 0x80) {
145         if (i != -1)
146             printf("Maui: Error status %02x\n", i);
147
148         return -(EIO);
149     }
150     return 0;
151 }
152
153 int
154 probe_maui(struct address_info * hw_config)
155 {
156     int             i;
157     int             tmp1, tmp2;
158
159     maui_base = hw_config->io_base;
160     maui_osp = hw_config->osp;
161
162     if (snd_set_irq_handler(hw_config->irq, mauiintr, maui_osp) < 0)
163         return 0;
164
165     if (!maui_write(0xCF)) {/* Report hardware version */
166         /* snd_release_irq(hw_config->irq); */
167         return 0;
168     }
169     if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) {
170         /* snd_release_irq(hw_config->irq); */
171         return 0;
172     }
173     printf("WaveFront hardware version %d.%d\n", tmp1, tmp2);
174
175     if (!maui_write(0x9F))      /* Report firmware version */
176         return 0;
177     if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
178         return 0;
179     printf("WaveFront firmware version %d.%d\n", tmp1, tmp2);
180
181     if (!maui_write(0x85))      /* Report free DRAM */
182         return 0;
183     tmp1 = 0;
184     for (i = 0; i < 4; i++) {
185         tmp1 |= maui_read() << (7 * i);
186     }
187     printf("Available DRAM %dk\n", tmp1 / 1024);
188
189     for (i = 0; i < 1000; i++)
190         if (probe_mpu401(hw_config))
191             break;
192
193     return probe_mpu401(hw_config);
194 }
195
196 void
197 attach_maui(struct address_info * hw_config)
198 {
199     int             this_dev = num_midis;
200
201     conf_printf("Maui", hw_config);
202
203     hw_config->irq *= -1;
204     attach_mpu401(hw_config);
205
206     if (num_midis > this_dev) { /* The MPU401 driver installed itself */
207         struct synth_operations *synth;
208
209         /*
210          * Intercept patch loading calls so that they canbe handled
211          * by the Maui driver.
212          */
213
214         synth = midi_devs[this_dev]->converter;
215
216         if (synth != NULL) {
217             orig_load_patch = synth->load_patch;
218             synth->load_patch = &maui_load_patch;
219         } else
220             printf("Maui: Can't install patch loader\n");
221     }
222     return;
223 }
224
225 #endif