aboutsummaryrefslogtreecommitdiffstats
path: root/sound/isa
diff options
context:
space:
mode:
authorKrzysztof Helt <krzysztof.h1@wp.pl>2009-01-24 07:35:28 -0500
committerTakashi Iwai <tiwai@suse.de>2009-01-28 01:47:36 -0500
commitf6c6383502751ceb6f2f3579ad22578ca44f91f5 (patch)
tree84a6334a964de74cfea170bf77dcab0281978756 /sound/isa
parentb1a0aac05f044e78a589bfd7a9e2334aa640eb45 (diff)
ALSA: Turtle Beach Multisound Classic/Pinnacle driver
This is driver for Turtle Beach Multisound cards: Classic, Fiji and Pinnacle. Tested pcm playback and recording and MIDI playback on Multisound Pinnacle. Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/isa')
-rw-r--r--sound/isa/Kconfig31
-rw-r--r--sound/isa/msnd/Makefile9
-rw-r--r--sound/isa/msnd/msnd.c702
-rw-r--r--sound/isa/msnd/msnd.h308
-rw-r--r--sound/isa/msnd/msnd_classic.c3
-rw-r--r--sound/isa/msnd/msnd_classic.h129
-rw-r--r--sound/isa/msnd/msnd_midi.c180
-rw-r--r--sound/isa/msnd/msnd_pinnacle.c1235
-rw-r--r--sound/isa/msnd/msnd_pinnacle.h181
-rw-r--r--sound/isa/msnd/msnd_pinnacle_mixer.c343
10 files changed, 3121 insertions, 0 deletions
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig
index ce0aa044e274..a74725950b02 100644
--- a/sound/isa/Kconfig
+++ b/sound/isa/Kconfig
@@ -411,5 +411,36 @@ config SND_WAVEFRONT_FIRMWARE_IN_KERNEL
411 you need to install the firmware files from the 411 you need to install the firmware files from the
412 alsa-firmware package. 412 alsa-firmware package.
413 413
414config SND_MSND_PINNACLE
415 tristate "Turtle Beach MultiSound Pinnacle/Fiji driver"
416 depends on X86 && EXPERIMENTAL
417 select FW_LOADER
418 select SND_MPU401_UART
419 select SND_PCM
420 help
421 Say Y to include support for Turtle Beach MultiSound Pinnacle/
422 Fiji soundcards.
423
424 To compile this driver as a module, choose M here: the module
425 will be called snd-msnd-pinnacle.
426
427config SND_MSND_CLASSIC
428 tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
429 depends on X86 && EXPERIMENTAL
430 select FW_LOADER
431 select SND_MPU401_UART
432 select SND_PCM
433 help
434 Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
435 Monterey (not for the Pinnacle or Fiji).
436
437 See <file:Documentation/sound/oss/MultiSound> for important information
438 about this driver. Note that it has been discontinued, but the
439 Voyetra Turtle Beach knowledge base entry for it is still available
440 at <http://www.turtlebeach.com/site/kb_ftp/790.asp>.
441
442 To compile this driver as a module, choose M here: the module
443 will be called snd-msnd-classic.
444
414endif # SND_ISA 445endif # SND_ISA
415 446
diff --git a/sound/isa/msnd/Makefile b/sound/isa/msnd/Makefile
new file mode 100644
index 000000000000..2171c0aa2f62
--- /dev/null
+++ b/sound/isa/msnd/Makefile
@@ -0,0 +1,9 @@
1
2snd-msnd-lib-objs := msnd.o msnd_midi.o msnd_pinnacle_mixer.o
3snd-msnd-pinnacle-objs := msnd_pinnacle.o
4snd-msnd-classic-objs := msnd_classic.o
5
6# Toplevel Module Dependency
7obj-$(CONFIG_SND_MSND_PINNACLE) += snd-msnd-pinnacle.o snd-msnd-lib.o
8obj-$(CONFIG_SND_MSND_CLASSIC) += snd-msnd-classic.o snd-msnd-lib.o
9
diff --git a/sound/isa/msnd/msnd.c b/sound/isa/msnd/msnd.c
new file mode 100644
index 000000000000..264e08212c69
--- /dev/null
+++ b/sound/isa/msnd/msnd.c
@@ -0,0 +1,702 @@
1/*********************************************************************
2 *
3 * 2002/06/30 Karsten Wiese:
4 * removed kernel-version dependencies.
5 * ripped from linux kernel 2.4.18 (OSS Implementation) by me.
6 * In the OSS Version, this file is compiled to a separate MODULE,
7 * that is used by the pinnacle and the classic driver.
8 * since there is no classic driver for alsa yet (i dont have a classic
9 * & writing one blindfold is difficult) this file's object is statically
10 * linked into the pinnacle-driver-module for now. look for the string
11 * "uncomment this to make this a module again"
12 * to do guess what.
13 *
14 * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
15 *
16 * msnd.c - Driver Base
17 *
18 * Turtle Beach MultiSound Sound Card Driver for Linux
19 *
20 * Copyright (C) 1998 Andrew Veliath
21 *
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *
36 ********************************************************************/
37
38#include <linux/kernel.h>
39#include <linux/types.h>
40#include <linux/interrupt.h>
41#include <linux/io.h>
42#include <linux/fs.h>
43#include <linux/delay.h>
44
45#include <sound/core.h>
46#include <sound/initval.h>
47#include <sound/pcm.h>
48#include <sound/pcm_params.h>
49
50#include "msnd.h"
51
52#define LOGNAME "msnd"
53
54
55void snd_msnd_init_queue(void *base, int start, int size)
56{
57 writew(PCTODSP_BASED(start), base + JQS_wStart);
58 writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
59 writew(0, base + JQS_wHead);
60 writew(0, base + JQS_wTail);
61}
62EXPORT_SYMBOL(snd_msnd_init_queue);
63
64static int snd_msnd_wait_TXDE(struct snd_msnd *dev)
65{
66 unsigned int io = dev->io;
67 int timeout = 1000;
68
69 while (timeout-- > 0)
70 if (inb(io + HP_ISR) & HPISR_TXDE)
71 return 0;
72
73 return -EIO;
74}
75
76static int snd_msnd_wait_HC0(struct snd_msnd *dev)
77{
78 unsigned int io = dev->io;
79 int timeout = 1000;
80
81 while (timeout-- > 0)
82 if (!(inb(io + HP_CVR) & HPCVR_HC))
83 return 0;
84
85 return -EIO;
86}
87
88int snd_msnd_send_dsp_cmd(struct snd_msnd *dev, u8 cmd)
89{
90 unsigned long flags;
91
92 spin_lock_irqsave(&dev->lock, flags);
93 if (snd_msnd_wait_HC0(dev) == 0) {
94 outb(cmd, dev->io + HP_CVR);
95 spin_unlock_irqrestore(&dev->lock, flags);
96 return 0;
97 }
98 spin_unlock_irqrestore(&dev->lock, flags);
99
100 snd_printd(KERN_ERR LOGNAME ": Send DSP command timeout\n");
101
102 return -EIO;
103}
104EXPORT_SYMBOL(snd_msnd_send_dsp_cmd);
105
106int snd_msnd_send_word(struct snd_msnd *dev, unsigned char high,
107 unsigned char mid, unsigned char low)
108{
109 unsigned int io = dev->io;
110
111 if (snd_msnd_wait_TXDE(dev) == 0) {
112 outb(high, io + HP_TXH);
113 outb(mid, io + HP_TXM);
114 outb(low, io + HP_TXL);
115 return 0;
116 }
117
118 snd_printd(KERN_ERR LOGNAME ": Send host word timeout\n");
119
120 return -EIO;
121}
122EXPORT_SYMBOL(snd_msnd_send_word);
123
124int snd_msnd_upload_host(struct snd_msnd *dev, const u8 *bin, int len)
125{
126 int i;
127
128 if (len % 3 != 0) {
129 snd_printk(KERN_ERR LOGNAME
130 ": Upload host data not multiple of 3!\n");
131 return -EINVAL;
132 }
133
134 for (i = 0; i < len; i += 3)
135 if (snd_msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]))
136 return -EIO;
137
138 inb(dev->io + HP_RXL);
139 inb(dev->io + HP_CVR);
140
141 return 0;
142}
143EXPORT_SYMBOL(snd_msnd_upload_host);
144
145int snd_msnd_enable_irq(struct snd_msnd *dev)
146{
147 unsigned long flags;
148
149 if (dev->irq_ref++)
150 return 0;
151
152 snd_printdd(LOGNAME ": Enabling IRQ\n");
153
154 spin_lock_irqsave(&dev->lock, flags);
155 if (snd_msnd_wait_TXDE(dev) == 0) {
156 outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
157 if (dev->type == msndClassic)
158 outb(dev->irqid, dev->io + HP_IRQM);
159
160 outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
161 outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
162 enable_irq(dev->irq);
163 snd_msnd_init_queue(dev->DSPQ, dev->dspq_data_buff,
164 dev->dspq_buff_size);
165 spin_unlock_irqrestore(&dev->lock, flags);
166 return 0;
167 }
168 spin_unlock_irqrestore(&dev->lock, flags);
169
170 snd_printd(KERN_ERR LOGNAME ": Enable IRQ failed\n");
171
172 return -EIO;
173}
174EXPORT_SYMBOL(snd_msnd_enable_irq);
175
176int snd_msnd_disable_irq(struct snd_msnd *dev)
177{
178 unsigned long flags;
179
180 if (--dev->irq_ref > 0)
181 return 0;
182
183 if (dev->irq_ref < 0)
184 snd_printd(KERN_WARNING LOGNAME ": IRQ ref count is %d\n",
185 dev->irq_ref);
186
187 snd_printdd(LOGNAME ": Disabling IRQ\n");
188
189 spin_lock_irqsave(&dev->lock, flags);
190 if (snd_msnd_wait_TXDE(dev) == 0) {
191 outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
192 if (dev->type == msndClassic)
193 outb(HPIRQ_NONE, dev->io + HP_IRQM);
194 disable_irq(dev->irq);
195 spin_unlock_irqrestore(&dev->lock, flags);
196 return 0;
197 }
198 spin_unlock_irqrestore(&dev->lock, flags);
199
200 snd_printd(KERN_ERR LOGNAME ": Disable IRQ failed\n");
201
202 return -EIO;
203}
204EXPORT_SYMBOL(snd_msnd_disable_irq);
205
206static inline long get_play_delay_jiffies(struct snd_msnd *chip, long size)
207{
208 long tmp = (size * HZ * chip->play_sample_size) / 8;
209 return tmp / (chip->play_sample_rate * chip->play_channels);
210}
211
212static void snd_msnd_dsp_write_flush(struct snd_msnd *chip)
213{
214 if (!(chip->mode & FMODE_WRITE) || !test_bit(F_WRITING, &chip->flags))
215 return;
216 set_bit(F_WRITEFLUSH, &chip->flags);
217/* interruptible_sleep_on_timeout(
218 &chip->writeflush,
219 get_play_delay_jiffies(&chip, chip->DAPF.len));*/
220 clear_bit(F_WRITEFLUSH, &chip->flags);
221 if (!signal_pending(current))
222 schedule_timeout_interruptible(
223 get_play_delay_jiffies(chip, chip->play_period_bytes));
224 clear_bit(F_WRITING, &chip->flags);
225}
226
227void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file)
228{
229 if ((file ? file->f_mode : chip->mode) & FMODE_READ) {
230 clear_bit(F_READING, &chip->flags);
231 snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
232 snd_msnd_disable_irq(chip);
233 if (file) {
234 snd_printd(KERN_INFO LOGNAME
235 ": Stopping read for %p\n", file);
236 chip->mode &= ~FMODE_READ;
237 }
238 clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
239 }
240 if ((file ? file->f_mode : chip->mode) & FMODE_WRITE) {
241 if (test_bit(F_WRITING, &chip->flags)) {
242 snd_msnd_dsp_write_flush(chip);
243 snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
244 }
245 snd_msnd_disable_irq(chip);
246 if (file) {
247 snd_printd(KERN_INFO
248 LOGNAME ": Stopping write for %p\n", file);
249 chip->mode &= ~FMODE_WRITE;
250 }
251 clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
252 }
253}
254EXPORT_SYMBOL(snd_msnd_dsp_halt);
255
256
257int snd_msnd_DARQ(struct snd_msnd *chip, int bank)
258{
259 int /*size, n,*/ timeout = 3;
260 u16 wTmp;
261 /* void *DAQD; */
262
263 /* Increment the tail and check for queue wrap */
264 wTmp = readw(chip->DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
265 if (wTmp > readw(chip->DARQ + JQS_wSize))
266 wTmp = 0;
267 while (wTmp == readw(chip->DARQ + JQS_wHead) && timeout--)
268 udelay(1);
269
270 if (chip->capturePeriods == 2) {
271 void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF +
272 bank * DAQDS__size + DAQDS_wStart;
273 unsigned short offset = 0x3000 + chip->capturePeriodBytes;
274
275 if (readw(pDAQ) != PCTODSP_BASED(0x3000))
276 offset = 0x3000;
277 writew(PCTODSP_BASED(offset), pDAQ);
278 }
279
280 writew(wTmp, chip->DARQ + JQS_wTail);
281
282#if 0
283 /* Get our digital audio queue struct */
284 DAQD = bank * DAQDS__size + chip->mappedbase + DARQ_DATA_BUFF;
285
286 /* Get length of data */
287 size = readw(DAQD + DAQDS_wSize);
288
289 /* Read data from the head (unprotected bank 1 access okay
290 since this is only called inside an interrupt) */
291 outb(HPBLKSEL_1, chip->io + HP_BLKS);
292 n = msnd_fifo_write(&chip->DARF,
293 (char *)(chip->base + bank * DAR_BUFF_SIZE),
294 size, 0);
295 if (n <= 0) {
296 outb(HPBLKSEL_0, chip->io + HP_BLKS);
297 return n;
298 }
299 outb(HPBLKSEL_0, chip->io + HP_BLKS);
300#endif
301
302 return 1;
303}
304EXPORT_SYMBOL(snd_msnd_DARQ);
305
306int snd_msnd_DAPQ(struct snd_msnd *chip, int start)
307{
308 u16 DAPQ_tail;
309 int protect = start, nbanks = 0;
310 void *DAQD;
311 static int play_banks_submitted;
312 /* unsigned long flags;
313 spin_lock_irqsave(&chip->lock, flags); not necessary */
314
315 DAPQ_tail = readw(chip->DAPQ + JQS_wTail);
316 while (DAPQ_tail != readw(chip->DAPQ + JQS_wHead) || start) {
317 int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
318
319 if (start) {
320 start = 0;
321 play_banks_submitted = 0;
322 }
323
324 /* Get our digital audio queue struct */
325 DAQD = bank_num * DAQDS__size + chip->mappedbase +
326 DAPQ_DATA_BUFF;
327
328 /* Write size of this bank */
329 writew(chip->play_period_bytes, DAQD + DAQDS_wSize);
330 if (play_banks_submitted < 3)
331 ++play_banks_submitted;
332 else if (chip->playPeriods == 2) {
333 unsigned short offset = chip->play_period_bytes;
334
335 if (readw(DAQD + DAQDS_wStart) != PCTODSP_BASED(0x0))
336 offset = 0;
337
338 writew(PCTODSP_BASED(offset), DAQD + DAQDS_wStart);
339 }
340 ++nbanks;
341
342 /* Then advance the tail */
343 /*
344 if (protect)
345 snd_printd(KERN_INFO "B %X %lX\n",
346 bank_num, xtime.tv_usec);
347 */
348
349 DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
350 writew(DAPQ_tail, chip->DAPQ + JQS_wTail);
351 /* Tell the DSP to play the bank */
352 snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_START);
353 if (protect)
354 if (2 == bank_num)
355 break;
356 }
357 /*
358 if (protect)
359 snd_printd(KERN_INFO "%lX\n", xtime.tv_usec);
360 */
361 /* spin_unlock_irqrestore(&chip->lock, flags); not necessary */
362 return nbanks;
363}
364EXPORT_SYMBOL(snd_msnd_DAPQ);
365
366static void snd_msnd_play_reset_queue(struct snd_msnd *chip,
367 unsigned int pcm_periods,
368 unsigned int pcm_count)
369{
370 int n;
371 void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
372
373 chip->last_playbank = -1;
374 chip->playLimit = pcm_count * (pcm_periods - 1);
375 chip->playPeriods = pcm_periods;
376 writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wHead);
377 writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DAPQ + JQS_wTail);
378
379 chip->play_period_bytes = pcm_count;
380
381 for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
382 writew(PCTODSP_BASED((u32)(pcm_count * n)),
383 pDAQ + DAQDS_wStart);
384 writew(0, pDAQ + DAQDS_wSize);
385 writew(1, pDAQ + DAQDS_wFormat);
386 writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
387 writew(chip->play_channels, pDAQ + DAQDS_wChannels);
388 writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
389 writew(HIMT_PLAY_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
390 writew(n, pDAQ + DAQDS_wFlags);
391 }
392}
393
394static void snd_msnd_capture_reset_queue(struct snd_msnd *chip,
395 unsigned int pcm_periods,
396 unsigned int pcm_count)
397{
398 int n;
399 void *pDAQ;
400 /* unsigned long flags; */
401
402 /* snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); */
403
404 chip->last_recbank = 2;
405 chip->captureLimit = pcm_count * (pcm_periods - 1);
406 chip->capturePeriods = pcm_periods;
407 writew(PCTODSP_OFFSET(0 * DAQDS__size), chip->DARQ + JQS_wHead);
408 writew(PCTODSP_OFFSET(chip->last_recbank * DAQDS__size),
409 chip->DARQ + JQS_wTail);
410
411#if 0 /* Critical section: bank 1 access. this is how the OSS driver does it:*/
412 spin_lock_irqsave(&chip->lock, flags);
413 outb(HPBLKSEL_1, chip->io + HP_BLKS);
414 memset_io(chip->mappedbase, 0, DAR_BUFF_SIZE * 3);
415 outb(HPBLKSEL_0, chip->io + HP_BLKS);
416 spin_unlock_irqrestore(&chip->lock, flags);
417#endif
418
419 chip->capturePeriodBytes = pcm_count;
420 snd_printdd("snd_msnd_capture_reset_queue() %i\n", pcm_count);
421
422 pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
423
424 for (n = 0; n < pcm_periods; ++n, pDAQ += DAQDS__size) {
425 u32 tmp = pcm_count * n;
426
427 writew(PCTODSP_BASED(tmp + 0x3000), pDAQ + DAQDS_wStart);
428 writew(pcm_count, pDAQ + DAQDS_wSize);
429 writew(1, pDAQ + DAQDS_wFormat);
430 writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
431 writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
432 writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
433 writew(HIMT_RECORD_DONE * 0x100 + n, pDAQ + DAQDS_wIntMsg);
434 writew(n, pDAQ + DAQDS_wFlags);
435 }
436}
437
438static struct snd_pcm_hardware snd_msnd_playback = {
439 .info = SNDRV_PCM_INFO_MMAP |
440 SNDRV_PCM_INFO_INTERLEAVED |
441 SNDRV_PCM_INFO_MMAP_VALID,
442 .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
443 .rates = SNDRV_PCM_RATE_8000_48000,
444 .rate_min = 8000,
445 .rate_max = 48000,
446 .channels_min = 1,
447 .channels_max = 2,
448 .buffer_bytes_max = 0x3000,
449 .period_bytes_min = 0x40,
450 .period_bytes_max = 0x1800,
451 .periods_min = 2,
452 .periods_max = 3,
453 .fifo_size = 0,
454};
455
456static struct snd_pcm_hardware snd_msnd_capture = {
457 .info = SNDRV_PCM_INFO_MMAP |
458 SNDRV_PCM_INFO_INTERLEAVED |
459 SNDRV_PCM_INFO_MMAP_VALID,
460 .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
461 .rates = SNDRV_PCM_RATE_8000_48000,
462 .rate_min = 8000,
463 .rate_max = 48000,
464 .channels_min = 1,
465 .channels_max = 2,
466 .buffer_bytes_max = 0x3000,
467 .period_bytes_min = 0x40,
468 .period_bytes_max = 0x1800,
469 .periods_min = 2,
470 .periods_max = 3,
471 .fifo_size = 0,
472};
473
474
475static int snd_msnd_playback_open(struct snd_pcm_substream *substream)
476{
477 struct snd_pcm_runtime *runtime = substream->runtime;
478 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
479
480 set_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
481 clear_bit(F_WRITING, &chip->flags);
482 snd_msnd_enable_irq(chip);
483
484 runtime->dma_area = chip->mappedbase;
485 runtime->dma_bytes = 0x3000;
486
487 chip->playback_substream = substream;
488 runtime->hw = snd_msnd_playback;
489 return 0;
490}
491
492static int snd_msnd_playback_close(struct snd_pcm_substream *substream)
493{
494 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
495
496 snd_msnd_disable_irq(chip);
497 clear_bit(F_AUDIO_WRITE_INUSE, &chip->flags);
498 return 0;
499}
500
501
502static int snd_msnd_playback_hw_params(struct snd_pcm_substream *substream,
503 struct snd_pcm_hw_params *params)
504{
505 int i;
506 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
507 void *pDAQ = chip->mappedbase + DAPQ_DATA_BUFF;
508
509 chip->play_sample_size = snd_pcm_format_width(params_format(params));
510 chip->play_channels = params_channels(params);
511 chip->play_sample_rate = params_rate(params);
512
513 for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
514 writew(chip->play_sample_size, pDAQ + DAQDS_wSampleSize);
515 writew(chip->play_channels, pDAQ + DAQDS_wChannels);
516 writew(chip->play_sample_rate, pDAQ + DAQDS_wSampleRate);
517 }
518 /* dont do this here:
519 * snd_msnd_calibrate_adc(chip->play_sample_rate);
520 */
521
522 return 0;
523}
524
525static int snd_msnd_playback_prepare(struct snd_pcm_substream *substream)
526{
527 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
528 unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
529 unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
530 unsigned int pcm_periods = pcm_size / pcm_count;
531
532 snd_msnd_play_reset_queue(chip, pcm_periods, pcm_count);
533 chip->playDMAPos = 0;
534 return 0;
535}
536
537static int snd_msnd_playback_trigger(struct snd_pcm_substream *substream,
538 int cmd)
539{
540 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
541 int result = 0;
542
543 if (cmd == SNDRV_PCM_TRIGGER_START) {
544 snd_printdd("snd_msnd_playback_trigger(START)\n");
545 chip->banksPlayed = 0;
546 set_bit(F_WRITING, &chip->flags);
547 snd_msnd_DAPQ(chip, 1);
548 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
549 snd_printdd("snd_msnd_playback_trigger(STop)\n");
550 /* interrupt diagnostic, comment this out later */
551 clear_bit(F_WRITING, &chip->flags);
552 snd_msnd_send_dsp_cmd(chip, HDEX_PLAY_STOP);
553 } else {
554 snd_printd(KERN_ERR "snd_msnd_playback_trigger(?????)\n");
555 result = -EINVAL;
556 }
557
558 snd_printdd("snd_msnd_playback_trigger() ENDE\n");
559 return result;
560}
561
562static snd_pcm_uframes_t
563snd_msnd_playback_pointer(struct snd_pcm_substream *substream)
564{
565 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
566
567 return bytes_to_frames(substream->runtime, chip->playDMAPos);
568}
569
570
571static struct snd_pcm_ops snd_msnd_playback_ops = {
572 .open = snd_msnd_playback_open,
573 .close = snd_msnd_playback_close,
574 .ioctl = snd_pcm_lib_ioctl,
575 .hw_params = snd_msnd_playback_hw_params,
576 .prepare = snd_msnd_playback_prepare,
577 .trigger = snd_msnd_playback_trigger,
578 .pointer = snd_msnd_playback_pointer,
579};
580
581static int snd_msnd_capture_open(struct snd_pcm_substream *substream)
582{
583 struct snd_pcm_runtime *runtime = substream->runtime;
584 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
585
586 set_bit(F_AUDIO_READ_INUSE, &chip->flags);
587 snd_msnd_enable_irq(chip);
588 runtime->dma_area = chip->mappedbase + 0x3000;
589 runtime->dma_bytes = 0x3000;
590 memset(runtime->dma_area, 0, runtime->dma_bytes);
591 chip->capture_substream = substream;
592 runtime->hw = snd_msnd_capture;
593 return 0;
594}
595
596static int snd_msnd_capture_close(struct snd_pcm_substream *substream)
597{
598 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
599
600 snd_msnd_disable_irq(chip);
601 clear_bit(F_AUDIO_READ_INUSE, &chip->flags);
602 return 0;
603}
604
605static int snd_msnd_capture_prepare(struct snd_pcm_substream *substream)
606{
607 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
608 unsigned int pcm_size = snd_pcm_lib_buffer_bytes(substream);
609 unsigned int pcm_count = snd_pcm_lib_period_bytes(substream);
610 unsigned int pcm_periods = pcm_size / pcm_count;
611
612 snd_msnd_capture_reset_queue(chip, pcm_periods, pcm_count);
613 chip->captureDMAPos = 0;
614 return 0;
615}
616
617static int snd_msnd_capture_trigger(struct snd_pcm_substream *substream,
618 int cmd)
619{
620 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
621
622 if (cmd == SNDRV_PCM_TRIGGER_START) {
623 chip->last_recbank = -1;
624 set_bit(F_READING, &chip->flags);
625 if (snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_START) == 0)
626 return 0;
627
628 clear_bit(F_READING, &chip->flags);
629 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
630 clear_bit(F_READING, &chip->flags);
631 snd_msnd_send_dsp_cmd(chip, HDEX_RECORD_STOP);
632 return 0;
633 }
634 return -EINVAL;
635}
636
637
638static snd_pcm_uframes_t
639snd_msnd_capture_pointer(struct snd_pcm_substream *substream)
640{
641 struct snd_pcm_runtime *runtime = substream->runtime;
642 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
643
644 return bytes_to_frames(runtime, chip->captureDMAPos);
645}
646
647
648static int snd_msnd_capture_hw_params(struct snd_pcm_substream *substream,
649 struct snd_pcm_hw_params *params)
650{
651 int i;
652 struct snd_msnd *chip = snd_pcm_substream_chip(substream);
653 void *pDAQ = chip->mappedbase + DARQ_DATA_BUFF;
654
655 chip->capture_sample_size = snd_pcm_format_width(params_format(params));
656 chip->capture_channels = params_channels(params);
657 chip->capture_sample_rate = params_rate(params);
658
659 for (i = 0; i < 3; ++i, pDAQ += DAQDS__size) {
660 writew(chip->capture_sample_size, pDAQ + DAQDS_wSampleSize);
661 writew(chip->capture_channels, pDAQ + DAQDS_wChannels);
662 writew(chip->capture_sample_rate, pDAQ + DAQDS_wSampleRate);
663 }
664 return 0;
665}
666
667
668static struct snd_pcm_ops snd_msnd_capture_ops = {
669 .open = snd_msnd_capture_open,
670 .close = snd_msnd_capture_close,
671 .ioctl = snd_pcm_lib_ioctl,
672 .hw_params = snd_msnd_capture_hw_params,
673 .prepare = snd_msnd_capture_prepare,
674 .trigger = snd_msnd_capture_trigger,
675 .pointer = snd_msnd_capture_pointer,
676};
677
678
679int snd_msnd_pcm(struct snd_card *card, int device,
680 struct snd_pcm **rpcm)
681{
682 struct snd_msnd *chip = card->private_data;
683 struct snd_pcm *pcm;
684 int err;
685
686 err = snd_pcm_new(card, "MSNDPINNACLE", device, 1, 1, &pcm);
687 if (err < 0)
688 return err;
689
690 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_msnd_playback_ops);
691 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_msnd_capture_ops);
692
693 pcm->private_data = chip;
694 strcpy(pcm->name, "Hurricane");
695
696
697 if (rpcm)
698 *rpcm = pcm;
699 return 0;
700}
701EXPORT_SYMBOL(snd_msnd_pcm);
702
diff --git a/sound/isa/msnd/msnd.h b/sound/isa/msnd/msnd.h
new file mode 100644
index 000000000000..3773e242b58e
--- /dev/null
+++ b/sound/isa/msnd/msnd.h
@@ -0,0 +1,308 @@
1/*********************************************************************
2 *
3 * msnd.h
4 *
5 * Turtle Beach MultiSound Sound Card Driver for Linux
6 *
7 * Some parts of this header file were derived from the Turtle Beach
8 * MultiSound Driver Development Kit.
9 *
10 * Copyright (C) 1998 Andrew Veliath
11 * Copyright (C) 1993 Turtle Beach Systems, Inc.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 ********************************************************************/
28#ifndef __MSND_H
29#define __MSND_H
30
31#define DEFSAMPLERATE 44100
32#define DEFSAMPLESIZE SNDRV_PCM_FORMAT_S16
33#define DEFCHANNELS 1
34
35#define SRAM_BANK_SIZE 0x8000
36#define SRAM_CNTL_START 0x7F00
37#define SMA_STRUCT_START 0x7F40
38
39#define DSP_BASE_ADDR 0x4000
40#define DSP_BANK_BASE 0x4000
41
42#define AGND 0x01
43#define SIGNAL 0x02
44
45#define EXT_DSP_BIT_DCAL 0x0001
46#define EXT_DSP_BIT_MIDI_CON 0x0002
47
48#define BUFFSIZE 0x8000
49#define HOSTQ_SIZE 0x40
50
51#define DAP_BUFF_SIZE 0x2400
52
53#define DAPQ_STRUCT_SIZE 0x10
54#define DARQ_STRUCT_SIZE 0x10
55#define DAPQ_BUFF_SIZE (3 * 0x10)
56#define DARQ_BUFF_SIZE (3 * 0x10)
57#define MODQ_BUFF_SIZE 0x400
58
59#define DAPQ_DATA_BUFF 0x6C00
60#define DARQ_DATA_BUFF 0x6C30
61#define MODQ_DATA_BUFF 0x6C60
62#define MIDQ_DATA_BUFF 0x7060
63
64#define DAPQ_OFFSET SRAM_CNTL_START
65#define DARQ_OFFSET (SRAM_CNTL_START + 0x08)
66#define MODQ_OFFSET (SRAM_CNTL_START + 0x10)
67#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18)
68#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20)
69
70#define HP_ICR 0x00
71#define HP_CVR 0x01
72#define HP_ISR 0x02
73#define HP_IVR 0x03
74#define HP_NU 0x04
75#define HP_INFO 0x04
76#define HP_TXH 0x05
77#define HP_RXH 0x05
78#define HP_TXM 0x06
79#define HP_RXM 0x06
80#define HP_TXL 0x07
81#define HP_RXL 0x07
82
83#define HP_ICR_DEF 0x00
84#define HP_CVR_DEF 0x12
85#define HP_ISR_DEF 0x06
86#define HP_IVR_DEF 0x0f
87#define HP_NU_DEF 0x00
88
89#define HP_IRQM 0x09
90
91#define HPR_BLRC 0x08
92#define HPR_SPR1 0x09
93#define HPR_SPR2 0x0A
94#define HPR_TCL0 0x0B
95#define HPR_TCL1 0x0C
96#define HPR_TCL2 0x0D
97#define HPR_TCL3 0x0E
98#define HPR_TCL4 0x0F
99
100#define HPICR_INIT 0x80
101#define HPICR_HM1 0x40
102#define HPICR_HM0 0x20
103#define HPICR_HF1 0x10
104#define HPICR_HF0 0x08
105#define HPICR_TREQ 0x02
106#define HPICR_RREQ 0x01
107
108#define HPCVR_HC 0x80
109
110#define HPISR_HREQ 0x80
111#define HPISR_DMA 0x40
112#define HPISR_HF3 0x10
113#define HPISR_HF2 0x08
114#define HPISR_TRDY 0x04
115#define HPISR_TXDE 0x02
116#define HPISR_RXDF 0x01
117
118#define HPIO_290 0
119#define HPIO_260 1
120#define HPIO_250 2
121#define HPIO_240 3
122#define HPIO_230 4
123#define HPIO_220 5
124#define HPIO_210 6
125#define HPIO_3E0 7
126
127#define HPMEM_NONE 0
128#define HPMEM_B000 1
129#define HPMEM_C800 2
130#define HPMEM_D000 3
131#define HPMEM_D400 4
132#define HPMEM_D800 5
133#define HPMEM_E000 6
134#define HPMEM_E800 7
135
136#define HPIRQ_NONE 0
137#define HPIRQ_5 1
138#define HPIRQ_7 2
139#define HPIRQ_9 3
140#define HPIRQ_10 4
141#define HPIRQ_11 5
142#define HPIRQ_12 6
143#define HPIRQ_15 7
144
145#define HIMT_PLAY_DONE 0x00
146#define HIMT_RECORD_DONE 0x01
147#define HIMT_MIDI_EOS 0x02
148#define HIMT_MIDI_OUT 0x03
149
150#define HIMT_MIDI_IN_UCHAR 0x0E
151#define HIMT_DSP 0x0F
152
153#define HDEX_BASE 0x92
154#define HDEX_PLAY_START (0 + HDEX_BASE)
155#define HDEX_PLAY_STOP (1 + HDEX_BASE)
156#define HDEX_PLAY_PAUSE (2 + HDEX_BASE)
157#define HDEX_PLAY_RESUME (3 + HDEX_BASE)
158#define HDEX_RECORD_START (4 + HDEX_BASE)
159#define HDEX_RECORD_STOP (5 + HDEX_BASE)
160#define HDEX_MIDI_IN_START (6 + HDEX_BASE)
161#define HDEX_MIDI_IN_STOP (7 + HDEX_BASE)
162#define HDEX_MIDI_OUT_START (8 + HDEX_BASE)
163#define HDEX_MIDI_OUT_STOP (9 + HDEX_BASE)
164#define HDEX_AUX_REQ (10 + HDEX_BASE)
165
166#define HDEXAR_CLEAR_PEAKS 1
167#define HDEXAR_IN_SET_POTS 2
168#define HDEXAR_AUX_SET_POTS 3
169#define HDEXAR_CAL_A_TO_D 4
170#define HDEXAR_RD_EXT_DSP_BITS 5
171
172/* Pinnacle only HDEXAR defs */
173#define HDEXAR_SET_ANA_IN 0
174#define HDEXAR_SET_SYNTH_IN 4
175#define HDEXAR_READ_DAT_IN 5
176#define HDEXAR_MIC_SET_POTS 6
177#define HDEXAR_SET_DAT_IN 7
178
179#define HDEXAR_SET_SYNTH_48 8
180#define HDEXAR_SET_SYNTH_44 9
181
182#define HIWORD(l) ((u16)((((u32)(l)) >> 16) & 0xFFFF))
183#define LOWORD(l) ((u16)(u32)(l))
184#define HIBYTE(w) ((u8)(((u16)(w) >> 8) & 0xFF))
185#define LOBYTE(w) ((u8)(w))
186#define MAKELONG(low, hi) ((long)(((u16)(low))|(((u32)((u16)(hi)))<<16)))
187#define MAKEWORD(low, hi) ((u16)(((u8)(low))|(((u16)((u8)(hi)))<<8)))
188
189#define PCTODSP_OFFSET(w) (u16)((w)/2)
190#define PCTODSP_BASED(w) (u16)(((w)/2) + DSP_BASE_ADDR)
191#define DSPTOPC_BASED(w) (((w) - DSP_BASE_ADDR) * 2)
192
193#ifdef SLOWIO
194# undef outb
195# undef inb
196# define outb outb_p
197# define inb inb_p
198#endif
199
200/* JobQueueStruct */
201#define JQS_wStart 0x00
202#define JQS_wSize 0x02
203#define JQS_wHead 0x04
204#define JQS_wTail 0x06
205#define JQS__size 0x08
206
207/* DAQueueDataStruct */
208#define DAQDS_wStart 0x00
209#define DAQDS_wSize 0x02
210#define DAQDS_wFormat 0x04
211#define DAQDS_wSampleSize 0x06
212#define DAQDS_wChannels 0x08
213#define DAQDS_wSampleRate 0x0A
214#define DAQDS_wIntMsg 0x0C
215#define DAQDS_wFlags 0x0E
216#define DAQDS__size 0x10
217
218#include <sound/pcm.h>
219
220struct snd_msnd {
221 void __iomem *mappedbase;
222 int play_period_bytes;
223 int playLimit;
224 int playPeriods;
225 int playDMAPos;
226 int banksPlayed;
227 int captureDMAPos;
228 int capturePeriodBytes;
229 int captureLimit;
230 int capturePeriods;
231 struct snd_card *card;
232 void *msndmidi_mpu;
233 struct snd_rawmidi *rmidi;
234
235 /* Hardware resources */
236 long io;
237 int memid, irqid;
238 int irq, irq_ref;
239 unsigned long base;
240
241 /* Motorola 56k DSP SMA */
242 void __iomem *SMA;
243 void __iomem *DAPQ;
244 void __iomem *DARQ;
245 void __iomem *MODQ;
246 void __iomem *MIDQ;
247 void __iomem *DSPQ;
248 int dspq_data_buff, dspq_buff_size;
249
250 /* State variables */
251 enum { msndClassic, msndPinnacle } type;
252 mode_t mode;
253 unsigned long flags;
254#define F_RESETTING 0
255#define F_HAVEDIGITAL 1
256#define F_AUDIO_WRITE_INUSE 2
257#define F_WRITING 3
258#define F_WRITEBLOCK 4
259#define F_WRITEFLUSH 5
260#define F_AUDIO_READ_INUSE 6
261#define F_READING 7
262#define F_READBLOCK 8
263#define F_EXT_MIDI_INUSE 9
264#define F_HDR_MIDI_INUSE 10
265#define F_DISABLE_WRITE_NDELAY 11
266 spinlock_t lock;
267 spinlock_t mixer_lock;
268 int nresets;
269 unsigned recsrc;
270#define LEVEL_ENTRIES 32
271 int left_levels[LEVEL_ENTRIES];
272 int right_levels[LEVEL_ENTRIES];
273 int calibrate_signal;
274 int play_sample_size, play_sample_rate, play_channels;
275 int play_ndelay;
276 int capture_sample_size, capture_sample_rate, capture_channels;
277 int capture_ndelay;
278 u8 bCurrentMidiPatch;
279
280 int last_playbank, last_recbank;
281 struct snd_pcm_substream *playback_substream;
282 struct snd_pcm_substream *capture_substream;
283
284};
285
286void snd_msnd_init_queue(void *base, int start, int size);
287
288int snd_msnd_send_dsp_cmd(struct snd_msnd *chip, u8 cmd);
289int snd_msnd_send_word(struct snd_msnd *chip,
290 unsigned char high,
291 unsigned char mid,
292 unsigned char low);
293int snd_msnd_upload_host(struct snd_msnd *chip,
294 const u8 *bin, int len);
295int snd_msnd_enable_irq(struct snd_msnd *chip);
296int snd_msnd_disable_irq(struct snd_msnd *chip);
297void snd_msnd_dsp_halt(struct snd_msnd *chip, struct file *file);
298int snd_msnd_DAPQ(struct snd_msnd *chip, int start);
299int snd_msnd_DARQ(struct snd_msnd *chip, int start);
300int snd_msnd_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm);
301
302int snd_msndmidi_new(struct snd_card *card, int device);
303void snd_msndmidi_input_read(void *mpu);
304
305void snd_msndmix_setup(struct snd_msnd *chip);
306int __devinit snd_msndmix_new(struct snd_card *card);
307int snd_msndmix_force_recsrc(struct snd_msnd *chip, int recsrc);
308#endif /* __MSND_H */
diff --git a/sound/isa/msnd/msnd_classic.c b/sound/isa/msnd/msnd_classic.c
new file mode 100644
index 000000000000..3b23a096fa4e
--- /dev/null
+++ b/sound/isa/msnd/msnd_classic.c
@@ -0,0 +1,3 @@
1/* The work is in msnd_pinnacle.c, just define MSND_CLASSIC before it. */
2#define MSND_CLASSIC
3#include "msnd_pinnacle.c"
diff --git a/sound/isa/msnd/msnd_classic.h b/sound/isa/msnd/msnd_classic.h
new file mode 100644
index 000000000000..f18d5fa5baf4
--- /dev/null
+++ b/sound/isa/msnd/msnd_classic.h
@@ -0,0 +1,129 @@
1/*********************************************************************
2 *
3 * msnd_classic.h
4 *
5 * Turtle Beach MultiSound Sound Card Driver for Linux
6 *
7 * Some parts of this header file were derived from the Turtle Beach
8 * MultiSound Driver Development Kit.
9 *
10 * Copyright (C) 1998 Andrew Veliath
11 * Copyright (C) 1993 Turtle Beach Systems, Inc.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 ********************************************************************/
28#ifndef __MSND_CLASSIC_H
29#define __MSND_CLASSIC_H
30
31#define DSP_NUMIO 0x10
32
33#define HP_MEMM 0x08
34
35#define HP_BITM 0x0E
36#define HP_WAIT 0x0D
37#define HP_DSPR 0x0A
38#define HP_PROR 0x0B
39#define HP_BLKS 0x0C
40
41#define HPPRORESET_OFF 0
42#define HPPRORESET_ON 1
43
44#define HPDSPRESET_OFF 0
45#define HPDSPRESET_ON 1
46
47#define HPBLKSEL_0 0
48#define HPBLKSEL_1 1
49
50#define HPWAITSTATE_0 0
51#define HPWAITSTATE_1 1
52
53#define HPBITMODE_16 0
54#define HPBITMODE_8 1
55
56#define HIDSP_INT_PLAY_UNDER 0x00
57#define HIDSP_INT_RECORD_OVER 0x01
58#define HIDSP_INPUT_CLIPPING 0x02
59#define HIDSP_MIDI_IN_OVER 0x10
60#define HIDSP_MIDI_OVERRUN_ERR 0x13
61
62#define TIME_PRO_RESET_DONE 0x028A
63#define TIME_PRO_SYSEX 0x0040
64#define TIME_PRO_RESET 0x0032
65
66#define DAR_BUFF_SIZE 0x2000
67
68#define MIDQ_BUFF_SIZE 0x200
69#define DSPQ_BUFF_SIZE 0x40
70
71#define DSPQ_DATA_BUFF 0x7260
72
73#define MOP_SYNTH 0x10
74#define MOP_EXTOUT 0x32
75#define MOP_EXTTHRU 0x02
76#define MOP_OUTMASK 0x01
77
78#define MIP_EXTIN 0x01
79#define MIP_SYNTH 0x00
80#define MIP_INMASK 0x32
81
82/* Classic SMA Common Data */
83#define SMA_wCurrPlayBytes 0x0000
84#define SMA_wCurrRecordBytes 0x0002
85#define SMA_wCurrPlayVolLeft 0x0004
86#define SMA_wCurrPlayVolRight 0x0006
87#define SMA_wCurrInVolLeft 0x0008
88#define SMA_wCurrInVolRight 0x000a
89#define SMA_wUser_3 0x000c
90#define SMA_wUser_4 0x000e
91#define SMA_dwUser_5 0x0010
92#define SMA_dwUser_6 0x0014
93#define SMA_wUser_7 0x0018
94#define SMA_wReserved_A 0x001a
95#define SMA_wReserved_B 0x001c
96#define SMA_wReserved_C 0x001e
97#define SMA_wReserved_D 0x0020
98#define SMA_wReserved_E 0x0022
99#define SMA_wReserved_F 0x0024
100#define SMA_wReserved_G 0x0026
101#define SMA_wReserved_H 0x0028
102#define SMA_wCurrDSPStatusFlags 0x002a
103#define SMA_wCurrHostStatusFlags 0x002c
104#define SMA_wCurrInputTagBits 0x002e
105#define SMA_wCurrLeftPeak 0x0030
106#define SMA_wCurrRightPeak 0x0032
107#define SMA_wExtDSPbits 0x0034
108#define SMA_bExtHostbits 0x0036
109#define SMA_bBoardLevel 0x0037
110#define SMA_bInPotPosRight 0x0038
111#define SMA_bInPotPosLeft 0x0039
112#define SMA_bAuxPotPosRight 0x003a
113#define SMA_bAuxPotPosLeft 0x003b
114#define SMA_wCurrMastVolLeft 0x003c
115#define SMA_wCurrMastVolRight 0x003e
116#define SMA_bUser_12 0x0040
117#define SMA_bUser_13 0x0041
118#define SMA_wUser_14 0x0042
119#define SMA_wUser_15 0x0044
120#define SMA_wCalFreqAtoD 0x0046
121#define SMA_wUser_16 0x0048
122#define SMA_wUser_17 0x004a
123#define SMA__size 0x004c
124
125#define INITCODEFILE "turtlebeach/msndinit.bin"
126#define PERMCODEFILE "turtlebeach/msndperm.bin"
127#define LONGNAME "MultiSound (Classic/Monterey/Tahiti)"
128
129#endif /* __MSND_CLASSIC_H */
diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c
new file mode 100644
index 000000000000..cb9aa4c4edd0
--- /dev/null
+++ b/sound/isa/msnd/msnd_midi.c
@@ -0,0 +1,180 @@
1/*
2 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
3 * Copyright (c) 2009 by Krzysztof Helt
4 * Routines for control of MPU-401 in UART mode
5 *
6 * MPU-401 supports UART mode which is not capable generate transmit
7 * interrupts thus output is done via polling. Also, if irq < 0, then
8 * input is done also via polling. Do not expect good performance.
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27#include <linux/io.h>
28#include <linux/delay.h>
29#include <linux/ioport.h>
30#include <linux/errno.h>
31#include <sound/core.h>
32#include <sound/rawmidi.h>
33
34#include "msnd.h"
35
36#define MSNDMIDI_MODE_BIT_INPUT 0
37#define MSNDMIDI_MODE_BIT_OUTPUT 1
38#define MSNDMIDI_MODE_BIT_INPUT_TRIGGER 2
39#define MSNDMIDI_MODE_BIT_OUTPUT_TRIGGER 3
40
41struct snd_msndmidi {
42 struct snd_msnd *dev;
43
44 unsigned long mode; /* MSNDMIDI_MODE_XXXX */
45
46 struct snd_rawmidi_substream *substream_input;
47
48 spinlock_t input_lock;
49};
50
51/*
52 * input/output open/close - protected by open_mutex in rawmidi.c
53 */
54static int snd_msndmidi_input_open(struct snd_rawmidi_substream *substream)
55{
56 struct snd_msndmidi *mpu;
57
58 snd_printdd("snd_msndmidi_input_open()\n");
59
60 mpu = substream->rmidi->private_data;
61
62 mpu->substream_input = substream;
63
64 snd_msnd_enable_irq(mpu->dev);
65
66 snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_START);
67 set_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
68 return 0;
69}
70
71static int snd_msndmidi_input_close(struct snd_rawmidi_substream *substream)
72{
73 struct snd_msndmidi *mpu;
74
75 mpu = substream->rmidi->private_data;
76 snd_msnd_send_dsp_cmd(mpu->dev, HDEX_MIDI_IN_STOP);
77 clear_bit(MSNDMIDI_MODE_BIT_INPUT, &mpu->mode);
78 mpu->substream_input = NULL;
79 snd_msnd_disable_irq(mpu->dev);
80 return 0;
81}
82
83static void snd_msndmidi_input_drop(struct snd_msndmidi *mpu)
84{
85 u16 tail;
86
87 tail = readw(mpu->dev->MIDQ + JQS_wTail);
88 writew(tail, mpu->dev->MIDQ + JQS_wHead);
89}
90
91/*
92 * trigger input
93 */
94static void snd_msndmidi_input_trigger(struct snd_rawmidi_substream *substream,
95 int up)
96{
97 unsigned long flags;
98 struct snd_msndmidi *mpu;
99
100 snd_printdd("snd_msndmidi_input_trigger(, %i)\n", up);
101
102 mpu = substream->rmidi->private_data;
103 spin_lock_irqsave(&mpu->input_lock, flags);
104 if (up) {
105 if (!test_and_set_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
106 &mpu->mode))
107 snd_msndmidi_input_drop(mpu);
108 } else {
109 clear_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER, &mpu->mode);
110 }
111 spin_unlock_irqrestore(&mpu->input_lock, flags);
112 if (up)
113 snd_msndmidi_input_read(mpu);
114}
115
116void snd_msndmidi_input_read(void *mpuv)
117{
118 unsigned long flags;
119 struct snd_msndmidi *mpu = mpuv;
120 void *pwMIDQData = mpu->dev->mappedbase + MIDQ_DATA_BUFF;
121
122 spin_lock_irqsave(&mpu->input_lock, flags);
123 while (readw(mpu->dev->MIDQ + JQS_wTail) !=
124 readw(mpu->dev->MIDQ + JQS_wHead)) {
125 u16 wTmp, val;
126 val = readw(pwMIDQData + 2 * readw(mpu->dev->MIDQ + JQS_wHead));
127
128 if (test_bit(MSNDMIDI_MODE_BIT_INPUT_TRIGGER,
129 &mpu->mode))
130 snd_rawmidi_receive(mpu->substream_input,
131 (unsigned char *)&val, 1);
132
133 wTmp = readw(mpu->dev->MIDQ + JQS_wHead) + 1;
134 if (wTmp > readw(mpu->dev->MIDQ + JQS_wSize))
135 writew(0, mpu->dev->MIDQ + JQS_wHead);
136 else
137 writew(wTmp, mpu->dev->MIDQ + JQS_wHead);
138 }
139 spin_unlock_irqrestore(&mpu->input_lock, flags);
140}
141EXPORT_SYMBOL(snd_msndmidi_input_read);
142
143static struct snd_rawmidi_ops snd_msndmidi_input = {
144 .open = snd_msndmidi_input_open,
145 .close = snd_msndmidi_input_close,
146 .trigger = snd_msndmidi_input_trigger,
147};
148
149static void snd_msndmidi_free(struct snd_rawmidi *rmidi)
150{
151 struct snd_msndmidi *mpu = rmidi->private_data;
152 kfree(mpu);
153}
154
155int snd_msndmidi_new(struct snd_card *card, int device)
156{
157 struct snd_msnd *chip = card->private_data;
158 struct snd_msndmidi *mpu;
159 struct snd_rawmidi *rmidi;
160 int err;
161
162 err = snd_rawmidi_new(card, "MSND-MIDI", device, 1, 1, &rmidi);
163 if (err < 0)
164 return err;
165 mpu = kcalloc(1, sizeof(*mpu), GFP_KERNEL);
166 if (mpu == NULL) {
167 snd_device_free(card, rmidi);
168 return -ENOMEM;
169 }
170 mpu->dev = chip;
171 chip->msndmidi_mpu = mpu;
172 rmidi->private_data = mpu;
173 rmidi->private_free = snd_msndmidi_free;
174 spin_lock_init(&mpu->input_lock);
175 strcpy(rmidi->name, "MSND MIDI");
176 snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
177 &snd_msndmidi_input);
178 rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
179 return 0;
180}
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c
new file mode 100644
index 000000000000..70559223e8f3
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle.c
@@ -0,0 +1,1235 @@
1/*********************************************************************
2 *
3 * Linux multisound pinnacle/fiji driver for ALSA.
4 *
5 * 2002/06/30 Karsten Wiese:
6 * for now this is only used to build a pinnacle / fiji driver.
7 * the OSS parent of this code is designed to also support
8 * the multisound classic via the file msnd_classic.c.
9 * to make it easier for some brave heart to implemt classic
10 * support in alsa, i left all the MSND_CLASSIC tokens in this file.
11 * but for now this untested & undone.
12 *
13 *
14 * ripped from linux kernel 2.4.18 by Karsten Wiese.
15 *
16 * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
17 *
18 * Turtle Beach MultiSound Sound Card Driver for Linux
19 * msnd_pinnacle.c / msnd_classic.c
20 *
21 * -- If MSND_CLASSIC is defined:
22 *
23 * -> driver for Turtle Beach Classic/Monterey/Tahiti
24 *
25 * -- Else
26 *
27 * -> driver for Turtle Beach Pinnacle/Fiji
28 *
29 * 12-3-2000 Modified IO port validation Steve Sycamore
30 *
31 * Copyright (C) 1998 Andrew Veliath
32 *
33 * This program is free software; you can redistribute it and/or modify
34 * it under the terms of the GNU General Public License as published by
35 * the Free Software Foundation; either version 2 of the License, or
36 * (at your option) any later version.
37 *
38 * This program is distributed in the hope that it will be useful,
39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
41 * GNU General Public License for more details.
42 *
43 * You should have received a copy of the GNU General Public License
44 * along with this program; if not, write to the Free Software
45 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
46 *
47 ********************************************************************/
48
49#include <linux/kernel.h>
50#include <linux/module.h>
51#include <linux/interrupt.h>
52#include <linux/types.h>
53#include <linux/delay.h>
54#include <linux/ioport.h>
55#include <linux/firmware.h>
56#include <linux/isa.h>
57#include <linux/isapnp.h>
58#include <linux/irq.h>
59#include <linux/io.h>
60
61#include <sound/core.h>
62#include <sound/initval.h>
63#include <sound/asound.h>
64#include <sound/pcm.h>
65#include <sound/mpu401.h>
66
67#ifdef MSND_CLASSIC
68# ifndef __alpha__
69# define SLOWIO
70# endif
71#endif
72#include "msnd.h"
73#ifdef MSND_CLASSIC
74# include "msnd_classic.h"
75# define LOGNAME "msnd_classic"
76#else
77# include "msnd_pinnacle.h"
78# define LOGNAME "snd_msnd_pinnacle"
79#endif
80
81static void __devinit set_default_audio_parameters(struct snd_msnd *chip)
82{
83 chip->play_sample_size = DEFSAMPLESIZE;
84 chip->play_sample_rate = DEFSAMPLERATE;
85 chip->play_channels = DEFCHANNELS;
86 chip->capture_sample_size = DEFSAMPLESIZE;
87 chip->capture_sample_rate = DEFSAMPLERATE;
88 chip->capture_channels = DEFCHANNELS;
89}
90
91static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
92{
93 switch (HIBYTE(wMessage)) {
94 case HIMT_PLAY_DONE: {
95 if (chip->banksPlayed < 3)
96 snd_printdd("%08X: HIMT_PLAY_DONE: %i\n",
97 (unsigned)jiffies, LOBYTE(wMessage));
98
99 if (chip->last_playbank == LOBYTE(wMessage)) {
100 snd_printdd("chip.last_playbank == LOBYTE(wMessage)\n");
101 break;
102 }
103 chip->banksPlayed++;
104
105 if (test_bit(F_WRITING, &chip->flags))
106 snd_msnd_DAPQ(chip, 0);
107
108 chip->last_playbank = LOBYTE(wMessage);
109 chip->playDMAPos += chip->play_period_bytes;
110 if (chip->playDMAPos > chip->playLimit)
111 chip->playDMAPos = 0;
112 snd_pcm_period_elapsed(chip->playback_substream);
113
114 break;
115 }
116 case HIMT_RECORD_DONE:
117 if (chip->last_recbank == LOBYTE(wMessage))
118 break;
119 chip->last_recbank = LOBYTE(wMessage);
120 chip->captureDMAPos += chip->capturePeriodBytes;
121 if (chip->captureDMAPos > (chip->captureLimit))
122 chip->captureDMAPos = 0;
123
124 if (test_bit(F_READING, &chip->flags))
125 snd_msnd_DARQ(chip, chip->last_recbank);
126
127 snd_pcm_period_elapsed(chip->capture_substream);
128 break;
129
130 case HIMT_DSP:
131 switch (LOBYTE(wMessage)) {
132#ifndef MSND_CLASSIC
133 case HIDSP_PLAY_UNDER:
134#endif
135 case HIDSP_INT_PLAY_UNDER:
136 snd_printd(KERN_WARNING LOGNAME ": Play underflow %i\n",
137 chip->banksPlayed);
138 if (chip->banksPlayed > 2)
139 clear_bit(F_WRITING, &chip->flags);
140 break;
141
142 case HIDSP_INT_RECORD_OVER:
143 snd_printd(KERN_WARNING LOGNAME ": Record overflow\n");
144 clear_bit(F_READING, &chip->flags);
145 break;
146
147 default:
148 snd_printd(KERN_WARNING LOGNAME
149 ": DSP message %d 0x%02x\n",
150 LOBYTE(wMessage), LOBYTE(wMessage));
151 break;
152 }
153 break;
154
155 case HIMT_MIDI_IN_UCHAR:
156 if (chip->msndmidi_mpu)
157 snd_msndmidi_input_read(chip->msndmidi_mpu);
158 break;
159
160 default:
161 snd_printd(KERN_WARNING LOGNAME ": HIMT message %d 0x%02x\n",
162 HIBYTE(wMessage), HIBYTE(wMessage));
163 break;
164 }
165}
166
167static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
168{
169 struct snd_msnd *chip = dev_id;
170 void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
171
172 /* Send ack to DSP */
173 /* inb(chip->io + HP_RXL); */
174
175 /* Evaluate queued DSP messages */
176 while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) {
177 u16 wTmp;
178
179 snd_msnd_eval_dsp_msg(chip,
180 readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead)));
181
182 wTmp = readw(chip->DSPQ + JQS_wHead) + 1;
183 if (wTmp > readw(chip->DSPQ + JQS_wSize))
184 writew(0, chip->DSPQ + JQS_wHead);
185 else
186 writew(wTmp, chip->DSPQ + JQS_wHead);
187 }
188 /* Send ack to DSP */
189 inb(chip->io + HP_RXL);
190 return IRQ_HANDLED;
191}
192
193
194static int snd_msnd_reset_dsp(long io, unsigned char *info)
195{
196 int timeout = 100;
197
198 outb(HPDSPRESET_ON, io + HP_DSPR);
199 msleep(1);
200#ifndef MSND_CLASSIC
201 if (info)
202 *info = inb(io + HP_INFO);
203#endif
204 outb(HPDSPRESET_OFF, io + HP_DSPR);
205 msleep(1);
206 while (timeout-- > 0) {
207 if (inb(io + HP_CVR) == HP_CVR_DEF)
208 return 0;
209 msleep(1);
210 }
211 snd_printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
212
213 return -EIO;
214}
215
216static int __devinit snd_msnd_probe(struct snd_card *card)
217{
218 struct snd_msnd *chip = card->private_data;
219 unsigned char info;
220#ifndef MSND_CLASSIC
221 char *xv, *rev = NULL;
222 char *pin = "TB Pinnacle", *fiji = "TB Fiji";
223 char *pinfiji = "TB Pinnacle/Fiji";
224#endif
225
226 if (!request_region(chip->io, DSP_NUMIO, "probing")) {
227 snd_printk(KERN_ERR LOGNAME ": I/O port conflict\n");
228 return -ENODEV;
229 }
230
231 if (snd_msnd_reset_dsp(chip->io, &info) < 0) {
232 release_region(chip->io, DSP_NUMIO);
233 return -ENODEV;
234 }
235
236#ifdef MSND_CLASSIC
237 strcpy(card->shortname, "Classic/Tahiti/Monterey");
238 strcpy(card->longname, "Turtle Beach Multisound");
239 printk(KERN_INFO LOGNAME ": %s, "
240 "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
241 card->shortname,
242 chip->io, chip->io + DSP_NUMIO - 1,
243 chip->irq,
244 chip->base, chip->base + 0x7fff);
245#else
246 switch (info >> 4) {
247 case 0xf:
248 xv = "<= 1.15";
249 break;
250 case 0x1:
251 xv = "1.18/1.2";
252 break;
253 case 0x2:
254 xv = "1.3";
255 break;
256 case 0x3:
257 xv = "1.4";
258 break;
259 default:
260 xv = "unknown";
261 break;
262 }
263
264 switch (info & 0x7) {
265 case 0x0:
266 rev = "I";
267 strcpy(card->shortname, pin);
268 break;
269 case 0x1:
270 rev = "F";
271 strcpy(card->shortname, pin);
272 break;
273 case 0x2:
274 rev = "G";
275 strcpy(card->shortname, pin);
276 break;
277 case 0x3:
278 rev = "H";
279 strcpy(card->shortname, pin);
280 break;
281 case 0x4:
282 rev = "E";
283 strcpy(card->shortname, fiji);
284 break;
285 case 0x5:
286 rev = "C";
287 strcpy(card->shortname, fiji);
288 break;
289 case 0x6:
290 rev = "D";
291 strcpy(card->shortname, fiji);
292 break;
293 case 0x7:
294 rev = "A-B (Fiji) or A-E (Pinnacle)";
295 strcpy(card->shortname, pinfiji);
296 break;
297 }
298 strcpy(card->longname, "Turtle Beach Multisound Pinnacle");
299 printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
300 "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
301 card->shortname,
302 rev, xv,
303 chip->io, chip->io + DSP_NUMIO - 1,
304 chip->irq,
305 chip->base, chip->base + 0x7fff);
306#endif
307
308 release_region(chip->io, DSP_NUMIO);
309 return 0;
310}
311
312static int snd_msnd_init_sma(struct snd_msnd *chip)
313{
314 static int initted;
315 u16 mastVolLeft, mastVolRight;
316 unsigned long flags;
317
318#ifdef MSND_CLASSIC
319 outb(chip->memid, chip->io + HP_MEMM);
320#endif
321 outb(HPBLKSEL_0, chip->io + HP_BLKS);
322 /* Motorola 56k shared memory base */
323 chip->SMA = chip->mappedbase + SMA_STRUCT_START;
324
325 if (initted) {
326 mastVolLeft = readw(chip->SMA + SMA_wCurrMastVolLeft);
327 mastVolRight = readw(chip->SMA + SMA_wCurrMastVolRight);
328 } else
329 mastVolLeft = mastVolRight = 0;
330 memset_io(chip->mappedbase, 0, 0x8000);
331
332 /* Critical section: bank 1 access */
333 spin_lock_irqsave(&chip->lock, flags);
334 outb(HPBLKSEL_1, chip->io + HP_BLKS);
335 memset_io(chip->mappedbase, 0, 0x8000);
336 outb(HPBLKSEL_0, chip->io + HP_BLKS);
337 spin_unlock_irqrestore(&chip->lock, flags);
338
339 /* Digital audio play queue */
340 chip->DAPQ = chip->mappedbase + DAPQ_OFFSET;
341 snd_msnd_init_queue(chip->DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);
342
343 /* Digital audio record queue */
344 chip->DARQ = chip->mappedbase + DARQ_OFFSET;
345 snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
346
347 /* MIDI out queue */
348 chip->MODQ = chip->mappedbase + MODQ_OFFSET;
349 snd_msnd_init_queue(chip->MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);
350
351 /* MIDI in queue */
352 chip->MIDQ = chip->mappedbase + MIDQ_OFFSET;
353 snd_msnd_init_queue(chip->MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);
354
355 /* DSP -> host message queue */
356 chip->DSPQ = chip->mappedbase + DSPQ_OFFSET;
357 snd_msnd_init_queue(chip->DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);
358
359 /* Setup some DSP values */
360#ifndef MSND_CLASSIC
361 writew(1, chip->SMA + SMA_wCurrPlayFormat);
362 writew(chip->play_sample_size, chip->SMA + SMA_wCurrPlaySampleSize);
363 writew(chip->play_channels, chip->SMA + SMA_wCurrPlayChannels);
364 writew(chip->play_sample_rate, chip->SMA + SMA_wCurrPlaySampleRate);
365#endif
366 writew(chip->play_sample_rate, chip->SMA + SMA_wCalFreqAtoD);
367 writew(mastVolLeft, chip->SMA + SMA_wCurrMastVolLeft);
368 writew(mastVolRight, chip->SMA + SMA_wCurrMastVolRight);
369#ifndef MSND_CLASSIC
370 writel(0x00010000, chip->SMA + SMA_dwCurrPlayPitch);
371 writel(0x00000001, chip->SMA + SMA_dwCurrPlayRate);
372#endif
373 writew(0x303, chip->SMA + SMA_wCurrInputTagBits);
374
375 initted = 1;
376
377 return 0;
378}
379
380
381static int upload_dsp_code(struct snd_card *card)
382{
383 struct snd_msnd *chip = card->private_data;
384 const struct firmware *init_fw = NULL, *perm_fw = NULL;
385 int err;
386
387 outb(HPBLKSEL_0, chip->io + HP_BLKS);
388
389 err = request_firmware(&init_fw, INITCODEFILE, card->dev);
390 if (err < 0) {
391 printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
392 goto cleanup1;
393 }
394 err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);
395 if (err < 0) {
396 printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
397 goto cleanup;
398 }
399
400 memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);
401 if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {
402 printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
403 err = -ENODEV;
404 goto cleanup;
405 }
406 printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");
407 err = 0;
408
409cleanup:
410 release_firmware(perm_fw);
411cleanup1:
412 release_firmware(init_fw);
413 return err;
414}
415
416#ifdef MSND_CLASSIC
417static void reset_proteus(struct snd_msnd *chip)
418{
419 outb(HPPRORESET_ON, chip->io + HP_PROR);
420 msleep(TIME_PRO_RESET);
421 outb(HPPRORESET_OFF, chip->io + HP_PROR);
422 msleep(TIME_PRO_RESET_DONE);
423}
424#endif
425
426static int snd_msnd_initialize(struct snd_card *card)
427{
428 struct snd_msnd *chip = card->private_data;
429 int err, timeout;
430
431#ifdef MSND_CLASSIC
432 outb(HPWAITSTATE_0, chip->io + HP_WAIT);
433 outb(HPBITMODE_16, chip->io + HP_BITM);
434
435 reset_proteus(chip);
436#endif
437 err = snd_msnd_init_sma(chip);
438 if (err < 0) {
439 printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
440 return err;
441 }
442
443 err = snd_msnd_reset_dsp(chip->io, NULL);
444 if (err < 0)
445 return err;
446
447 err = upload_dsp_code(card);
448 if (err < 0) {
449 printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
450 return err;
451 }
452
453 timeout = 200;
454
455 while (readw(chip->mappedbase)) {
456 msleep(1);
457 if (!timeout--) {
458 snd_printd(KERN_ERR LOGNAME ": DSP reset timeout\n");
459 return -EIO;
460 }
461 }
462
463 snd_msndmix_setup(chip);
464 return 0;
465}
466
467static int snd_msnd_dsp_full_reset(struct snd_card *card)
468{
469 struct snd_msnd *chip = card->private_data;
470 int rv;
471
472 if (test_bit(F_RESETTING, &chip->flags) || ++chip->nresets > 10)
473 return 0;
474
475 set_bit(F_RESETTING, &chip->flags);
476 snd_msnd_dsp_halt(chip, NULL); /* Unconditionally halt */
477
478 rv = snd_msnd_initialize(card);
479 if (rv)
480 printk(KERN_WARNING LOGNAME ": DSP reset failed\n");
481 snd_msndmix_force_recsrc(chip, 0);
482 clear_bit(F_RESETTING, &chip->flags);
483 return rv;
484}
485
486static int snd_msnd_dev_free(struct snd_device *device)
487{
488 snd_printdd("snd_msnd_chip_free()\n");
489 return 0;
490}
491
492static int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, u8 cmd)
493{
494 if (snd_msnd_send_dsp_cmd(chip, cmd) == 0)
495 return 0;
496 snd_msnd_dsp_full_reset(chip->card);
497 return snd_msnd_send_dsp_cmd(chip, cmd);
498}
499
500static int __devinit snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
501{
502 snd_printdd("snd_msnd_calibrate_adc(%i)\n", srate);
503 writew(srate, chip->SMA + SMA_wCalFreqAtoD);
504 if (chip->calibrate_signal == 0)
505 writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
506 | 0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
507 else
508 writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
509 & ~0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
510 if (snd_msnd_send_word(chip, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
511 snd_msnd_send_dsp_cmd_chk(chip, HDEX_AUX_REQ) == 0) {
512 schedule_timeout_interruptible(msecs_to_jiffies(333));
513 return 0;
514 }
515 printk(KERN_WARNING LOGNAME ": ADC calibration failed\n");
516 return -EIO;
517}
518
519/*
520 * ALSA callback function, called when attempting to open the MIDI device.
521 */
522static int snd_msnd_mpu401_open(struct snd_mpu401 *mpu)
523{
524 snd_msnd_enable_irq(mpu->private_data);
525 snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_START);
526 return 0;
527}
528
529static void snd_msnd_mpu401_close(struct snd_mpu401 *mpu)
530{
531 snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_STOP);
532 snd_msnd_disable_irq(mpu->private_data);
533}
534
535static long mpu_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
536static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
537
538static int __devinit snd_msnd_attach(struct snd_card *card)
539{
540 struct snd_msnd *chip = card->private_data;
541 int err;
542 static struct snd_device_ops ops = {
543 .dev_free = snd_msnd_dev_free,
544 };
545
546 err = request_irq(chip->irq, snd_msnd_interrupt, 0, card->shortname,
547 chip);
548 if (err < 0) {
549 printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
550 return err;
551 }
552 request_region(chip->io, DSP_NUMIO, card->shortname);
553
554 if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) {
555 printk(KERN_ERR LOGNAME
556 ": unable to grab memory region 0x%lx-0x%lx\n",
557 chip->base, chip->base + BUFFSIZE - 1);
558 release_region(chip->io, DSP_NUMIO);
559 free_irq(chip->irq, chip);
560 return -EBUSY;
561 }
562 chip->mappedbase = ioremap_nocache(chip->base, 0x8000);
563 if (!chip->mappedbase) {
564 printk(KERN_ERR LOGNAME
565 ": unable to map memory region 0x%lx-0x%lx\n",
566 chip->base, chip->base + BUFFSIZE - 1);
567 err = -EIO;
568 goto err_release_region;
569 }
570
571 err = snd_msnd_dsp_full_reset(card);
572 if (err < 0)
573 goto err_release_region;
574
575 /* Register device */
576 err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
577 if (err < 0)
578 goto err_release_region;
579
580 err = snd_msnd_pcm(card, 0, NULL);
581 if (err < 0) {
582 printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
583 goto err_release_region;
584 }
585
586 err = snd_msndmix_new(card);
587 if (err < 0) {
588 printk(KERN_ERR LOGNAME ": error creating new Mixer device\n");
589 goto err_release_region;
590 }
591
592
593 if (mpu_io[0] != SNDRV_AUTO_PORT) {
594 struct snd_mpu401 *mpu;
595
596 err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
597 mpu_io[0],
598 MPU401_MODE_INPUT |
599 MPU401_MODE_OUTPUT,
600 mpu_irq[0], IRQF_DISABLED,
601 &chip->rmidi);
602 if (err < 0) {
603 printk(KERN_ERR LOGNAME
604 ": error creating new Midi device\n");
605 goto err_release_region;
606 }
607 mpu = chip->rmidi->private_data;
608
609 mpu->open_input = snd_msnd_mpu401_open;
610 mpu->close_input = snd_msnd_mpu401_close;
611 mpu->private_data = chip;
612 }
613
614 disable_irq(chip->irq);
615 snd_msnd_calibrate_adc(chip, chip->play_sample_rate);
616 snd_msndmix_force_recsrc(chip, 0);
617
618 err = snd_card_register(card);
619 if (err < 0)
620 goto err_release_region;
621
622 return 0;
623
624err_release_region:
625 if (chip->mappedbase)
626 iounmap(chip->mappedbase);
627 release_mem_region(chip->base, BUFFSIZE);
628 release_region(chip->io, DSP_NUMIO);
629 free_irq(chip->irq, chip);
630 return err;
631}
632
633
634static void __devexit snd_msnd_unload(struct snd_card *card)
635{
636 struct snd_msnd *chip = card->private_data;
637
638 iounmap(chip->mappedbase);
639 release_mem_region(chip->base, BUFFSIZE);
640 release_region(chip->io, DSP_NUMIO);
641 free_irq(chip->irq, chip);
642 snd_card_free(card);
643}
644
645#ifndef MSND_CLASSIC
646
647/* Pinnacle/Fiji Logical Device Configuration */
648
649static int __devinit snd_msnd_write_cfg(int cfg, int reg, int value)
650{
651 outb(reg, cfg);
652 outb(value, cfg + 1);
653 if (value != inb(cfg + 1)) {
654 printk(KERN_ERR LOGNAME ": snd_msnd_write_cfg: I/O error\n");
655 return -EIO;
656 }
657 return 0;
658}
659
660static int __devinit snd_msnd_write_cfg_io0(int cfg, int num, u16 io)
661{
662 if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
663 return -EIO;
664 if (snd_msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
665 return -EIO;
666 if (snd_msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
667 return -EIO;
668 return 0;
669}
670
671static int __devinit snd_msnd_write_cfg_io1(int cfg, int num, u16 io)
672{
673 if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
674 return -EIO;
675 if (snd_msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
676 return -EIO;
677 if (snd_msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
678 return -EIO;
679 return 0;
680}
681
682static int __devinit snd_msnd_write_cfg_irq(int cfg, int num, u16 irq)
683{
684 if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
685 return -EIO;
686 if (snd_msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
687 return -EIO;
688 if (snd_msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
689 return -EIO;
690 return 0;
691}
692
693static int __devinit snd_msnd_write_cfg_mem(int cfg, int num, int mem)
694{
695 u16 wmem;
696
697 mem >>= 8;
698 wmem = (u16)(mem & 0xfff);
699 if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
700 return -EIO;
701 if (snd_msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
702 return -EIO;
703 if (snd_msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
704 return -EIO;
705 if (wmem && snd_msnd_write_cfg(cfg, IREG_MEMCONTROL,
706 MEMTYPE_HIADDR | MEMTYPE_16BIT))
707 return -EIO;
708 return 0;
709}
710
711static int __devinit snd_msnd_activate_logical(int cfg, int num)
712{
713 if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
714 return -EIO;
715 if (snd_msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
716 return -EIO;
717 return 0;
718}
719
720static int __devinit snd_msnd_write_cfg_logical(int cfg, int num, u16 io0,
721 u16 io1, u16 irq, int mem)
722{
723 if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
724 return -EIO;
725 if (snd_msnd_write_cfg_io0(cfg, num, io0))
726 return -EIO;
727 if (snd_msnd_write_cfg_io1(cfg, num, io1))
728 return -EIO;
729 if (snd_msnd_write_cfg_irq(cfg, num, irq))
730 return -EIO;
731 if (snd_msnd_write_cfg_mem(cfg, num, mem))
732 return -EIO;
733 if (snd_msnd_activate_logical(cfg, num))
734 return -EIO;
735 return 0;
736}
737
738static int __devinit snd_msnd_pinnacle_cfg_reset(int cfg)
739{
740 int i;
741
742 /* Reset devices if told to */
743 printk(KERN_INFO LOGNAME ": Resetting all devices\n");
744 for (i = 0; i < 4; ++i)
745 if (snd_msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0))
746 return -EIO;
747
748 return 0;
749}
750#endif
751
752static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
753static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
754
755module_param_array(index, int, NULL, S_IRUGO);
756MODULE_PARM_DESC(index, "Index value for msnd_pinnacle soundcard.");
757module_param_array(id, charp, NULL, S_IRUGO);
758MODULE_PARM_DESC(id, "ID string for msnd_pinnacle soundcard.");
759
760static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
761static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
762static long mem[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
763
764static long cfg[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
765
766#ifndef MSND_CLASSIC
767/* Extra Peripheral Configuration (Default: Disable) */
768static long ide_io0[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
769static long ide_io1[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
770static int ide_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
771
772static long joystick_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
773/* If we have the digital daugherboard... */
774static int digital[SNDRV_CARDS];
775
776/* Extra Peripheral Configuration */
777static int reset[SNDRV_CARDS];
778#endif
779
780static int write_ndelay[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
781
782static int calibrate_signal;
783
784#ifdef CONFIG_PNP
785static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
786module_param_array(isapnp, bool, NULL, 0444);
787MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
788#endif
789
790MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
791MODULE_DESCRIPTION("Turtle Beach " LONGNAME " Linux Driver");
792MODULE_LICENSE("GPL");
793MODULE_FIRMWARE(INITCODEFILE);
794MODULE_FIRMWARE(PERMCODEFILE);
795
796module_param_array(io, long, NULL, S_IRUGO);
797MODULE_PARM_DESC(io, "IO port #");
798module_param_array(irq, int, NULL, S_IRUGO);
799module_param_array(mem, long, NULL, S_IRUGO);
800module_param_array(write_ndelay, int, NULL, S_IRUGO);
801module_param(calibrate_signal, int, S_IRUGO);
802#ifndef MSND_CLASSIC
803module_param_array(digital, int, NULL, S_IRUGO);
804module_param_array(cfg, long, NULL, S_IRUGO);
805module_param_array(reset, int, 0, S_IRUGO);
806module_param_array(mpu_io, long, NULL, S_IRUGO);
807module_param_array(mpu_irq, int, NULL, S_IRUGO);
808module_param_array(ide_io0, long, NULL, S_IRUGO);
809module_param_array(ide_io1, long, NULL, S_IRUGO);
810module_param_array(ide_irq, int, NULL, S_IRUGO);
811module_param_array(joystick_io, long, NULL, S_IRUGO);
812#endif
813
814
815static int __devinit snd_msnd_isa_match(struct device *pdev, unsigned int i)
816{
817 if (io[i] == SNDRV_AUTO_PORT)
818 return 0;
819
820 if (irq[i] == SNDRV_AUTO_PORT || mem[i] == SNDRV_AUTO_PORT) {
821 printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
822 return 0;
823 }
824
825#ifdef MSND_CLASSIC
826 if (!(io[i] == 0x290 ||
827 io[i] == 0x260 ||
828 io[i] == 0x250 ||
829 io[i] == 0x240 ||
830 io[i] == 0x230 ||
831 io[i] == 0x220 ||
832 io[i] == 0x210 ||
833 io[i] == 0x3e0)) {
834 printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set "
835 " to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, "
836 "or 0x3E0\n");
837 return 0;
838 }
839#else
840 if (io[i] < 0x100 || io[i] > 0x3e0 || (io[i] % 0x10) != 0) {
841 printk(KERN_ERR LOGNAME
842 ": \"io\" - DSP I/O base must within the range 0x100 "
843 "to 0x3E0 and must be evenly divisible by 0x10\n");
844 return 0;
845 }
846#endif /* MSND_CLASSIC */
847
848 if (!(irq[i] == 5 ||
849 irq[i] == 7 ||
850 irq[i] == 9 ||
851 irq[i] == 10 ||
852 irq[i] == 11 ||
853 irq[i] == 12)) {
854 printk(KERN_ERR LOGNAME
855 ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
856 return 0;
857 }
858
859 if (!(mem[i] == 0xb0000 ||
860 mem[i] == 0xc8000 ||
861 mem[i] == 0xd0000 ||
862 mem[i] == 0xd8000 ||
863 mem[i] == 0xe0000 ||
864 mem[i] == 0xe8000)) {
865 printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
866 "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or "
867 "0xe8000\n");
868 return 0;
869 }
870
871#ifndef MSND_CLASSIC
872 if (cfg[i] == SNDRV_AUTO_PORT) {
873 printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
874 } else if (cfg[i] != 0x250 && cfg[i] != 0x260 && cfg[i] != 0x270) {
875 printk(KERN_INFO LOGNAME
876 ": Config port must be 0x250, 0x260 or 0x270 "
877 "(or unspecified for PnP mode)\n");
878 return 0;
879 }
880#endif /* MSND_CLASSIC */
881
882 return 1;
883}
884
885static int __devinit snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
886{
887 int err;
888 struct snd_card *card;
889 struct snd_msnd *chip;
890
891 if (isapnp[idx] || cfg[idx] == SNDRV_AUTO_PORT) {
892 printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
893 return -ENODEV;
894 }
895
896 err = snd_card_create(index[idx], id[idx], THIS_MODULE,
897 sizeof(struct snd_msnd), &card);
898 if (err < 0)
899 return err;
900
901 snd_card_set_dev(card, pdev);
902 chip = card->private_data;
903 chip->card = card;
904
905#ifdef MSND_CLASSIC
906 switch (irq[idx]) {
907 case 5:
908 chip->irqid = HPIRQ_5; break;
909 case 7:
910 chip->irqid = HPIRQ_7; break;
911 case 9:
912 chip->irqid = HPIRQ_9; break;
913 case 10:
914 chip->irqid = HPIRQ_10; break;
915 case 11:
916 chip->irqid = HPIRQ_11; break;
917 case 12:
918 chip->irqid = HPIRQ_12; break;
919 }
920
921 switch (mem[idx]) {
922 case 0xb0000:
923 chip->memid = HPMEM_B000; break;
924 case 0xc8000:
925 chip->memid = HPMEM_C800; break;
926 case 0xd0000:
927 chip->memid = HPMEM_D000; break;
928 case 0xd8000:
929 chip->memid = HPMEM_D800; break;
930 case 0xe0000:
931 chip->memid = HPMEM_E000; break;
932 case 0xe8000:
933 chip->memid = HPMEM_E800; break;
934 }
935#else
936 printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%lx\n",
937 cfg[idx]);
938
939 if (!request_region(cfg[idx], 2, "Pinnacle/Fiji Config")) {
940 printk(KERN_ERR LOGNAME ": Config port 0x%lx conflict\n",
941 cfg[idx]);
942 snd_card_free(card);
943 return -EIO;
944 }
945 if (reset[idx])
946 if (snd_msnd_pinnacle_cfg_reset(cfg[idx])) {
947 err = -EIO;
948 goto cfg_error;
949 }
950
951 /* DSP */
952 err = snd_msnd_write_cfg_logical(cfg[idx], 0,
953 io[idx], 0,
954 irq[idx], mem[idx]);
955
956 if (err)
957 goto cfg_error;
958
959 /* The following are Pinnacle specific */
960
961 /* MPU */
962 if (mpu_io[idx] != SNDRV_AUTO_PORT
963 && mpu_irq[idx] != SNDRV_AUTO_IRQ) {
964 printk(KERN_INFO LOGNAME
965 ": Configuring MPU to I/O 0x%lx IRQ %d\n",
966 mpu_io[idx], mpu_irq[idx]);
967 err = snd_msnd_write_cfg_logical(cfg[idx], 1,
968 mpu_io[idx], 0,
969 mpu_irq[idx], 0);
970
971 if (err)
972 goto cfg_error;
973 }
974
975 /* IDE */
976 if (ide_io0[idx] != SNDRV_AUTO_PORT
977 && ide_io1[idx] != SNDRV_AUTO_PORT
978 && ide_irq[idx] != SNDRV_AUTO_IRQ) {
979 printk(KERN_INFO LOGNAME
980 ": Configuring IDE to I/O 0x%lx, 0x%lx IRQ %d\n",
981 ide_io0[idx], ide_io1[idx], ide_irq[idx]);
982 err = snd_msnd_write_cfg_logical(cfg[idx], 2,
983 ide_io0[idx], ide_io1[idx],
984 ide_irq[idx], 0);
985
986 if (err)
987 goto cfg_error;
988 }
989
990 /* Joystick */
991 if (joystick_io[idx] != SNDRV_AUTO_PORT) {
992 printk(KERN_INFO LOGNAME
993 ": Configuring joystick to I/O 0x%lx\n",
994 joystick_io[idx]);
995 err = snd_msnd_write_cfg_logical(cfg[idx], 3,
996 joystick_io[idx], 0,
997 0, 0);
998
999 if (err)
1000 goto cfg_error;
1001 }
1002 release_region(cfg[idx], 2);
1003
1004#endif /* MSND_CLASSIC */
1005
1006 set_default_audio_parameters(chip);
1007#ifdef MSND_CLASSIC
1008 chip->type = msndClassic;
1009#else
1010 chip->type = msndPinnacle;
1011#endif
1012 chip->io = io[idx];
1013 chip->irq = irq[idx];
1014 chip->base = mem[idx];
1015
1016 chip->calibrate_signal = calibrate_signal ? 1 : 0;
1017 chip->recsrc = 0;
1018 chip->dspq_data_buff = DSPQ_DATA_BUFF;
1019 chip->dspq_buff_size = DSPQ_BUFF_SIZE;
1020 if (write_ndelay[idx])
1021 clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1022 else
1023 set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1024#ifndef MSND_CLASSIC
1025 if (digital[idx])
1026 set_bit(F_HAVEDIGITAL, &chip->flags);
1027#endif
1028 spin_lock_init(&chip->lock);
1029 err = snd_msnd_probe(card);
1030 if (err < 0) {
1031 printk(KERN_ERR LOGNAME ": Probe failed\n");
1032 snd_card_free(card);
1033 return err;
1034 }
1035
1036 err = snd_msnd_attach(card);
1037 if (err < 0) {
1038 printk(KERN_ERR LOGNAME ": Attach failed\n");
1039 snd_card_free(card);
1040 return err;
1041 }
1042 dev_set_drvdata(pdev, card);
1043
1044 return 0;
1045
1046#ifndef MSND_CLASSIC
1047cfg_error:
1048 release_region(cfg[idx], 2);
1049 snd_card_free(card);
1050 return err;
1051#endif
1052}
1053
1054static int __devexit snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
1055{
1056 snd_msnd_unload(dev_get_drvdata(pdev));
1057 dev_set_drvdata(pdev, NULL);
1058 return 0;
1059}
1060
1061#define DEV_NAME "msnd-pinnacle"
1062
1063static struct isa_driver snd_msnd_driver = {
1064 .match = snd_msnd_isa_match,
1065 .probe = snd_msnd_isa_probe,
1066 .remove = __devexit_p(snd_msnd_isa_remove),
1067 /* FIXME: suspend, resume */
1068 .driver = {
1069 .name = DEV_NAME
1070 },
1071};
1072
1073#ifdef CONFIG_PNP
1074static int __devinit snd_msnd_pnp_detect(struct pnp_card_link *pcard,
1075 const struct pnp_card_device_id *pid)
1076{
1077 static int idx;
1078 struct pnp_dev *pnp_dev;
1079 struct pnp_dev *mpu_dev;
1080 struct snd_card *card;
1081 struct snd_msnd *chip;
1082 int ret;
1083
1084 for ( ; idx < SNDRV_CARDS; idx++) {
1085 if (isapnp[idx])
1086 break;
1087 }
1088 if (idx >= SNDRV_CARDS)
1089 return -ENODEV;
1090
1091 /*
1092 * Check that we still have room for another sound card ...
1093 */
1094 pnp_dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
1095 if (!pnp_dev)
1096 return -ENODEV;
1097
1098 mpu_dev = pnp_request_card_device(pcard, pid->devs[1].id, NULL);
1099 if (!mpu_dev)
1100 return -ENODEV;
1101
1102 if (!pnp_is_active(pnp_dev) && pnp_activate_dev(pnp_dev) < 0) {
1103 printk(KERN_INFO "msnd_pinnacle: device is inactive\n");
1104 return -EBUSY;
1105 }
1106
1107 if (!pnp_is_active(mpu_dev) && pnp_activate_dev(mpu_dev) < 0) {
1108 printk(KERN_INFO "msnd_pinnacle: MPU device is inactive\n");
1109 return -EBUSY;
1110 }
1111
1112 /*
1113 * Create a new ALSA sound card entry, in anticipation
1114 * of detecting our hardware ...
1115 */
1116 ret = snd_card_create(index[idx], id[idx], THIS_MODULE,
1117 sizeof(struct snd_msnd), &card);
1118 if (ret < 0)
1119 return ret;
1120
1121 chip = card->private_data;
1122 chip->card = card;
1123 snd_card_set_dev(card, &pcard->card->dev);
1124
1125 /*
1126 * Read the correct parameters off the ISA PnP bus ...
1127 */
1128 io[idx] = pnp_port_start(pnp_dev, 0);
1129 irq[idx] = pnp_irq(pnp_dev, 0);
1130 mem[idx] = pnp_mem_start(pnp_dev, 0);
1131 mpu_io[idx] = pnp_port_start(mpu_dev, 0);
1132 mpu_irq[idx] = pnp_irq(mpu_dev, 0);
1133
1134 set_default_audio_parameters(chip);
1135#ifdef MSND_CLASSIC
1136 chip->type = msndClassic;
1137#else
1138 chip->type = msndPinnacle;
1139#endif
1140 chip->io = io[idx];
1141 chip->irq = irq[idx];
1142 chip->base = mem[idx];
1143
1144 chip->calibrate_signal = calibrate_signal ? 1 : 0;
1145 chip->recsrc = 0;
1146 chip->dspq_data_buff = DSPQ_DATA_BUFF;
1147 chip->dspq_buff_size = DSPQ_BUFF_SIZE;
1148 if (write_ndelay[idx])
1149 clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1150 else
1151 set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1152#ifndef MSND_CLASSIC
1153 if (digital[idx])
1154 set_bit(F_HAVEDIGITAL, &chip->flags);
1155#endif
1156 spin_lock_init(&chip->lock);
1157 ret = snd_msnd_probe(card);
1158 if (ret < 0) {
1159 printk(KERN_ERR LOGNAME ": Probe failed\n");
1160 goto _release_card;
1161 }
1162
1163 ret = snd_msnd_attach(card);
1164 if (ret < 0) {
1165 printk(KERN_ERR LOGNAME ": Attach failed\n");
1166 goto _release_card;
1167 }
1168
1169 pnp_set_card_drvdata(pcard, card);
1170 ++idx;
1171 return 0;
1172
1173_release_card:
1174 snd_card_free(card);
1175 return ret;
1176}
1177
1178static void __devexit snd_msnd_pnp_remove(struct pnp_card_link *pcard)
1179{
1180 snd_msnd_unload(pnp_get_card_drvdata(pcard));
1181 pnp_set_card_drvdata(pcard, NULL);
1182}
1183
1184static int isa_registered;
1185static int pnp_registered;
1186
1187static struct pnp_card_device_id msnd_pnpids[] = {
1188 /* Pinnacle PnP */
1189 { .id = "BVJ0440", .devs = { { "TBS0000" }, { "TBS0001" } } },
1190 { .id = "" } /* end */
1191};
1192
1193MODULE_DEVICE_TABLE(pnp_card, msnd_pnpids);
1194
1195static struct pnp_card_driver msnd_pnpc_driver = {
1196 .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
1197 .name = "msnd_pinnacle",
1198 .id_table = msnd_pnpids,
1199 .probe = snd_msnd_pnp_detect,
1200 .remove = __devexit_p(snd_msnd_pnp_remove),
1201};
1202#endif /* CONFIG_PNP */
1203
1204static int __init snd_msnd_init(void)
1205{
1206 int err;
1207
1208 err = isa_register_driver(&snd_msnd_driver, SNDRV_CARDS);
1209#ifdef CONFIG_PNP
1210 if (!err)
1211 isa_registered = 1;
1212
1213 err = pnp_register_card_driver(&msnd_pnpc_driver);
1214 if (!err)
1215 pnp_registered = 1;
1216
1217 if (isa_registered)
1218 err = 0;
1219#endif
1220 return err;
1221}
1222
1223static void __exit snd_msnd_exit(void)
1224{
1225#ifdef CONFIG_PNP
1226 if (pnp_registered)
1227 pnp_unregister_card_driver(&msnd_pnpc_driver);
1228 if (isa_registered)
1229#endif
1230 isa_unregister_driver(&snd_msnd_driver);
1231}
1232
1233module_init(snd_msnd_init);
1234module_exit(snd_msnd_exit);
1235
diff --git a/sound/isa/msnd/msnd_pinnacle.h b/sound/isa/msnd/msnd_pinnacle.h
new file mode 100644
index 000000000000..48318d1ee340
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle.h
@@ -0,0 +1,181 @@
1/*********************************************************************
2 *
3 * msnd_pinnacle.h
4 *
5 * Turtle Beach MultiSound Sound Card Driver for Linux
6 *
7 * Some parts of this header file were derived from the Turtle Beach
8 * MultiSound Driver Development Kit.
9 *
10 * Copyright (C) 1998 Andrew Veliath
11 * Copyright (C) 1993 Turtle Beach Systems, Inc.
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 ********************************************************************/
28#ifndef __MSND_PINNACLE_H
29#define __MSND_PINNACLE_H
30
31#define DSP_NUMIO 0x08
32
33#define IREG_LOGDEVICE 0x07
34#define IREG_ACTIVATE 0x30
35#define LD_ACTIVATE 0x01
36#define LD_DISACTIVATE 0x00
37#define IREG_EECONTROL 0x3F
38#define IREG_MEMBASEHI 0x40
39#define IREG_MEMBASELO 0x41
40#define IREG_MEMCONTROL 0x42
41#define IREG_MEMRANGEHI 0x43
42#define IREG_MEMRANGELO 0x44
43#define MEMTYPE_8BIT 0x00
44#define MEMTYPE_16BIT 0x02
45#define MEMTYPE_RANGE 0x00
46#define MEMTYPE_HIADDR 0x01
47#define IREG_IO0_BASEHI 0x60
48#define IREG_IO0_BASELO 0x61
49#define IREG_IO1_BASEHI 0x62
50#define IREG_IO1_BASELO 0x63
51#define IREG_IRQ_NUMBER 0x70
52#define IREG_IRQ_TYPE 0x71
53#define IRQTYPE_HIGH 0x02
54#define IRQTYPE_LOW 0x00
55#define IRQTYPE_LEVEL 0x01
56#define IRQTYPE_EDGE 0x00
57
58#define HP_DSPR 0x04
59#define HP_BLKS 0x04
60
61#define HPDSPRESET_OFF 2
62#define HPDSPRESET_ON 0
63
64#define HPBLKSEL_0 2
65#define HPBLKSEL_1 3
66
67#define HIMT_DAT_OFF 0x03
68
69#define HIDSP_PLAY_UNDER 0x00
70#define HIDSP_INT_PLAY_UNDER 0x01
71#define HIDSP_SSI_TX_UNDER 0x02
72#define HIDSP_RECQ_OVERFLOW 0x08
73#define HIDSP_INT_RECORD_OVER 0x09
74#define HIDSP_SSI_RX_OVERFLOW 0x0a
75
76#define HIDSP_MIDI_IN_OVER 0x10
77
78#define HIDSP_MIDI_FRAME_ERR 0x11
79#define HIDSP_MIDI_PARITY_ERR 0x12
80#define HIDSP_MIDI_OVERRUN_ERR 0x13
81
82#define HIDSP_INPUT_CLIPPING 0x20
83#define HIDSP_MIX_CLIPPING 0x30
84#define HIDSP_DAT_IN_OFF 0x21
85
86#define TIME_PRO_RESET_DONE 0x028A
87#define TIME_PRO_SYSEX 0x001E
88#define TIME_PRO_RESET 0x0032
89
90#define DAR_BUFF_SIZE 0x1000
91
92#define MIDQ_BUFF_SIZE 0x800
93#define DSPQ_BUFF_SIZE 0x5A0
94
95#define DSPQ_DATA_BUFF 0x7860
96
97#define MOP_WAVEHDR 0
98#define MOP_EXTOUT 1
99#define MOP_HWINIT 0xfe
100#define MOP_NONE 0xff
101#define MOP_MAX 1
102
103#define MIP_EXTIN 0
104#define MIP_WAVEHDR 1
105#define MIP_HWINIT 0xfe
106#define MIP_MAX 1
107
108/* Pinnacle/Fiji SMA Common Data */
109#define SMA_wCurrPlayBytes 0x0000
110#define SMA_wCurrRecordBytes 0x0002
111#define SMA_wCurrPlayVolLeft 0x0004
112#define SMA_wCurrPlayVolRight 0x0006
113#define SMA_wCurrInVolLeft 0x0008
114#define SMA_wCurrInVolRight 0x000a
115#define SMA_wCurrMHdrVolLeft 0x000c
116#define SMA_wCurrMHdrVolRight 0x000e
117#define SMA_dwCurrPlayPitch 0x0010
118#define SMA_dwCurrPlayRate 0x0014
119#define SMA_wCurrMIDIIOPatch 0x0018
120#define SMA_wCurrPlayFormat 0x001a
121#define SMA_wCurrPlaySampleSize 0x001c
122#define SMA_wCurrPlayChannels 0x001e
123#define SMA_wCurrPlaySampleRate 0x0020
124#define SMA_wCurrRecordFormat 0x0022
125#define SMA_wCurrRecordSampleSize 0x0024
126#define SMA_wCurrRecordChannels 0x0026
127#define SMA_wCurrRecordSampleRate 0x0028
128#define SMA_wCurrDSPStatusFlags 0x002a
129#define SMA_wCurrHostStatusFlags 0x002c
130#define SMA_wCurrInputTagBits 0x002e
131#define SMA_wCurrLeftPeak 0x0030
132#define SMA_wCurrRightPeak 0x0032
133#define SMA_bMicPotPosLeft 0x0034
134#define SMA_bMicPotPosRight 0x0035
135#define SMA_bMicPotMaxLeft 0x0036
136#define SMA_bMicPotMaxRight 0x0037
137#define SMA_bInPotPosLeft 0x0038
138#define SMA_bInPotPosRight 0x0039
139#define SMA_bAuxPotPosLeft 0x003a
140#define SMA_bAuxPotPosRight 0x003b
141#define SMA_bInPotMaxLeft 0x003c
142#define SMA_bInPotMaxRight 0x003d
143#define SMA_bAuxPotMaxLeft 0x003e
144#define SMA_bAuxPotMaxRight 0x003f
145#define SMA_bInPotMaxMethod 0x0040
146#define SMA_bAuxPotMaxMethod 0x0041
147#define SMA_wCurrMastVolLeft 0x0042
148#define SMA_wCurrMastVolRight 0x0044
149#define SMA_wCalFreqAtoD 0x0046
150#define SMA_wCurrAuxVolLeft 0x0048
151#define SMA_wCurrAuxVolRight 0x004a
152#define SMA_wCurrPlay1VolLeft 0x004c
153#define SMA_wCurrPlay1VolRight 0x004e
154#define SMA_wCurrPlay2VolLeft 0x0050
155#define SMA_wCurrPlay2VolRight 0x0052
156#define SMA_wCurrPlay3VolLeft 0x0054
157#define SMA_wCurrPlay3VolRight 0x0056
158#define SMA_wCurrPlay4VolLeft 0x0058
159#define SMA_wCurrPlay4VolRight 0x005a
160#define SMA_wCurrPlay1PeakLeft 0x005c
161#define SMA_wCurrPlay1PeakRight 0x005e
162#define SMA_wCurrPlay2PeakLeft 0x0060
163#define SMA_wCurrPlay2PeakRight 0x0062
164#define SMA_wCurrPlay3PeakLeft 0x0064
165#define SMA_wCurrPlay3PeakRight 0x0066
166#define SMA_wCurrPlay4PeakLeft 0x0068
167#define SMA_wCurrPlay4PeakRight 0x006a
168#define SMA_wCurrPlayPeakLeft 0x006c
169#define SMA_wCurrPlayPeakRight 0x006e
170#define SMA_wCurrDATSR 0x0070
171#define SMA_wCurrDATRXCHNL 0x0072
172#define SMA_wCurrDATTXCHNL 0x0074
173#define SMA_wCurrDATRXRate 0x0076
174#define SMA_dwDSPPlayCount 0x0078
175#define SMA__size 0x007c
176
177#define INITCODEFILE "turtlebeach/pndspini.bin"
178#define PERMCODEFILE "turtlebeach/pndsperm.bin"
179#define LONGNAME "MultiSound (Pinnacle/Fiji)"
180
181#endif /* __MSND_PINNACLE_H */
diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c
new file mode 100644
index 000000000000..494058a1a502
--- /dev/null
+++ b/sound/isa/msnd/msnd_pinnacle_mixer.c
@@ -0,0 +1,343 @@
1/***************************************************************************
2 msnd_pinnacle_mixer.c - description
3 -------------------
4 begin : Fre Jun 7 2002
5 copyright : (C) 2002 by karsten wiese
6 email : annabellesgarden@yahoo.de
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include <linux/io.h>
19
20#include <sound/core.h>
21#include <sound/control.h>
22#include "msnd.h"
23#include "msnd_pinnacle.h"
24
25
26#define MSND_MIXER_VOLUME 0
27#define MSND_MIXER_PCM 1
28#define MSND_MIXER_AUX 2 /* Input source 1 (aux1) */
29#define MSND_MIXER_IMIX 3 /* Recording monitor */
30#define MSND_MIXER_SYNTH 4
31#define MSND_MIXER_SPEAKER 5
32#define MSND_MIXER_LINE 6
33#define MSND_MIXER_MIC 7
34#define MSND_MIXER_RECLEV 11 /* Recording level */
35#define MSND_MIXER_IGAIN 12 /* Input gain */
36#define MSND_MIXER_OGAIN 13 /* Output gain */
37#define MSND_MIXER_DIGITAL 17 /* Digital (input) 1 */
38
39/* Device mask bits */
40
41#define MSND_MASK_VOLUME (1 << MSND_MIXER_VOLUME)
42#define MSND_MASK_SYNTH (1 << MSND_MIXER_SYNTH)
43#define MSND_MASK_PCM (1 << MSND_MIXER_PCM)
44#define MSND_MASK_SPEAKER (1 << MSND_MIXER_SPEAKER)
45#define MSND_MASK_LINE (1 << MSND_MIXER_LINE)
46#define MSND_MASK_MIC (1 << MSND_MIXER_MIC)
47#define MSND_MASK_IMIX (1 << MSND_MIXER_IMIX)
48#define MSND_MASK_RECLEV (1 << MSND_MIXER_RECLEV)
49#define MSND_MASK_IGAIN (1 << MSND_MIXER_IGAIN)
50#define MSND_MASK_OGAIN (1 << MSND_MIXER_OGAIN)
51#define MSND_MASK_AUX (1 << MSND_MIXER_AUX)
52#define MSND_MASK_DIGITAL (1 << MSND_MIXER_DIGITAL)
53
54static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol,
55 struct snd_ctl_elem_info *uinfo)
56{
57 static char *texts[3] = {
58 "Analog", "MASS", "SPDIF",
59 };
60 struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
61 unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2;
62
63 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
64 uinfo->count = 1;
65 uinfo->value.enumerated.items = items;
66 if (uinfo->value.enumerated.item >= items)
67 uinfo->value.enumerated.item = items - 1;
68 strcpy(uinfo->value.enumerated.name,
69 texts[uinfo->value.enumerated.item]);
70 return 0;
71}
72
73static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol,
74 struct snd_ctl_elem_value *ucontrol)
75{
76 struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
77 /* MSND_MASK_IMIX is the default */
78 ucontrol->value.enumerated.item[0] = 0;
79
80 if (chip->recsrc & MSND_MASK_SYNTH) {
81 ucontrol->value.enumerated.item[0] = 1;
82 } else if ((chip->recsrc & MSND_MASK_DIGITAL) &&
83 test_bit(F_HAVEDIGITAL, &chip->flags)) {
84 ucontrol->value.enumerated.item[0] = 2;
85 }
86
87
88 return 0;
89}
90
91static int snd_msndmix_set_mux(struct snd_msnd *chip, int val)
92{
93 unsigned newrecsrc;
94 int change;
95 unsigned char msndbyte;
96
97 switch (val) {
98 case 0:
99 newrecsrc = MSND_MASK_IMIX;
100 msndbyte = HDEXAR_SET_ANA_IN;
101 break;
102 case 1:
103 newrecsrc = MSND_MASK_SYNTH;
104 msndbyte = HDEXAR_SET_SYNTH_IN;
105 break;
106 case 2:
107 newrecsrc = MSND_MASK_DIGITAL;
108 msndbyte = HDEXAR_SET_DAT_IN;
109 break;
110 default:
111 return -EINVAL;
112 }
113 change = newrecsrc != chip->recsrc;
114 if (change) {
115 change = 0;
116 if (!snd_msnd_send_word(chip, 0, 0, msndbyte))
117 if (!snd_msnd_send_dsp_cmd(chip, HDEX_AUX_REQ)) {
118 chip->recsrc = newrecsrc;
119 change = 1;
120 }
121 }
122 return change;
123}
124
125static int snd_msndmix_put_mux(struct snd_kcontrol *kcontrol,
126 struct snd_ctl_elem_value *ucontrol)
127{
128 struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
129 return snd_msndmix_set_mux(msnd, ucontrol->value.enumerated.item[0]);
130}
131
132
133static int snd_msndmix_volume_info(struct snd_kcontrol *kcontrol,
134 struct snd_ctl_elem_info *uinfo)
135{
136 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
137 uinfo->count = 2;
138 uinfo->value.integer.min = 0;
139 uinfo->value.integer.max = 100;
140 return 0;
141}
142
143static int snd_msndmix_volume_get(struct snd_kcontrol *kcontrol,
144 struct snd_ctl_elem_value *ucontrol)
145{
146 struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
147 int addr = kcontrol->private_value;
148 unsigned long flags;
149
150 spin_lock_irqsave(&msnd->mixer_lock, flags);
151 ucontrol->value.integer.value[0] = msnd->left_levels[addr] * 100;
152 ucontrol->value.integer.value[0] /= 0xFFFF;
153 ucontrol->value.integer.value[1] = msnd->right_levels[addr] * 100;
154 ucontrol->value.integer.value[1] /= 0xFFFF;
155 spin_unlock_irqrestore(&msnd->mixer_lock, flags);
156 return 0;
157}
158
159#define update_volm(a, b) \
160 do { \
161 writew((dev->left_levels[a] >> 1) * \
162 readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
163 dev->SMA + SMA_##b##Left); \
164 writew((dev->right_levels[a] >> 1) * \
165 readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
166 dev->SMA + SMA_##b##Right); \
167 } while (0);
168
169#define update_potm(d, s, ar) \
170 do { \
171 writeb((dev->left_levels[d] >> 8) * \
172 readw(dev->SMA + SMA_wCurrMastVolLeft) / 0xffff, \
173 dev->SMA + SMA_##s##Left); \
174 writeb((dev->right_levels[d] >> 8) * \
175 readw(dev->SMA + SMA_wCurrMastVolRight) / 0xffff, \
176 dev->SMA + SMA_##s##Right); \
177 if (snd_msnd_send_word(dev, 0, 0, ar) == 0) \
178 snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ); \
179 } while (0);
180
181#define update_pot(d, s, ar) \
182 do { \
183 writeb(dev->left_levels[d] >> 8, \
184 dev->SMA + SMA_##s##Left); \
185 writeb(dev->right_levels[d] >> 8, \
186 dev->SMA + SMA_##s##Right); \
187 if (snd_msnd_send_word(dev, 0, 0, ar) == 0) \
188 snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ); \
189 } while (0);
190
191
192static int snd_msndmix_set(struct snd_msnd *dev, int d, int left, int right)
193{
194 int bLeft, bRight;
195 int wLeft, wRight;
196 int updatemaster = 0;
197
198 if (d >= LEVEL_ENTRIES)
199 return -EINVAL;
200
201 bLeft = left * 0xff / 100;
202 wLeft = left * 0xffff / 100;
203
204 bRight = right * 0xff / 100;
205 wRight = right * 0xffff / 100;
206
207 dev->left_levels[d] = wLeft;
208 dev->right_levels[d] = wRight;
209
210 switch (d) {
211 /* master volume unscaled controls */
212 case MSND_MIXER_LINE: /* line pot control */
213 /* scaled by IMIX in digital mix */
214 writeb(bLeft, dev->SMA + SMA_bInPotPosLeft);
215 writeb(bRight, dev->SMA + SMA_bInPotPosRight);
216 if (snd_msnd_send_word(dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
217 snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
218 break;
219 case MSND_MIXER_MIC: /* mic pot control */
220 if (dev->type == msndClassic)
221 return -EINVAL;
222 /* scaled by IMIX in digital mix */
223 writeb(bLeft, dev->SMA + SMA_bMicPotPosLeft);
224 writeb(bRight, dev->SMA + SMA_bMicPotPosRight);
225 if (snd_msnd_send_word(dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
226 snd_msnd_send_dsp_cmd(dev, HDEX_AUX_REQ);
227 break;
228 case MSND_MIXER_VOLUME: /* master volume */
229 writew(wLeft, dev->SMA + SMA_wCurrMastVolLeft);
230 writew(wRight, dev->SMA + SMA_wCurrMastVolRight);
231 /* fall through */
232
233 case MSND_MIXER_AUX: /* aux pot control */
234 /* scaled by master volume */
235 /* fall through */
236
237 /* digital controls */
238 case MSND_MIXER_SYNTH: /* synth vol (dsp mix) */
239 case MSND_MIXER_PCM: /* pcm vol (dsp mix) */
240 case MSND_MIXER_IMIX: /* input monitor (dsp mix) */
241 /* scaled by master volume */
242 updatemaster = 1;
243 break;
244
245 default:
246 return -EINVAL;
247 }
248
249 if (updatemaster) {
250 /* update master volume scaled controls */
251 update_volm(MSND_MIXER_PCM, wCurrPlayVol);
252 update_volm(MSND_MIXER_IMIX, wCurrInVol);
253 if (dev->type == msndPinnacle)
254 update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
255 update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
256 }
257
258 return 0;
259}
260
261static int snd_msndmix_volume_put(struct snd_kcontrol *kcontrol,
262 struct snd_ctl_elem_value *ucontrol)
263{
264 struct snd_msnd *msnd = snd_kcontrol_chip(kcontrol);
265 int change, addr = kcontrol->private_value;
266 int left, right;
267 unsigned long flags;
268
269 left = ucontrol->value.integer.value[0] % 101;
270 right = ucontrol->value.integer.value[1] % 101;
271 spin_lock_irqsave(&msnd->mixer_lock, flags);
272 change = msnd->left_levels[addr] != left
273 || msnd->right_levels[addr] != right;
274 snd_msndmix_set(msnd, addr, left, right);
275 spin_unlock_irqrestore(&msnd->mixer_lock, flags);
276 return change;
277}
278
279
280#define DUMMY_VOLUME(xname, xindex, addr) \
281{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
282 .info = snd_msndmix_volume_info, \
283 .get = snd_msndmix_volume_get, .put = snd_msndmix_volume_put, \
284 .private_value = addr }
285
286
287static struct snd_kcontrol_new snd_msnd_controls[] = {
288DUMMY_VOLUME("Master Volume", 0, MSND_MIXER_VOLUME),
289DUMMY_VOLUME("PCM Volume", 0, MSND_MIXER_PCM),
290DUMMY_VOLUME("Aux Volume", 0, MSND_MIXER_AUX),
291DUMMY_VOLUME("Line Volume", 0, MSND_MIXER_LINE),
292DUMMY_VOLUME("Mic Volume", 0, MSND_MIXER_MIC),
293DUMMY_VOLUME("Monitor", 0, MSND_MIXER_IMIX),
294{
295 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
296 .name = "Capture Source",
297 .info = snd_msndmix_info_mux,
298 .get = snd_msndmix_get_mux,
299 .put = snd_msndmix_put_mux,
300}
301};
302
303
304int __devinit snd_msndmix_new(struct snd_card *card)
305{
306 struct snd_msnd *chip = card->private_data;
307 unsigned int idx;
308 int err;
309
310 if (snd_BUG_ON(!chip))
311 return -EINVAL;
312 spin_lock_init(&chip->mixer_lock);
313 strcpy(card->mixername, "MSND Pinnacle Mixer");
314
315 for (idx = 0; idx < ARRAY_SIZE(snd_msnd_controls); idx++)
316 err = snd_ctl_add(card,
317 snd_ctl_new1(snd_msnd_controls + idx, chip));
318 if (err < 0)
319 return err;
320
321 return 0;
322}
323EXPORT_SYMBOL(snd_msndmix_new);
324
325void snd_msndmix_setup(struct snd_msnd *dev)
326{
327 update_pot(MSND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS);
328 update_potm(MSND_MIXER_AUX, bAuxPotPos, HDEXAR_AUX_SET_POTS);
329 update_volm(MSND_MIXER_PCM, wCurrPlayVol);
330 update_volm(MSND_MIXER_IMIX, wCurrInVol);
331 if (dev->type == msndPinnacle) {
332 update_pot(MSND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS);
333 update_volm(MSND_MIXER_SYNTH, wCurrMHdrVol);
334 }
335}
336EXPORT_SYMBOL(snd_msndmix_setup);
337
338int snd_msndmix_force_recsrc(struct snd_msnd *dev, int recsrc)
339{
340 dev->recsrc = -1;
341 return snd_msndmix_set_mux(dev, recsrc);
342}
343EXPORT_SYMBOL(snd_msndmix_force_recsrc);