diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/isa/wavefront |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/isa/wavefront')
-rw-r--r-- | sound/isa/wavefront/Makefile | 9 | ||||
-rw-r--r-- | sound/isa/wavefront/wavefront.c | 716 | ||||
-rw-r--r-- | sound/isa/wavefront/wavefront_fx.c | 1019 | ||||
-rw-r--r-- | sound/isa/wavefront/wavefront_midi.c | 570 | ||||
-rw-r--r-- | sound/isa/wavefront/wavefront_synth.c | 2243 |
5 files changed, 4557 insertions, 0 deletions
diff --git a/sound/isa/wavefront/Makefile b/sound/isa/wavefront/Makefile new file mode 100644 index 000000000000..b4cb28422db0 --- /dev/null +++ b/sound/isa/wavefront/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for ALSA | ||
3 | # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> | ||
4 | # | ||
5 | |||
6 | snd-wavefront-objs := wavefront.o wavefront_fx.o wavefront_synth.o wavefront_midi.o | ||
7 | |||
8 | # Toplevel Module Dependency | ||
9 | obj-$(CONFIG_SND_WAVEFRONT) += snd-wavefront.o | ||
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c new file mode 100644 index 000000000000..79b022070ba3 --- /dev/null +++ b/sound/isa/wavefront/wavefront.c | |||
@@ -0,0 +1,716 @@ | |||
1 | /* | ||
2 | * ALSA card-level driver for Turtle Beach Wavefront cards | ||
3 | * (Maui,Tropez,Tropez+) | ||
4 | * | ||
5 | * Copyright (c) 1997-1999 by Paul Barton-Davis <pbd@op.net> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/pnp.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/initval.h> | ||
30 | #include <sound/opl3.h> | ||
31 | #include <sound/snd_wavefront.h> | ||
32 | |||
33 | MODULE_AUTHOR("Paul Barton-Davis <pbd@op.net>"); | ||
34 | MODULE_DESCRIPTION("Turtle Beach Wavefront"); | ||
35 | MODULE_LICENSE("GPL"); | ||
36 | MODULE_SUPPORTED_DEVICE("{{Turtle Beach,Maui/Tropez/Tropez+}}"); | ||
37 | |||
38 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
39 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
40 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ | ||
41 | static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; | ||
42 | static long cs4232_pcm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
43 | static int cs4232_pcm_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,11,12,15 */ | ||
44 | static long cs4232_mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
45 | static int cs4232_mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 9,11,12,15 */ | ||
46 | static long ics2115_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
47 | static int ics2115_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 2,9,11,12,15 */ | ||
48 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
49 | static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ | ||
50 | static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3,5,6,7 */ | ||
51 | static int use_cs4232_midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; | ||
52 | |||
53 | module_param_array(index, int, NULL, 0444); | ||
54 | MODULE_PARM_DESC(index, "Index value for WaveFront soundcard."); | ||
55 | module_param_array(id, charp, NULL, 0444); | ||
56 | MODULE_PARM_DESC(id, "ID string for WaveFront soundcard."); | ||
57 | module_param_array(enable, bool, NULL, 0444); | ||
58 | MODULE_PARM_DESC(enable, "Enable WaveFront soundcard."); | ||
59 | #ifdef CONFIG_PNP | ||
60 | module_param_array(isapnp, bool, NULL, 0444); | ||
61 | MODULE_PARM_DESC(isapnp, "ISA PnP detection for WaveFront soundcards."); | ||
62 | #endif | ||
63 | module_param_array(cs4232_pcm_port, long, NULL, 0444); | ||
64 | MODULE_PARM_DESC(cs4232_pcm_port, "Port # for CS4232 PCM interface."); | ||
65 | module_param_array(cs4232_pcm_irq, int, NULL, 0444); | ||
66 | MODULE_PARM_DESC(cs4232_pcm_irq, "IRQ # for CS4232 PCM interface."); | ||
67 | module_param_array(dma1, int, NULL, 0444); | ||
68 | MODULE_PARM_DESC(dma1, "DMA1 # for CS4232 PCM interface."); | ||
69 | module_param_array(dma2, int, NULL, 0444); | ||
70 | MODULE_PARM_DESC(dma2, "DMA2 # for CS4232 PCM interface."); | ||
71 | module_param_array(cs4232_mpu_port, long, NULL, 0444); | ||
72 | MODULE_PARM_DESC(cs4232_mpu_port, "port # for CS4232 MPU-401 interface."); | ||
73 | module_param_array(cs4232_mpu_irq, int, NULL, 0444); | ||
74 | MODULE_PARM_DESC(cs4232_mpu_irq, "IRQ # for CS4232 MPU-401 interface."); | ||
75 | module_param_array(ics2115_irq, int, NULL, 0444); | ||
76 | MODULE_PARM_DESC(ics2115_irq, "IRQ # for ICS2115."); | ||
77 | module_param_array(ics2115_port, long, NULL, 0444); | ||
78 | MODULE_PARM_DESC(ics2115_port, "Port # for ICS2115."); | ||
79 | module_param_array(fm_port, long, NULL, 0444); | ||
80 | MODULE_PARM_DESC(fm_port, "FM port #."); | ||
81 | module_param_array(use_cs4232_midi, bool, NULL, 0444); | ||
82 | MODULE_PARM_DESC(use_cs4232_midi, "Use CS4232 MPU-401 interface (inaccessibly located inside your computer)"); | ||
83 | |||
84 | static snd_card_t *snd_wavefront_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; | ||
85 | |||
86 | #ifdef CONFIG_PNP | ||
87 | |||
88 | static struct pnp_card_device_id snd_wavefront_pnpids[] = { | ||
89 | /* Tropez */ | ||
90 | { .id = "CSC7532", .devs = { { "CSC0000" }, { "CSC0010" }, { "PnPb006" }, { "CSC0004" } } }, | ||
91 | /* Tropez+ */ | ||
92 | { .id = "CSC7632", .devs = { { "CSC0000" }, { "CSC0010" }, { "PnPb006" }, { "CSC0004" } } }, | ||
93 | { .id = "" } | ||
94 | }; | ||
95 | |||
96 | MODULE_DEVICE_TABLE(pnp_card, snd_wavefront_pnpids); | ||
97 | |||
98 | static int __devinit | ||
99 | snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *card, | ||
100 | const struct pnp_card_device_id *id) | ||
101 | { | ||
102 | struct pnp_dev *pdev; | ||
103 | struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); | ||
104 | int err; | ||
105 | |||
106 | if (!cfg) | ||
107 | return -ENOMEM; | ||
108 | |||
109 | /* Check for each logical device. */ | ||
110 | |||
111 | /* CS4232 chip (aka "windows sound system") is logical device 0 */ | ||
112 | |||
113 | acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL); | ||
114 | if (acard->wss == NULL) { | ||
115 | kfree(cfg); | ||
116 | return -EBUSY; | ||
117 | } | ||
118 | |||
119 | /* there is a game port at logical device 1, but we ignore it completely */ | ||
120 | |||
121 | /* the control interface is logical device 2, but we ignore it | ||
122 | completely. in fact, nobody even seems to know what it | ||
123 | does. | ||
124 | */ | ||
125 | |||
126 | /* Only configure the CS4232 MIDI interface if its been | ||
127 | specifically requested. It is logical device 3. | ||
128 | */ | ||
129 | |||
130 | if (use_cs4232_midi[dev]) { | ||
131 | acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL); | ||
132 | if (acard->mpu == NULL) { | ||
133 | kfree(cfg); | ||
134 | return -EBUSY; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /* The ICS2115 synth is logical device 4 */ | ||
139 | |||
140 | acard->synth = pnp_request_card_device(card, id->devs[3].id, NULL); | ||
141 | if (acard->synth == NULL) { | ||
142 | kfree(cfg); | ||
143 | return -EBUSY; | ||
144 | } | ||
145 | |||
146 | /* PCM/FM initialization */ | ||
147 | |||
148 | pdev = acard->wss; | ||
149 | |||
150 | pnp_init_resource_table(cfg); | ||
151 | |||
152 | /* An interesting note from the Tropez+ FAQ: | ||
153 | |||
154 | Q. [Ports] Why is the base address of the WSS I/O ports off by 4? | ||
155 | |||
156 | A. WSS I/O requires a block of 8 I/O addresses ("ports"). Of these, the first | ||
157 | 4 are used to identify and configure the board. With the advent of PnP, | ||
158 | these first 4 addresses have become obsolete, and software applications | ||
159 | only use the last 4 addresses to control the codec chip. Therefore, the | ||
160 | base address setting "skips past" the 4 unused addresses. | ||
161 | |||
162 | */ | ||
163 | |||
164 | if (cs4232_pcm_port[dev] != SNDRV_AUTO_PORT) | ||
165 | pnp_resource_change(&cfg->port_resource[0], cs4232_pcm_port[dev], 4); | ||
166 | if (fm_port[dev] != SNDRV_AUTO_PORT) | ||
167 | pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); | ||
168 | if (dma1[dev] != SNDRV_AUTO_DMA) | ||
169 | pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1); | ||
170 | if (dma2[dev] != SNDRV_AUTO_DMA) | ||
171 | pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1); | ||
172 | if (cs4232_pcm_irq[dev] != SNDRV_AUTO_IRQ) | ||
173 | pnp_resource_change(&cfg->irq_resource[0], cs4232_pcm_irq[dev], 1); | ||
174 | |||
175 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
176 | snd_printk(KERN_ERR "PnP WSS the requested resources are invalid, using auto config\n"); | ||
177 | err = pnp_activate_dev(pdev); | ||
178 | if (err < 0) { | ||
179 | snd_printk(KERN_ERR "PnP WSS pnp configure failure\n"); | ||
180 | kfree(cfg); | ||
181 | return err; | ||
182 | } | ||
183 | |||
184 | cs4232_pcm_port[dev] = pnp_port_start(pdev, 0); | ||
185 | fm_port[dev] = pnp_port_start(pdev, 1); | ||
186 | dma1[dev] = pnp_dma(pdev, 0); | ||
187 | dma2[dev] = pnp_dma(pdev, 1); | ||
188 | cs4232_pcm_irq[dev] = pnp_irq(pdev, 0); | ||
189 | |||
190 | /* Synth initialization */ | ||
191 | |||
192 | pdev = acard->synth; | ||
193 | |||
194 | pnp_init_resource_table(cfg); | ||
195 | |||
196 | if (ics2115_port[dev] != SNDRV_AUTO_PORT) { | ||
197 | pnp_resource_change(&cfg->port_resource[0], ics2115_port[dev], 16); | ||
198 | } | ||
199 | |||
200 | if (ics2115_port[dev] != SNDRV_AUTO_IRQ) { | ||
201 | pnp_resource_change(&cfg->irq_resource[0], ics2115_irq[dev], 1); | ||
202 | } | ||
203 | |||
204 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
205 | snd_printk(KERN_ERR "PnP ICS2115 the requested resources are invalid, using auto config\n"); | ||
206 | err = pnp_activate_dev(pdev); | ||
207 | if (err < 0) { | ||
208 | snd_printk(KERN_ERR "PnP ICS2115 pnp configure failure\n"); | ||
209 | kfree(cfg); | ||
210 | return err; | ||
211 | } | ||
212 | |||
213 | ics2115_port[dev] = pnp_port_start(pdev, 0); | ||
214 | ics2115_irq[dev] = pnp_irq(pdev, 0); | ||
215 | |||
216 | /* CS4232 MPU initialization. Configure this only if | ||
217 | explicitly requested, since its physically inaccessible and | ||
218 | consumes another IRQ. | ||
219 | */ | ||
220 | |||
221 | if (use_cs4232_midi[dev]) { | ||
222 | |||
223 | pdev = acard->mpu; | ||
224 | |||
225 | pnp_init_resource_table(cfg); | ||
226 | |||
227 | if (cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) | ||
228 | pnp_resource_change(&cfg->port_resource[0], cs4232_mpu_port[dev], 2); | ||
229 | if (cs4232_mpu_irq[dev] != SNDRV_AUTO_IRQ) | ||
230 | pnp_resource_change(&cfg->port_resource[0], cs4232_mpu_irq[dev], 1); | ||
231 | |||
232 | if (pnp_manual_config_dev(pdev, cfg, 0) < 0) | ||
233 | snd_printk(KERN_ERR "PnP MPU401 the requested resources are invalid, using auto config\n"); | ||
234 | err = pnp_activate_dev(pdev); | ||
235 | if (err < 0) { | ||
236 | snd_printk(KERN_ERR "PnP MPU401 pnp configure failure\n"); | ||
237 | cs4232_mpu_port[dev] = SNDRV_AUTO_PORT; | ||
238 | } else { | ||
239 | cs4232_mpu_port[dev] = pnp_port_start(pdev, 0); | ||
240 | cs4232_mpu_irq[dev] = pnp_irq(pdev, 0); | ||
241 | } | ||
242 | |||
243 | snd_printk ("CS4232 MPU: port=0x%lx, irq=%i\n", | ||
244 | cs4232_mpu_port[dev], | ||
245 | cs4232_mpu_irq[dev]); | ||
246 | } | ||
247 | |||
248 | snd_printdd ("CS4232: pcm port=0x%lx, fm port=0x%lx, dma1=%i, dma2=%i, irq=%i\nICS2115: port=0x%lx, irq=%i\n", | ||
249 | cs4232_pcm_port[dev], | ||
250 | fm_port[dev], | ||
251 | dma1[dev], | ||
252 | dma2[dev], | ||
253 | cs4232_pcm_irq[dev], | ||
254 | ics2115_port[dev], | ||
255 | ics2115_irq[dev]); | ||
256 | |||
257 | kfree(cfg); | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | #endif /* CONFIG_PNP */ | ||
262 | |||
263 | static irqreturn_t snd_wavefront_ics2115_interrupt(int irq, | ||
264 | void *dev_id, | ||
265 | struct pt_regs *regs) | ||
266 | { | ||
267 | snd_wavefront_card_t *acard; | ||
268 | |||
269 | acard = (snd_wavefront_card_t *) dev_id; | ||
270 | |||
271 | if (acard == NULL) | ||
272 | return IRQ_NONE; | ||
273 | |||
274 | if (acard->wavefront.interrupts_are_midi) { | ||
275 | snd_wavefront_midi_interrupt (acard); | ||
276 | } else { | ||
277 | snd_wavefront_internal_interrupt (acard); | ||
278 | } | ||
279 | return IRQ_HANDLED; | ||
280 | } | ||
281 | |||
282 | static snd_hwdep_t * __devinit | ||
283 | snd_wavefront_new_synth (snd_card_t *card, | ||
284 | int hw_dev, | ||
285 | snd_wavefront_card_t *acard) | ||
286 | { | ||
287 | snd_hwdep_t *wavefront_synth; | ||
288 | |||
289 | if (snd_wavefront_detect (acard) < 0) { | ||
290 | return NULL; | ||
291 | } | ||
292 | |||
293 | if (snd_wavefront_start (&acard->wavefront) < 0) { | ||
294 | return NULL; | ||
295 | } | ||
296 | |||
297 | if (snd_hwdep_new(card, "WaveFront", hw_dev, &wavefront_synth) < 0) | ||
298 | return NULL; | ||
299 | strcpy (wavefront_synth->name, | ||
300 | "WaveFront (ICS2115) wavetable synthesizer"); | ||
301 | wavefront_synth->ops.open = snd_wavefront_synth_open; | ||
302 | wavefront_synth->ops.release = snd_wavefront_synth_release; | ||
303 | wavefront_synth->ops.ioctl = snd_wavefront_synth_ioctl; | ||
304 | |||
305 | return wavefront_synth; | ||
306 | } | ||
307 | |||
308 | static snd_hwdep_t * __devinit | ||
309 | snd_wavefront_new_fx (snd_card_t *card, | ||
310 | int hw_dev, | ||
311 | snd_wavefront_card_t *acard, | ||
312 | unsigned long port) | ||
313 | |||
314 | { | ||
315 | snd_hwdep_t *fx_processor; | ||
316 | |||
317 | if (snd_wavefront_fx_start (&acard->wavefront)) { | ||
318 | snd_printk ("cannot initialize YSS225 FX processor"); | ||
319 | return NULL; | ||
320 | } | ||
321 | |||
322 | if (snd_hwdep_new (card, "YSS225", hw_dev, &fx_processor) < 0) | ||
323 | return NULL; | ||
324 | sprintf (fx_processor->name, "YSS225 FX Processor at 0x%lx", port); | ||
325 | fx_processor->ops.open = snd_wavefront_fx_open; | ||
326 | fx_processor->ops.release = snd_wavefront_fx_release; | ||
327 | fx_processor->ops.ioctl = snd_wavefront_fx_ioctl; | ||
328 | |||
329 | return fx_processor; | ||
330 | } | ||
331 | |||
332 | static snd_wavefront_mpu_id internal_id = internal_mpu; | ||
333 | static snd_wavefront_mpu_id external_id = external_mpu; | ||
334 | |||
335 | static snd_rawmidi_t * __devinit | ||
336 | snd_wavefront_new_midi (snd_card_t *card, | ||
337 | int midi_dev, | ||
338 | snd_wavefront_card_t *acard, | ||
339 | unsigned long port, | ||
340 | snd_wavefront_mpu_id mpu) | ||
341 | |||
342 | { | ||
343 | snd_rawmidi_t *rmidi; | ||
344 | static int first = 1; | ||
345 | |||
346 | if (first) { | ||
347 | first = 0; | ||
348 | acard->wavefront.midi.base = port; | ||
349 | if (snd_wavefront_midi_start (acard)) { | ||
350 | snd_printk ("cannot initialize MIDI interface\n"); | ||
351 | return NULL; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | if (snd_rawmidi_new (card, "WaveFront MIDI", midi_dev, 1, 1, &rmidi) < 0) | ||
356 | return NULL; | ||
357 | |||
358 | if (mpu == internal_mpu) { | ||
359 | strcpy(rmidi->name, "WaveFront MIDI (Internal)"); | ||
360 | rmidi->private_data = &internal_id; | ||
361 | } else { | ||
362 | strcpy(rmidi->name, "WaveFront MIDI (External)"); | ||
363 | rmidi->private_data = &external_id; | ||
364 | } | ||
365 | |||
366 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_wavefront_midi_output); | ||
367 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_wavefront_midi_input); | ||
368 | |||
369 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | | ||
370 | SNDRV_RAWMIDI_INFO_INPUT | | ||
371 | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
372 | |||
373 | return rmidi; | ||
374 | } | ||
375 | |||
376 | static void | ||
377 | snd_wavefront_free(snd_card_t *card) | ||
378 | { | ||
379 | snd_wavefront_card_t *acard = (snd_wavefront_card_t *)card->private_data; | ||
380 | |||
381 | if (acard) { | ||
382 | if (acard->wavefront.res_base != NULL) { | ||
383 | release_resource(acard->wavefront.res_base); | ||
384 | kfree_nocheck(acard->wavefront.res_base); | ||
385 | } | ||
386 | if (acard->wavefront.irq > 0) | ||
387 | free_irq(acard->wavefront.irq, (void *)acard); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | static int __devinit | ||
392 | snd_wavefront_probe (int dev, struct pnp_card_link *pcard, | ||
393 | const struct pnp_card_device_id *pid) | ||
394 | { | ||
395 | snd_card_t *card; | ||
396 | snd_wavefront_card_t *acard; | ||
397 | cs4231_t *chip; | ||
398 | snd_hwdep_t *wavefront_synth; | ||
399 | snd_rawmidi_t *ics2115_internal_rmidi = NULL; | ||
400 | snd_rawmidi_t *ics2115_external_rmidi = NULL; | ||
401 | snd_hwdep_t *fx_processor; | ||
402 | int hw_dev = 0, midi_dev = 0, err; | ||
403 | |||
404 | #ifdef CONFIG_PNP | ||
405 | if (!isapnp[dev]) { | ||
406 | #endif | ||
407 | if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) { | ||
408 | snd_printk("specify CS4232 port\n"); | ||
409 | return -EINVAL; | ||
410 | } | ||
411 | if (ics2115_port[dev] == SNDRV_AUTO_PORT) { | ||
412 | snd_printk("specify ICS2115 port\n"); | ||
413 | return -ENODEV; | ||
414 | } | ||
415 | #ifdef CONFIG_PNP | ||
416 | } | ||
417 | #endif | ||
418 | card = snd_card_new (index[dev], | ||
419 | id[dev], | ||
420 | THIS_MODULE, | ||
421 | sizeof(snd_wavefront_card_t)); | ||
422 | |||
423 | if (card == NULL) { | ||
424 | return -ENOMEM; | ||
425 | } | ||
426 | acard = (snd_wavefront_card_t *)card->private_data; | ||
427 | acard->wavefront.irq = -1; | ||
428 | spin_lock_init(&acard->wavefront.irq_lock); | ||
429 | init_waitqueue_head(&acard->wavefront.interrupt_sleeper); | ||
430 | spin_lock_init(&acard->wavefront.midi.open); | ||
431 | spin_lock_init(&acard->wavefront.midi.virtual); | ||
432 | card->private_free = snd_wavefront_free; | ||
433 | |||
434 | #ifdef CONFIG_PNP | ||
435 | if (isapnp[dev]) { | ||
436 | if (snd_wavefront_pnp (dev, acard, pcard, pid) < 0) { | ||
437 | if (cs4232_pcm_port[dev] == SNDRV_AUTO_PORT) { | ||
438 | snd_printk ("isapnp detection failed\n"); | ||
439 | snd_card_free (card); | ||
440 | return -ENODEV; | ||
441 | } | ||
442 | } | ||
443 | snd_card_set_dev(card, &pcard->card->dev); | ||
444 | } | ||
445 | #endif /* CONFIG_PNP */ | ||
446 | |||
447 | /* --------- PCM --------------- */ | ||
448 | |||
449 | if ((err = snd_cs4231_create (card, | ||
450 | cs4232_pcm_port[dev], | ||
451 | -1, | ||
452 | cs4232_pcm_irq[dev], | ||
453 | dma1[dev], | ||
454 | dma2[dev], | ||
455 | CS4231_HW_DETECT, 0, &chip)) < 0) { | ||
456 | snd_card_free(card); | ||
457 | snd_printk ("can't allocate CS4231 device\n"); | ||
458 | return err; | ||
459 | } | ||
460 | |||
461 | if ((err = snd_cs4231_pcm (chip, 0, NULL)) < 0) { | ||
462 | snd_card_free(card); | ||
463 | return err; | ||
464 | } | ||
465 | if ((err = snd_cs4231_timer (chip, 0, NULL)) < 0) { | ||
466 | snd_card_free(card); | ||
467 | return err; | ||
468 | } | ||
469 | |||
470 | /* ---------- OPL3 synth --------- */ | ||
471 | |||
472 | if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { | ||
473 | opl3_t *opl3; | ||
474 | |||
475 | if ((err = snd_opl3_create(card, | ||
476 | fm_port[dev], | ||
477 | fm_port[dev] + 2, | ||
478 | OPL3_HW_OPL3_CS, | ||
479 | 0, &opl3)) < 0) { | ||
480 | snd_printk ("can't allocate or detect OPL3 synth\n"); | ||
481 | snd_card_free(card); | ||
482 | return err; | ||
483 | } | ||
484 | |||
485 | if ((err = snd_opl3_hwdep_new(opl3, hw_dev, 1, NULL)) < 0) { | ||
486 | snd_card_free(card); | ||
487 | return err; | ||
488 | } | ||
489 | hw_dev++; | ||
490 | } | ||
491 | |||
492 | /* ------- ICS2115 Wavetable synth ------- */ | ||
493 | |||
494 | if ((acard->wavefront.res_base = request_region(ics2115_port[dev], 16, "ICS2115")) == NULL) { | ||
495 | snd_printk("unable to grab ICS2115 i/o region 0x%lx-0x%lx\n", ics2115_port[dev], ics2115_port[dev] + 16 - 1); | ||
496 | snd_card_free(card); | ||
497 | return -EBUSY; | ||
498 | } | ||
499 | if (request_irq(ics2115_irq[dev], snd_wavefront_ics2115_interrupt, SA_INTERRUPT, "ICS2115", (void *)acard)) { | ||
500 | snd_printk("unable to use ICS2115 IRQ %d\n", ics2115_irq[dev]); | ||
501 | snd_card_free(card); | ||
502 | return -EBUSY; | ||
503 | } | ||
504 | |||
505 | acard->wavefront.irq = ics2115_irq[dev]; | ||
506 | acard->wavefront.base = ics2115_port[dev]; | ||
507 | |||
508 | if ((wavefront_synth = snd_wavefront_new_synth (card, hw_dev, acard)) == NULL) { | ||
509 | snd_printk ("can't create WaveFront synth device\n"); | ||
510 | snd_card_free(card); | ||
511 | return -ENOMEM; | ||
512 | } | ||
513 | |||
514 | strcpy (wavefront_synth->name, "ICS2115 Wavetable MIDI Synthesizer"); | ||
515 | wavefront_synth->iface = SNDRV_HWDEP_IFACE_ICS2115; | ||
516 | hw_dev++; | ||
517 | |||
518 | /* --------- Mixer ------------ */ | ||
519 | |||
520 | if ((err = snd_cs4231_mixer(chip)) < 0) { | ||
521 | snd_printk ("can't allocate mixer device\n"); | ||
522 | snd_card_free(card); | ||
523 | return err; | ||
524 | } | ||
525 | |||
526 | /* -------- CS4232 MPU-401 interface -------- */ | ||
527 | |||
528 | if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) { | ||
529 | if ((err = snd_mpu401_uart_new(card, midi_dev, MPU401_HW_CS4232, | ||
530 | cs4232_mpu_port[dev], 0, | ||
531 | cs4232_mpu_irq[dev], | ||
532 | SA_INTERRUPT, | ||
533 | NULL)) < 0) { | ||
534 | snd_printk ("can't allocate CS4232 MPU-401 device\n"); | ||
535 | snd_card_free(card); | ||
536 | return err; | ||
537 | } | ||
538 | midi_dev++; | ||
539 | } | ||
540 | |||
541 | /* ------ ICS2115 internal MIDI ------------ */ | ||
542 | |||
543 | if (ics2115_port[dev] > 0 && ics2115_port[dev] != SNDRV_AUTO_PORT) { | ||
544 | ics2115_internal_rmidi = | ||
545 | snd_wavefront_new_midi (card, | ||
546 | midi_dev, | ||
547 | acard, | ||
548 | ics2115_port[dev], | ||
549 | internal_mpu); | ||
550 | if (ics2115_internal_rmidi == NULL) { | ||
551 | snd_printk ("can't setup ICS2115 internal MIDI device\n"); | ||
552 | snd_card_free(card); | ||
553 | return -ENOMEM; | ||
554 | } | ||
555 | midi_dev++; | ||
556 | } | ||
557 | |||
558 | /* ------ ICS2115 external MIDI ------------ */ | ||
559 | |||
560 | if (ics2115_port[dev] > 0 && ics2115_port[dev] != SNDRV_AUTO_PORT) { | ||
561 | ics2115_external_rmidi = | ||
562 | snd_wavefront_new_midi (card, | ||
563 | midi_dev, | ||
564 | acard, | ||
565 | ics2115_port[dev], | ||
566 | external_mpu); | ||
567 | if (ics2115_external_rmidi == NULL) { | ||
568 | snd_printk ("can't setup ICS2115 external MIDI device\n"); | ||
569 | snd_card_free(card); | ||
570 | return -ENOMEM; | ||
571 | } | ||
572 | midi_dev++; | ||
573 | } | ||
574 | |||
575 | /* FX processor for Tropez+ */ | ||
576 | |||
577 | if (acard->wavefront.has_fx) { | ||
578 | fx_processor = snd_wavefront_new_fx (card, | ||
579 | hw_dev, | ||
580 | acard, | ||
581 | ics2115_port[dev]); | ||
582 | if (fx_processor == NULL) { | ||
583 | snd_printk ("can't setup FX device\n"); | ||
584 | snd_card_free(card); | ||
585 | return -ENOMEM; | ||
586 | } | ||
587 | |||
588 | hw_dev++; | ||
589 | |||
590 | strcpy(card->driver, "Tropez+"); | ||
591 | strcpy(card->shortname, "Turtle Beach Tropez+"); | ||
592 | } else { | ||
593 | /* Need a way to distinguish between Maui and Tropez */ | ||
594 | strcpy(card->driver, "WaveFront"); | ||
595 | strcpy(card->shortname, "Turtle Beach WaveFront"); | ||
596 | } | ||
597 | |||
598 | /* ----- Register the card --------- */ | ||
599 | |||
600 | /* Not safe to include "Turtle Beach" in longname, due to | ||
601 | length restrictions | ||
602 | */ | ||
603 | |||
604 | sprintf(card->longname, "%s PCM 0x%lx irq %d dma %d", | ||
605 | card->driver, | ||
606 | chip->port, | ||
607 | cs4232_pcm_irq[dev], | ||
608 | dma1[dev]); | ||
609 | |||
610 | if (dma2[dev] >= 0 && dma2[dev] < 8) | ||
611 | sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); | ||
612 | |||
613 | if (cs4232_mpu_port[dev] > 0 && cs4232_mpu_port[dev] != SNDRV_AUTO_PORT) { | ||
614 | sprintf (card->longname + strlen (card->longname), | ||
615 | " MPU-401 0x%lx irq %d", | ||
616 | cs4232_mpu_port[dev], | ||
617 | cs4232_mpu_irq[dev]); | ||
618 | } | ||
619 | |||
620 | sprintf (card->longname + strlen (card->longname), | ||
621 | " SYNTH 0x%lx irq %d", | ||
622 | ics2115_port[dev], | ||
623 | ics2115_irq[dev]); | ||
624 | |||
625 | if ((err = snd_card_register(card)) < 0) { | ||
626 | snd_card_free(card); | ||
627 | return err; | ||
628 | } | ||
629 | if (pcard) | ||
630 | pnp_set_card_drvdata(pcard, card); | ||
631 | else | ||
632 | snd_wavefront_legacy[dev] = card; | ||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | #ifdef CONFIG_PNP | ||
637 | |||
638 | static int __devinit snd_wavefront_pnp_detect(struct pnp_card_link *card, | ||
639 | const struct pnp_card_device_id *id) | ||
640 | { | ||
641 | static int dev; | ||
642 | int res; | ||
643 | |||
644 | for ( ; dev < SNDRV_CARDS; dev++) { | ||
645 | if (!enable[dev] || !isapnp[dev]) | ||
646 | continue; | ||
647 | res = snd_wavefront_probe(dev, card, id); | ||
648 | if (res < 0) | ||
649 | return res; | ||
650 | dev++; | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | return -ENODEV; | ||
655 | } | ||
656 | |||
657 | static void __devexit snd_wavefront_pnp_remove(struct pnp_card_link * pcard) | ||
658 | { | ||
659 | snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard); | ||
660 | |||
661 | snd_card_disconnect(card); | ||
662 | snd_card_free_in_thread(card); | ||
663 | } | ||
664 | |||
665 | static struct pnp_card_driver wavefront_pnpc_driver = { | ||
666 | .flags = PNP_DRIVER_RES_DISABLE, | ||
667 | .name = "wavefront", | ||
668 | .id_table = snd_wavefront_pnpids, | ||
669 | .probe = snd_wavefront_pnp_detect, | ||
670 | .remove = __devexit_p(snd_wavefront_pnp_remove), | ||
671 | }; | ||
672 | |||
673 | #endif /* CONFIG_PNP */ | ||
674 | |||
675 | static int __init alsa_card_wavefront_init(void) | ||
676 | { | ||
677 | int cards = 0; | ||
678 | int dev; | ||
679 | for (dev = 0; dev < SNDRV_CARDS; dev++) { | ||
680 | if (!enable[dev]) | ||
681 | continue; | ||
682 | #ifdef CONFIG_PNP | ||
683 | if (isapnp[dev]) | ||
684 | continue; | ||
685 | #endif | ||
686 | if (snd_wavefront_probe(dev, NULL, NULL) >= 0) | ||
687 | cards++; | ||
688 | } | ||
689 | #ifdef CONFIG_PNP | ||
690 | cards += pnp_register_card_driver(&wavefront_pnpc_driver); | ||
691 | #endif | ||
692 | if (!cards) { | ||
693 | #ifdef CONFIG_PNP | ||
694 | pnp_unregister_card_driver(&wavefront_pnpc_driver); | ||
695 | #endif | ||
696 | #ifdef MODULE | ||
697 | printk (KERN_ERR "No WaveFront cards found or devices busy\n"); | ||
698 | #endif | ||
699 | return -ENODEV; | ||
700 | } | ||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | static void __exit alsa_card_wavefront_exit(void) | ||
705 | { | ||
706 | int idx; | ||
707 | |||
708 | #ifdef CONFIG_PNP | ||
709 | pnp_unregister_card_driver(&wavefront_pnpc_driver); | ||
710 | #endif | ||
711 | for (idx = 0; idx < SNDRV_CARDS; idx++) | ||
712 | snd_card_free(snd_wavefront_legacy[idx]); | ||
713 | } | ||
714 | |||
715 | module_init(alsa_card_wavefront_init) | ||
716 | module_exit(alsa_card_wavefront_exit) | ||
diff --git a/sound/isa/wavefront/wavefront_fx.c b/sound/isa/wavefront/wavefront_fx.c new file mode 100644 index 000000000000..0e13623f69f0 --- /dev/null +++ b/sound/isa/wavefront/wavefront_fx.c | |||
@@ -0,0 +1,1019 @@ | |||
1 | /* | ||
2 | * Copyright (c) 1998-2002 by Paul Davis <pbd@op.net> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include <sound/driver.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/time.h> | ||
23 | #include <linux/wait.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/snd_wavefront.h> | ||
26 | #include <sound/initval.h> | ||
27 | |||
28 | /* Control bits for the Load Control Register | ||
29 | */ | ||
30 | |||
31 | #define FX_LSB_TRANSFER 0x01 /* transfer after DSP LSB byte written */ | ||
32 | #define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */ | ||
33 | #define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */ | ||
34 | |||
35 | /* weird stuff, derived from port I/O tracing with dosemu */ | ||
36 | |||
37 | unsigned char page_zero[] __initdata = { | ||
38 | 0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00, | ||
39 | 0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00, | ||
40 | 0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00, | ||
41 | 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
42 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
43 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
44 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
45 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
47 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
48 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
49 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19, | ||
50 | 0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01, | ||
51 | 0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00, | ||
52 | 0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02, | ||
53 | 0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17, | ||
54 | 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00, | ||
55 | 0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00, | ||
56 | 0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02, | ||
57 | 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40, | ||
58 | 0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02, | ||
59 | 0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, | ||
60 | 0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00, | ||
61 | 0x1d, 0x02, 0xdf | ||
62 | }; | ||
63 | |||
64 | unsigned char page_one[] __initdata = { | ||
65 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00, | ||
66 | 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00, | ||
67 | 0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, | ||
68 | 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
70 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
71 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
72 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
74 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
75 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
76 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60, | ||
77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00, | ||
78 | 0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7, | ||
79 | 0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00, | ||
80 | 0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0, | ||
81 | 0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00, | ||
82 | 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0, | ||
83 | 0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, | ||
84 | 0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
85 | 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, | ||
86 | 0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, | ||
87 | 0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02, | ||
88 | 0x60, 0x00, 0x1b | ||
89 | }; | ||
90 | |||
91 | unsigned char page_two[] __initdata = { | ||
92 | 0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4, | ||
93 | 0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, | ||
94 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
96 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
97 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07, | ||
98 | 0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46, | ||
99 | 0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46, | ||
100 | 0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, | ||
101 | 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05, | ||
102 | 0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05, | ||
103 | 0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44 | ||
104 | }; | ||
105 | |||
106 | unsigned char page_three[] __initdata = { | ||
107 | 0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06, | ||
108 | 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
109 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
110 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, | ||
113 | 0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, | ||
114 | 0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40, | ||
115 | 0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, | ||
116 | 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, | ||
117 | 0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00, | ||
118 | 0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40 | ||
119 | }; | ||
120 | |||
121 | unsigned char page_four[] __initdata = { | ||
122 | 0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02, | ||
123 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
124 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
125 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
126 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
127 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, | ||
128 | 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, | ||
129 | 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00, | ||
130 | 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, | ||
131 | 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, | ||
132 | 0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22, | ||
133 | 0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01 | ||
134 | }; | ||
135 | |||
136 | unsigned char page_six[] __initdata = { | ||
137 | 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, | ||
138 | 0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e, | ||
139 | 0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00, | ||
140 | 0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00, | ||
141 | 0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24, | ||
142 | 0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00, | ||
143 | 0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00, | ||
144 | 0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a, | ||
145 | 0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00, | ||
146 | 0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d, | ||
147 | 0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50, | ||
148 | 0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00, | ||
149 | 0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17, | ||
150 | 0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66, | ||
151 | 0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c, | ||
152 | 0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00, | ||
153 | 0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c, | ||
154 | 0x80, 0x00, 0x7e, 0x80, 0x80 | ||
155 | }; | ||
156 | |||
157 | unsigned char page_seven[] __initdata = { | ||
158 | 0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, | ||
159 | 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, | ||
160 | 0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f, | ||
161 | 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
162 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
163 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
164 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
165 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
166 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
167 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
168 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
169 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
170 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
171 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff, | ||
172 | 0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f, | ||
173 | 0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38, | ||
174 | 0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06, | ||
175 | 0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b, | ||
176 | 0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06, | ||
177 | 0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, | ||
178 | 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14, | ||
179 | 0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93, | ||
180 | 0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
181 | 0x00, 0x02, 0x00 | ||
182 | }; | ||
183 | |||
184 | unsigned char page_zero_v2[] __initdata = { | ||
185 | 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
186 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
187 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
188 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
189 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
190 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
191 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
193 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
194 | }; | ||
195 | |||
196 | unsigned char page_one_v2[] __initdata = { | ||
197 | 0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
198 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
199 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
200 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
201 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
202 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
203 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
204 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
206 | }; | ||
207 | |||
208 | unsigned char page_two_v2[] __initdata = { | ||
209 | 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
210 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
211 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
212 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
213 | 0x00, 0x00, 0x00, 0x00 | ||
214 | }; | ||
215 | unsigned char page_three_v2[] __initdata = { | ||
216 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
217 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
218 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
219 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
220 | 0x00, 0x00, 0x00, 0x00 | ||
221 | }; | ||
222 | unsigned char page_four_v2[] __initdata = { | ||
223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
224 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
225 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
226 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
227 | 0x00, 0x00, 0x00, 0x00 | ||
228 | }; | ||
229 | |||
230 | unsigned char page_seven_v2[] __initdata = { | ||
231 | 0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
232 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
233 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
234 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
235 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
236 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
237 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
238 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
239 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
240 | }; | ||
241 | |||
242 | unsigned char mod_v2[] __initdata = { | ||
243 | 0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02, | ||
244 | 0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05, | ||
245 | 0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0, | ||
246 | 0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20, | ||
247 | 0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3, | ||
248 | 0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff, | ||
249 | 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16, | ||
250 | 0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff, | ||
251 | 0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31, | ||
252 | 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00, | ||
253 | 0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44, | ||
254 | 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00, | ||
255 | 0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, | ||
256 | 0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00, | ||
257 | 0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72, | ||
258 | 0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0, | ||
259 | 0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85, | ||
260 | 0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00, | ||
261 | 0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0, | ||
262 | 0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00, | ||
263 | 0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3, | ||
264 | 0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00, | ||
265 | 0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6, | ||
266 | 0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00, | ||
267 | 0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02, | ||
268 | 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03, | ||
269 | 0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01, | ||
270 | 0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01 | ||
271 | }; | ||
272 | unsigned char coefficients[] __initdata = { | ||
273 | 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03, | ||
274 | 0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, | ||
275 | 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01, | ||
276 | 0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00, | ||
277 | 0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00, | ||
278 | 0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47, | ||
279 | 0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07, | ||
280 | 0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00, | ||
281 | 0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01, | ||
282 | 0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, | ||
283 | 0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07, | ||
284 | 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, | ||
285 | 0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02, | ||
286 | 0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44, | ||
287 | 0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, | ||
288 | 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40, | ||
289 | 0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a, | ||
290 | 0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56, | ||
291 | 0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07, | ||
292 | 0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda, | ||
293 | 0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05, | ||
294 | 0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79, | ||
295 | 0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07, | ||
296 | 0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52, | ||
297 | 0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03, | ||
298 | 0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a, | ||
299 | 0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06, | ||
300 | 0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3, | ||
301 | 0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20, | ||
302 | 0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c, | ||
303 | 0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06, | ||
304 | 0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48, | ||
305 | 0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02, | ||
306 | 0xba | ||
307 | }; | ||
308 | unsigned char coefficients2[] __initdata = { | ||
309 | 0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f, | ||
310 | 0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d, | ||
311 | 0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07, | ||
312 | 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, | ||
313 | 0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00 | ||
314 | }; | ||
315 | unsigned char coefficients3[] __initdata = { | ||
316 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00, | ||
317 | 0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc, | ||
318 | 0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01, | ||
319 | 0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99, | ||
320 | 0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02, | ||
321 | 0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f, | ||
322 | 0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03, | ||
323 | 0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c, | ||
324 | 0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03, | ||
325 | 0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51, | ||
326 | 0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04, | ||
327 | 0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e, | ||
328 | 0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05, | ||
329 | 0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14, | ||
330 | 0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06, | ||
331 | 0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1, | ||
332 | 0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07, | ||
333 | 0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7, | ||
334 | 0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08, | ||
335 | 0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3, | ||
336 | 0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09, | ||
337 | 0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99, | ||
338 | 0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a, | ||
339 | 0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66, | ||
340 | 0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a, | ||
341 | 0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c, | ||
342 | 0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b, | ||
343 | 0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28, | ||
344 | 0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c, | ||
345 | 0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e, | ||
346 | 0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d, | ||
347 | 0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb, | ||
348 | 0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e, | ||
349 | 0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1, | ||
350 | 0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f, | ||
351 | 0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae, | ||
352 | 0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff | ||
353 | }; | ||
354 | |||
355 | static int | ||
356 | wavefront_fx_idle (snd_wavefront_t *dev) | ||
357 | |||
358 | { | ||
359 | int i; | ||
360 | unsigned int x = 0x80; | ||
361 | |||
362 | for (i = 0; i < 1000; i++) { | ||
363 | x = inb (dev->fx_status); | ||
364 | if ((x & 0x80) == 0) { | ||
365 | break; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | if (x & 0x80) { | ||
370 | snd_printk ("FX device never idle.\n"); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | return (1); | ||
375 | } | ||
376 | |||
377 | static void | ||
378 | wavefront_fx_mute (snd_wavefront_t *dev, int onoff) | ||
379 | |||
380 | { | ||
381 | if (!wavefront_fx_idle(dev)) { | ||
382 | return; | ||
383 | } | ||
384 | |||
385 | outb (onoff ? 0x02 : 0x00, dev->fx_op); | ||
386 | } | ||
387 | |||
388 | static int | ||
389 | wavefront_fx_memset (snd_wavefront_t *dev, | ||
390 | int page, | ||
391 | int addr, | ||
392 | int cnt, | ||
393 | unsigned short *data) | ||
394 | { | ||
395 | if (page < 0 || page > 7) { | ||
396 | snd_printk ("FX memset: " | ||
397 | "page must be >= 0 and <= 7\n"); | ||
398 | return -(EINVAL); | ||
399 | } | ||
400 | |||
401 | if (addr < 0 || addr > 0x7f) { | ||
402 | snd_printk ("FX memset: " | ||
403 | "addr must be >= 0 and <= 7f\n"); | ||
404 | return -(EINVAL); | ||
405 | } | ||
406 | |||
407 | if (cnt == 1) { | ||
408 | |||
409 | outb (FX_LSB_TRANSFER, dev->fx_lcr); | ||
410 | outb (page, dev->fx_dsp_page); | ||
411 | outb (addr, dev->fx_dsp_addr); | ||
412 | outb ((data[0] >> 8), dev->fx_dsp_msb); | ||
413 | outb ((data[0] & 0xff), dev->fx_dsp_lsb); | ||
414 | |||
415 | snd_printk ("FX: addr %d:%x set to 0x%x\n", | ||
416 | page, addr, data[0]); | ||
417 | |||
418 | } else { | ||
419 | int i; | ||
420 | |||
421 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
422 | outb (page, dev->fx_dsp_page); | ||
423 | outb (addr, dev->fx_dsp_addr); | ||
424 | |||
425 | for (i = 0; i < cnt; i++) { | ||
426 | outb ((data[i] >> 8), dev->fx_dsp_msb); | ||
427 | outb ((data[i] & 0xff), dev->fx_dsp_lsb); | ||
428 | if (!wavefront_fx_idle (dev)) { | ||
429 | break; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | if (i != cnt) { | ||
434 | snd_printk ("FX memset " | ||
435 | "(0x%x, 0x%x, 0x%lx, %d) incomplete\n", | ||
436 | page, addr, (unsigned long) data, cnt); | ||
437 | return -(EIO); | ||
438 | } | ||
439 | } | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | int | ||
445 | snd_wavefront_fx_detect (snd_wavefront_t *dev) | ||
446 | |||
447 | { | ||
448 | /* This is a crude check, but its the best one I have for now. | ||
449 | Certainly on the Maui and the Tropez, wavefront_fx_idle() will | ||
450 | report "never idle", which suggests that this test should | ||
451 | work OK. | ||
452 | */ | ||
453 | |||
454 | if (inb (dev->fx_status) & 0x80) { | ||
455 | snd_printk ("Hmm, probably a Maui or Tropez.\n"); | ||
456 | return -1; | ||
457 | } | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | int | ||
463 | snd_wavefront_fx_open (snd_hwdep_t *hw, struct file *file) | ||
464 | |||
465 | { | ||
466 | if (!try_module_get(hw->card->module)) | ||
467 | return -EFAULT; | ||
468 | file->private_data = hw; | ||
469 | return 0; | ||
470 | } | ||
471 | |||
472 | int | ||
473 | snd_wavefront_fx_release (snd_hwdep_t *hw, struct file *file) | ||
474 | |||
475 | { | ||
476 | module_put(hw->card->module); | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | int | ||
481 | snd_wavefront_fx_ioctl (snd_hwdep_t *sdev, struct file *file, | ||
482 | unsigned int cmd, unsigned long arg) | ||
483 | |||
484 | { | ||
485 | snd_card_t *card; | ||
486 | snd_wavefront_card_t *acard; | ||
487 | snd_wavefront_t *dev; | ||
488 | wavefront_fx_info r; | ||
489 | unsigned short *page_data = NULL; | ||
490 | unsigned short *pd; | ||
491 | int err = 0; | ||
492 | |||
493 | snd_assert(sdev->card != NULL, return -ENODEV); | ||
494 | |||
495 | card = sdev->card; | ||
496 | |||
497 | snd_assert(card->private_data != NULL, return -ENODEV); | ||
498 | |||
499 | acard = card->private_data; | ||
500 | dev = &acard->wavefront; | ||
501 | |||
502 | if (copy_from_user (&r, (void __user *)arg, sizeof (wavefront_fx_info))) | ||
503 | return -EFAULT; | ||
504 | |||
505 | switch (r.request) { | ||
506 | case WFFX_MUTE: | ||
507 | wavefront_fx_mute (dev, r.data[0]); | ||
508 | return -EIO; | ||
509 | |||
510 | case WFFX_MEMSET: | ||
511 | if (r.data[2] <= 0) { | ||
512 | snd_printk ("cannot write " | ||
513 | "<= 0 bytes to FX\n"); | ||
514 | return -EIO; | ||
515 | } else if (r.data[2] == 1) { | ||
516 | pd = (unsigned short *) &r.data[3]; | ||
517 | } else { | ||
518 | if (r.data[2] > 256) { | ||
519 | snd_printk ("cannot write " | ||
520 | "> 512 bytes to FX\n"); | ||
521 | return -EIO; | ||
522 | } | ||
523 | page_data = kmalloc(r.data[2] * sizeof(short), GFP_KERNEL); | ||
524 | if (!page_data) | ||
525 | return -ENOMEM; | ||
526 | if (copy_from_user (page_data, | ||
527 | (unsigned char __user *) r.data[3], | ||
528 | r.data[2] * sizeof(short))) { | ||
529 | kfree(page_data); | ||
530 | return -EFAULT; | ||
531 | } | ||
532 | pd = page_data; | ||
533 | } | ||
534 | |||
535 | err = wavefront_fx_memset (dev, | ||
536 | r.data[0], /* page */ | ||
537 | r.data[1], /* addr */ | ||
538 | r.data[2], /* cnt */ | ||
539 | pd); | ||
540 | kfree(page_data); | ||
541 | break; | ||
542 | |||
543 | default: | ||
544 | snd_printk ("FX: ioctl %d not yet supported\n", | ||
545 | r.request); | ||
546 | return -ENOTTY; | ||
547 | } | ||
548 | return err; | ||
549 | } | ||
550 | |||
551 | /* YSS225 initialization. | ||
552 | |||
553 | This code was developed using DOSEMU. The Turtle Beach SETUPSND | ||
554 | utility was run with I/O tracing in DOSEMU enabled, and a reconstruction | ||
555 | of the port I/O done, using the Yamaha faxback document as a guide | ||
556 | to add more logic to the code. Its really pretty weird. | ||
557 | |||
558 | There was an alternative approach of just dumping the whole I/O | ||
559 | sequence as a series of port/value pairs and a simple loop | ||
560 | that output it. However, I hope that eventually I'll get more | ||
561 | control over what this code does, and so I tried to stick with | ||
562 | a somewhat "algorithmic" approach. | ||
563 | */ | ||
564 | |||
565 | |||
566 | int __init | ||
567 | snd_wavefront_fx_start (snd_wavefront_t *dev) | ||
568 | |||
569 | { | ||
570 | unsigned int i, j; | ||
571 | |||
572 | /* Set all bits for all channels on the MOD unit to zero */ | ||
573 | /* XXX But why do this twice ? */ | ||
574 | |||
575 | for (j = 0; j < 2; j++) { | ||
576 | for (i = 0x10; i <= 0xff; i++) { | ||
577 | |||
578 | if (!wavefront_fx_idle (dev)) { | ||
579 | return (-1); | ||
580 | } | ||
581 | |||
582 | outb (i, dev->fx_mod_addr); | ||
583 | outb (0x0, dev->fx_mod_data); | ||
584 | } | ||
585 | } | ||
586 | |||
587 | if (!wavefront_fx_idle (dev)) return (-1); | ||
588 | outb (0x02, dev->fx_op); /* mute on */ | ||
589 | |||
590 | if (!wavefront_fx_idle (dev)) return (-1); | ||
591 | outb (0x07, dev->fx_dsp_page); | ||
592 | outb (0x44, dev->fx_dsp_addr); | ||
593 | outb (0x00, dev->fx_dsp_msb); | ||
594 | outb (0x00, dev->fx_dsp_lsb); | ||
595 | if (!wavefront_fx_idle (dev)) return (-1); | ||
596 | outb (0x07, dev->fx_dsp_page); | ||
597 | outb (0x42, dev->fx_dsp_addr); | ||
598 | outb (0x00, dev->fx_dsp_msb); | ||
599 | outb (0x00, dev->fx_dsp_lsb); | ||
600 | if (!wavefront_fx_idle (dev)) return (-1); | ||
601 | outb (0x07, dev->fx_dsp_page); | ||
602 | outb (0x43, dev->fx_dsp_addr); | ||
603 | outb (0x00, dev->fx_dsp_msb); | ||
604 | outb (0x00, dev->fx_dsp_lsb); | ||
605 | if (!wavefront_fx_idle (dev)) return (-1); | ||
606 | outb (0x07, dev->fx_dsp_page); | ||
607 | outb (0x7c, dev->fx_dsp_addr); | ||
608 | outb (0x00, dev->fx_dsp_msb); | ||
609 | outb (0x00, dev->fx_dsp_lsb); | ||
610 | if (!wavefront_fx_idle (dev)) return (-1); | ||
611 | outb (0x07, dev->fx_dsp_page); | ||
612 | outb (0x7e, dev->fx_dsp_addr); | ||
613 | outb (0x00, dev->fx_dsp_msb); | ||
614 | outb (0x00, dev->fx_dsp_lsb); | ||
615 | if (!wavefront_fx_idle (dev)) return (-1); | ||
616 | outb (0x07, dev->fx_dsp_page); | ||
617 | outb (0x46, dev->fx_dsp_addr); | ||
618 | outb (0x00, dev->fx_dsp_msb); | ||
619 | outb (0x00, dev->fx_dsp_lsb); | ||
620 | if (!wavefront_fx_idle (dev)) return (-1); | ||
621 | outb (0x07, dev->fx_dsp_page); | ||
622 | outb (0x49, dev->fx_dsp_addr); | ||
623 | outb (0x00, dev->fx_dsp_msb); | ||
624 | outb (0x00, dev->fx_dsp_lsb); | ||
625 | if (!wavefront_fx_idle (dev)) return (-1); | ||
626 | outb (0x07, dev->fx_dsp_page); | ||
627 | outb (0x47, dev->fx_dsp_addr); | ||
628 | outb (0x00, dev->fx_dsp_msb); | ||
629 | outb (0x00, dev->fx_dsp_lsb); | ||
630 | if (!wavefront_fx_idle (dev)) return (-1); | ||
631 | outb (0x07, dev->fx_dsp_page); | ||
632 | outb (0x4a, dev->fx_dsp_addr); | ||
633 | outb (0x00, dev->fx_dsp_msb); | ||
634 | outb (0x00, dev->fx_dsp_lsb); | ||
635 | |||
636 | /* either because of stupidity by TB's programmers, or because it | ||
637 | actually does something, rezero the MOD page. | ||
638 | */ | ||
639 | for (i = 0x10; i <= 0xff; i++) { | ||
640 | |||
641 | if (!wavefront_fx_idle (dev)) { | ||
642 | return (-1); | ||
643 | } | ||
644 | |||
645 | outb (i, dev->fx_mod_addr); | ||
646 | outb (0x0, dev->fx_mod_data); | ||
647 | } | ||
648 | /* load page zero */ | ||
649 | |||
650 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
651 | outb (0x00, dev->fx_dsp_page); | ||
652 | outb (0x00, dev->fx_dsp_addr); | ||
653 | |||
654 | for (i = 0; i < sizeof (page_zero); i += 2) { | ||
655 | outb (page_zero[i], dev->fx_dsp_msb); | ||
656 | outb (page_zero[i+1], dev->fx_dsp_lsb); | ||
657 | if (!wavefront_fx_idle (dev)) return (-1); | ||
658 | } | ||
659 | |||
660 | /* Now load page one */ | ||
661 | |||
662 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
663 | outb (0x01, dev->fx_dsp_page); | ||
664 | outb (0x00, dev->fx_dsp_addr); | ||
665 | |||
666 | for (i = 0; i < sizeof (page_one); i += 2) { | ||
667 | outb (page_one[i], dev->fx_dsp_msb); | ||
668 | outb (page_one[i+1], dev->fx_dsp_lsb); | ||
669 | if (!wavefront_fx_idle (dev)) return (-1); | ||
670 | } | ||
671 | |||
672 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
673 | outb (0x02, dev->fx_dsp_page); | ||
674 | outb (0x00, dev->fx_dsp_addr); | ||
675 | |||
676 | for (i = 0; i < sizeof (page_two); i++) { | ||
677 | outb (page_two[i], dev->fx_dsp_lsb); | ||
678 | if (!wavefront_fx_idle (dev)) return (-1); | ||
679 | } | ||
680 | |||
681 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
682 | outb (0x03, dev->fx_dsp_page); | ||
683 | outb (0x00, dev->fx_dsp_addr); | ||
684 | |||
685 | for (i = 0; i < sizeof (page_three); i++) { | ||
686 | outb (page_three[i], dev->fx_dsp_lsb); | ||
687 | if (!wavefront_fx_idle (dev)) return (-1); | ||
688 | } | ||
689 | |||
690 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
691 | outb (0x04, dev->fx_dsp_page); | ||
692 | outb (0x00, dev->fx_dsp_addr); | ||
693 | |||
694 | for (i = 0; i < sizeof (page_four); i++) { | ||
695 | outb (page_four[i], dev->fx_dsp_lsb); | ||
696 | if (!wavefront_fx_idle (dev)) return (-1); | ||
697 | } | ||
698 | |||
699 | /* Load memory area (page six) */ | ||
700 | |||
701 | outb (FX_LSB_TRANSFER, dev->fx_lcr); | ||
702 | outb (0x06, dev->fx_dsp_page); | ||
703 | |||
704 | for (i = 0; i < sizeof (page_six); i += 3) { | ||
705 | outb (page_six[i], dev->fx_dsp_addr); | ||
706 | outb (page_six[i+1], dev->fx_dsp_msb); | ||
707 | outb (page_six[i+2], dev->fx_dsp_lsb); | ||
708 | if (!wavefront_fx_idle (dev)) return (-1); | ||
709 | } | ||
710 | |||
711 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
712 | outb (0x07, dev->fx_dsp_page); | ||
713 | outb (0x00, dev->fx_dsp_addr); | ||
714 | |||
715 | for (i = 0; i < sizeof (page_seven); i += 2) { | ||
716 | outb (page_seven[i], dev->fx_dsp_msb); | ||
717 | outb (page_seven[i+1], dev->fx_dsp_lsb); | ||
718 | if (!wavefront_fx_idle (dev)) return (-1); | ||
719 | } | ||
720 | |||
721 | /* Now setup the MOD area. We do this algorithmically in order to | ||
722 | save a little data space. It could be done in the same fashion | ||
723 | as the "pages". | ||
724 | */ | ||
725 | |||
726 | for (i = 0x00; i <= 0x0f; i++) { | ||
727 | outb (0x01, dev->fx_mod_addr); | ||
728 | outb (i, dev->fx_mod_data); | ||
729 | if (!wavefront_fx_idle (dev)) return (-1); | ||
730 | outb (0x02, dev->fx_mod_addr); | ||
731 | outb (0x00, dev->fx_mod_data); | ||
732 | if (!wavefront_fx_idle (dev)) return (-1); | ||
733 | } | ||
734 | |||
735 | for (i = 0xb0; i <= 0xbf; i++) { | ||
736 | outb (i, dev->fx_mod_addr); | ||
737 | outb (0x20, dev->fx_mod_data); | ||
738 | if (!wavefront_fx_idle (dev)) return (-1); | ||
739 | } | ||
740 | |||
741 | for (i = 0xf0; i <= 0xff; i++) { | ||
742 | outb (i, dev->fx_mod_addr); | ||
743 | outb (0x20, dev->fx_mod_data); | ||
744 | if (!wavefront_fx_idle (dev)) return (-1); | ||
745 | } | ||
746 | |||
747 | for (i = 0x10; i <= 0x1d; i++) { | ||
748 | outb (i, dev->fx_mod_addr); | ||
749 | outb (0xff, dev->fx_mod_data); | ||
750 | if (!wavefront_fx_idle (dev)) return (-1); | ||
751 | } | ||
752 | |||
753 | outb (0x1e, dev->fx_mod_addr); | ||
754 | outb (0x40, dev->fx_mod_data); | ||
755 | if (!wavefront_fx_idle (dev)) return (-1); | ||
756 | |||
757 | for (i = 0x1f; i <= 0x2d; i++) { | ||
758 | outb (i, dev->fx_mod_addr); | ||
759 | outb (0xff, dev->fx_mod_data); | ||
760 | if (!wavefront_fx_idle (dev)) return (-1); | ||
761 | } | ||
762 | |||
763 | outb (0x2e, dev->fx_mod_addr); | ||
764 | outb (0x00, dev->fx_mod_data); | ||
765 | if (!wavefront_fx_idle (dev)) return (-1); | ||
766 | |||
767 | for (i = 0x2f; i <= 0x3e; i++) { | ||
768 | outb (i, dev->fx_mod_addr); | ||
769 | outb (0x00, dev->fx_mod_data); | ||
770 | if (!wavefront_fx_idle (dev)) return (-1); | ||
771 | } | ||
772 | |||
773 | outb (0x3f, dev->fx_mod_addr); | ||
774 | outb (0x20, dev->fx_mod_data); | ||
775 | if (!wavefront_fx_idle (dev)) return (-1); | ||
776 | |||
777 | for (i = 0x40; i <= 0x4d; i++) { | ||
778 | outb (i, dev->fx_mod_addr); | ||
779 | outb (0x00, dev->fx_mod_data); | ||
780 | if (!wavefront_fx_idle (dev)) return (-1); | ||
781 | } | ||
782 | |||
783 | outb (0x4e, dev->fx_mod_addr); | ||
784 | outb (0x0e, dev->fx_mod_data); | ||
785 | if (!wavefront_fx_idle (dev)) return (-1); | ||
786 | outb (0x4f, dev->fx_mod_addr); | ||
787 | outb (0x0e, dev->fx_mod_data); | ||
788 | if (!wavefront_fx_idle (dev)) return (-1); | ||
789 | |||
790 | |||
791 | for (i = 0x50; i <= 0x6b; i++) { | ||
792 | outb (i, dev->fx_mod_addr); | ||
793 | outb (0x00, dev->fx_mod_data); | ||
794 | if (!wavefront_fx_idle (dev)) return (-1); | ||
795 | } | ||
796 | |||
797 | outb (0x6c, dev->fx_mod_addr); | ||
798 | outb (0x40, dev->fx_mod_data); | ||
799 | if (!wavefront_fx_idle (dev)) return (-1); | ||
800 | |||
801 | outb (0x6d, dev->fx_mod_addr); | ||
802 | outb (0x00, dev->fx_mod_data); | ||
803 | if (!wavefront_fx_idle (dev)) return (-1); | ||
804 | |||
805 | outb (0x6e, dev->fx_mod_addr); | ||
806 | outb (0x40, dev->fx_mod_data); | ||
807 | if (!wavefront_fx_idle (dev)) return (-1); | ||
808 | |||
809 | outb (0x6f, dev->fx_mod_addr); | ||
810 | outb (0x40, dev->fx_mod_data); | ||
811 | if (!wavefront_fx_idle (dev)) return (-1); | ||
812 | |||
813 | for (i = 0x70; i <= 0x7f; i++) { | ||
814 | outb (i, dev->fx_mod_addr); | ||
815 | outb (0xc0, dev->fx_mod_data); | ||
816 | if (!wavefront_fx_idle (dev)) return (-1); | ||
817 | } | ||
818 | |||
819 | for (i = 0x80; i <= 0xaf; i++) { | ||
820 | outb (i, dev->fx_mod_addr); | ||
821 | outb (0x00, dev->fx_mod_data); | ||
822 | if (!wavefront_fx_idle (dev)) return (-1); | ||
823 | } | ||
824 | |||
825 | for (i = 0xc0; i <= 0xdd; i++) { | ||
826 | outb (i, dev->fx_mod_addr); | ||
827 | outb (0x00, dev->fx_mod_data); | ||
828 | if (!wavefront_fx_idle (dev)) return (-1); | ||
829 | } | ||
830 | |||
831 | outb (0xde, dev->fx_mod_addr); | ||
832 | outb (0x10, dev->fx_mod_data); | ||
833 | if (!wavefront_fx_idle (dev)) return (-1); | ||
834 | outb (0xdf, dev->fx_mod_addr); | ||
835 | outb (0x10, dev->fx_mod_data); | ||
836 | if (!wavefront_fx_idle (dev)) return (-1); | ||
837 | |||
838 | for (i = 0xe0; i <= 0xef; i++) { | ||
839 | outb (i, dev->fx_mod_addr); | ||
840 | outb (0x00, dev->fx_mod_data); | ||
841 | if (!wavefront_fx_idle (dev)) return (-1); | ||
842 | } | ||
843 | |||
844 | for (i = 0x00; i <= 0x0f; i++) { | ||
845 | outb (0x01, dev->fx_mod_addr); | ||
846 | outb (i, dev->fx_mod_data); | ||
847 | outb (0x02, dev->fx_mod_addr); | ||
848 | outb (0x01, dev->fx_mod_data); | ||
849 | if (!wavefront_fx_idle (dev)) return (-1); | ||
850 | } | ||
851 | |||
852 | outb (0x02, dev->fx_op); /* mute on */ | ||
853 | |||
854 | /* Now set the coefficients and so forth for the programs above */ | ||
855 | |||
856 | for (i = 0; i < sizeof (coefficients); i += 4) { | ||
857 | outb (coefficients[i], dev->fx_dsp_page); | ||
858 | outb (coefficients[i+1], dev->fx_dsp_addr); | ||
859 | outb (coefficients[i+2], dev->fx_dsp_msb); | ||
860 | outb (coefficients[i+3], dev->fx_dsp_lsb); | ||
861 | if (!wavefront_fx_idle (dev)) return (-1); | ||
862 | } | ||
863 | |||
864 | /* Some settings (?) that are too small to bundle into loops */ | ||
865 | |||
866 | if (!wavefront_fx_idle (dev)) return (-1); | ||
867 | outb (0x1e, dev->fx_mod_addr); | ||
868 | outb (0x14, dev->fx_mod_data); | ||
869 | if (!wavefront_fx_idle (dev)) return (-1); | ||
870 | outb (0xde, dev->fx_mod_addr); | ||
871 | outb (0x20, dev->fx_mod_data); | ||
872 | if (!wavefront_fx_idle (dev)) return (-1); | ||
873 | outb (0xdf, dev->fx_mod_addr); | ||
874 | outb (0x20, dev->fx_mod_data); | ||
875 | |||
876 | /* some more coefficients */ | ||
877 | |||
878 | if (!wavefront_fx_idle (dev)) return (-1); | ||
879 | outb (0x06, dev->fx_dsp_page); | ||
880 | outb (0x78, dev->fx_dsp_addr); | ||
881 | outb (0x00, dev->fx_dsp_msb); | ||
882 | outb (0x40, dev->fx_dsp_lsb); | ||
883 | if (!wavefront_fx_idle (dev)) return (-1); | ||
884 | outb (0x07, dev->fx_dsp_page); | ||
885 | outb (0x03, dev->fx_dsp_addr); | ||
886 | outb (0x0f, dev->fx_dsp_msb); | ||
887 | outb (0xff, dev->fx_dsp_lsb); | ||
888 | if (!wavefront_fx_idle (dev)) return (-1); | ||
889 | outb (0x07, dev->fx_dsp_page); | ||
890 | outb (0x0b, dev->fx_dsp_addr); | ||
891 | outb (0x0f, dev->fx_dsp_msb); | ||
892 | outb (0xff, dev->fx_dsp_lsb); | ||
893 | if (!wavefront_fx_idle (dev)) return (-1); | ||
894 | outb (0x07, dev->fx_dsp_page); | ||
895 | outb (0x02, dev->fx_dsp_addr); | ||
896 | outb (0x00, dev->fx_dsp_msb); | ||
897 | outb (0x00, dev->fx_dsp_lsb); | ||
898 | if (!wavefront_fx_idle (dev)) return (-1); | ||
899 | outb (0x07, dev->fx_dsp_page); | ||
900 | outb (0x0a, dev->fx_dsp_addr); | ||
901 | outb (0x00, dev->fx_dsp_msb); | ||
902 | outb (0x00, dev->fx_dsp_lsb); | ||
903 | if (!wavefront_fx_idle (dev)) return (-1); | ||
904 | outb (0x07, dev->fx_dsp_page); | ||
905 | outb (0x46, dev->fx_dsp_addr); | ||
906 | outb (0x00, dev->fx_dsp_msb); | ||
907 | outb (0x00, dev->fx_dsp_lsb); | ||
908 | if (!wavefront_fx_idle (dev)) return (-1); | ||
909 | outb (0x07, dev->fx_dsp_page); | ||
910 | outb (0x49, dev->fx_dsp_addr); | ||
911 | outb (0x00, dev->fx_dsp_msb); | ||
912 | outb (0x00, dev->fx_dsp_lsb); | ||
913 | |||
914 | /* Now, for some strange reason, lets reload every page | ||
915 | and all the coefficients over again. I have *NO* idea | ||
916 | why this is done. I do know that no sound is produced | ||
917 | is this phase is omitted. | ||
918 | */ | ||
919 | |||
920 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
921 | outb (0x00, dev->fx_dsp_page); | ||
922 | outb (0x10, dev->fx_dsp_addr); | ||
923 | |||
924 | for (i = 0; i < sizeof (page_zero_v2); i += 2) { | ||
925 | outb (page_zero_v2[i], dev->fx_dsp_msb); | ||
926 | outb (page_zero_v2[i+1], dev->fx_dsp_lsb); | ||
927 | if (!wavefront_fx_idle (dev)) return (-1); | ||
928 | } | ||
929 | |||
930 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
931 | outb (0x01, dev->fx_dsp_page); | ||
932 | outb (0x10, dev->fx_dsp_addr); | ||
933 | |||
934 | for (i = 0; i < sizeof (page_one_v2); i += 2) { | ||
935 | outb (page_one_v2[i], dev->fx_dsp_msb); | ||
936 | outb (page_one_v2[i+1], dev->fx_dsp_lsb); | ||
937 | if (!wavefront_fx_idle (dev)) return (-1); | ||
938 | } | ||
939 | |||
940 | if (!wavefront_fx_idle (dev)) return (-1); | ||
941 | if (!wavefront_fx_idle (dev)) return (-1); | ||
942 | |||
943 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
944 | outb (0x02, dev->fx_dsp_page); | ||
945 | outb (0x10, dev->fx_dsp_addr); | ||
946 | |||
947 | for (i = 0; i < sizeof (page_two_v2); i++) { | ||
948 | outb (page_two_v2[i], dev->fx_dsp_lsb); | ||
949 | if (!wavefront_fx_idle (dev)) return (-1); | ||
950 | } | ||
951 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
952 | outb (0x03, dev->fx_dsp_page); | ||
953 | outb (0x10, dev->fx_dsp_addr); | ||
954 | |||
955 | for (i = 0; i < sizeof (page_three_v2); i++) { | ||
956 | outb (page_three_v2[i], dev->fx_dsp_lsb); | ||
957 | if (!wavefront_fx_idle (dev)) return (-1); | ||
958 | } | ||
959 | |||
960 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
961 | outb (0x04, dev->fx_dsp_page); | ||
962 | outb (0x10, dev->fx_dsp_addr); | ||
963 | |||
964 | for (i = 0; i < sizeof (page_four_v2); i++) { | ||
965 | outb (page_four_v2[i], dev->fx_dsp_lsb); | ||
966 | if (!wavefront_fx_idle (dev)) return (-1); | ||
967 | } | ||
968 | |||
969 | outb (FX_LSB_TRANSFER, dev->fx_lcr); | ||
970 | outb (0x06, dev->fx_dsp_page); | ||
971 | |||
972 | /* Page six v.2 is algorithmic */ | ||
973 | |||
974 | for (i = 0x10; i <= 0x3e; i += 2) { | ||
975 | outb (i, dev->fx_dsp_addr); | ||
976 | outb (0x00, dev->fx_dsp_msb); | ||
977 | outb (0x00, dev->fx_dsp_lsb); | ||
978 | if (!wavefront_fx_idle (dev)) return (-1); | ||
979 | } | ||
980 | |||
981 | outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev->fx_lcr); | ||
982 | outb (0x07, dev->fx_dsp_page); | ||
983 | outb (0x10, dev->fx_dsp_addr); | ||
984 | |||
985 | for (i = 0; i < sizeof (page_seven_v2); i += 2) { | ||
986 | outb (page_seven_v2[i], dev->fx_dsp_msb); | ||
987 | outb (page_seven_v2[i+1], dev->fx_dsp_lsb); | ||
988 | if (!wavefront_fx_idle (dev)) return (-1); | ||
989 | } | ||
990 | |||
991 | for (i = 0x00; i < sizeof(mod_v2); i += 2) { | ||
992 | outb (mod_v2[i], dev->fx_mod_addr); | ||
993 | outb (mod_v2[i+1], dev->fx_mod_data); | ||
994 | if (!wavefront_fx_idle (dev)) return (-1); | ||
995 | } | ||
996 | |||
997 | for (i = 0; i < sizeof (coefficients2); i += 4) { | ||
998 | outb (coefficients2[i], dev->fx_dsp_page); | ||
999 | outb (coefficients2[i+1], dev->fx_dsp_addr); | ||
1000 | outb (coefficients2[i+2], dev->fx_dsp_msb); | ||
1001 | outb (coefficients2[i+3], dev->fx_dsp_lsb); | ||
1002 | if (!wavefront_fx_idle (dev)) return (-1); | ||
1003 | } | ||
1004 | |||
1005 | for (i = 0; i < sizeof (coefficients3); i += 2) { | ||
1006 | int x; | ||
1007 | |||
1008 | outb (0x07, dev->fx_dsp_page); | ||
1009 | x = (i % 4) ? 0x4e : 0x4c; | ||
1010 | outb (x, dev->fx_dsp_addr); | ||
1011 | outb (coefficients3[i], dev->fx_dsp_msb); | ||
1012 | outb (coefficients3[i+1], dev->fx_dsp_lsb); | ||
1013 | } | ||
1014 | |||
1015 | outb (0x00, dev->fx_op); /* mute off */ | ||
1016 | if (!wavefront_fx_idle (dev)) return (-1); | ||
1017 | |||
1018 | return (0); | ||
1019 | } | ||
diff --git a/sound/isa/wavefront/wavefront_midi.c b/sound/isa/wavefront/wavefront_midi.c new file mode 100644 index 000000000000..6f51d64fb565 --- /dev/null +++ b/sound/isa/wavefront/wavefront_midi.c | |||
@@ -0,0 +1,570 @@ | |||
1 | /* | ||
2 | * Copyright (C) by Paul Barton-Davis 1998-1999 | ||
3 | * | ||
4 | * This file is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | ||
5 | * Version 2 (June 1991). See the "COPYING" file distributed with this | ||
6 | * software for more info. | ||
7 | */ | ||
8 | |||
9 | /* The low level driver for the WaveFront ICS2115 MIDI interface(s) | ||
10 | * | ||
11 | * Note that there is also an MPU-401 emulation (actually, a UART-401 | ||
12 | * emulation) on the CS4232 on the Tropez and Tropez Plus. This code | ||
13 | * has nothing to do with that interface at all. | ||
14 | * | ||
15 | * The interface is essentially just a UART-401, but is has the | ||
16 | * interesting property of supporting what Turtle Beach called | ||
17 | * "Virtual MIDI" mode. In this mode, there are effectively *two* | ||
18 | * MIDI buses accessible via the interface, one that is routed | ||
19 | * solely to/from the external WaveFront synthesizer and the other | ||
20 | * corresponding to the pin/socket connector used to link external | ||
21 | * MIDI devices to the board. | ||
22 | * | ||
23 | * This driver fully supports this mode, allowing two distinct MIDI | ||
24 | * busses to be used completely independently, giving 32 channels of | ||
25 | * MIDI routing, 16 to the WaveFront synth and 16 to the external MIDI | ||
26 | * bus. The devices are named /dev/snd/midiCnD0 and /dev/snd/midiCnD1, | ||
27 | * where `n' is the card number. Note that the device numbers may be | ||
28 | * something other than 0 and 1 if the CS4232 UART/MPU-401 interface | ||
29 | * is enabled. | ||
30 | * | ||
31 | * Switching between the two is accomplished externally by the driver | ||
32 | * using the two otherwise unused MIDI bytes. See the code for more details. | ||
33 | * | ||
34 | * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see lowlevel/isa/wavefront.c) | ||
35 | * | ||
36 | * The main reason to turn off Virtual MIDI mode is when you want to | ||
37 | * tightly couple the WaveFront synth with an external MIDI | ||
38 | * device. You won't be able to distinguish the source of any MIDI | ||
39 | * data except via SysEx ID, but thats probably OK, since for the most | ||
40 | * part, the WaveFront won't be sending any MIDI data at all. | ||
41 | * | ||
42 | * The main reason to turn on Virtual MIDI Mode is to provide two | ||
43 | * completely independent 16-channel MIDI buses, one to the | ||
44 | * WaveFront and one to any external MIDI devices. Given the 32 | ||
45 | * voice nature of the WaveFront, its pretty easy to find a use | ||
46 | * for all 16 channels driving just that synth. | ||
47 | * | ||
48 | */ | ||
49 | |||
50 | #include <sound/driver.h> | ||
51 | #include <asm/io.h> | ||
52 | #include <linux/init.h> | ||
53 | #include <linux/time.h> | ||
54 | #include <linux/wait.h> | ||
55 | #include <sound/core.h> | ||
56 | #include <sound/snd_wavefront.h> | ||
57 | |||
58 | static inline int | ||
59 | wf_mpu_status (snd_wavefront_midi_t *midi) | ||
60 | |||
61 | { | ||
62 | return inb (midi->mpu_status_port); | ||
63 | } | ||
64 | |||
65 | static inline int | ||
66 | input_avail (snd_wavefront_midi_t *midi) | ||
67 | |||
68 | { | ||
69 | return !(wf_mpu_status(midi) & INPUT_AVAIL); | ||
70 | } | ||
71 | |||
72 | static inline int | ||
73 | output_ready (snd_wavefront_midi_t *midi) | ||
74 | |||
75 | { | ||
76 | return !(wf_mpu_status(midi) & OUTPUT_READY); | ||
77 | } | ||
78 | |||
79 | static inline int | ||
80 | read_data (snd_wavefront_midi_t *midi) | ||
81 | |||
82 | { | ||
83 | return inb (midi->mpu_data_port); | ||
84 | } | ||
85 | |||
86 | static inline void | ||
87 | write_data (snd_wavefront_midi_t *midi, unsigned char byte) | ||
88 | |||
89 | { | ||
90 | outb (byte, midi->mpu_data_port); | ||
91 | } | ||
92 | |||
93 | static snd_wavefront_midi_t * | ||
94 | get_wavefront_midi (snd_rawmidi_substream_t *substream) | ||
95 | |||
96 | { | ||
97 | snd_card_t *card; | ||
98 | snd_wavefront_card_t *acard; | ||
99 | |||
100 | if (substream == NULL || substream->rmidi == NULL) | ||
101 | return NULL; | ||
102 | |||
103 | card = substream->rmidi->card; | ||
104 | |||
105 | if (card == NULL) | ||
106 | return NULL; | ||
107 | |||
108 | if (card->private_data == NULL) | ||
109 | return NULL; | ||
110 | |||
111 | acard = card->private_data; | ||
112 | |||
113 | return &acard->wavefront.midi; | ||
114 | } | ||
115 | |||
116 | static void snd_wavefront_midi_output_write(snd_wavefront_card_t *card) | ||
117 | { | ||
118 | snd_wavefront_midi_t *midi = &card->wavefront.midi; | ||
119 | snd_wavefront_mpu_id mpu; | ||
120 | unsigned long flags; | ||
121 | unsigned char midi_byte; | ||
122 | int max = 256, mask = 1; | ||
123 | int timeout; | ||
124 | |||
125 | /* Its not OK to try to change the status of "virtuality" of | ||
126 | the MIDI interface while we're outputting stuff. See | ||
127 | snd_wavefront_midi_{enable,disable}_virtual () for the | ||
128 | other half of this. | ||
129 | |||
130 | The first loop attempts to flush any data from the | ||
131 | current output device, and then the second | ||
132 | emits the switch byte (if necessary), and starts | ||
133 | outputting data for the output device currently in use. | ||
134 | */ | ||
135 | |||
136 | if (midi->substream_output[midi->output_mpu] == NULL) { | ||
137 | goto __second; | ||
138 | } | ||
139 | |||
140 | while (max > 0) { | ||
141 | |||
142 | /* XXX fix me - no hard timing loops allowed! */ | ||
143 | |||
144 | for (timeout = 30000; timeout > 0; timeout--) { | ||
145 | if (output_ready (midi)) | ||
146 | break; | ||
147 | } | ||
148 | |||
149 | spin_lock_irqsave (&midi->virtual, flags); | ||
150 | if ((midi->mode[midi->output_mpu] & MPU401_MODE_OUTPUT) == 0) { | ||
151 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
152 | goto __second; | ||
153 | } | ||
154 | if (output_ready (midi)) { | ||
155 | if (snd_rawmidi_transmit(midi->substream_output[midi->output_mpu], &midi_byte, 1) == 1) { | ||
156 | if (!midi->isvirtual || | ||
157 | (midi_byte != WF_INTERNAL_SWITCH && | ||
158 | midi_byte != WF_EXTERNAL_SWITCH)) | ||
159 | write_data(midi, midi_byte); | ||
160 | max--; | ||
161 | } else { | ||
162 | if (midi->istimer) { | ||
163 | if (--midi->istimer <= 0) | ||
164 | del_timer(&midi->timer); | ||
165 | } | ||
166 | midi->mode[midi->output_mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; | ||
167 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
168 | goto __second; | ||
169 | } | ||
170 | } else { | ||
171 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
172 | return; | ||
173 | } | ||
174 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
175 | } | ||
176 | |||
177 | __second: | ||
178 | |||
179 | if (midi->substream_output[!midi->output_mpu] == NULL) { | ||
180 | return; | ||
181 | } | ||
182 | |||
183 | while (max > 0) { | ||
184 | |||
185 | /* XXX fix me - no hard timing loops allowed! */ | ||
186 | |||
187 | for (timeout = 30000; timeout > 0; timeout--) { | ||
188 | if (output_ready (midi)) | ||
189 | break; | ||
190 | } | ||
191 | |||
192 | spin_lock_irqsave (&midi->virtual, flags); | ||
193 | if (!midi->isvirtual) | ||
194 | mask = 0; | ||
195 | mpu = midi->output_mpu ^ mask; | ||
196 | mask = 0; /* don't invert the value from now */ | ||
197 | if ((midi->mode[mpu] & MPU401_MODE_OUTPUT) == 0) { | ||
198 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
199 | return; | ||
200 | } | ||
201 | if (snd_rawmidi_transmit_empty(midi->substream_output[mpu])) | ||
202 | goto __timer; | ||
203 | if (output_ready (midi)) { | ||
204 | if (mpu != midi->output_mpu) { | ||
205 | write_data(midi, mpu == internal_mpu ? | ||
206 | WF_INTERNAL_SWITCH : | ||
207 | WF_EXTERNAL_SWITCH); | ||
208 | midi->output_mpu = mpu; | ||
209 | } else if (snd_rawmidi_transmit(midi->substream_output[mpu], &midi_byte, 1) == 1) { | ||
210 | if (!midi->isvirtual || | ||
211 | (midi_byte != WF_INTERNAL_SWITCH && | ||
212 | midi_byte != WF_EXTERNAL_SWITCH)) | ||
213 | write_data(midi, midi_byte); | ||
214 | max--; | ||
215 | } else { | ||
216 | __timer: | ||
217 | if (midi->istimer) { | ||
218 | if (--midi->istimer <= 0) | ||
219 | del_timer(&midi->timer); | ||
220 | } | ||
221 | midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; | ||
222 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
223 | return; | ||
224 | } | ||
225 | } else { | ||
226 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
227 | return; | ||
228 | } | ||
229 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
230 | } | ||
231 | } | ||
232 | |||
233 | static int snd_wavefront_midi_input_open(snd_rawmidi_substream_t * substream) | ||
234 | { | ||
235 | unsigned long flags; | ||
236 | snd_wavefront_midi_t *midi; | ||
237 | snd_wavefront_mpu_id mpu; | ||
238 | |||
239 | snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO); | ||
240 | snd_assert(substream->rmidi->private_data != NULL, return -EIO); | ||
241 | |||
242 | mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); | ||
243 | |||
244 | if ((midi = get_wavefront_midi (substream)) == NULL) | ||
245 | return -EIO; | ||
246 | |||
247 | spin_lock_irqsave (&midi->open, flags); | ||
248 | midi->mode[mpu] |= MPU401_MODE_INPUT; | ||
249 | midi->substream_input[mpu] = substream; | ||
250 | spin_unlock_irqrestore (&midi->open, flags); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int snd_wavefront_midi_output_open(snd_rawmidi_substream_t * substream) | ||
256 | { | ||
257 | unsigned long flags; | ||
258 | snd_wavefront_midi_t *midi; | ||
259 | snd_wavefront_mpu_id mpu; | ||
260 | |||
261 | snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO); | ||
262 | snd_assert(substream->rmidi->private_data != NULL, return -EIO); | ||
263 | |||
264 | mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); | ||
265 | |||
266 | if ((midi = get_wavefront_midi (substream)) == NULL) | ||
267 | return -EIO; | ||
268 | |||
269 | spin_lock_irqsave (&midi->open, flags); | ||
270 | midi->mode[mpu] |= MPU401_MODE_OUTPUT; | ||
271 | midi->substream_output[mpu] = substream; | ||
272 | spin_unlock_irqrestore (&midi->open, flags); | ||
273 | |||
274 | return 0; | ||
275 | } | ||
276 | |||
277 | static int snd_wavefront_midi_input_close(snd_rawmidi_substream_t * substream) | ||
278 | { | ||
279 | unsigned long flags; | ||
280 | snd_wavefront_midi_t *midi; | ||
281 | snd_wavefront_mpu_id mpu; | ||
282 | |||
283 | snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO); | ||
284 | snd_assert(substream->rmidi->private_data != NULL, return -EIO); | ||
285 | |||
286 | mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); | ||
287 | |||
288 | if ((midi = get_wavefront_midi (substream)) == NULL) | ||
289 | return -EIO; | ||
290 | |||
291 | spin_lock_irqsave (&midi->open, flags); | ||
292 | midi->mode[mpu] &= ~MPU401_MODE_INPUT; | ||
293 | spin_unlock_irqrestore (&midi->open, flags); | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | static int snd_wavefront_midi_output_close(snd_rawmidi_substream_t * substream) | ||
299 | { | ||
300 | unsigned long flags; | ||
301 | snd_wavefront_midi_t *midi; | ||
302 | snd_wavefront_mpu_id mpu; | ||
303 | |||
304 | snd_assert(substream != NULL && substream->rmidi != NULL, return -EIO); | ||
305 | snd_assert(substream->rmidi->private_data != NULL, return -EIO); | ||
306 | |||
307 | mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); | ||
308 | |||
309 | if ((midi = get_wavefront_midi (substream)) == NULL) | ||
310 | return -EIO; | ||
311 | |||
312 | spin_lock_irqsave (&midi->open, flags); | ||
313 | midi->mode[mpu] &= ~MPU401_MODE_OUTPUT; | ||
314 | spin_unlock_irqrestore (&midi->open, flags); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static void snd_wavefront_midi_input_trigger(snd_rawmidi_substream_t * substream, int up) | ||
319 | { | ||
320 | unsigned long flags; | ||
321 | snd_wavefront_midi_t *midi; | ||
322 | snd_wavefront_mpu_id mpu; | ||
323 | |||
324 | if (substream == NULL || substream->rmidi == NULL) | ||
325 | return; | ||
326 | |||
327 | if (substream->rmidi->private_data == NULL) | ||
328 | return; | ||
329 | |||
330 | mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); | ||
331 | |||
332 | if ((midi = get_wavefront_midi (substream)) == NULL) { | ||
333 | return; | ||
334 | } | ||
335 | |||
336 | spin_lock_irqsave (&midi->virtual, flags); | ||
337 | if (up) { | ||
338 | midi->mode[mpu] |= MPU401_MODE_INPUT_TRIGGER; | ||
339 | } else { | ||
340 | midi->mode[mpu] &= ~MPU401_MODE_INPUT_TRIGGER; | ||
341 | } | ||
342 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
343 | } | ||
344 | |||
345 | static void snd_wavefront_midi_output_timer(unsigned long data) | ||
346 | { | ||
347 | snd_wavefront_card_t *card = (snd_wavefront_card_t *)data; | ||
348 | snd_wavefront_midi_t *midi = &card->wavefront.midi; | ||
349 | unsigned long flags; | ||
350 | |||
351 | spin_lock_irqsave (&midi->virtual, flags); | ||
352 | midi->timer.expires = 1 + jiffies; | ||
353 | add_timer(&midi->timer); | ||
354 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
355 | snd_wavefront_midi_output_write(card); | ||
356 | } | ||
357 | |||
358 | static void snd_wavefront_midi_output_trigger(snd_rawmidi_substream_t * substream, int up) | ||
359 | { | ||
360 | unsigned long flags; | ||
361 | snd_wavefront_midi_t *midi; | ||
362 | snd_wavefront_mpu_id mpu; | ||
363 | |||
364 | if (substream == NULL || substream->rmidi == NULL) | ||
365 | return; | ||
366 | |||
367 | if (substream->rmidi->private_data == NULL) | ||
368 | return; | ||
369 | |||
370 | mpu = *((snd_wavefront_mpu_id *) substream->rmidi->private_data); | ||
371 | |||
372 | if ((midi = get_wavefront_midi (substream)) == NULL) { | ||
373 | return; | ||
374 | } | ||
375 | |||
376 | spin_lock_irqsave (&midi->virtual, flags); | ||
377 | if (up) { | ||
378 | if ((midi->mode[mpu] & MPU401_MODE_OUTPUT_TRIGGER) == 0) { | ||
379 | if (!midi->istimer) { | ||
380 | init_timer(&midi->timer); | ||
381 | midi->timer.function = snd_wavefront_midi_output_timer; | ||
382 | midi->timer.data = (unsigned long) substream->rmidi->card->private_data; | ||
383 | midi->timer.expires = 1 + jiffies; | ||
384 | add_timer(&midi->timer); | ||
385 | } | ||
386 | midi->istimer++; | ||
387 | midi->mode[mpu] |= MPU401_MODE_OUTPUT_TRIGGER; | ||
388 | } | ||
389 | } else { | ||
390 | midi->mode[mpu] &= ~MPU401_MODE_OUTPUT_TRIGGER; | ||
391 | } | ||
392 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
393 | |||
394 | if (up) | ||
395 | snd_wavefront_midi_output_write((snd_wavefront_card_t *)substream->rmidi->card->private_data); | ||
396 | } | ||
397 | |||
398 | void | ||
399 | snd_wavefront_midi_interrupt (snd_wavefront_card_t *card) | ||
400 | |||
401 | { | ||
402 | unsigned long flags; | ||
403 | snd_wavefront_midi_t *midi; | ||
404 | static snd_rawmidi_substream_t *substream = NULL; | ||
405 | static int mpu = external_mpu; | ||
406 | int max = 128; | ||
407 | unsigned char byte; | ||
408 | |||
409 | midi = &card->wavefront.midi; | ||
410 | |||
411 | if (!input_avail (midi)) { /* not for us */ | ||
412 | snd_wavefront_midi_output_write(card); | ||
413 | return; | ||
414 | } | ||
415 | |||
416 | spin_lock_irqsave (&midi->virtual, flags); | ||
417 | while (--max) { | ||
418 | |||
419 | if (input_avail (midi)) { | ||
420 | byte = read_data (midi); | ||
421 | |||
422 | if (midi->isvirtual) { | ||
423 | if (byte == WF_EXTERNAL_SWITCH) { | ||
424 | substream = midi->substream_input[external_mpu]; | ||
425 | mpu = external_mpu; | ||
426 | } else if (byte == WF_INTERNAL_SWITCH) { | ||
427 | substream = midi->substream_output[internal_mpu]; | ||
428 | mpu = internal_mpu; | ||
429 | } /* else just leave it as it is */ | ||
430 | } else { | ||
431 | substream = midi->substream_input[internal_mpu]; | ||
432 | mpu = internal_mpu; | ||
433 | } | ||
434 | |||
435 | if (substream == NULL) { | ||
436 | continue; | ||
437 | } | ||
438 | |||
439 | if (midi->mode[mpu] & MPU401_MODE_INPUT_TRIGGER) { | ||
440 | snd_rawmidi_receive(substream, &byte, 1); | ||
441 | } | ||
442 | } else { | ||
443 | break; | ||
444 | } | ||
445 | } | ||
446 | spin_unlock_irqrestore (&midi->virtual, flags); | ||
447 | |||
448 | snd_wavefront_midi_output_write(card); | ||
449 | } | ||
450 | |||
451 | void | ||
452 | snd_wavefront_midi_enable_virtual (snd_wavefront_card_t *card) | ||
453 | |||
454 | { | ||
455 | unsigned long flags; | ||
456 | |||
457 | spin_lock_irqsave (&card->wavefront.midi.virtual, flags); | ||
458 | card->wavefront.midi.isvirtual = 1; | ||
459 | card->wavefront.midi.output_mpu = internal_mpu; | ||
460 | card->wavefront.midi.input_mpu = internal_mpu; | ||
461 | spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags); | ||
462 | } | ||
463 | |||
464 | void | ||
465 | snd_wavefront_midi_disable_virtual (snd_wavefront_card_t *card) | ||
466 | |||
467 | { | ||
468 | unsigned long flags; | ||
469 | |||
470 | spin_lock_irqsave (&card->wavefront.midi.virtual, flags); | ||
471 | // snd_wavefront_midi_input_close (card->ics2115_external_rmidi); | ||
472 | // snd_wavefront_midi_output_close (card->ics2115_external_rmidi); | ||
473 | card->wavefront.midi.isvirtual = 0; | ||
474 | spin_unlock_irqrestore (&card->wavefront.midi.virtual, flags); | ||
475 | } | ||
476 | |||
477 | int __init | ||
478 | snd_wavefront_midi_start (snd_wavefront_card_t *card) | ||
479 | |||
480 | { | ||
481 | int ok, i; | ||
482 | unsigned char rbuf[4], wbuf[4]; | ||
483 | snd_wavefront_t *dev; | ||
484 | snd_wavefront_midi_t *midi; | ||
485 | |||
486 | dev = &card->wavefront; | ||
487 | midi = &dev->midi; | ||
488 | |||
489 | /* The ICS2115 MPU-401 interface doesn't do anything | ||
490 | until its set into UART mode. | ||
491 | */ | ||
492 | |||
493 | /* XXX fix me - no hard timing loops allowed! */ | ||
494 | |||
495 | for (i = 0; i < 30000 && !output_ready (midi); i++); | ||
496 | |||
497 | if (!output_ready (midi)) { | ||
498 | snd_printk ("MIDI interface not ready for command\n"); | ||
499 | return -1; | ||
500 | } | ||
501 | |||
502 | /* Any interrupts received from now on | ||
503 | are owned by the MIDI side of things. | ||
504 | */ | ||
505 | |||
506 | dev->interrupts_are_midi = 1; | ||
507 | |||
508 | outb (UART_MODE_ON, midi->mpu_command_port); | ||
509 | |||
510 | for (ok = 0, i = 50000; i > 0 && !ok; i--) { | ||
511 | if (input_avail (midi)) { | ||
512 | if (read_data (midi) == MPU_ACK) { | ||
513 | ok = 1; | ||
514 | break; | ||
515 | } | ||
516 | } | ||
517 | } | ||
518 | |||
519 | if (!ok) { | ||
520 | snd_printk ("cannot set UART mode for MIDI interface"); | ||
521 | dev->interrupts_are_midi = 0; | ||
522 | return -1; | ||
523 | } | ||
524 | |||
525 | /* Route external MIDI to WaveFront synth (by default) */ | ||
526 | |||
527 | if (snd_wavefront_cmd (dev, WFC_MISYNTH_ON, rbuf, wbuf)) { | ||
528 | snd_printk ("can't enable MIDI-IN-2-synth routing.\n"); | ||
529 | /* XXX error ? */ | ||
530 | } | ||
531 | |||
532 | /* Turn on Virtual MIDI, but first *always* turn it off, | ||
533 | since otherwise consectutive reloads of the driver will | ||
534 | never cause the hardware to generate the initial "internal" or | ||
535 | "external" source bytes in the MIDI data stream. This | ||
536 | is pretty important, since the internal hardware generally will | ||
537 | be used to generate none or very little MIDI output, and | ||
538 | thus the only source of MIDI data is actually external. Without | ||
539 | the switch bytes, the driver will think it all comes from | ||
540 | the internal interface. Duh. | ||
541 | */ | ||
542 | |||
543 | if (snd_wavefront_cmd (dev, WFC_VMIDI_OFF, rbuf, wbuf)) { | ||
544 | snd_printk ("virtual MIDI mode not disabled\n"); | ||
545 | return 0; /* We're OK, but missing the external MIDI dev */ | ||
546 | } | ||
547 | |||
548 | snd_wavefront_midi_enable_virtual (card); | ||
549 | |||
550 | if (snd_wavefront_cmd (dev, WFC_VMIDI_ON, rbuf, wbuf)) { | ||
551 | snd_printk ("cannot enable virtual MIDI mode.\n"); | ||
552 | snd_wavefront_midi_disable_virtual (card); | ||
553 | } | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | snd_rawmidi_ops_t snd_wavefront_midi_output = | ||
558 | { | ||
559 | .open = snd_wavefront_midi_output_open, | ||
560 | .close = snd_wavefront_midi_output_close, | ||
561 | .trigger = snd_wavefront_midi_output_trigger, | ||
562 | }; | ||
563 | |||
564 | snd_rawmidi_ops_t snd_wavefront_midi_input = | ||
565 | { | ||
566 | .open = snd_wavefront_midi_input_open, | ||
567 | .close = snd_wavefront_midi_input_close, | ||
568 | .trigger = snd_wavefront_midi_input_trigger, | ||
569 | }; | ||
570 | |||
diff --git a/sound/isa/wavefront/wavefront_synth.c b/sound/isa/wavefront/wavefront_synth.c new file mode 100644 index 000000000000..0c3c951009d8 --- /dev/null +++ b/sound/isa/wavefront/wavefront_synth.c | |||
@@ -0,0 +1,2243 @@ | |||
1 | /* Copyright (C) by Paul Barton-Davis 1998-1999 | ||
2 | * | ||
3 | * Some portions of this file are taken from work that is | ||
4 | * copyright (C) by Hannu Savolainen 1993-1996 | ||
5 | * | ||
6 | * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | ||
7 | * Version 2 (June 1991). See the "COPYING" file distributed with this software | ||
8 | * for more info. | ||
9 | */ | ||
10 | |||
11 | /* | ||
12 | * An ALSA lowlevel driver for Turtle Beach ICS2115 wavetable synth | ||
13 | * (Maui, Tropez, Tropez Plus) | ||
14 | * | ||
15 | * This driver supports the onboard wavetable synthesizer (an ICS2115), | ||
16 | * including patch, sample and program loading and unloading, conversion | ||
17 | * of GUS patches during loading, and full user-level access to all | ||
18 | * WaveFront commands. It tries to provide semi-intelligent patch and | ||
19 | * sample management as well. | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <sound/driver.h> | ||
24 | #include <asm/io.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/time.h> | ||
29 | #include <linux/wait.h> | ||
30 | #include <linux/moduleparam.h> | ||
31 | #include <sound/core.h> | ||
32 | #include <sound/snd_wavefront.h> | ||
33 | #include <sound/initval.h> | ||
34 | |||
35 | static int wf_raw = 0; /* we normally check for "raw state" to firmware | ||
36 | loading. if non-zero, then during driver loading, the | ||
37 | state of the board is ignored, and we reset the | ||
38 | board and load the firmware anyway. | ||
39 | */ | ||
40 | |||
41 | static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in | ||
42 | whatever state it is when the driver is loaded. | ||
43 | The default is to download the microprogram and | ||
44 | associated coefficients to set it up for "default" | ||
45 | operation, whatever that means. | ||
46 | */ | ||
47 | |||
48 | static int debug_default = 0; /* you can set this to control debugging | ||
49 | during driver loading. it takes any combination | ||
50 | of the WF_DEBUG_* flags defined in | ||
51 | wavefront.h | ||
52 | */ | ||
53 | |||
54 | /* XXX this needs to be made firmware and hardware version dependent */ | ||
55 | |||
56 | static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed | ||
57 | version of the WaveFront OS | ||
58 | */ | ||
59 | |||
60 | static int wait_usecs = 150; /* This magic number seems to give pretty optimal | ||
61 | throughput based on my limited experimentation. | ||
62 | If you want to play around with it and find a better | ||
63 | value, be my guest. Remember, the idea is to | ||
64 | get a number that causes us to just busy wait | ||
65 | for as many WaveFront commands as possible, without | ||
66 | coming up with a number so large that we hog the | ||
67 | whole CPU. | ||
68 | |||
69 | Specifically, with this number, out of about 134,000 | ||
70 | status waits, only about 250 result in a sleep. | ||
71 | */ | ||
72 | |||
73 | static int sleep_interval = 100; /* HZ/sleep_interval seconds per sleep */ | ||
74 | static int sleep_tries = 50; /* number of times we'll try to sleep */ | ||
75 | |||
76 | static int reset_time = 2; /* hundreths of a second we wait after a HW | ||
77 | reset for the expected interrupt. | ||
78 | */ | ||
79 | |||
80 | static int ramcheck_time = 20; /* time in seconds to wait while ROM code | ||
81 | checks on-board RAM. | ||
82 | */ | ||
83 | |||
84 | static int osrun_time = 10; /* time in seconds we wait for the OS to | ||
85 | start running. | ||
86 | */ | ||
87 | module_param(wf_raw, int, 0444); | ||
88 | MODULE_PARM_DESC(wf_raw, "if non-zero, assume that we need to boot the OS"); | ||
89 | module_param(fx_raw, int, 0444); | ||
90 | MODULE_PARM_DESC(fx_raw, "if non-zero, assume that the FX process needs help"); | ||
91 | module_param(debug_default, int, 0444); | ||
92 | MODULE_PARM_DESC(debug_default, "debug parameters for card initialization"); | ||
93 | module_param(wait_usecs, int, 0444); | ||
94 | MODULE_PARM_DESC(wait_usecs, "how long to wait without sleeping, usecs"); | ||
95 | module_param(sleep_interval, int, 0444); | ||
96 | MODULE_PARM_DESC(sleep_interval, "how long to sleep when waiting for reply"); | ||
97 | module_param(sleep_tries, int, 0444); | ||
98 | MODULE_PARM_DESC(sleep_tries, "how many times to try sleeping during a wait"); | ||
99 | module_param(ospath, charp, 0444); | ||
100 | MODULE_PARM_DESC(ospath, "full pathname to processed ICS2115 OS firmware"); | ||
101 | module_param(reset_time, int, 0444); | ||
102 | MODULE_PARM_DESC(reset_time, "how long to wait for a reset to take effect"); | ||
103 | module_param(ramcheck_time, int, 0444); | ||
104 | MODULE_PARM_DESC(ramcheck_time, "how many seconds to wait for the RAM test"); | ||
105 | module_param(osrun_time, int, 0444); | ||
106 | MODULE_PARM_DESC(osrun_time, "how many seconds to wait for the ICS2115 OS"); | ||
107 | |||
108 | /* if WF_DEBUG not defined, no run-time debugging messages will | ||
109 | be available via the debug flag setting. Given the current | ||
110 | beta state of the driver, this will remain set until a future | ||
111 | version. | ||
112 | */ | ||
113 | |||
114 | #define WF_DEBUG 1 | ||
115 | |||
116 | #ifdef WF_DEBUG | ||
117 | |||
118 | #if defined(NEW_MACRO_VARARGS) || __GNUC__ >= 3 | ||
119 | #define DPRINT(cond, ...) \ | ||
120 | if ((dev->debug & (cond)) == (cond)) { \ | ||
121 | snd_printk (__VA_ARGS__); \ | ||
122 | } | ||
123 | #else | ||
124 | #define DPRINT(cond, args...) \ | ||
125 | if ((dev->debug & (cond)) == (cond)) { \ | ||
126 | snd_printk (args); \ | ||
127 | } | ||
128 | #endif | ||
129 | #else | ||
130 | #define DPRINT(cond, args...) | ||
131 | #endif /* WF_DEBUG */ | ||
132 | |||
133 | #define LOGNAME "WaveFront: " | ||
134 | |||
135 | /* bitmasks for WaveFront status port value */ | ||
136 | |||
137 | #define STAT_RINTR_ENABLED 0x01 | ||
138 | #define STAT_CAN_READ 0x02 | ||
139 | #define STAT_INTR_READ 0x04 | ||
140 | #define STAT_WINTR_ENABLED 0x10 | ||
141 | #define STAT_CAN_WRITE 0x20 | ||
142 | #define STAT_INTR_WRITE 0x40 | ||
143 | |||
144 | static int wavefront_delete_sample (snd_wavefront_t *, int sampnum); | ||
145 | static int wavefront_find_free_sample (snd_wavefront_t *); | ||
146 | |||
147 | typedef struct { | ||
148 | int cmd; | ||
149 | char *action; | ||
150 | unsigned int read_cnt; | ||
151 | unsigned int write_cnt; | ||
152 | int need_ack; | ||
153 | } wavefront_command; | ||
154 | |||
155 | static struct { | ||
156 | int errno; | ||
157 | const char *errstr; | ||
158 | } wavefront_errors[] = { | ||
159 | { 0x01, "Bad sample number" }, | ||
160 | { 0x02, "Out of sample memory" }, | ||
161 | { 0x03, "Bad patch number" }, | ||
162 | { 0x04, "Error in number of voices" }, | ||
163 | { 0x06, "Sample load already in progress" }, | ||
164 | { 0x0B, "No sample load request pending" }, | ||
165 | { 0x0E, "Bad MIDI channel number" }, | ||
166 | { 0x10, "Download Record Error" }, | ||
167 | { 0x80, "Success" }, | ||
168 | { 0x0 } | ||
169 | }; | ||
170 | |||
171 | #define NEEDS_ACK 1 | ||
172 | |||
173 | static wavefront_command wavefront_commands[] = { | ||
174 | { WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK }, | ||
175 | { WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0}, | ||
176 | { WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK }, | ||
177 | { WFC_GET_NVOICES, "get number of voices", 1, 0, 0 }, | ||
178 | { WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK }, | ||
179 | { WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 }, | ||
180 | { WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK }, | ||
181 | { WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK }, | ||
182 | { WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 }, | ||
183 | { WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK }, | ||
184 | { WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK }, | ||
185 | { WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK }, | ||
186 | { WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK }, | ||
187 | { WFC_MIDI_STATUS, "report midi status", 1, 0, 0 }, | ||
188 | { WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 }, | ||
189 | { WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 }, | ||
190 | { WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 }, | ||
191 | { WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 }, | ||
192 | { WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 }, | ||
193 | { WFC_DOWNLOAD_SAMPLE, "download sample", | ||
194 | 0, WF_SAMPLE_BYTES, NEEDS_ACK }, | ||
195 | { WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK}, | ||
196 | { WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header", | ||
197 | 0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK }, | ||
198 | { WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 }, | ||
199 | |||
200 | /* This command requires a variable number of bytes to be written. | ||
201 | There is a hack in snd_wavefront_cmd() to support this. The actual | ||
202 | count is passed in as the read buffer ptr, cast appropriately. | ||
203 | Ugh. | ||
204 | */ | ||
205 | |||
206 | { WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK }, | ||
207 | |||
208 | /* This one is a hack as well. We just read the first byte of the | ||
209 | response, don't fetch an ACK, and leave the rest to the | ||
210 | calling function. Ugly, ugly, ugly. | ||
211 | */ | ||
212 | |||
213 | { WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 }, | ||
214 | { WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias", | ||
215 | 0, WF_ALIAS_BYTES, NEEDS_ACK }, | ||
216 | { WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0}, | ||
217 | { WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK }, | ||
218 | { WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 }, | ||
219 | { WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" }, | ||
220 | { WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 }, | ||
221 | { WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK }, | ||
222 | { WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 }, | ||
223 | { WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK }, | ||
224 | { WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 }, | ||
225 | { WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9, | ||
226 | NEEDS_ACK}, | ||
227 | { WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0}, | ||
228 | { WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel", | ||
229 | 0, 1, NEEDS_ACK }, | ||
230 | { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK }, | ||
231 | { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers", | ||
232 | 32, 0, 0 }, | ||
233 | { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK }, | ||
234 | { 0x00 } | ||
235 | }; | ||
236 | |||
237 | static const char * | ||
238 | wavefront_errorstr (int errnum) | ||
239 | |||
240 | { | ||
241 | int i; | ||
242 | |||
243 | for (i = 0; wavefront_errors[i].errstr; i++) { | ||
244 | if (wavefront_errors[i].errno == errnum) { | ||
245 | return wavefront_errors[i].errstr; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | return "Unknown WaveFront error"; | ||
250 | } | ||
251 | |||
252 | static wavefront_command * | ||
253 | wavefront_get_command (int cmd) | ||
254 | |||
255 | { | ||
256 | int i; | ||
257 | |||
258 | for (i = 0; wavefront_commands[i].cmd != 0; i++) { | ||
259 | if (cmd == wavefront_commands[i].cmd) { | ||
260 | return &wavefront_commands[i]; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | return (wavefront_command *) 0; | ||
265 | } | ||
266 | |||
267 | static inline int | ||
268 | wavefront_status (snd_wavefront_t *dev) | ||
269 | |||
270 | { | ||
271 | return inb (dev->status_port); | ||
272 | } | ||
273 | |||
274 | static int | ||
275 | wavefront_sleep (int limit) | ||
276 | |||
277 | { | ||
278 | set_current_state(TASK_INTERRUPTIBLE); | ||
279 | schedule_timeout(limit); | ||
280 | |||
281 | return signal_pending(current); | ||
282 | } | ||
283 | |||
284 | static int | ||
285 | wavefront_wait (snd_wavefront_t *dev, int mask) | ||
286 | |||
287 | { | ||
288 | int i; | ||
289 | |||
290 | /* Spin for a short period of time, because >99% of all | ||
291 | requests to the WaveFront can be serviced inline like this. | ||
292 | */ | ||
293 | |||
294 | for (i = 0; i < wait_usecs; i += 5) { | ||
295 | if (wavefront_status (dev) & mask) { | ||
296 | return 1; | ||
297 | } | ||
298 | udelay(5); | ||
299 | } | ||
300 | |||
301 | for (i = 0; i < sleep_tries; i++) { | ||
302 | |||
303 | if (wavefront_status (dev) & mask) { | ||
304 | return 1; | ||
305 | } | ||
306 | |||
307 | if (wavefront_sleep (HZ/sleep_interval)) { | ||
308 | return (0); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | return (0); | ||
313 | } | ||
314 | |||
315 | static int | ||
316 | wavefront_read (snd_wavefront_t *dev) | ||
317 | |||
318 | { | ||
319 | if (wavefront_wait (dev, STAT_CAN_READ)) | ||
320 | return inb (dev->data_port); | ||
321 | |||
322 | DPRINT (WF_DEBUG_DATA, "read timeout.\n"); | ||
323 | |||
324 | return -1; | ||
325 | } | ||
326 | |||
327 | static int | ||
328 | wavefront_write (snd_wavefront_t *dev, unsigned char data) | ||
329 | |||
330 | { | ||
331 | if (wavefront_wait (dev, STAT_CAN_WRITE)) { | ||
332 | outb (data, dev->data_port); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | DPRINT (WF_DEBUG_DATA, "write timeout.\n"); | ||
337 | |||
338 | return -1; | ||
339 | } | ||
340 | |||
341 | int | ||
342 | snd_wavefront_cmd (snd_wavefront_t *dev, | ||
343 | int cmd, unsigned char *rbuf, unsigned char *wbuf) | ||
344 | |||
345 | { | ||
346 | int ack; | ||
347 | unsigned int i; | ||
348 | int c; | ||
349 | wavefront_command *wfcmd; | ||
350 | |||
351 | if ((wfcmd = wavefront_get_command (cmd)) == (wavefront_command *) 0) { | ||
352 | snd_printk ("command 0x%x not supported.\n", | ||
353 | cmd); | ||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | /* Hack to handle the one variable-size write command. See | ||
358 | wavefront_send_multisample() for the other half of this | ||
359 | gross and ugly strategy. | ||
360 | */ | ||
361 | |||
362 | if (cmd == WFC_DOWNLOAD_MULTISAMPLE) { | ||
363 | wfcmd->write_cnt = (unsigned long) rbuf; | ||
364 | rbuf = NULL; | ||
365 | } | ||
366 | |||
367 | DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n", | ||
368 | cmd, wfcmd->action, wfcmd->read_cnt, | ||
369 | wfcmd->write_cnt, wfcmd->need_ack); | ||
370 | |||
371 | if (wavefront_write (dev, cmd)) { | ||
372 | DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request " | ||
373 | "0x%x [%s].\n", | ||
374 | cmd, wfcmd->action); | ||
375 | return 1; | ||
376 | } | ||
377 | |||
378 | if (wfcmd->write_cnt > 0) { | ||
379 | DPRINT (WF_DEBUG_DATA, "writing %d bytes " | ||
380 | "for 0x%x\n", | ||
381 | wfcmd->write_cnt, cmd); | ||
382 | |||
383 | for (i = 0; i < wfcmd->write_cnt; i++) { | ||
384 | if (wavefront_write (dev, wbuf[i])) { | ||
385 | DPRINT (WF_DEBUG_IO, "bad write for byte " | ||
386 | "%d of 0x%x [%s].\n", | ||
387 | i, cmd, wfcmd->action); | ||
388 | return 1; | ||
389 | } | ||
390 | |||
391 | DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n", | ||
392 | i, wbuf[i]); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | if (wfcmd->read_cnt > 0) { | ||
397 | DPRINT (WF_DEBUG_DATA, "reading %d ints " | ||
398 | "for 0x%x\n", | ||
399 | wfcmd->read_cnt, cmd); | ||
400 | |||
401 | for (i = 0; i < wfcmd->read_cnt; i++) { | ||
402 | |||
403 | if ((c = wavefront_read (dev)) == -1) { | ||
404 | DPRINT (WF_DEBUG_IO, "bad read for byte " | ||
405 | "%d of 0x%x [%s].\n", | ||
406 | i, cmd, wfcmd->action); | ||
407 | return 1; | ||
408 | } | ||
409 | |||
410 | /* Now handle errors. Lots of special cases here */ | ||
411 | |||
412 | if (c == 0xff) { | ||
413 | if ((c = wavefront_read (dev)) == -1) { | ||
414 | DPRINT (WF_DEBUG_IO, "bad read for " | ||
415 | "error byte at " | ||
416 | "read byte %d " | ||
417 | "of 0x%x [%s].\n", | ||
418 | i, cmd, | ||
419 | wfcmd->action); | ||
420 | return 1; | ||
421 | } | ||
422 | |||
423 | /* Can you believe this madness ? */ | ||
424 | |||
425 | if (c == 1 && | ||
426 | wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) { | ||
427 | rbuf[0] = WF_ST_EMPTY; | ||
428 | return (0); | ||
429 | |||
430 | } else if (c == 3 && | ||
431 | wfcmd->cmd == WFC_UPLOAD_PATCH) { | ||
432 | |||
433 | return 3; | ||
434 | |||
435 | } else if (c == 1 && | ||
436 | wfcmd->cmd == WFC_UPLOAD_PROGRAM) { | ||
437 | |||
438 | return 1; | ||
439 | |||
440 | } else { | ||
441 | |||
442 | DPRINT (WF_DEBUG_IO, "error %d (%s) " | ||
443 | "during " | ||
444 | "read for byte " | ||
445 | "%d of 0x%x " | ||
446 | "[%s].\n", | ||
447 | c, | ||
448 | wavefront_errorstr (c), | ||
449 | i, cmd, | ||
450 | wfcmd->action); | ||
451 | return 1; | ||
452 | |||
453 | } | ||
454 | |||
455 | } else { | ||
456 | rbuf[i] = c; | ||
457 | } | ||
458 | |||
459 | DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]); | ||
460 | } | ||
461 | } | ||
462 | |||
463 | if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) { | ||
464 | |||
465 | DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd); | ||
466 | |||
467 | /* Some commands need an ACK, but return zero instead | ||
468 | of the standard value. | ||
469 | */ | ||
470 | |||
471 | if ((ack = wavefront_read (dev)) == 0) { | ||
472 | ack = WF_ACK; | ||
473 | } | ||
474 | |||
475 | if (ack != WF_ACK) { | ||
476 | if (ack == -1) { | ||
477 | DPRINT (WF_DEBUG_IO, "cannot read ack for " | ||
478 | "0x%x [%s].\n", | ||
479 | cmd, wfcmd->action); | ||
480 | return 1; | ||
481 | |||
482 | } else { | ||
483 | int err = -1; /* something unknown */ | ||
484 | |||
485 | if (ack == 0xff) { /* explicit error */ | ||
486 | |||
487 | if ((err = wavefront_read (dev)) == -1) { | ||
488 | DPRINT (WF_DEBUG_DATA, | ||
489 | "cannot read err " | ||
490 | "for 0x%x [%s].\n", | ||
491 | cmd, wfcmd->action); | ||
492 | } | ||
493 | } | ||
494 | |||
495 | DPRINT (WF_DEBUG_IO, "0x%x [%s] " | ||
496 | "failed (0x%x, 0x%x, %s)\n", | ||
497 | cmd, wfcmd->action, ack, err, | ||
498 | wavefront_errorstr (err)); | ||
499 | |||
500 | return -err; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | DPRINT (WF_DEBUG_DATA, "ack received " | ||
505 | "for 0x%x [%s]\n", | ||
506 | cmd, wfcmd->action); | ||
507 | } else { | ||
508 | |||
509 | DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need " | ||
510 | "ACK (%d,%d,%d)\n", | ||
511 | cmd, wfcmd->action, wfcmd->read_cnt, | ||
512 | wfcmd->write_cnt, wfcmd->need_ack); | ||
513 | } | ||
514 | |||
515 | return 0; | ||
516 | |||
517 | } | ||
518 | |||
519 | /*********************************************************************** | ||
520 | WaveFront data munging | ||
521 | |||
522 | Things here are weird. All data written to the board cannot | ||
523 | have its most significant bit set. Any data item with values | ||
524 | potentially > 0x7F (127) must be split across multiple bytes. | ||
525 | |||
526 | Sometimes, we need to munge numeric values that are represented on | ||
527 | the x86 side as 8-32 bit values. Sometimes, we need to munge data | ||
528 | that is represented on the x86 side as an array of bytes. The most | ||
529 | efficient approach to handling both cases seems to be to use 2 | ||
530 | different functions for munging and 2 for de-munging. This avoids | ||
531 | weird casting and worrying about bit-level offsets. | ||
532 | |||
533 | **********************************************************************/ | ||
534 | |||
535 | static unsigned char * | ||
536 | munge_int32 (unsigned int src, | ||
537 | unsigned char *dst, | ||
538 | unsigned int dst_size) | ||
539 | { | ||
540 | unsigned int i; | ||
541 | |||
542 | for (i = 0; i < dst_size; i++) { | ||
543 | *dst = src & 0x7F; /* Mask high bit of LSB */ | ||
544 | src = src >> 7; /* Rotate Right 7 bits */ | ||
545 | /* Note: we leave the upper bits in place */ | ||
546 | |||
547 | dst++; | ||
548 | }; | ||
549 | return dst; | ||
550 | }; | ||
551 | |||
552 | static int | ||
553 | demunge_int32 (unsigned char* src, int src_size) | ||
554 | |||
555 | { | ||
556 | int i; | ||
557 | int outval = 0; | ||
558 | |||
559 | for (i = src_size - 1; i >= 0; i--) { | ||
560 | outval=(outval<<7)+src[i]; | ||
561 | } | ||
562 | |||
563 | return outval; | ||
564 | }; | ||
565 | |||
566 | static | ||
567 | unsigned char * | ||
568 | munge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size) | ||
569 | |||
570 | { | ||
571 | unsigned int i; | ||
572 | unsigned int last = dst_size / 2; | ||
573 | |||
574 | for (i = 0; i < last; i++) { | ||
575 | *dst++ = src[i] & 0x7f; | ||
576 | *dst++ = src[i] >> 7; | ||
577 | } | ||
578 | return dst; | ||
579 | } | ||
580 | |||
581 | static | ||
582 | unsigned char * | ||
583 | demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes) | ||
584 | |||
585 | { | ||
586 | int i; | ||
587 | unsigned char *end = src + src_bytes; | ||
588 | |||
589 | end = src + src_bytes; | ||
590 | |||
591 | /* NOTE: src and dst *CAN* point to the same address */ | ||
592 | |||
593 | for (i = 0; src != end; i++) { | ||
594 | dst[i] = *src++; | ||
595 | dst[i] |= (*src++)<<7; | ||
596 | } | ||
597 | |||
598 | return dst; | ||
599 | } | ||
600 | |||
601 | /*********************************************************************** | ||
602 | WaveFront: sample, patch and program management. | ||
603 | ***********************************************************************/ | ||
604 | |||
605 | static int | ||
606 | wavefront_delete_sample (snd_wavefront_t *dev, int sample_num) | ||
607 | |||
608 | { | ||
609 | unsigned char wbuf[2]; | ||
610 | int x; | ||
611 | |||
612 | wbuf[0] = sample_num & 0x7f; | ||
613 | wbuf[1] = sample_num >> 7; | ||
614 | |||
615 | if ((x = snd_wavefront_cmd (dev, WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) { | ||
616 | dev->sample_status[sample_num] = WF_ST_EMPTY; | ||
617 | } | ||
618 | |||
619 | return x; | ||
620 | } | ||
621 | |||
622 | static int | ||
623 | wavefront_get_sample_status (snd_wavefront_t *dev, int assume_rom) | ||
624 | |||
625 | { | ||
626 | int i; | ||
627 | unsigned char rbuf[32], wbuf[32]; | ||
628 | unsigned int sc_real, sc_alias, sc_multi; | ||
629 | |||
630 | /* check sample status */ | ||
631 | |||
632 | if (snd_wavefront_cmd (dev, WFC_GET_NSAMPLES, rbuf, wbuf)) { | ||
633 | snd_printk ("cannot request sample count.\n"); | ||
634 | return -1; | ||
635 | } | ||
636 | |||
637 | sc_real = sc_alias = sc_multi = dev->samples_used = 0; | ||
638 | |||
639 | for (i = 0; i < WF_MAX_SAMPLE; i++) { | ||
640 | |||
641 | wbuf[0] = i & 0x7f; | ||
642 | wbuf[1] = i >> 7; | ||
643 | |||
644 | if (snd_wavefront_cmd (dev, WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) { | ||
645 | snd_printk("cannot identify sample " | ||
646 | "type of slot %d\n", i); | ||
647 | dev->sample_status[i] = WF_ST_EMPTY; | ||
648 | continue; | ||
649 | } | ||
650 | |||
651 | dev->sample_status[i] = (WF_SLOT_FILLED|rbuf[0]); | ||
652 | |||
653 | if (assume_rom) { | ||
654 | dev->sample_status[i] |= WF_SLOT_ROM; | ||
655 | } | ||
656 | |||
657 | switch (rbuf[0] & WF_ST_MASK) { | ||
658 | case WF_ST_SAMPLE: | ||
659 | sc_real++; | ||
660 | break; | ||
661 | case WF_ST_MULTISAMPLE: | ||
662 | sc_multi++; | ||
663 | break; | ||
664 | case WF_ST_ALIAS: | ||
665 | sc_alias++; | ||
666 | break; | ||
667 | case WF_ST_EMPTY: | ||
668 | break; | ||
669 | |||
670 | default: | ||
671 | snd_printk ("unknown sample type for " | ||
672 | "slot %d (0x%x)\n", | ||
673 | i, rbuf[0]); | ||
674 | } | ||
675 | |||
676 | if (rbuf[0] != WF_ST_EMPTY) { | ||
677 | dev->samples_used++; | ||
678 | } | ||
679 | } | ||
680 | |||
681 | snd_printk ("%d samples used (%d real, %d aliases, %d multi), " | ||
682 | "%d empty\n", dev->samples_used, sc_real, sc_alias, sc_multi, | ||
683 | WF_MAX_SAMPLE - dev->samples_used); | ||
684 | |||
685 | |||
686 | return (0); | ||
687 | |||
688 | } | ||
689 | |||
690 | static int | ||
691 | wavefront_get_patch_status (snd_wavefront_t *dev) | ||
692 | |||
693 | { | ||
694 | unsigned char patchbuf[WF_PATCH_BYTES]; | ||
695 | unsigned char patchnum[2]; | ||
696 | wavefront_patch *p; | ||
697 | int i, x, cnt, cnt2; | ||
698 | |||
699 | for (i = 0; i < WF_MAX_PATCH; i++) { | ||
700 | patchnum[0] = i & 0x7f; | ||
701 | patchnum[1] = i >> 7; | ||
702 | |||
703 | if ((x = snd_wavefront_cmd (dev, WFC_UPLOAD_PATCH, patchbuf, | ||
704 | patchnum)) == 0) { | ||
705 | |||
706 | dev->patch_status[i] |= WF_SLOT_FILLED; | ||
707 | p = (wavefront_patch *) patchbuf; | ||
708 | dev->sample_status | ||
709 | [p->sample_number|(p->sample_msb<<7)] |= | ||
710 | WF_SLOT_USED; | ||
711 | |||
712 | } else if (x == 3) { /* Bad patch number */ | ||
713 | dev->patch_status[i] = 0; | ||
714 | } else { | ||
715 | snd_printk ("upload patch " | ||
716 | "error 0x%x\n", x); | ||
717 | dev->patch_status[i] = 0; | ||
718 | return 1; | ||
719 | } | ||
720 | } | ||
721 | |||
722 | /* program status has already filled in slot_used bits */ | ||
723 | |||
724 | for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) { | ||
725 | if (dev->patch_status[i] & WF_SLOT_FILLED) { | ||
726 | cnt++; | ||
727 | } | ||
728 | if (dev->patch_status[i] & WF_SLOT_USED) { | ||
729 | cnt2++; | ||
730 | } | ||
731 | |||
732 | } | ||
733 | snd_printk ("%d patch slots filled, %d in use\n", cnt, cnt2); | ||
734 | |||
735 | return (0); | ||
736 | } | ||
737 | |||
738 | static int | ||
739 | wavefront_get_program_status (snd_wavefront_t *dev) | ||
740 | |||
741 | { | ||
742 | unsigned char progbuf[WF_PROGRAM_BYTES]; | ||
743 | wavefront_program prog; | ||
744 | unsigned char prognum; | ||
745 | int i, x, l, cnt; | ||
746 | |||
747 | for (i = 0; i < WF_MAX_PROGRAM; i++) { | ||
748 | prognum = i; | ||
749 | |||
750 | if ((x = snd_wavefront_cmd (dev, WFC_UPLOAD_PROGRAM, progbuf, | ||
751 | &prognum)) == 0) { | ||
752 | |||
753 | dev->prog_status[i] |= WF_SLOT_USED; | ||
754 | |||
755 | demunge_buf (progbuf, (unsigned char *) &prog, | ||
756 | WF_PROGRAM_BYTES); | ||
757 | |||
758 | for (l = 0; l < WF_NUM_LAYERS; l++) { | ||
759 | if (prog.layer[l].mute) { | ||
760 | dev->patch_status | ||
761 | [prog.layer[l].patch_number] |= | ||
762 | WF_SLOT_USED; | ||
763 | } | ||
764 | } | ||
765 | } else if (x == 1) { /* Bad program number */ | ||
766 | dev->prog_status[i] = 0; | ||
767 | } else { | ||
768 | snd_printk ("upload program " | ||
769 | "error 0x%x\n", x); | ||
770 | dev->prog_status[i] = 0; | ||
771 | } | ||
772 | } | ||
773 | |||
774 | for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) { | ||
775 | if (dev->prog_status[i]) { | ||
776 | cnt++; | ||
777 | } | ||
778 | } | ||
779 | |||
780 | snd_printk ("%d programs slots in use\n", cnt); | ||
781 | |||
782 | return (0); | ||
783 | } | ||
784 | |||
785 | static int | ||
786 | wavefront_send_patch (snd_wavefront_t *dev, wavefront_patch_info *header) | ||
787 | |||
788 | { | ||
789 | unsigned char buf[WF_PATCH_BYTES+2]; | ||
790 | unsigned char *bptr; | ||
791 | |||
792 | DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n", | ||
793 | header->number); | ||
794 | |||
795 | dev->patch_status[header->number] |= WF_SLOT_FILLED; | ||
796 | |||
797 | bptr = buf; | ||
798 | bptr = munge_int32 (header->number, buf, 2); | ||
799 | munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES); | ||
800 | |||
801 | if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PATCH, NULL, buf)) { | ||
802 | snd_printk ("download patch failed\n"); | ||
803 | return -(EIO); | ||
804 | } | ||
805 | |||
806 | return (0); | ||
807 | } | ||
808 | |||
809 | static int | ||
810 | wavefront_send_program (snd_wavefront_t *dev, wavefront_patch_info *header) | ||
811 | |||
812 | { | ||
813 | unsigned char buf[WF_PROGRAM_BYTES+1]; | ||
814 | int i; | ||
815 | |||
816 | DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n", | ||
817 | header->number); | ||
818 | |||
819 | dev->prog_status[header->number] = WF_SLOT_USED; | ||
820 | |||
821 | /* XXX need to zero existing SLOT_USED bit for program_status[i] | ||
822 | where `i' is the program that's being (potentially) overwritten. | ||
823 | */ | ||
824 | |||
825 | for (i = 0; i < WF_NUM_LAYERS; i++) { | ||
826 | if (header->hdr.pr.layer[i].mute) { | ||
827 | dev->patch_status[header->hdr.pr.layer[i].patch_number] |= | ||
828 | WF_SLOT_USED; | ||
829 | |||
830 | /* XXX need to mark SLOT_USED for sample used by | ||
831 | patch_number, but this means we have to load it. Ick. | ||
832 | */ | ||
833 | } | ||
834 | } | ||
835 | |||
836 | buf[0] = header->number; | ||
837 | munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES); | ||
838 | |||
839 | if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_PROGRAM, NULL, buf)) { | ||
840 | snd_printk ("download patch failed\n"); | ||
841 | return -(EIO); | ||
842 | } | ||
843 | |||
844 | return (0); | ||
845 | } | ||
846 | |||
847 | static int | ||
848 | wavefront_freemem (snd_wavefront_t *dev) | ||
849 | |||
850 | { | ||
851 | char rbuf[8]; | ||
852 | |||
853 | if (snd_wavefront_cmd (dev, WFC_REPORT_FREE_MEMORY, rbuf, NULL)) { | ||
854 | snd_printk ("can't get memory stats.\n"); | ||
855 | return -1; | ||
856 | } else { | ||
857 | return demunge_int32 (rbuf, 4); | ||
858 | } | ||
859 | } | ||
860 | |||
861 | static int | ||
862 | wavefront_send_sample (snd_wavefront_t *dev, | ||
863 | wavefront_patch_info *header, | ||
864 | u16 __user *dataptr, | ||
865 | int data_is_unsigned) | ||
866 | |||
867 | { | ||
868 | /* samples are downloaded via a 16-bit wide i/o port | ||
869 | (you could think of it as 2 adjacent 8-bit wide ports | ||
870 | but its less efficient that way). therefore, all | ||
871 | the blocksizes and so forth listed in the documentation, | ||
872 | and used conventionally to refer to sample sizes, | ||
873 | which are given in 8-bit units (bytes), need to be | ||
874 | divided by 2. | ||
875 | */ | ||
876 | |||
877 | u16 sample_short; | ||
878 | u32 length; | ||
879 | u16 __user *data_end = NULL; | ||
880 | unsigned int i; | ||
881 | const unsigned int max_blksize = 4096/2; | ||
882 | unsigned int written; | ||
883 | unsigned int blocksize; | ||
884 | int dma_ack; | ||
885 | int blocknum; | ||
886 | unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES]; | ||
887 | unsigned char *shptr; | ||
888 | int skip = 0; | ||
889 | int initial_skip = 0; | ||
890 | |||
891 | DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, " | ||
892 | "type %d, %d bytes from 0x%lx\n", | ||
893 | header->size ? "" : "header ", | ||
894 | header->number, header->subkey, | ||
895 | header->size, | ||
896 | (unsigned long) header->dataptr); | ||
897 | |||
898 | if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) { | ||
899 | int x; | ||
900 | |||
901 | if ((x = wavefront_find_free_sample (dev)) < 0) { | ||
902 | return -ENOMEM; | ||
903 | } | ||
904 | snd_printk ("unspecified sample => %d\n", x); | ||
905 | header->number = x; | ||
906 | } | ||
907 | |||
908 | if (header->size) { | ||
909 | |||
910 | /* XXX it's a debatable point whether or not RDONLY semantics | ||
911 | on the ROM samples should cover just the sample data or | ||
912 | the sample header. For now, it only covers the sample data, | ||
913 | so anyone is free at all times to rewrite sample headers. | ||
914 | |||
915 | My reason for this is that we have the sample headers | ||
916 | available in the WFB file for General MIDI, and so these | ||
917 | can always be reset if needed. The sample data, however, | ||
918 | cannot be recovered without a complete reset and firmware | ||
919 | reload of the ICS2115, which is a very expensive operation. | ||
920 | |||
921 | So, doing things this way allows us to honor the notion of | ||
922 | "RESETSAMPLES" reasonably cheaply. Note however, that this | ||
923 | is done purely at user level: there is no WFB parser in | ||
924 | this driver, and so a complete reset (back to General MIDI, | ||
925 | or theoretically some other configuration) is the | ||
926 | responsibility of the user level library. | ||
927 | |||
928 | To try to do this in the kernel would be a little | ||
929 | crazy: we'd need 158K of kernel space just to hold | ||
930 | a copy of the patch/program/sample header data. | ||
931 | */ | ||
932 | |||
933 | if (dev->rom_samples_rdonly) { | ||
934 | if (dev->sample_status[header->number] & WF_SLOT_ROM) { | ||
935 | snd_printk ("sample slot %d " | ||
936 | "write protected\n", | ||
937 | header->number); | ||
938 | return -EACCES; | ||
939 | } | ||
940 | } | ||
941 | |||
942 | wavefront_delete_sample (dev, header->number); | ||
943 | } | ||
944 | |||
945 | if (header->size) { | ||
946 | dev->freemem = wavefront_freemem (dev); | ||
947 | |||
948 | if (dev->freemem < (int)header->size) { | ||
949 | snd_printk ("insufficient memory to " | ||
950 | "load %d byte sample.\n", | ||
951 | header->size); | ||
952 | return -ENOMEM; | ||
953 | } | ||
954 | |||
955 | } | ||
956 | |||
957 | skip = WF_GET_CHANNEL(&header->hdr.s); | ||
958 | |||
959 | if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) { | ||
960 | snd_printk ("channel selection only " | ||
961 | "possible on 16-bit samples"); | ||
962 | return -(EINVAL); | ||
963 | } | ||
964 | |||
965 | switch (skip) { | ||
966 | case 0: | ||
967 | initial_skip = 0; | ||
968 | skip = 1; | ||
969 | break; | ||
970 | case 1: | ||
971 | initial_skip = 0; | ||
972 | skip = 2; | ||
973 | break; | ||
974 | case 2: | ||
975 | initial_skip = 1; | ||
976 | skip = 2; | ||
977 | break; | ||
978 | case 3: | ||
979 | initial_skip = 2; | ||
980 | skip = 3; | ||
981 | break; | ||
982 | case 4: | ||
983 | initial_skip = 3; | ||
984 | skip = 4; | ||
985 | break; | ||
986 | case 5: | ||
987 | initial_skip = 4; | ||
988 | skip = 5; | ||
989 | break; | ||
990 | case 6: | ||
991 | initial_skip = 5; | ||
992 | skip = 6; | ||
993 | break; | ||
994 | } | ||
995 | |||
996 | DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => " | ||
997 | "initial skip = %d, skip = %d\n", | ||
998 | WF_GET_CHANNEL (&header->hdr.s), | ||
999 | initial_skip, skip); | ||
1000 | |||
1001 | /* Be safe, and zero the "Unused" bits ... */ | ||
1002 | |||
1003 | WF_SET_CHANNEL(&header->hdr.s, 0); | ||
1004 | |||
1005 | /* adjust size for 16 bit samples by dividing by two. We always | ||
1006 | send 16 bits per write, even for 8 bit samples, so the length | ||
1007 | is always half the size of the sample data in bytes. | ||
1008 | */ | ||
1009 | |||
1010 | length = header->size / 2; | ||
1011 | |||
1012 | /* the data we're sent has not been munged, and in fact, the | ||
1013 | header we have to send isn't just a munged copy either. | ||
1014 | so, build the sample header right here. | ||
1015 | */ | ||
1016 | |||
1017 | shptr = &sample_hdr[0]; | ||
1018 | |||
1019 | shptr = munge_int32 (header->number, shptr, 2); | ||
1020 | |||
1021 | if (header->size) { | ||
1022 | shptr = munge_int32 (length, shptr, 4); | ||
1023 | } | ||
1024 | |||
1025 | /* Yes, a 4 byte result doesn't contain all of the offset bits, | ||
1026 | but the offset only uses 24 bits. | ||
1027 | */ | ||
1028 | |||
1029 | shptr = munge_int32 (*((u32 *) &header->hdr.s.sampleStartOffset), | ||
1030 | shptr, 4); | ||
1031 | shptr = munge_int32 (*((u32 *) &header->hdr.s.loopStartOffset), | ||
1032 | shptr, 4); | ||
1033 | shptr = munge_int32 (*((u32 *) &header->hdr.s.loopEndOffset), | ||
1034 | shptr, 4); | ||
1035 | shptr = munge_int32 (*((u32 *) &header->hdr.s.sampleEndOffset), | ||
1036 | shptr, 4); | ||
1037 | |||
1038 | /* This one is truly weird. What kind of weirdo decided that in | ||
1039 | a system dominated by 16 and 32 bit integers, they would use | ||
1040 | a just 12 bits ? | ||
1041 | */ | ||
1042 | |||
1043 | shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); | ||
1044 | |||
1045 | /* Why is this nybblified, when the MSB is *always* zero ? | ||
1046 | Anyway, we can't take address of bitfield, so make a | ||
1047 | good-faith guess at where it starts. | ||
1048 | */ | ||
1049 | |||
1050 | shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1), | ||
1051 | shptr, 2); | ||
1052 | |||
1053 | if (snd_wavefront_cmd (dev, | ||
1054 | header->size ? | ||
1055 | WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER, | ||
1056 | NULL, sample_hdr)) { | ||
1057 | snd_printk ("sample %sdownload refused.\n", | ||
1058 | header->size ? "" : "header "); | ||
1059 | return -(EIO); | ||
1060 | } | ||
1061 | |||
1062 | if (header->size == 0) { | ||
1063 | goto sent; /* Sorry. Just had to have one somewhere */ | ||
1064 | } | ||
1065 | |||
1066 | data_end = dataptr + length; | ||
1067 | |||
1068 | /* Do any initial skip over an unused channel's data */ | ||
1069 | |||
1070 | dataptr += initial_skip; | ||
1071 | |||
1072 | for (written = 0, blocknum = 0; | ||
1073 | written < length; written += max_blksize, blocknum++) { | ||
1074 | |||
1075 | if ((length - written) > max_blksize) { | ||
1076 | blocksize = max_blksize; | ||
1077 | } else { | ||
1078 | /* round to nearest 16-byte value */ | ||
1079 | blocksize = ((length-written+7)&~0x7); | ||
1080 | } | ||
1081 | |||
1082 | if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_BLOCK, NULL, NULL)) { | ||
1083 | snd_printk ("download block " | ||
1084 | "request refused.\n"); | ||
1085 | return -(EIO); | ||
1086 | } | ||
1087 | |||
1088 | for (i = 0; i < blocksize; i++) { | ||
1089 | |||
1090 | if (dataptr < data_end) { | ||
1091 | |||
1092 | __get_user (sample_short, dataptr); | ||
1093 | dataptr += skip; | ||
1094 | |||
1095 | if (data_is_unsigned) { /* GUS ? */ | ||
1096 | |||
1097 | if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) { | ||
1098 | |||
1099 | /* 8 bit sample | ||
1100 | resolution, sign | ||
1101 | extend both bytes. | ||
1102 | */ | ||
1103 | |||
1104 | ((unsigned char*) | ||
1105 | &sample_short)[0] += 0x7f; | ||
1106 | ((unsigned char*) | ||
1107 | &sample_short)[1] += 0x7f; | ||
1108 | |||
1109 | } else { | ||
1110 | |||
1111 | /* 16 bit sample | ||
1112 | resolution, sign | ||
1113 | extend the MSB. | ||
1114 | */ | ||
1115 | |||
1116 | sample_short += 0x7fff; | ||
1117 | } | ||
1118 | } | ||
1119 | |||
1120 | } else { | ||
1121 | |||
1122 | /* In padding section of final block: | ||
1123 | |||
1124 | Don't fetch unsupplied data from | ||
1125 | user space, just continue with | ||
1126 | whatever the final value was. | ||
1127 | */ | ||
1128 | } | ||
1129 | |||
1130 | if (i < blocksize - 1) { | ||
1131 | outw (sample_short, dev->block_port); | ||
1132 | } else { | ||
1133 | outw (sample_short, dev->last_block_port); | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | /* Get "DMA page acknowledge", even though its really | ||
1138 | nothing to do with DMA at all. | ||
1139 | */ | ||
1140 | |||
1141 | if ((dma_ack = wavefront_read (dev)) != WF_DMA_ACK) { | ||
1142 | if (dma_ack == -1) { | ||
1143 | snd_printk ("upload sample " | ||
1144 | "DMA ack timeout\n"); | ||
1145 | return -(EIO); | ||
1146 | } else { | ||
1147 | snd_printk ("upload sample " | ||
1148 | "DMA ack error 0x%x\n", | ||
1149 | dma_ack); | ||
1150 | return -(EIO); | ||
1151 | } | ||
1152 | } | ||
1153 | } | ||
1154 | |||
1155 | dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE); | ||
1156 | |||
1157 | /* Note, label is here because sending the sample header shouldn't | ||
1158 | alter the sample_status info at all. | ||
1159 | */ | ||
1160 | |||
1161 | sent: | ||
1162 | return (0); | ||
1163 | } | ||
1164 | |||
1165 | static int | ||
1166 | wavefront_send_alias (snd_wavefront_t *dev, wavefront_patch_info *header) | ||
1167 | |||
1168 | { | ||
1169 | unsigned char alias_hdr[WF_ALIAS_BYTES]; | ||
1170 | |||
1171 | DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is " | ||
1172 | "alias for %d\n", | ||
1173 | header->number, | ||
1174 | header->hdr.a.OriginalSample); | ||
1175 | |||
1176 | munge_int32 (header->number, &alias_hdr[0], 2); | ||
1177 | munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2); | ||
1178 | munge_int32 (*((unsigned int *)&header->hdr.a.sampleStartOffset), | ||
1179 | &alias_hdr[4], 4); | ||
1180 | munge_int32 (*((unsigned int *)&header->hdr.a.loopStartOffset), | ||
1181 | &alias_hdr[8], 4); | ||
1182 | munge_int32 (*((unsigned int *)&header->hdr.a.loopEndOffset), | ||
1183 | &alias_hdr[12], 4); | ||
1184 | munge_int32 (*((unsigned int *)&header->hdr.a.sampleEndOffset), | ||
1185 | &alias_hdr[16], 4); | ||
1186 | munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3); | ||
1187 | munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2); | ||
1188 | |||
1189 | if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) { | ||
1190 | snd_printk ("download alias failed.\n"); | ||
1191 | return -(EIO); | ||
1192 | } | ||
1193 | |||
1194 | dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS); | ||
1195 | |||
1196 | return (0); | ||
1197 | } | ||
1198 | |||
1199 | static int | ||
1200 | wavefront_send_multisample (snd_wavefront_t *dev, wavefront_patch_info *header) | ||
1201 | { | ||
1202 | int i; | ||
1203 | int num_samples; | ||
1204 | unsigned char *msample_hdr; | ||
1205 | |||
1206 | msample_hdr = kmalloc(sizeof(WF_MSAMPLE_BYTES), GFP_KERNEL); | ||
1207 | if (! msample_hdr) | ||
1208 | return -ENOMEM; | ||
1209 | |||
1210 | munge_int32 (header->number, &msample_hdr[0], 2); | ||
1211 | |||
1212 | /* You'll recall at this point that the "number of samples" value | ||
1213 | in a wavefront_multisample struct is actually the log2 of the | ||
1214 | real number of samples. | ||
1215 | */ | ||
1216 | |||
1217 | num_samples = (1<<(header->hdr.ms.NumberOfSamples&7)); | ||
1218 | msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples; | ||
1219 | |||
1220 | DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n", | ||
1221 | header->number, | ||
1222 | header->hdr.ms.NumberOfSamples, | ||
1223 | num_samples); | ||
1224 | |||
1225 | for (i = 0; i < num_samples; i++) { | ||
1226 | DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n", | ||
1227 | i, header->hdr.ms.SampleNumber[i]); | ||
1228 | munge_int32 (header->hdr.ms.SampleNumber[i], | ||
1229 | &msample_hdr[3+(i*2)], 2); | ||
1230 | } | ||
1231 | |||
1232 | /* Need a hack here to pass in the number of bytes | ||
1233 | to be written to the synth. This is ugly, and perhaps | ||
1234 | one day, I'll fix it. | ||
1235 | */ | ||
1236 | |||
1237 | if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_MULTISAMPLE, | ||
1238 | (unsigned char *) (long) ((num_samples*2)+3), | ||
1239 | msample_hdr)) { | ||
1240 | snd_printk ("download of multisample failed.\n"); | ||
1241 | kfree(msample_hdr); | ||
1242 | return -(EIO); | ||
1243 | } | ||
1244 | |||
1245 | dev->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE); | ||
1246 | |||
1247 | kfree(msample_hdr); | ||
1248 | return (0); | ||
1249 | } | ||
1250 | |||
1251 | static int | ||
1252 | wavefront_fetch_multisample (snd_wavefront_t *dev, | ||
1253 | wavefront_patch_info *header) | ||
1254 | { | ||
1255 | int i; | ||
1256 | unsigned char log_ns[1]; | ||
1257 | unsigned char number[2]; | ||
1258 | int num_samples; | ||
1259 | |||
1260 | munge_int32 (header->number, number, 2); | ||
1261 | |||
1262 | if (snd_wavefront_cmd (dev, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) { | ||
1263 | snd_printk ("upload multisample failed.\n"); | ||
1264 | return -(EIO); | ||
1265 | } | ||
1266 | |||
1267 | DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n", | ||
1268 | header->number, log_ns[0]); | ||
1269 | |||
1270 | header->hdr.ms.NumberOfSamples = log_ns[0]; | ||
1271 | |||
1272 | /* get the number of samples ... */ | ||
1273 | |||
1274 | num_samples = (1 << log_ns[0]); | ||
1275 | |||
1276 | for (i = 0; i < num_samples; i++) { | ||
1277 | char d[2]; | ||
1278 | int val; | ||
1279 | |||
1280 | if ((val = wavefront_read (dev)) == -1) { | ||
1281 | snd_printk ("upload multisample failed " | ||
1282 | "during sample loop.\n"); | ||
1283 | return -(EIO); | ||
1284 | } | ||
1285 | d[0] = val; | ||
1286 | |||
1287 | if ((val = wavefront_read (dev)) == -1) { | ||
1288 | snd_printk ("upload multisample failed " | ||
1289 | "during sample loop.\n"); | ||
1290 | return -(EIO); | ||
1291 | } | ||
1292 | d[1] = val; | ||
1293 | |||
1294 | header->hdr.ms.SampleNumber[i] = | ||
1295 | demunge_int32 ((unsigned char *) d, 2); | ||
1296 | |||
1297 | DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n", | ||
1298 | i, header->hdr.ms.SampleNumber[i]); | ||
1299 | } | ||
1300 | |||
1301 | return (0); | ||
1302 | } | ||
1303 | |||
1304 | |||
1305 | static int | ||
1306 | wavefront_send_drum (snd_wavefront_t *dev, wavefront_patch_info *header) | ||
1307 | |||
1308 | { | ||
1309 | unsigned char drumbuf[WF_DRUM_BYTES]; | ||
1310 | wavefront_drum *drum = &header->hdr.d; | ||
1311 | int i; | ||
1312 | |||
1313 | DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI " | ||
1314 | "note %d, patch = %d\n", | ||
1315 | header->number, drum->PatchNumber); | ||
1316 | |||
1317 | drumbuf[0] = header->number & 0x7f; | ||
1318 | |||
1319 | for (i = 0; i < 4; i++) { | ||
1320 | munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2); | ||
1321 | } | ||
1322 | |||
1323 | if (snd_wavefront_cmd (dev, WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) { | ||
1324 | snd_printk ("download drum failed.\n"); | ||
1325 | return -(EIO); | ||
1326 | } | ||
1327 | |||
1328 | return (0); | ||
1329 | } | ||
1330 | |||
1331 | static int | ||
1332 | wavefront_find_free_sample (snd_wavefront_t *dev) | ||
1333 | |||
1334 | { | ||
1335 | int i; | ||
1336 | |||
1337 | for (i = 0; i < WF_MAX_SAMPLE; i++) { | ||
1338 | if (!(dev->sample_status[i] & WF_SLOT_FILLED)) { | ||
1339 | return i; | ||
1340 | } | ||
1341 | } | ||
1342 | snd_printk ("no free sample slots!\n"); | ||
1343 | return -1; | ||
1344 | } | ||
1345 | |||
1346 | #if 0 | ||
1347 | static int | ||
1348 | wavefront_find_free_patch (snd_wavefront_t *dev) | ||
1349 | |||
1350 | { | ||
1351 | int i; | ||
1352 | |||
1353 | for (i = 0; i < WF_MAX_PATCH; i++) { | ||
1354 | if (!(dev->patch_status[i] & WF_SLOT_FILLED)) { | ||
1355 | return i; | ||
1356 | } | ||
1357 | } | ||
1358 | snd_printk ("no free patch slots!\n"); | ||
1359 | return -1; | ||
1360 | } | ||
1361 | #endif | ||
1362 | |||
1363 | static int | ||
1364 | wavefront_load_patch (snd_wavefront_t *dev, const char __user *addr) | ||
1365 | { | ||
1366 | wavefront_patch_info *header; | ||
1367 | int err; | ||
1368 | |||
1369 | header = kmalloc(sizeof(*header), GFP_KERNEL); | ||
1370 | if (! header) | ||
1371 | return -ENOMEM; | ||
1372 | |||
1373 | if (copy_from_user (header, addr, sizeof(wavefront_patch_info) - | ||
1374 | sizeof(wavefront_any))) { | ||
1375 | snd_printk ("bad address for load patch.\n"); | ||
1376 | err = -EFAULT; | ||
1377 | goto __error; | ||
1378 | } | ||
1379 | |||
1380 | DPRINT (WF_DEBUG_LOAD_PATCH, "download " | ||
1381 | "Sample type: %d " | ||
1382 | "Sample number: %d " | ||
1383 | "Sample size: %d\n", | ||
1384 | header->subkey, | ||
1385 | header->number, | ||
1386 | header->size); | ||
1387 | |||
1388 | switch (header->subkey) { | ||
1389 | case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */ | ||
1390 | |||
1391 | if (copy_from_user (&header->hdr.s, header->hdrptr, | ||
1392 | sizeof (wavefront_sample))) { | ||
1393 | err = -EFAULT; | ||
1394 | break; | ||
1395 | } | ||
1396 | |||
1397 | err = wavefront_send_sample (dev, header, header->dataptr, 0); | ||
1398 | break; | ||
1399 | |||
1400 | case WF_ST_MULTISAMPLE: | ||
1401 | |||
1402 | if (copy_from_user (&header->hdr.s, header->hdrptr, | ||
1403 | sizeof (wavefront_multisample))) { | ||
1404 | err = -EFAULT; | ||
1405 | break; | ||
1406 | } | ||
1407 | |||
1408 | err = wavefront_send_multisample (dev, header); | ||
1409 | break; | ||
1410 | |||
1411 | case WF_ST_ALIAS: | ||
1412 | |||
1413 | if (copy_from_user (&header->hdr.a, header->hdrptr, | ||
1414 | sizeof (wavefront_alias))) { | ||
1415 | err = -EFAULT; | ||
1416 | break; | ||
1417 | } | ||
1418 | |||
1419 | err = wavefront_send_alias (dev, header); | ||
1420 | break; | ||
1421 | |||
1422 | case WF_ST_DRUM: | ||
1423 | if (copy_from_user (&header->hdr.d, header->hdrptr, | ||
1424 | sizeof (wavefront_drum))) { | ||
1425 | err = -EFAULT; | ||
1426 | break; | ||
1427 | } | ||
1428 | |||
1429 | err = wavefront_send_drum (dev, header); | ||
1430 | break; | ||
1431 | |||
1432 | case WF_ST_PATCH: | ||
1433 | if (copy_from_user (&header->hdr.p, header->hdrptr, | ||
1434 | sizeof (wavefront_patch))) { | ||
1435 | err = -EFAULT; | ||
1436 | break; | ||
1437 | } | ||
1438 | |||
1439 | err = wavefront_send_patch (dev, header); | ||
1440 | break; | ||
1441 | |||
1442 | case WF_ST_PROGRAM: | ||
1443 | if (copy_from_user (&header->hdr.pr, header->hdrptr, | ||
1444 | sizeof (wavefront_program))) { | ||
1445 | err = -EFAULT; | ||
1446 | break; | ||
1447 | } | ||
1448 | |||
1449 | err = wavefront_send_program (dev, header); | ||
1450 | break; | ||
1451 | |||
1452 | default: | ||
1453 | snd_printk ("unknown patch type %d.\n", | ||
1454 | header->subkey); | ||
1455 | err = -EINVAL; | ||
1456 | break; | ||
1457 | } | ||
1458 | |||
1459 | __error: | ||
1460 | kfree(header); | ||
1461 | return err; | ||
1462 | } | ||
1463 | |||
1464 | /*********************************************************************** | ||
1465 | WaveFront: hardware-dependent interface | ||
1466 | ***********************************************************************/ | ||
1467 | |||
1468 | static void | ||
1469 | process_sample_hdr (u8 *buf) | ||
1470 | |||
1471 | { | ||
1472 | wavefront_sample s; | ||
1473 | u8 *ptr; | ||
1474 | |||
1475 | ptr = buf; | ||
1476 | |||
1477 | /* The board doesn't send us an exact copy of a "wavefront_sample" | ||
1478 | in response to an Upload Sample Header command. Instead, we | ||
1479 | have to convert the data format back into our data structure, | ||
1480 | just as in the Download Sample command, where we have to do | ||
1481 | something very similar in the reverse direction. | ||
1482 | */ | ||
1483 | |||
1484 | *((u32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4; | ||
1485 | *((u32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4; | ||
1486 | *((u32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4; | ||
1487 | *((u32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4; | ||
1488 | *((u32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3; | ||
1489 | |||
1490 | s.SampleResolution = *ptr & 0x3; | ||
1491 | s.Loop = *ptr & 0x8; | ||
1492 | s.Bidirectional = *ptr & 0x10; | ||
1493 | s.Reverse = *ptr & 0x40; | ||
1494 | |||
1495 | /* Now copy it back to where it came from */ | ||
1496 | |||
1497 | memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample)); | ||
1498 | } | ||
1499 | |||
1500 | static int | ||
1501 | wavefront_synth_control (snd_wavefront_card_t *acard, | ||
1502 | wavefront_control *wc) | ||
1503 | |||
1504 | { | ||
1505 | snd_wavefront_t *dev = &acard->wavefront; | ||
1506 | unsigned char patchnumbuf[2]; | ||
1507 | int i; | ||
1508 | |||
1509 | DPRINT (WF_DEBUG_CMD, "synth control with " | ||
1510 | "cmd 0x%x\n", wc->cmd); | ||
1511 | |||
1512 | /* Pre-handling of or for various commands */ | ||
1513 | |||
1514 | switch (wc->cmd) { | ||
1515 | |||
1516 | case WFC_DISABLE_INTERRUPTS: | ||
1517 | snd_printk ("interrupts disabled.\n"); | ||
1518 | outb (0x80|0x20, dev->control_port); | ||
1519 | dev->interrupts_are_midi = 1; | ||
1520 | return 0; | ||
1521 | |||
1522 | case WFC_ENABLE_INTERRUPTS: | ||
1523 | snd_printk ("interrupts enabled.\n"); | ||
1524 | outb (0x80|0x40|0x20, dev->control_port); | ||
1525 | dev->interrupts_are_midi = 1; | ||
1526 | return 0; | ||
1527 | |||
1528 | case WFC_INTERRUPT_STATUS: | ||
1529 | wc->rbuf[0] = dev->interrupts_are_midi; | ||
1530 | return 0; | ||
1531 | |||
1532 | case WFC_ROMSAMPLES_RDONLY: | ||
1533 | dev->rom_samples_rdonly = wc->wbuf[0]; | ||
1534 | wc->status = 0; | ||
1535 | return 0; | ||
1536 | |||
1537 | case WFC_IDENTIFY_SLOT_TYPE: | ||
1538 | i = wc->wbuf[0] | (wc->wbuf[1] << 7); | ||
1539 | if (i <0 || i >= WF_MAX_SAMPLE) { | ||
1540 | snd_printk ("invalid slot ID %d\n", | ||
1541 | i); | ||
1542 | wc->status = EINVAL; | ||
1543 | return -EINVAL; | ||
1544 | } | ||
1545 | wc->rbuf[0] = dev->sample_status[i]; | ||
1546 | wc->status = 0; | ||
1547 | return 0; | ||
1548 | |||
1549 | case WFC_DEBUG_DRIVER: | ||
1550 | dev->debug = wc->wbuf[0]; | ||
1551 | snd_printk ("debug = 0x%x\n", dev->debug); | ||
1552 | return 0; | ||
1553 | |||
1554 | case WFC_UPLOAD_PATCH: | ||
1555 | munge_int32 (*((u32 *) wc->wbuf), patchnumbuf, 2); | ||
1556 | memcpy (wc->wbuf, patchnumbuf, 2); | ||
1557 | break; | ||
1558 | |||
1559 | case WFC_UPLOAD_MULTISAMPLE: | ||
1560 | /* multisamples have to be handled differently, and | ||
1561 | cannot be dealt with properly by snd_wavefront_cmd() alone. | ||
1562 | */ | ||
1563 | wc->status = wavefront_fetch_multisample | ||
1564 | (dev, (wavefront_patch_info *) wc->rbuf); | ||
1565 | return 0; | ||
1566 | |||
1567 | case WFC_UPLOAD_SAMPLE_ALIAS: | ||
1568 | snd_printk ("support for sample alias upload " | ||
1569 | "being considered.\n"); | ||
1570 | wc->status = EINVAL; | ||
1571 | return -EINVAL; | ||
1572 | } | ||
1573 | |||
1574 | wc->status = snd_wavefront_cmd (dev, wc->cmd, wc->rbuf, wc->wbuf); | ||
1575 | |||
1576 | /* Post-handling of certain commands. | ||
1577 | |||
1578 | In particular, if the command was an upload, demunge the data | ||
1579 | so that the user-level doesn't have to think about it. | ||
1580 | */ | ||
1581 | |||
1582 | if (wc->status == 0) { | ||
1583 | switch (wc->cmd) { | ||
1584 | /* intercept any freemem requests so that we know | ||
1585 | we are always current with the user-level view | ||
1586 | of things. | ||
1587 | */ | ||
1588 | |||
1589 | case WFC_REPORT_FREE_MEMORY: | ||
1590 | dev->freemem = demunge_int32 (wc->rbuf, 4); | ||
1591 | break; | ||
1592 | |||
1593 | case WFC_UPLOAD_PATCH: | ||
1594 | demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES); | ||
1595 | break; | ||
1596 | |||
1597 | case WFC_UPLOAD_PROGRAM: | ||
1598 | demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES); | ||
1599 | break; | ||
1600 | |||
1601 | case WFC_UPLOAD_EDRUM_PROGRAM: | ||
1602 | demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1); | ||
1603 | break; | ||
1604 | |||
1605 | case WFC_UPLOAD_SAMPLE_HEADER: | ||
1606 | process_sample_hdr (wc->rbuf); | ||
1607 | break; | ||
1608 | |||
1609 | case WFC_UPLOAD_SAMPLE_ALIAS: | ||
1610 | snd_printk ("support for " | ||
1611 | "sample aliases still " | ||
1612 | "being considered.\n"); | ||
1613 | break; | ||
1614 | |||
1615 | case WFC_VMIDI_OFF: | ||
1616 | snd_wavefront_midi_disable_virtual (acard); | ||
1617 | break; | ||
1618 | |||
1619 | case WFC_VMIDI_ON: | ||
1620 | snd_wavefront_midi_enable_virtual (acard); | ||
1621 | break; | ||
1622 | } | ||
1623 | } | ||
1624 | |||
1625 | return 0; | ||
1626 | } | ||
1627 | |||
1628 | int | ||
1629 | snd_wavefront_synth_open (snd_hwdep_t *hw, struct file *file) | ||
1630 | |||
1631 | { | ||
1632 | if (!try_module_get(hw->card->module)) | ||
1633 | return -EFAULT; | ||
1634 | file->private_data = hw; | ||
1635 | return 0; | ||
1636 | } | ||
1637 | |||
1638 | int | ||
1639 | snd_wavefront_synth_release (snd_hwdep_t *hw, struct file *file) | ||
1640 | |||
1641 | { | ||
1642 | module_put(hw->card->module); | ||
1643 | return 0; | ||
1644 | } | ||
1645 | |||
1646 | int | ||
1647 | snd_wavefront_synth_ioctl (snd_hwdep_t *hw, struct file *file, | ||
1648 | unsigned int cmd, unsigned long arg) | ||
1649 | |||
1650 | { | ||
1651 | snd_card_t *card; | ||
1652 | snd_wavefront_t *dev; | ||
1653 | snd_wavefront_card_t *acard; | ||
1654 | wavefront_control *wc; | ||
1655 | void __user *argp = (void __user *)arg; | ||
1656 | int err; | ||
1657 | |||
1658 | card = (snd_card_t *) hw->card; | ||
1659 | |||
1660 | snd_assert(card != NULL, return -ENODEV); | ||
1661 | |||
1662 | snd_assert(card->private_data != NULL, return -ENODEV); | ||
1663 | |||
1664 | acard = card->private_data; | ||
1665 | dev = &acard->wavefront; | ||
1666 | |||
1667 | switch (cmd) { | ||
1668 | case WFCTL_LOAD_SPP: | ||
1669 | if (wavefront_load_patch (dev, argp) != 0) { | ||
1670 | return -EIO; | ||
1671 | } | ||
1672 | break; | ||
1673 | |||
1674 | case WFCTL_WFCMD: | ||
1675 | wc = kmalloc(sizeof(*wc), GFP_KERNEL); | ||
1676 | if (! wc) | ||
1677 | return -ENOMEM; | ||
1678 | if (copy_from_user (wc, argp, sizeof (*wc))) | ||
1679 | err = -EFAULT; | ||
1680 | else if (wavefront_synth_control (acard, wc) < 0) | ||
1681 | err = -EIO; | ||
1682 | else if (copy_to_user (argp, wc, sizeof (*wc))) | ||
1683 | err = -EFAULT; | ||
1684 | else | ||
1685 | err = 0; | ||
1686 | kfree(wc); | ||
1687 | return err; | ||
1688 | |||
1689 | default: | ||
1690 | return -EINVAL; | ||
1691 | } | ||
1692 | |||
1693 | return 0; | ||
1694 | } | ||
1695 | |||
1696 | |||
1697 | /***********************************************************************/ | ||
1698 | /* WaveFront: interface for card-level wavefront module */ | ||
1699 | /***********************************************************************/ | ||
1700 | |||
1701 | void | ||
1702 | snd_wavefront_internal_interrupt (snd_wavefront_card_t *card) | ||
1703 | { | ||
1704 | snd_wavefront_t *dev = &card->wavefront; | ||
1705 | |||
1706 | /* | ||
1707 | Some comments on interrupts. I attempted a version of this | ||
1708 | driver that used interrupts throughout the code instead of | ||
1709 | doing busy and/or sleep-waiting. Alas, it appears that once | ||
1710 | the Motorola firmware is downloaded, the card *never* | ||
1711 | generates an RX interrupt. These are successfully generated | ||
1712 | during firmware loading, and after that wavefront_status() | ||
1713 | reports that an interrupt is pending on the card from time | ||
1714 | to time, but it never seems to be delivered to this | ||
1715 | driver. Note also that wavefront_status() continues to | ||
1716 | report that RX interrupts are enabled, suggesting that I | ||
1717 | didn't goof up and disable them by mistake. | ||
1718 | |||
1719 | Thus, I stepped back to a prior version of | ||
1720 | wavefront_wait(), the only place where this really | ||
1721 | matters. Its sad, but I've looked through the code to check | ||
1722 | on things, and I really feel certain that the Motorola | ||
1723 | firmware prevents RX-ready interrupts. | ||
1724 | */ | ||
1725 | |||
1726 | if ((wavefront_status(dev) & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) { | ||
1727 | return; | ||
1728 | } | ||
1729 | |||
1730 | spin_lock(&dev->irq_lock); | ||
1731 | dev->irq_ok = 1; | ||
1732 | dev->irq_cnt++; | ||
1733 | spin_unlock(&dev->irq_lock); | ||
1734 | wake_up(&dev->interrupt_sleeper); | ||
1735 | } | ||
1736 | |||
1737 | /* STATUS REGISTER | ||
1738 | |||
1739 | 0 Host Rx Interrupt Enable (1=Enabled) | ||
1740 | 1 Host Rx Register Full (1=Full) | ||
1741 | 2 Host Rx Interrupt Pending (1=Interrupt) | ||
1742 | 3 Unused | ||
1743 | 4 Host Tx Interrupt (1=Enabled) | ||
1744 | 5 Host Tx Register empty (1=Empty) | ||
1745 | 6 Host Tx Interrupt Pending (1=Interrupt) | ||
1746 | 7 Unused | ||
1747 | */ | ||
1748 | |||
1749 | static int __init | ||
1750 | snd_wavefront_interrupt_bits (int irq) | ||
1751 | |||
1752 | { | ||
1753 | int bits; | ||
1754 | |||
1755 | switch (irq) { | ||
1756 | case 9: | ||
1757 | bits = 0x00; | ||
1758 | break; | ||
1759 | case 5: | ||
1760 | bits = 0x08; | ||
1761 | break; | ||
1762 | case 12: | ||
1763 | bits = 0x10; | ||
1764 | break; | ||
1765 | case 15: | ||
1766 | bits = 0x18; | ||
1767 | break; | ||
1768 | |||
1769 | default: | ||
1770 | snd_printk ("invalid IRQ %d\n", irq); | ||
1771 | bits = -1; | ||
1772 | } | ||
1773 | |||
1774 | return bits; | ||
1775 | } | ||
1776 | |||
1777 | static void __init | ||
1778 | wavefront_should_cause_interrupt (snd_wavefront_t *dev, | ||
1779 | int val, int port, int timeout) | ||
1780 | |||
1781 | { | ||
1782 | wait_queue_t wait; | ||
1783 | |||
1784 | init_waitqueue_entry(&wait, current); | ||
1785 | spin_lock_irq(&dev->irq_lock); | ||
1786 | add_wait_queue(&dev->interrupt_sleeper, &wait); | ||
1787 | dev->irq_ok = 0; | ||
1788 | outb (val,port); | ||
1789 | spin_unlock_irq(&dev->irq_lock); | ||
1790 | while (1) { | ||
1791 | set_current_state(TASK_INTERRUPTIBLE); | ||
1792 | if ((timeout = schedule_timeout(timeout)) == 0) | ||
1793 | return; | ||
1794 | if (dev->irq_ok) | ||
1795 | return; | ||
1796 | } | ||
1797 | } | ||
1798 | |||
1799 | static int __init | ||
1800 | wavefront_reset_to_cleanliness (snd_wavefront_t *dev) | ||
1801 | |||
1802 | { | ||
1803 | int bits; | ||
1804 | int hwv[2]; | ||
1805 | |||
1806 | /* IRQ already checked */ | ||
1807 | |||
1808 | bits = snd_wavefront_interrupt_bits (dev->irq); | ||
1809 | |||
1810 | /* try reset of port */ | ||
1811 | |||
1812 | outb (0x0, dev->control_port); | ||
1813 | |||
1814 | /* At this point, the board is in reset, and the H/W initialization | ||
1815 | register is accessed at the same address as the data port. | ||
1816 | |||
1817 | Bit 7 - Enable IRQ Driver | ||
1818 | 0 - Tri-state the Wave-Board drivers for the PC Bus IRQs | ||
1819 | 1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus. | ||
1820 | |||
1821 | Bit 6 - MIDI Interface Select | ||
1822 | |||
1823 | 0 - Use the MIDI Input from the 26-pin WaveBlaster | ||
1824 | compatible header as the serial MIDI source | ||
1825 | 1 - Use the MIDI Input from the 9-pin D connector as the | ||
1826 | serial MIDI source. | ||
1827 | |||
1828 | Bits 5:3 - IRQ Selection | ||
1829 | 0 0 0 - IRQ 2/9 | ||
1830 | 0 0 1 - IRQ 5 | ||
1831 | 0 1 0 - IRQ 12 | ||
1832 | 0 1 1 - IRQ 15 | ||
1833 | 1 0 0 - Reserved | ||
1834 | 1 0 1 - Reserved | ||
1835 | 1 1 0 - Reserved | ||
1836 | 1 1 1 - Reserved | ||
1837 | |||
1838 | Bits 2:1 - Reserved | ||
1839 | Bit 0 - Disable Boot ROM | ||
1840 | 0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM | ||
1841 | 1 - memory accesses to 03FC30-03FFFFH are directed to external | ||
1842 | storage. | ||
1843 | |||
1844 | */ | ||
1845 | |||
1846 | /* configure hardware: IRQ, enable interrupts, | ||
1847 | plus external 9-pin MIDI interface selected | ||
1848 | */ | ||
1849 | |||
1850 | outb (0x80 | 0x40 | bits, dev->data_port); | ||
1851 | |||
1852 | /* CONTROL REGISTER | ||
1853 | |||
1854 | 0 Host Rx Interrupt Enable (1=Enabled) 0x1 | ||
1855 | 1 Unused 0x2 | ||
1856 | 2 Unused 0x4 | ||
1857 | 3 Unused 0x8 | ||
1858 | 4 Host Tx Interrupt Enable 0x10 | ||
1859 | 5 Mute (0=Mute; 1=Play) 0x20 | ||
1860 | 6 Master Interrupt Enable (1=Enabled) 0x40 | ||
1861 | 7 Master Reset (0=Reset; 1=Run) 0x80 | ||
1862 | |||
1863 | Take us out of reset, mute output, master + TX + RX interrupts on. | ||
1864 | |||
1865 | We'll get an interrupt presumably to tell us that the TX | ||
1866 | register is clear. | ||
1867 | */ | ||
1868 | |||
1869 | wavefront_should_cause_interrupt(dev, 0x80|0x40|0x10|0x1, | ||
1870 | dev->control_port, | ||
1871 | (reset_time*HZ)/100); | ||
1872 | |||
1873 | /* Note: data port is now the data port, not the h/w initialization | ||
1874 | port. | ||
1875 | */ | ||
1876 | |||
1877 | if (!dev->irq_ok) { | ||
1878 | snd_printk ("intr not received after h/w un-reset.\n"); | ||
1879 | goto gone_bad; | ||
1880 | } | ||
1881 | |||
1882 | /* Note: data port is now the data port, not the h/w initialization | ||
1883 | port. | ||
1884 | |||
1885 | At this point, only "HW VERSION" or "DOWNLOAD OS" commands | ||
1886 | will work. So, issue one of them, and wait for TX | ||
1887 | interrupt. This can take a *long* time after a cold boot, | ||
1888 | while the ISC ROM does its RAM test. The SDK says up to 4 | ||
1889 | seconds - with 12MB of RAM on a Tropez+, it takes a lot | ||
1890 | longer than that (~16secs). Note that the card understands | ||
1891 | the difference between a warm and a cold boot, so | ||
1892 | subsequent ISC2115 reboots (say, caused by module | ||
1893 | reloading) will get through this much faster. | ||
1894 | |||
1895 | XXX Interesting question: why is no RX interrupt received first ? | ||
1896 | */ | ||
1897 | |||
1898 | wavefront_should_cause_interrupt(dev, WFC_HARDWARE_VERSION, | ||
1899 | dev->data_port, ramcheck_time*HZ); | ||
1900 | |||
1901 | if (!dev->irq_ok) { | ||
1902 | snd_printk ("post-RAM-check interrupt not received.\n"); | ||
1903 | goto gone_bad; | ||
1904 | } | ||
1905 | |||
1906 | if (!wavefront_wait (dev, STAT_CAN_READ)) { | ||
1907 | snd_printk ("no response to HW version cmd.\n"); | ||
1908 | goto gone_bad; | ||
1909 | } | ||
1910 | |||
1911 | if ((hwv[0] = wavefront_read (dev)) == -1) { | ||
1912 | snd_printk ("board not responding correctly.\n"); | ||
1913 | goto gone_bad; | ||
1914 | } | ||
1915 | |||
1916 | if (hwv[0] == 0xFF) { /* NAK */ | ||
1917 | |||
1918 | /* Board's RAM test failed. Try to read error code, | ||
1919 | and tell us about it either way. | ||
1920 | */ | ||
1921 | |||
1922 | if ((hwv[0] = wavefront_read (dev)) == -1) { | ||
1923 | snd_printk ("on-board RAM test failed " | ||
1924 | "(bad error code).\n"); | ||
1925 | } else { | ||
1926 | snd_printk ("on-board RAM test failed " | ||
1927 | "(error code: 0x%x).\n", | ||
1928 | hwv[0]); | ||
1929 | } | ||
1930 | goto gone_bad; | ||
1931 | } | ||
1932 | |||
1933 | /* We're OK, just get the next byte of the HW version response */ | ||
1934 | |||
1935 | if ((hwv[1] = wavefront_read (dev)) == -1) { | ||
1936 | snd_printk ("incorrect h/w response.\n"); | ||
1937 | goto gone_bad; | ||
1938 | } | ||
1939 | |||
1940 | snd_printk ("hardware version %d.%d\n", | ||
1941 | hwv[0], hwv[1]); | ||
1942 | |||
1943 | return 0; | ||
1944 | |||
1945 | |||
1946 | gone_bad: | ||
1947 | return (1); | ||
1948 | } | ||
1949 | |||
1950 | #include <linux/fs.h> | ||
1951 | #include <linux/mm.h> | ||
1952 | #include <linux/slab.h> | ||
1953 | #include <linux/unistd.h> | ||
1954 | #include <linux/syscalls.h> | ||
1955 | #include <asm/uaccess.h> | ||
1956 | |||
1957 | |||
1958 | static int __init | ||
1959 | wavefront_download_firmware (snd_wavefront_t *dev, char *path) | ||
1960 | |||
1961 | { | ||
1962 | unsigned char section[WF_SECTION_MAX]; | ||
1963 | signed char section_length; /* yes, just a char; max value is WF_SECTION_MAX */ | ||
1964 | int section_cnt_downloaded = 0; | ||
1965 | int fd; | ||
1966 | int c; | ||
1967 | int i; | ||
1968 | mm_segment_t fs; | ||
1969 | |||
1970 | /* This tries to be a bit cleverer than the stuff Alan Cox did for | ||
1971 | the generic sound firmware, in that it actually knows | ||
1972 | something about the structure of the Motorola firmware. In | ||
1973 | particular, it uses a version that has been stripped of the | ||
1974 | 20K of useless header information, and had section lengths | ||
1975 | added, making it possible to load the entire OS without any | ||
1976 | [kv]malloc() activity, since the longest entity we ever read is | ||
1977 | 42 bytes (well, WF_SECTION_MAX) long. | ||
1978 | */ | ||
1979 | |||
1980 | fs = get_fs(); | ||
1981 | set_fs (get_ds()); | ||
1982 | |||
1983 | if ((fd = sys_open ((char __user *) path, 0, 0)) < 0) { | ||
1984 | snd_printk ("Unable to load \"%s\".\n", | ||
1985 | path); | ||
1986 | return 1; | ||
1987 | } | ||
1988 | |||
1989 | while (1) { | ||
1990 | int x; | ||
1991 | |||
1992 | if ((x = sys_read (fd, (char __user *) §ion_length, sizeof (section_length))) != | ||
1993 | sizeof (section_length)) { | ||
1994 | snd_printk ("firmware read error.\n"); | ||
1995 | goto failure; | ||
1996 | } | ||
1997 | |||
1998 | if (section_length == 0) { | ||
1999 | break; | ||
2000 | } | ||
2001 | |||
2002 | if (section_length < 0 || section_length > WF_SECTION_MAX) { | ||
2003 | snd_printk ("invalid firmware section length %d\n", | ||
2004 | section_length); | ||
2005 | goto failure; | ||
2006 | } | ||
2007 | |||
2008 | if (sys_read (fd, (char __user *) section, section_length) != section_length) { | ||
2009 | snd_printk ("firmware section " | ||
2010 | "read error.\n"); | ||
2011 | goto failure; | ||
2012 | } | ||
2013 | |||
2014 | /* Send command */ | ||
2015 | |||
2016 | if (wavefront_write (dev, WFC_DOWNLOAD_OS)) { | ||
2017 | goto failure; | ||
2018 | } | ||
2019 | |||
2020 | for (i = 0; i < section_length; i++) { | ||
2021 | if (wavefront_write (dev, section[i])) { | ||
2022 | goto failure; | ||
2023 | } | ||
2024 | } | ||
2025 | |||
2026 | /* get ACK */ | ||
2027 | |||
2028 | if (wavefront_wait (dev, STAT_CAN_READ)) { | ||
2029 | |||
2030 | if ((c = inb (dev->data_port)) != WF_ACK) { | ||
2031 | |||
2032 | snd_printk ("download " | ||
2033 | "of section #%d not " | ||
2034 | "acknowledged, ack = 0x%x\n", | ||
2035 | section_cnt_downloaded + 1, c); | ||
2036 | goto failure; | ||
2037 | |||
2038 | } | ||
2039 | |||
2040 | } else { | ||
2041 | snd_printk ("time out for firmware ACK.\n"); | ||
2042 | goto failure; | ||
2043 | } | ||
2044 | |||
2045 | } | ||
2046 | |||
2047 | sys_close (fd); | ||
2048 | set_fs (fs); | ||
2049 | return 0; | ||
2050 | |||
2051 | failure: | ||
2052 | sys_close (fd); | ||
2053 | set_fs (fs); | ||
2054 | snd_printk ("firmware download failed!!!\n"); | ||
2055 | return 1; | ||
2056 | } | ||
2057 | |||
2058 | |||
2059 | static int __init | ||
2060 | wavefront_do_reset (snd_wavefront_t *dev) | ||
2061 | |||
2062 | { | ||
2063 | char voices[1]; | ||
2064 | |||
2065 | if (wavefront_reset_to_cleanliness (dev)) { | ||
2066 | snd_printk ("hw reset failed.\n"); | ||
2067 | goto gone_bad; | ||
2068 | } | ||
2069 | |||
2070 | if (dev->israw) { | ||
2071 | if (wavefront_download_firmware (dev, ospath)) { | ||
2072 | goto gone_bad; | ||
2073 | } | ||
2074 | |||
2075 | dev->israw = 0; | ||
2076 | |||
2077 | /* Wait for the OS to get running. The protocol for | ||
2078 | this is non-obvious, and was determined by | ||
2079 | using port-IO tracing in DOSemu and some | ||
2080 | experimentation here. | ||
2081 | |||
2082 | Rather than using timed waits, use interrupts creatively. | ||
2083 | */ | ||
2084 | |||
2085 | wavefront_should_cause_interrupt (dev, WFC_NOOP, | ||
2086 | dev->data_port, | ||
2087 | (osrun_time*HZ)); | ||
2088 | |||
2089 | if (!dev->irq_ok) { | ||
2090 | snd_printk ("no post-OS interrupt.\n"); | ||
2091 | goto gone_bad; | ||
2092 | } | ||
2093 | |||
2094 | /* Now, do it again ! */ | ||
2095 | |||
2096 | wavefront_should_cause_interrupt (dev, WFC_NOOP, | ||
2097 | dev->data_port, (10*HZ)); | ||
2098 | |||
2099 | if (!dev->irq_ok) { | ||
2100 | snd_printk ("no post-OS interrupt(2).\n"); | ||
2101 | goto gone_bad; | ||
2102 | } | ||
2103 | |||
2104 | /* OK, no (RX/TX) interrupts any more, but leave mute | ||
2105 | in effect. | ||
2106 | */ | ||
2107 | |||
2108 | outb (0x80|0x40, dev->control_port); | ||
2109 | } | ||
2110 | |||
2111 | /* SETUPSND.EXE asks for sample memory config here, but since i | ||
2112 | have no idea how to interpret the result, we'll forget | ||
2113 | about it. | ||
2114 | */ | ||
2115 | |||
2116 | if ((dev->freemem = wavefront_freemem (dev)) < 0) { | ||
2117 | goto gone_bad; | ||
2118 | } | ||
2119 | |||
2120 | snd_printk ("available DRAM %dk\n", dev->freemem / 1024); | ||
2121 | |||
2122 | if (wavefront_write (dev, 0xf0) || | ||
2123 | wavefront_write (dev, 1) || | ||
2124 | (wavefront_read (dev) < 0)) { | ||
2125 | dev->debug = 0; | ||
2126 | snd_printk ("MPU emulation mode not set.\n"); | ||
2127 | goto gone_bad; | ||
2128 | } | ||
2129 | |||
2130 | voices[0] = 32; | ||
2131 | |||
2132 | if (snd_wavefront_cmd (dev, WFC_SET_NVOICES, NULL, voices)) { | ||
2133 | snd_printk ("cannot set number of voices to 32.\n"); | ||
2134 | goto gone_bad; | ||
2135 | } | ||
2136 | |||
2137 | |||
2138 | return 0; | ||
2139 | |||
2140 | gone_bad: | ||
2141 | /* reset that sucker so that it doesn't bother us. */ | ||
2142 | |||
2143 | outb (0x0, dev->control_port); | ||
2144 | dev->interrupts_are_midi = 0; | ||
2145 | return 1; | ||
2146 | } | ||
2147 | |||
2148 | int __init | ||
2149 | snd_wavefront_start (snd_wavefront_t *dev) | ||
2150 | |||
2151 | { | ||
2152 | int samples_are_from_rom; | ||
2153 | |||
2154 | /* IMPORTANT: assumes that snd_wavefront_detect() and/or | ||
2155 | wavefront_reset_to_cleanliness() has already been called | ||
2156 | */ | ||
2157 | |||
2158 | if (dev->israw) { | ||
2159 | samples_are_from_rom = 1; | ||
2160 | } else { | ||
2161 | /* XXX is this always true ? */ | ||
2162 | samples_are_from_rom = 0; | ||
2163 | } | ||
2164 | |||
2165 | if (dev->israw || fx_raw) { | ||
2166 | if (wavefront_do_reset (dev)) { | ||
2167 | return -1; | ||
2168 | } | ||
2169 | } | ||
2170 | /* Check for FX device, present only on Tropez+ */ | ||
2171 | |||
2172 | dev->has_fx = (snd_wavefront_fx_detect (dev) == 0); | ||
2173 | |||
2174 | if (dev->has_fx && fx_raw) { | ||
2175 | snd_wavefront_fx_start (dev); | ||
2176 | } | ||
2177 | |||
2178 | wavefront_get_sample_status (dev, samples_are_from_rom); | ||
2179 | wavefront_get_program_status (dev); | ||
2180 | wavefront_get_patch_status (dev); | ||
2181 | |||
2182 | /* Start normal operation: unreset, master interrupt enabled, no mute | ||
2183 | */ | ||
2184 | |||
2185 | outb (0x80|0x40|0x20, dev->control_port); | ||
2186 | |||
2187 | return (0); | ||
2188 | } | ||
2189 | |||
2190 | int __init | ||
2191 | snd_wavefront_detect (snd_wavefront_card_t *card) | ||
2192 | |||
2193 | { | ||
2194 | unsigned char rbuf[4], wbuf[4]; | ||
2195 | snd_wavefront_t *dev = &card->wavefront; | ||
2196 | |||
2197 | /* returns zero if a WaveFront card is successfully detected. | ||
2198 | negative otherwise. | ||
2199 | */ | ||
2200 | |||
2201 | dev->israw = 0; | ||
2202 | dev->has_fx = 0; | ||
2203 | dev->debug = debug_default; | ||
2204 | dev->interrupts_are_midi = 0; | ||
2205 | dev->irq_cnt = 0; | ||
2206 | dev->rom_samples_rdonly = 1; | ||
2207 | |||
2208 | if (snd_wavefront_cmd (dev, WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) { | ||
2209 | |||
2210 | dev->fw_version[0] = rbuf[0]; | ||
2211 | dev->fw_version[1] = rbuf[1]; | ||
2212 | |||
2213 | snd_printk ("firmware %d.%d already loaded.\n", | ||
2214 | rbuf[0], rbuf[1]); | ||
2215 | |||
2216 | /* check that a command actually works */ | ||
2217 | |||
2218 | if (snd_wavefront_cmd (dev, WFC_HARDWARE_VERSION, | ||
2219 | rbuf, wbuf) == 0) { | ||
2220 | dev->hw_version[0] = rbuf[0]; | ||
2221 | dev->hw_version[1] = rbuf[1]; | ||
2222 | } else { | ||
2223 | snd_printk ("not raw, but no " | ||
2224 | "hardware version!\n"); | ||
2225 | return -1; | ||
2226 | } | ||
2227 | |||
2228 | if (!wf_raw) { | ||
2229 | return 0; | ||
2230 | } else { | ||
2231 | snd_printk ("reloading firmware as you requested.\n"); | ||
2232 | dev->israw = 1; | ||
2233 | } | ||
2234 | |||
2235 | } else { | ||
2236 | |||
2237 | dev->israw = 1; | ||
2238 | snd_printk ("no response to firmware probe, assume raw.\n"); | ||
2239 | |||
2240 | } | ||
2241 | |||
2242 | return 0; | ||
2243 | } | ||