diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-01-04 16:03:48 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-01-04 16:03:48 +0000 |
commit | 78c388aed2b7184182c08428db1de6c872d815f5 (patch) | |
tree | 4b2003b1b4ceb241a17faa995da8dd1004bb8e45 /drivers/sound | |
parent | eb7a5bf93aaa4be1d7c6181100ab7639e74d67f7 (diff) |
Merge with Linux 2.1.131 and more MIPS goodies.
(Did I mention that CVS is buggy ...)
Diffstat (limited to 'drivers/sound')
43 files changed, 1807 insertions, 892 deletions
diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index b23a61f74..b13122e4e 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -11,43 +11,62 @@ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND + if [ "$CONFIG_SOUND_ES1370" = "y" ]; then + bool 'Joystick support at boot time' CONFIG_SOUND_ES1370_JOYPORT_BOOT + fi dep_tristate 'Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND dep_tristate 'S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND fi dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then + if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then + comment 'Compiled-in MSND Classic support requires firmware during compilation.' + define_bool CONFIG_MSNDCLAS_HAVE_BOOT y + else + define_bool CONFIG_MSNDCLAS_HAVE_BOOT n + fi string ' Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE "/etc/sound/msndinit.bin" string ' Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE "/etc/sound/msndperm.bin" fi if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then int 'MSND Classic IRQ 5,7,9,10,11,12' CONFIG_MSNDCLAS_IRQ 5 - hex 'MSND Classic Memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDCLAS_MEM D0000 + hex 'MSND Classic memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDCLAS_MEM D0000 hex 'MSND Classic I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDCLAS_IO 290 fi dep_tristate 'Support for Turtle Beach MultiSound Pinnacle, Fiji' CONFIG_SOUND_MSNDPIN $CONFIG_SOUND if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDPIN" = "m" ]; then + if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then + comment 'Compiled-in MSND Pinnacle support requires firmware during compilation.' + define_bool CONFIG_MSNDPIN_HAVE_BOOT y + else + define_bool CONFIG_MSNDPIN_HAVE_BOOT n + fi string ' Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE "/etc/sound/pndspini.bin" string ' Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE "/etc/sound/pndsperm.bin" fi if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then int 'MSND Pinnacle IRQ 5,7,9,10,11,12' CONFIG_MSNDPIN_IRQ 5 - hex 'MSND Pinnacle Memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDPIN_MEM D0000 + hex 'MSND Pinnacle memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDPIN_MEM D0000 hex 'MSND Pinnacle I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDPIN_IO 290 - bool 'MSND Pinnacle Non-PnP Mode' CONFIG_MSNDPIN_NONPNP + bool 'MSND Pinnacle has S/PDIF I/O' CONFIG_MSNDPIN_DIGITAL + bool 'MSND Pinnacle non-PnP Mode' CONFIG_MSNDPIN_NONPNP if [ "$CONFIG_MSNDPIN_NONPNP" = "y" ]; then comment 'MSND Pinnacle DSP section will be configured to above parameters.' - hex 'MSDN Pinnacle Config Port 250,260,270' CONFIG_MSNDPIN_CFG 250 + hex 'MSND Pinnacle config port 250,260,270' CONFIG_MSNDPIN_CFG 250 comment 'Pinnacle-specific Device Configuration (0 disables)' - hex 'MSDN Pinnacle MPU I/O (e.g. 330)' CONFIG_MSNDPIN_MPU_IO 0 - int 'MSDN Pinnacle MPU IRQ (e.g. 9)' CONFIG_MSNDPIN_MPU_IRQ 0 - hex 'MSDN Pinnacle IDE I/O 0 (e.g. 170)' CONFIG_MSNDPIN_IDE_IO0 0 - hex 'MSDN Pinnacle IDE I/O 1 (e.g. 376)' CONFIG_MSNDPIN_IDE_IO1 0 - int 'MSDN Pinnacle IDE IRQ (e.g. 15)' CONFIG_MSNDPIN_IDE_IRQ 0 - hex 'MSDN Pinnacle Joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0 + hex 'MSND Pinnacle MPU I/O (e.g. 330)' CONFIG_MSNDPIN_MPU_IO 0 + int 'MSND Pinnacle MPU IRQ (e.g. 9)' CONFIG_MSNDPIN_MPU_IRQ 0 + hex 'MSND Pinnacle IDE I/O 0 (e.g. 170)' CONFIG_MSNDPIN_IDE_IO0 0 + hex 'MSND Pinnacle IDE I/O 1 (e.g. 376)' CONFIG_MSNDPIN_IDE_IO1 0 + int 'MSND Pinnacle IDE IRQ (e.g. 15)' CONFIG_MSNDPIN_IDE_IRQ 0 + hex 'MSND Pinnacle joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0 fi fi +if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then + int 'MSND buffer size (kB)' CONFIG_MSND_FIFOSIZE 128 +fi dep_tristate 'OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND @@ -176,6 +195,16 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_MPU_IRQ 9 fi + dep_tristate 'Support for Yamaha OPL3-SA[2,3,x] based (PnP) cards' CONFIG_SOUND_OPL3SA2 $CONFIG_SOUND_OSS + if [ "$CONFIG_SOUND_OPL3SA2" = "y" ]; then + hex 'OPL3SA2 audio I/O base 530, 604, E80 or F40' CONFIG_OPL3SA2_BASE 530 + int 'OPL3SA2 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_IRQ 11 + int 'OPL3SA2 audio DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA 0 + int 'OPL3SA2 second (duplex) DMA 0, 1 or 3' CONFIG_OPL3SA2_DMA2 1 + hex 'OPL3SA2 MIDI I/O base 330, 370, 3B0 or 3F0' CONFIG_OPL3SA2_MPU_BASE 330 + int 'OPL3SA2 MIDI IRQ 5, 7, 9, 11, 12 or 15' CONFIG_OPL3SA2_MPU_IRQ 9 + fi + dep_tristate 'Limited support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_SOUND_MAUI $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_MAUI" = "y" ]; then hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_MAUI_BASE 330 diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index f072b7fad..c4fb47dce 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -41,19 +41,7 @@ obj- := # Each configuration option enables a list of files. obj-$(CONFIG_SOUND) += soundcore.o - -ifeq ($(ARCH),m68k) - -obj-$(CONFIG_DMASOUND) += dmasound.o - -else - -ifeq ($(CONFIG_PMAC),y) - obj-$(CONFIG_DMASOUND) += dmasound.o - -else - obj-$(CONFIG_SOUND_OSS) += sound.o obj-$(CONFIG_SOUND_ADLIB) += adlib_card.o opl3.o obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o @@ -72,6 +60,7 @@ obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_MSS) += ad1848.o obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o +obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o uart401.o mpu401.o obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o uart401.o obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_SB) += sb.o uart401.o @@ -89,9 +78,6 @@ obj-$(CONFIG_SOUND_ES1370) += es1370.o obj-$(CONFIG_SOUND_ES1371) += es1371.o obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o -endif -endif - # Declare multi-part drivers. list-multi := sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o \ @@ -219,7 +205,7 @@ maui.o: maui_boot.h ifeq ($(CONFIG_MAUI_HAVE_BOOT),y) maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) bin2hex - bin2hex -i maui_os < $(CONFIG_MAUI_BOOT_FILE) > $@ + ./bin2hex -i maui_os < $(CONFIG_MAUI_BOOT_FILE) > $@ else maui_boot.h: ( \ @@ -235,6 +221,50 @@ endif +# Turtle Beach MultiSound + +ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y) + msnd_classic.o: msndperm.c msndinit.c + + msndperm.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_PERM_FILE)) bin2hex + ./bin2hex msndperm < $(CONFIG_MSNDCLAS_PERM_FILE) > $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_MSNDCLAS_HAVE_BOOT) $(CONFIG_MSNDCLAS_PERM_FILE)),$$(strip $$(CONFIG_MSNDCLAS_HAVE_BOOT) $$(CONFIG_MSNDCLAS_PERM_FILE)))'; \ + echo 'FILES_BOOT_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) > .$@.boot + + msndinit.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_INIT_FILE)) bin2hex + ./bin2hex msndinit < $(CONFIG_MSNDCLAS_INIT_FILE) > $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_MSNDCLAS_HAVE_BOOT) $(CONFIG_MSNDCLAS_INIT_FILE)),$$(strip $$(CONFIG_MSNDCLAS_HAVE_BOOT) $$(CONFIG_MSNDCLAS_INIT_FILE)))'; \ + echo 'FILES_BOOT_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) > .$@.boot +endif + +ifeq ($(CONFIG_MSNDPIN_HAVE_BOOT),y) + msnd_pinnacle.o: pndsperm.c pndspini.c + + pndsperm.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_PERM_FILE)) bin2hex + ./bin2hex pndsperm < $(CONFIG_MSNDPIN_PERM_FILE) > $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_MSNDPIN_HAVE_BOOT) $(CONFIG_MSNDPIN_PERM_FILE)),$$(strip $$(CONFIG_MSNDPIN_HAVE_BOOT) $$(CONFIG_MSNDPIN_PERM_FILE)))'; \ + echo 'FILES_BOOT_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) > .$@.boot + + pndspini.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_INIT_FILE)) bin2hex + ./bin2hex pndspini < $(CONFIG_MSNDPIN_INIT_FILE) > $@ + @ ( \ + echo 'ifeq ($(strip $(CONFIG_MSNDPIN_HAVE_BOOT) $(CONFIG_MSNDPIN_INIT_FILE)),$$(strip $$(CONFIG_MSNDPIN_HAVE_BOOT) $$(CONFIG_MSNDPIN_INIT_FILE)))'; \ + echo 'FILES_BOOT_UP_TO_DATE += $@'; \ + echo 'endif' \ + ) > .$@.boot +endif + + + # PSS (ECHO-ADI2111) pss.o: pss_boot.h diff --git a/drivers/sound/Readme b/drivers/sound/Readme index 2bb76549f..cd506f29a 100644 --- a/drivers/sound/Readme +++ b/drivers/sound/Readme @@ -168,7 +168,7 @@ The following errors are likely with /dev/dsp and /dev/audio. with impossible parameters. Check that the application is for sound driver version 2.X or later. -In general the printout of of /dev/sndstat should tell what is the problem. +In general the printout of /dev/sndstat should tell what is the problem. It's possible that there are bugs in the sound driver but 99% of the problems reported to me are caused by somehow incorrect setup during "make config". diff --git a/drivers/sound/Readme.modules b/drivers/sound/Readme.modules index 9740035b4..670fbe87b 100644 --- a/drivers/sound/Readme.modules +++ b/drivers/sound/Readme.modules @@ -66,6 +66,34 @@ modprobe -k adlib_card io=0x388 recommend using /etc/modules.conf. +Persistent DMA Buffers: + +The sound modules normally allocate DMA buffers during open() and +deallocate them during close(). Linux can often have problems allocating +DMA buffers for ISA cards on machines with more than 16MB RAM. This is +because ISA DMA buffers must exist below the 16MB boundry and it is quite +possible that we can't find a large enough free block in this region after +the machine has been running for any amount of time. The way to avoid this +problem is to allocate the DMA buffers during module load and deallocate +them when the module is unloaded. For this to be effective we need to load +the sound modules right after the kernel boots, either manually or by an +init script, and keep them around until we shut down. This is a little +wasteful of RAM, but it guarantees that sound always works. + +To make the sound driver use persistent DMA buffers we need to pass the +sound.o module a "dmabuf=1" command-line argument. This is normally done +in /etc/conf.modules (or the more proper /etc/modules.conf) like so: + +options sound dmabuf=1 + +If you have 16MB or less RAM or a PCI sound card, this is wasteful and +unnecessary. It is possible that machine with 16MB or less RAM will find +this option useful, but if your machine is so memory-starved that it +cannot find a 64K block free, you will be wasting even more RAM by keeping +the sound modules loaded and the DMA buffers allocated when they are not +needed. The proper solution is to upgrade your RAM. But you do also have +this improper solution as well. Use it wisely. + I'm afraid I know nothing about anything but my setup, being more of a text-mode guy anyway. If you have options for other cards or other helpful hints, send them to me, Jim Bray, jb@as220.org, http://as220.org/jb. diff --git a/drivers/sound/ad1848.c b/drivers/sound/ad1848.c index 34148d990..d3a743550 100644 --- a/drivers/sound/ad1848.c +++ b/drivers/sound/ad1848.c @@ -206,7 +206,7 @@ static void wait_for_calibration(ad1848_info * devc) return; timeout = 80000; - while (timeout > 0 && ad_read(devc, 11) & 0x20) + while (timeout > 0 && (ad_read(devc, 11) & 0x20)) timeout--; if (ad_read(devc, 11) & 0x20) if (devc->model != MD_1845) @@ -916,7 +916,7 @@ static void ad1848_output_block(int dev, unsigned long buf, int count, int intrf cnt >>= 1; cnt--; - if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE && + if ((devc->audio_mode & PCM_ENABLE_OUTPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) && intrflag && cnt == devc->xfer_count) { @@ -958,7 +958,7 @@ static void ad1848_start_input(int dev, unsigned long buf, int count, int intrfl cnt >>= 1; cnt--; - if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE && + if ((devc->audio_mode & PCM_ENABLE_INPUT) && (audio_devs[dev]->flags & DMA_AUTOMODE) && intrflag && cnt == devc->xfer_count) { @@ -1182,10 +1182,10 @@ static void ad1848_halt(int dev) unsigned char bits = ad_read(devc, 9); - if (bits & 0x01 && portc->open_mode & OPEN_WRITE) + if (bits & 0x01 && (portc->open_mode & OPEN_WRITE)) ad1848_halt_output(dev); - if (bits & 0x02 && portc->open_mode & OPEN_READ) + if (bits & 0x02 && (portc->open_mode & OPEN_READ)) ad1848_halt_input(dev); devc->audio_mode = 0; } @@ -1308,7 +1308,7 @@ static void ad1848_init_hw(ad1848_info * devc) 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, /* Positions 16 to 31 just for CS4231/2 and ad1845 */ - 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x1f, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -1814,7 +1814,7 @@ int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capt ad_write(devc, 16, tmp & ~0x40); /* Disable timer */ if (devc->timer_ticks == 0) - printk(KERN_WARNING "ad1848: Interrupt test failed (IRQ%d)\n", devc->irq); + printk(KERN_WARNING "ad1848: Interrupt test failed (IRQ%d)\n", irq); else { DDB(printk("Interrupt test OK\n")); @@ -1934,8 +1934,8 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int if (!share_dma) { - if (irq > 0) - free_irq(devc->irq, NULL); + if (devc->irq > 0) /* There is no point in freeing irq, if it wasn't allocated */ + free_irq(devc->irq, (void *)devc->dev_no); sound_free_dma(audio_devs[dev]->dmap_out->dma); @@ -1945,6 +1945,10 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int mixer = audio_devs[devc->dev_no]->mixer_dev; if(mixer>=0) sound_unload_mixerdev(mixer); + + nr_ad1848_devs--; + for ( ; i < nr_ad1848_devs ; i++) + adev_info[i] = adev_info[i+1]; } else printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base); @@ -1997,16 +2001,16 @@ interrupt_again: /* Jump back here if int status doesn't reset */ ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */ } - if (devc->open_mode & OPEN_READ && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) + if ((devc->open_mode & OPEN_READ) && (devc->audio_mode & PCM_ENABLE_INPUT) && (alt_stat & 0x20)) { DMAbuf_inputintr(devc->record_dev); } - if (devc->open_mode & OPEN_WRITE && devc->audio_mode & PCM_ENABLE_OUTPUT && - alt_stat & 0x10) + if ((devc->open_mode & OPEN_WRITE) && (devc->audio_mode & PCM_ENABLE_OUTPUT) && + (alt_stat & 0x10)) { DMAbuf_outputintr(devc->playback_dev, 1); } - if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ + if (devc->model != MD_1848 && (alt_stat & 0x40)) /* Timer interrupt */ { devc->timer_ticks++; #if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) @@ -2401,7 +2405,6 @@ void attach_ms_sound(struct address_info *hw_config) void unload_ms_sound(struct address_info *hw_config) { - int mixer = audio_devs[hw_config->slots[0]]->mixer_dev; ad1848_unload(hw_config->io_base + 4, hw_config->irq, hw_config->dma, diff --git a/drivers/sound/ad1848_mixer.h b/drivers/sound/ad1848_mixer.h index ab8eb2035..5768420a9 100644 --- a/drivers/sound/ad1848_mixer.h +++ b/drivers/sound/ad1848_mixer.h @@ -17,7 +17,7 @@ * The AD1848 codec has generic input lines called Line, Aux1 and Aux2. * Sound card manufacturers have connected actual inputs (CD, synth, line, * etc) to these inputs in different order. Therefore it's difficult - * to assign mixer channels to to these inputs correctly. The following + * to assign mixer channels to these inputs correctly. The following * contains two alternative mappings. The first one is for GUS MAX and * the second is just a generic one (line1, line2 and line3). * (Actually this is not a mapping but rather some kind of interleaving diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index 54d8e5f5b..286eca011 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -18,6 +18,8 @@ * lifetime as the rest in there and dynamic allocation saves * 12k or so * Thomas Sailer : use more logical O_NONBLOCK semantics + * Daniel Rodriksson: reworked the use of the device specific copy_user + * still generic */ #include <linux/config.h> @@ -155,10 +157,21 @@ void audio_release(int dev, struct file *file) dev = dev >> 4; + /* + * We do this in DMAbuf_release(). Why are we doing it + * here? Why don't we test the file mode before setting + * both flags? DMAbuf_release() does. + * ...pester...pester...pester... + */ audio_devs[dev]->dmap_out->closing = 1; audio_devs[dev]->dmap_in->closing = 1; - sync_output(dev); + /* + * We need to make sure we allocated the dmap_out buffer + * before we go mucking around with it in sync_output(). + */ + if (mode & OPEN_WRITE) + sync_output(dev); if (audio_devs[dev]->coproc) audio_devs[dev]->coproc->close(audio_devs[dev]->coproc->devc, COPR_PCM); @@ -178,7 +191,7 @@ static void translate_bytes(const unsigned char *table, unsigned char *buff, int int audio_write(int dev, struct file *file, const char *buf, int count) { - int c, p, l, buf_size; + int c, p, l, buf_size, used, returned; int err; char *dma_buf; @@ -215,6 +228,8 @@ int audio_write(int dev, struct file *file, const char *buf, int count) if (l > buf_size) l = buf_size; + returned = l; + used = l; if (!audio_devs[dev]->d->copy_user) { if ((dma_buf + l) > @@ -231,7 +246,13 @@ int audio_write(int dev, struct file *file, const char *buf, int count) if(copy_from_user(dma_buf, &(buf)[p], l)) return -EFAULT; } - else audio_devs[dev]->d->copy_user(dev, dma_buf, 0, buf, p, l); + else audio_devs[dev]->d->copy_user (dev, + dma_buf, 0, + buf, p, + c, buf_size, + &used, &returned, + l); + l = returned; if (audio_devs[dev]->local_conversion & CNV_MU_LAW) { @@ -241,8 +262,8 @@ int audio_write(int dev, struct file *file, const char *buf, int count) sti(); translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l); } - c -= l; - p += l; + c -= used; + p += used; DMAbuf_move_wrpointer(dev, l); } @@ -279,7 +300,7 @@ int audio_read(int dev, struct file *file, char *buf, int count) * Nonblocking mode handling. Return current # of bytes */ - if (file->f_flags & O_NONBLOCK && buf_no == -EAGAIN) + if ((file->f_flags & O_NONBLOCK) && buf_no == -EAGAIN) return p; if (p > 0) /* Avoid throwing away data */ diff --git a/drivers/sound/cs4232.c b/drivers/sound/cs4232.c index 43bc92911..122b0198f 100644 --- a/drivers/sound/cs4232.c +++ b/drivers/sound/cs4232.c @@ -96,9 +96,7 @@ static unsigned char crystal_key[] = /* A 32 byte magic key sequence */ static void sleep(unsigned howlong) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + howlong; - schedule(); - current->timeout = 0; + schedule_timeout(howlong); } int probe_cs4232(struct address_info *hw_config) diff --git a/drivers/sound/dev_table.c b/drivers/sound/dev_table.c index 99e15cb22..7e5c4b76c 100644 --- a/drivers/sound/dev_table.c +++ b/drivers/sound/dev_table.c @@ -516,6 +516,7 @@ void sound_unload_audiodev(int dev) { if (dev != -1) { + DMAbuf_deinit(dev); audio_devs[dev] = NULL; unregister_sound_dsp((dev<<4)+3); } @@ -534,6 +535,7 @@ int sound_alloc_audiodev(void) int sound_alloc_mididev(void) { +#ifdef CONFIG_MIDI int i = register_sound_midi(&oss_sound_fops); if(i==-1) return i; @@ -541,6 +543,9 @@ int sound_alloc_mididev(void) if(i>=num_midis) num_midis = i + 1; return i; +#else + return (-1); +#endif } int sound_alloc_synthdev(void) diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index 215df408a..b440f3c09 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -31,6 +31,8 @@ #define SNDCARD_SOFTOSS 36 #define SNDCARD_VMIDI 37 #define SNDCARD_WAVEFRONT 41 +#define SNDCARD_OPL3SA2 42 +#define SNDCARD_OPL3SA2_MPU 43 void attach_opl3sa_wss (struct address_info *hw_config); int probe_opl3sa_wss (struct address_info *hw_config); @@ -186,8 +188,12 @@ struct audio_driver int (*prepare_for_output) (int dev, int bufsize, int nbufs); void (*halt_io) (int dev); int (*local_qlen)(int dev); - void (*copy_user)(int dev, char *localbuf, int localoffs, - const char *userbuf, int useroffs, int len); + void (*copy_user) (int dev, + char *localbuf, int localoffs, + const char *userbuf, int useroffs, + int max_in, int max_out, + int *used, int *returned, + int len); void (*halt_input) (int dev); void (*halt_output) (int dev); void (*trigger) (int dev, int bits); @@ -412,6 +418,11 @@ struct driver_info sound_drivers[] = {"CS4232MPU", 0, SNDCARD_CS4232_MPU, "CS4232 MIDI", attach_cs4232_mpu, probe_cs4232_mpu, unload_cs4232_mpu}, #endif +#ifdef CONFIG_SOUND_OPL3SA2 + {"OPL3SA2", 0, SNDCARD_OPL3SA2, "OPL3SA2", attach_opl3sa2, probe_opl3sa2, unload_opl3sa2}, + {"OPL3SA2MPU", 0, SNDCARD_OPL3SA2_MPU, "OPL3SA2 MIDI", attach_opl3sa2_mpu, probe_opl3sa2_mpu, unload_opl3sa2_mpu}, +#endif + #ifdef CONFIG_SGALAXY {"SGALAXY", 0, SNDCARD_SGALAXY, "Sound Galaxy WSS", attach_sgalaxy, probe_sgalaxy, unload_sgalaxy}, #endif @@ -560,6 +571,16 @@ struct card_info snd_installed_cards[] = {SNDCARD_CS4232, {CONFIG_CS4232_BASE, CONFIG_CS4232_IRQ, CONFIG_CS4232_DMA, CONFIG_CS4232_DMA2}, SND_DEFAULT_ENABLE}, #endif +#ifdef CONFIG_SOUND_OPL3SA2 +#ifndef CONFIG_OPL3SA2_DMA2 +#define CONFIG_OPL3SA2_DMA2 CONFIG_OPL3SA2_DMA +#endif +#ifdef CONFIG_OPL3SA2_MPU_BASE + {SNDCARD_OPL3SA2_MPU, {CONFIG_OPL3SA2_MPU_BASE, CONFIG_OPL3SA2_MPU_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, +#endif + {SNDCARD_OPL3SA2, {CONFIG_OPL3SA2_BASE, CONFIG_OPL3SA2_IRQ, CONFIG_OPL3SA2_DMA, CONFIG_OPL3SA2_DMA2}, SND_DEFAULT_ENABLE}, +#endif + #ifdef CONFIG_SGALAXY #ifndef CONFIG_SGALAXY_DMA2 #define CONFIG_SGALAXY_DMA2 CONFIG_SGALAXY_DMA diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index 51b9d87de..014d6a73c 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -16,9 +16,12 @@ * 12k or so * Thomas Sailer : remove {in,out}_sleep_flag. It was used for the sleeper to * determine if it was woken up by the expiring timeout or by - * an explicit wake_up. current->timeout can be used instead; - * if 0, the wakeup was due to the timeout. + * an explicit wake_up. The return value from schedule_timeout + * can be used instead; if 0, the wakeup was due to the timeout. + * + * Rob Riggs Added persistent DMA buffers (1998/10/17) */ + #include <linux/config.h> #define BE_CONSERVATIVE @@ -28,6 +31,9 @@ #if defined(CONFIG_AUDIO) || defined(CONFIG_GUS) +#define DMAP_FREE_ON_CLOSE 0 +#define DMAP_KEEP_ON_CLOSE 1 +extern int sound_dmap_flag; static void dma_reset_output(int dev); static void dma_reset_input(int dev); @@ -38,9 +44,9 @@ static int local_start_dma(struct audio_operations *adev, unsigned long physaddr static int debugmem = 0; /* switched off by default */ static int dma_buffsize = DSP_BUFFSIZE; -static void dmabuf_set_timeout(struct dma_buffparms *dmap) +static long dmabuf_timeout(struct dma_buffparms *dmap) { - unsigned long tmout; + long tmout; tmout = (dmap->fragment_size * HZ) / dmap->data_rate; tmout += HZ / 5; /* Some safety distance */ @@ -48,7 +54,7 @@ static void dmabuf_set_timeout(struct dma_buffparms *dmap) tmout = HZ / 2; if (tmout > 20 * HZ) tmout = 20 * HZ; - current->timeout = jiffies + tmout; + return tmout; } static int sound_alloc_dmap(struct dma_buffparms *dmap) @@ -138,15 +144,15 @@ static int sound_start_dma(struct dma_buffparms *dmap, unsigned long physaddr, i int chan = dmap->dma; /* printk( "Start DMA%d %d, %d\n", chan, (int)(physaddr-dmap->raw_buf_phys), count); */ - save_flags(flags); - cli(); + + flags = claim_dma_lock(); disable_dma(chan); clear_dma_ff(chan); set_dma_mode(chan, dma_mode); set_dma_addr(chan, physaddr); set_dma_count(chan, count); enable_dma(chan); - restore_flags(flags); + release_dma_lock(flags); return 0; } @@ -201,12 +207,19 @@ static int open_dmap(struct audio_operations *adev, int mode, struct dma_buffpar static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap) { + unsigned long flags; + sound_close_dma(dmap->dma); if (dmap->flags & DMA_BUSY) dmap->dma_mode = DMODE_NONE; dmap->flags &= ~DMA_BUSY; + + flags=claim_dma_lock(); disable_dma(dmap->dma); - sound_free_dmap(dmap); + release_dma_lock(flags); + + if (sound_dmap_flag == DMAP_FREE_ON_CLOSE) + sound_free_dmap(dmap); } @@ -279,7 +292,7 @@ int DMAbuf_open(int dev, int mode) } adev->enable_bits = mode; - if (mode == OPEN_READ || (mode != OPEN_WRITE && adev->flags & DMA_DUPLEX)) { + if (mode == OPEN_READ || (mode != OPEN_WRITE && (adev->flags & DMA_DUPLEX))) { if ((retval = open_dmap(adev, mode, dmap_in)) < 0) { adev->d->close(dev); if (mode & OPEN_WRITE) @@ -311,7 +324,7 @@ void DMAbuf_reset(int dev) static void dma_reset_output(int dev) { struct audio_operations *adev = audio_devs[dev]; - unsigned long flags; + unsigned long flags,f ; struct dma_buffparms *dmap = adev->dmap_out; if (!(dmap->flags & DMA_STARTED)) /* DMA is not active */ @@ -326,11 +339,9 @@ static void dma_reset_output(int dev) adev->dmap_out->underrun_count = 0; if (!signal_pending(current) && adev->dmap_out->qlen && - adev->dmap_out->underrun_count == 0) { - dmabuf_set_timeout(dmap); - interruptible_sleep_on(&adev->out_sleeper); - current->timeout = 0; - } + adev->dmap_out->underrun_count == 0) + interruptible_sleep_on_timeout(&adev->out_sleeper, + dmabuf_timeout(dmap)); adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); /* @@ -341,8 +352,12 @@ static void dma_reset_output(int dev) else adev->d->halt_output(dev); adev->dmap_out->flags &= ~DMA_STARTED; + + f=claim_dma_lock(); clear_dma_ff(dmap->dma); disable_dma(dmap->dma); + release_dma_lock(f); + restore_flags(flags); dmap->byte_counter = 0; reorganize_buffers(dev, adev->dmap_out, 0); @@ -377,7 +392,7 @@ void DMAbuf_launch_output(int dev, struct dma_buffparms *dmap) return; /* Don't start DMA yet */ dmap->dma_mode = DMODE_OUTPUT; - if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) { + if (!(dmap->flags & DMA_ACTIVE) || !(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) { if (!(dmap->flags & DMA_STARTED)) { reorganize_buffers(dev, dmap, 0); if (adev->d->prepare_for_output(dev, dmap->fragment_size, dmap->nbufs)) @@ -404,7 +419,7 @@ int DMAbuf_sync(int dev) int n = 0; struct dma_buffparms *dmap; - if (!adev->go && (!adev->enable_bits & PCM_ENABLE_OUTPUT)) + if (!adev->go && !(adev->enable_bits & PCM_ENABLE_OUTPUT)) return 0; if (adev->dmap_out->dma_mode == DMODE_OUTPUT) { @@ -417,14 +432,14 @@ int DMAbuf_sync(int dev) adev->dmap_out->underrun_count = 0; while (!signal_pending(current) && n++ <= adev->dmap_out->nbufs && adev->dmap_out->qlen && adev->dmap_out->underrun_count == 0) { - dmabuf_set_timeout(dmap); - interruptible_sleep_on(&adev->out_sleeper); - if (!current->timeout) { + long t = dmabuf_timeout(dmap); + t = interruptible_sleep_on_timeout(&adev->out_sleeper, + t); + if (!t) { adev->dmap_out->flags &= ~DMA_SYNCING; restore_flags(flags); return adev->dmap_out->qlen; } - current->timeout = 0; } adev->dmap_out->flags &= ~(DMA_SYNCING | DMA_ACTIVE); restore_flags(flags); @@ -437,11 +452,10 @@ int DMAbuf_sync(int dev) save_flags(flags); cli(); if (adev->d->local_qlen) { /* Device has hidden buffers */ - while (!signal_pending(current) && adev->d->local_qlen(dev)) { - dmabuf_set_timeout(dmap); - interruptible_sleep_on(&adev->out_sleeper); - current->timeout = 0; - } + while (!signal_pending(current) && + adev->d->local_qlen(dev)) + interruptible_sleep_on_timeout(&adev->out_sleeper, + dmabuf_timeout(dmap)); } restore_flags(flags); } @@ -476,7 +490,7 @@ int DMAbuf_release(int dev, int mode) if (adev->open_mode == OPEN_READ || (adev->open_mode != OPEN_WRITE && - adev->flags & DMA_DUPLEX)) + (adev->flags & DMA_DUPLEX))) close_dmap(adev, adev->dmap_in); adev->open_mode = 0; restore_flags(flags); @@ -536,6 +550,7 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) restore_flags(flags); return -EINVAL; } else while (dmap->qlen <= 0 && n++ < 10) { + long timeout = MAX_SCHEDULE_TIMEOUT; if (!(adev->enable_bits & PCM_ENABLE_INPUT) || !adev->go) { restore_flags(flags); return -EAGAIN; @@ -550,19 +565,17 @@ int DMAbuf_getrdbuffer(int dev, char **buf, int *len, int dontblock) restore_flags(flags); return -EAGAIN; } - if (!(go = adev->go)) - current->timeout = 0; - else - dmabuf_set_timeout(dmap); - interruptible_sleep_on(&adev->in_sleeper); - if (go && !current->timeout) { + if ((go = adev->go)) + timeout = dmabuf_timeout(dmap); + timeout = interruptible_sleep_on_timeout(&adev->in_sleeper, + timeout); + if (!timeout) { /* FIXME: include device name */ err = -EIO; printk(KERN_WARNING "Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); dma_reset_input(dev); } else err = -EINTR; - current->timeout = 0; } restore_flags(flags); @@ -606,6 +619,7 @@ int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction int pos; unsigned long flags; + unsigned long f; save_flags(flags); cli(); @@ -613,9 +627,12 @@ int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction pos = 0; else { int chan = dmap->dma; + + f=claim_dma_lock(); clear_dma_ff(chan); disable_dma(dmap->dma); pos = get_dma_residue(chan); + pos = dmap->bytes_in_use - pos; if (!(dmap->mapping_flags & DMA_MAP_MAPPED)) { @@ -634,6 +651,7 @@ int DMAbuf_get_buffer_pointer(int dev, struct dma_buffparms *dmap, int direction if (pos >= dmap->bytes_in_use) pos = 0; enable_dma(dmap->dma); + release_dma_lock(f); } restore_flags(flags); /* printk( "%04x ", pos); */ @@ -710,6 +728,7 @@ static int output_sleep(int dev, int dontblock) int err = 0; struct dma_buffparms *dmap = adev->dmap_out; int timeout; + long timeout_value; if (dontblock) return -EAGAIN; @@ -720,18 +739,18 @@ static int output_sleep(int dev, int dontblock) * Wait for free space */ if (signal_pending(current)) - return -EIO; + return -EINTR; timeout = (adev->go && !(dmap->flags & DMA_NOTIMEOUT)); if (timeout) - dmabuf_set_timeout(dmap); + timeout_value = dmabuf_timeout(dmap); else - current->timeout = 0; - interruptible_sleep_on(&adev->out_sleeper); - if (timeout && !current->timeout) { + timeout_value = MAX_SCHEDULE_TIMEOUT; + timeout_value = interruptible_sleep_on_timeout(&adev->out_sleeper, + timeout_value); + if (timeout != MAX_SCHEDULE_TIMEOUT && !timeout_value) { printk(KERN_WARNING "Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); dma_reset_output(dev); } else { - current->timeout = 0; if (signal_pending(current)) err = -EINTR; } @@ -961,10 +980,16 @@ static void do_outputintr(int dev, int dummy) } if (!(adev->flags & DMA_AUTOMODE)) dmap->flags &= ~DMA_ACTIVE; - while (dmap->qlen <= 0) { + + /* + * This is dmap->qlen <= 0 except when closing when + * dmap->qlen < 0 + */ + + while (dmap->qlen <= -dmap->closing) { dmap->underrun_count++; dmap->qlen++; - if (dmap->flags & DMA_DIRTY && dmap->applic_profile != APF_CPUINTENS) { + if ((dmap->flags & DMA_DIRTY) && dmap->applic_profile != APF_CPUINTENS) { dmap->flags &= ~DMA_DIRTY; memset(adev->dmap_out->raw_buf, adev->dmap_out->neutral_byte, adev->dmap_out->buffsize); @@ -988,10 +1013,15 @@ void DMAbuf_outputintr(int dev, int notify_only) cli(); if (!(dmap->flags & DMA_NODMA)) { int chan = dmap->dma, pos, n; - clear_dma_ff(chan); + unsigned long f; + + f=claim_dma_lock(); disable_dma(dmap->dma); + clear_dma_ff(chan); pos = dmap->bytes_in_use - get_dma_residue(chan); enable_dma(dmap->dma); + release_dma_lock(f); + pos = pos / dmap->fragment_size; /* Actual qhead */ if (pos < 0 || pos >= dmap->nbufs) pos = 0; @@ -1056,7 +1086,7 @@ static void do_inputintr(int dev) } } } - if (!(adev->flags & DMA_AUTOMODE) || dmap->flags & DMA_NODMA) { + if (!(adev->flags & DMA_AUTOMODE) || (dmap->flags & DMA_NODMA)) { local_start_dma(adev, dmap->raw_buf_phys, dmap->bytes_in_use, DMA_MODE_READ); adev->d->start_input(dev, dmap->raw_buf_phys + dmap->qtail * dmap->fragment_size, dmap->fragment_size, 1); if (adev->d->trigger) @@ -1078,10 +1108,14 @@ void DMAbuf_inputintr(int dev) if (!(dmap->flags & DMA_NODMA)) { int chan = dmap->dma, pos, n; - clear_dma_ff(chan); + unsigned long f; + + f=claim_dma_lock(); disable_dma(dmap->dma); + clear_dma_ff(chan); pos = dmap->bytes_in_use - get_dma_residue(chan); enable_dma(dmap->dma); + release_dma_lock(f); pos = pos / dmap->fragment_size; /* Actual qhead */ if (pos < 0 || pos >= dmap->nbufs) @@ -1112,11 +1146,10 @@ int DMAbuf_open_dma(int dev) if (adev->dmap_out->dma >= 0) { unsigned long flags; - save_flags(flags); - cli(); + flags=claim_dma_lock(); clear_dma_ff(adev->dmap_out->dma); disable_dma(adev->dmap_out->dma); - restore_flags(flags); + release_dma_lock(flags); } return 0; } @@ -1155,6 +1188,13 @@ void DMAbuf_init(int dev, int dma1, int dma2) adev->dmap_in->dma = dma2; } } + /* Persistent DMA buffers allocated here */ + if (sound_dmap_flag == DMAP_KEEP_ON_CLOSE) { + if (adev->dmap_in->raw_buf == NULL) + sound_alloc_dmap(adev->dmap_in); + if (adev->dmap_out->raw_buf == NULL) + sound_alloc_dmap(adev->dmap_out); + } } } @@ -1225,12 +1265,13 @@ void DMAbuf_deinit(int dev) /* This routine is called when driver is being unloaded */ if (!adev) return; -#ifdef RUNTIME_DMA_ALLOC - sound_free_dmap(adev->dmap_out); - if (adev->flags & DMA_DUPLEX) - sound_free_dmap(adev->dmap_in); -#endif + /* Persistent DMA buffers deallocated here */ + if (sound_dmap_flag == DMAP_KEEP_ON_CLOSE) { + sound_free_dmap(adev->dmap_out); + if (adev->flags & DMA_DUPLEX) + sound_free_dmap(adev->dmap_in); + } } #endif diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c index b351c73db..aaf21e2ba 100644 --- a/drivers/sound/dmasound.c +++ b/drivers/sound/dmasound.c @@ -107,18 +107,17 @@ History: #include <asm/amigahw.h> #include <asm/amigaints.h> #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC #include <asm/prom.h> #include <asm/io.h> #include <asm/dbdma.h> -#ifdef CONFIG_PMAC_PBOOK #include <asm/adb.h> +#include <asm/cuda.h> #include <asm/pmu.h> -#endif /* CONFIG_PMAC_PBOOK */ #include "awacs_defs.h" #include <linux/nvram.h> #include <linux/vt_kern.h> -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ #include "dmasound.h" #include <linux/soundcard.h> @@ -165,7 +164,7 @@ extern u_short amiga_audio_period; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC /* * Interrupt numbers and addresses, obtained from the device tree. */ @@ -174,6 +173,8 @@ static volatile struct awacs_regs *awacs; static volatile struct dbdma_regs *awacs_txdma, *awacs_rxdma; static int awacs_rate_index; static int awacs_subframe; +static int awacs_revision; +static int awacs_spkr_vol; /* * Space for the DBDMA command blocks. @@ -249,7 +250,7 @@ struct notifier_block awacs_sleep_notifier = { }; #endif /* CONFIG_PMAC_PBOOK */ -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ /*** Some declarations *******************************************************/ @@ -587,7 +588,7 @@ static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount, ssize_t frameLeft); #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft); @@ -618,7 +619,7 @@ static ssize_t pmac_ctx_s16(const u_char *userPtr, size_t userCount, static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft); -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ /*** Machine definitions *****************************************************/ @@ -675,7 +676,7 @@ struct sound_settings { int treble; int gain; int minDev; /* minor device number currently open */ -#if defined(CONFIG_ATARI) || defined(CONFIG_PMAC) +#if defined(CONFIG_ATARI) || defined(CONFIG_PPC) int bal; /* balance factor for expanding (not volume!) */ u_long data; /* data for expanding */ #endif /* CONFIG_ATARI */ @@ -724,7 +725,7 @@ static void AmiPlay(void); static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp); #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC static void *PMacAlloc(unsigned int size, int flags) __init; static void PMacFree(void *ptr, unsigned int size) __init; static int PMacIrqInit(void) __init; @@ -743,7 +744,7 @@ static int awacs_get_volume(int reg, int lshift); static int awacs_volume_setter(int volume, int n, int mute, int lshift); static void awacs_mksound(unsigned int hz, unsigned int ticks); static void awacs_nosound(unsigned long xx); -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ /*** Mid level stuff *********************************************************/ @@ -816,8 +817,7 @@ static struct sound_queue sq; #define ONE_SECOND HZ /* in jiffies (100ths of a second) */ #define NO_TIME_LIMIT 0xffffffff #define SLEEP(queue, time_limit) \ - current->timeout = jiffies+(time_limit); \ - interruptible_sleep_on(&queue); + interruptible_sleep_on_timeout(&queue, (time_limit)); #define WAKE_UP(queue) (wake_up_interruptible(&queue)) /* @@ -1778,7 +1778,7 @@ static ssize_t ami_ct_u16le(const u_char *userPtr, size_t userCount, } #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC static ssize_t pmac_ct_law(const u_char *userPtr, size_t userCount, u_char frame[], ssize_t *frameUsed, ssize_t frameLeft) @@ -2162,7 +2162,7 @@ static ssize_t pmac_ctx_u16(const u_char *userPtr, size_t userCount, return stereo? utotal * 4: utotal * 2; } -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ #ifdef CONFIG_ATARI @@ -2192,7 +2192,7 @@ static TRANS transAmiga = { }; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC static TRANS transAwacsNormal = { pmac_ct_law, pmac_ct_law, pmac_ct_s8, pmac_ct_u8, pmac_ct_s16, pmac_ct_u16, pmac_ct_s16, pmac_ct_u16 @@ -2202,7 +2202,7 @@ static TRANS transAwacsExpand = { pmac_ctx_law, pmac_ctx_law, pmac_ctx_s8, pmac_ctx_u8, pmac_ctx_s16, pmac_ctx_u16, pmac_ctx_s16, pmac_ctx_u16 }; -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ /*** Low level stuff *********************************************************/ @@ -2972,7 +2972,7 @@ static void ami_sq_interrupt(int irq, void *dummy, struct pt_regs *fp) } #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC /* * PCI PowerMac, with AWACS and DBDMA. @@ -3227,7 +3227,7 @@ awacs_write(int val) { while (in_le32(&awacs->codec_ctrl) & MASK_NEWECMD) ; /* XXX should have timeout */ - out_le32(&awacs->codec_ctrl, val); + out_le32(&awacs->codec_ctrl, val | (awacs_subframe << 22)); } static void awacs_nosound(unsigned long xx) @@ -3344,7 +3344,38 @@ static int awacs_sleep_notify(struct notifier_block *this, } #endif /* CONFIG_PMAC_PBOOK */ -#endif /* CONFIG_PMAC */ +/* Turn on sound output, needed on G3 desktop powermacs */ +static void +awacs_enable_amp(int spkr_vol) +{ + struct adb_request req; + + awacs_spkr_vol = spkr_vol; + if (adb_hardware != ADB_VIACUDA) + return; + + /* turn on headphones */ + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x8a, 4, 0); + while (!req.complete) cuda_poll(); + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x8a, 6, 0); + while (!req.complete) cuda_poll(); + + /* turn on speaker */ + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x8a, 3, (100 - (spkr_vol & 0xff)) * 32 / 100); + while (!req.complete) cuda_poll(); + cuda_request(&req, NULL, 5, CUDA_PACKET, CUDA_GET_SET_IIC, + 0x8a, 5, (100 - ((spkr_vol >> 8) & 0xff)) * 32 / 100); + while (!req.complete) cuda_poll(); + + cuda_request(&req, NULL, 5, CUDA_PACKET, + CUDA_GET_SET_IIC, 0x8a, 1, 0x29); + while (!req.complete) cuda_poll(); +} + +#endif /* CONFIG_PPC */ /*** Machine definitions *****************************************************/ @@ -3383,7 +3414,7 @@ static MACHINE machAmiga = { }; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC static MACHINE machPMac = { DMASND_AWACS, PMacAlloc, PMacFree, PMacIrqInit, #ifdef MODULE @@ -3684,7 +3715,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, break; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC case DMASND_AWACS: switch (cmd) { case SOUND_MIXER_READ_DEVMASK: @@ -3734,12 +3765,18 @@ static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, IOCTL_IN(arg, data); return IOCTL_OUT(arg, sound_set_volume(data)); case SOUND_MIXER_READ_SPEAKER: - data = (awacs_reg[1] & MASK_CMUTE)? 0: - awacs_get_volume(awacs_reg[4], 6); + if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA) + data = awacs_spkr_vol; + else + data = (awacs_reg[1] & MASK_CMUTE)? 0: + awacs_get_volume(awacs_reg[4], 6); return IOCTL_OUT(arg, data); case SOUND_MIXER_WRITE_SPEAKER: IOCTL_IN(arg, data); - data = awacs_volume_setter(data, 4, MASK_CMUTE, 6); + if (awacs_revision >= 3 && adb_hardware == ADB_VIACUDA) + awacs_enable_amp(data); + else + data = awacs_volume_setter(data, 4, MASK_CMUTE, 6); return IOCTL_OUT(arg, data); case SOUND_MIXER_WRITE_ALTPCM: /* really bell volume */ IOCTL_IN(arg, data); @@ -3863,10 +3900,10 @@ __initfunc(static void mixer_init(void)) static void sq_setup(int numBufs, int bufSize, char **buffers) { -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC int i; volatile struct dbdma_cmd *cp; -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ sq.max_count = numBufs; sq.max_active = numBufs; @@ -3888,7 +3925,7 @@ static void sq_setup(int numBufs, int bufSize, char **buffers) sq.block_size_half = sq.block_size>>1; sq.block_size_quarter = sq.block_size_half>>1; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC cp = awacs_tx_cmds; memset((void *) cp, 0, (numBufs + 1) * sizeof(struct dbdma_cmd)); for (i = 0; i < numBufs; ++i, ++cp) { @@ -3898,7 +3935,7 @@ static void sq_setup(int numBufs, int bufSize, char **buffers) st_le32(&cp->cmd_dep, virt_to_bus(awacs_tx_cmds)); out_le32(&awacs_txdma->control, (RUN|PAUSE|FLUSH|WAKE) << 16); out_le32(&awacs_txdma->cmdptr, virt_to_bus(awacs_tx_cmds)); -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ } static void sq_play(void) @@ -4207,11 +4244,11 @@ __initfunc(static void sq_init(void)) sound.dsp.speed = 8000; break; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC case DMASND_AWACS: sound.dsp.speed = 8000; break; -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ } /* before the first open to /dev/dsp this wouldn't be set */ @@ -4252,11 +4289,11 @@ static int state_open(struct inode *inode, struct file *file) mach = "Amiga "; break; #endif /* CONFIG_AMIGA */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC case DMASND_AWACS: mach = "PowerMac "; break; -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ } len += sprintf(buffer+len, "%sDMA sound driver:\n", mach); @@ -4397,7 +4434,7 @@ __initfunc(void dmasound_init(void)) { int has_sound = 0; int i; -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC struct device_node *np; #endif @@ -4431,7 +4468,7 @@ __initfunc(void dmasound_init(void)) } #endif /* __mc68000__ */ -#ifdef CONFIG_PMAC +#ifdef CONFIG_PPC awacs_subframe = 0; np = find_devices("awacs"); if (np == 0) { @@ -4480,6 +4517,13 @@ __initfunc(void dmasound_init(void)) awacs_write(awacs_reg[2] + MASK_ADDR2); awacs_write(awacs_reg[4] + MASK_ADDR4); + /* Initialize recent versions of the awacs */ + awacs_revision = (in_le32(&awacs->codec_stat) >> 12) & 0xf; + if (awacs_revision >= 3) { + awacs_write(0x6000); + awacs_enable_amp(100 * 0x101); + } + /* Initialize beep stuff */ beep_dbdma_cmd = awacs_tx_cmds + (numBufs + 1); orig_mksound = kd_mksound; @@ -4493,7 +4537,7 @@ __initfunc(void dmasound_init(void)) &awacs_sleep_notifier); #endif /* CONFIG_PMAC_PBOOK */ } -#endif /* CONFIG_PMAC */ +#endif /* CONFIG_PPC */ if (!has_sound) return; diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index 00794bf39..f7dd0c8a3 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -24,9 +24,10 @@ * * Module command line parameters: * joystick if 1 enables the joystick interface on the card; but it still - * needs a separate joystick driver (presumably PC standard, although - * the chip doc doesn't say anything and it looks slightly fishy from - * the PCI standpoint...) + * needs a driver for joysticks connected to a standard IBM-PC + * joyport. It is tested with the joy-analog driver. This + * module must be loaded before the joystick driver. Kmod will + * not ensure that. * lineout if 1 the LINE jack is used as an output instead of an input. * LINE then contains the unmixed dsp output. This can be used * to make the card a four channel one: use dsp to output two @@ -76,6 +77,8 @@ * 22.08.98 0.12 Mixer registers actually have 5 instead of 4 bits * pointed out by Itai Nahshon * 31.08.98 0.13 Fix realplayer problems - dac.count issues + * 08.10.98 0.14 Joystick support fixed + * -- Oliver Neukum <c188@org.chemie.uni-muenchen.de> * * some important things missing in Ensoniq documentation: * @@ -98,6 +101,7 @@ /*****************************************************************************/ +#include <linux/config.h> #include <linux/version.h> #include <linux/module.h> #include <linux/string.h> @@ -1013,11 +1017,8 @@ static int drain_dac1(struct es1370_state *s, int nonblock) } tmo = (count * HZ) / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL]; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; - current->timeout = jiffies + (tmo ? tmo : 1); - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1370: dma timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->dma_dac1.wait, &wait); current->state = TASK_RUNNING; @@ -1051,11 +1052,8 @@ static int drain_dac2(struct es1370_state *s, int nonblock) } tmo = (count * HZ) / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV); tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; - current->timeout = jiffies + (tmo ? tmo : 1); - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1370: dma timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->dma_dac2.wait, &wait); current->state = TASK_RUNNING; @@ -2197,11 +2195,8 @@ static int es1370_midi_release(struct inode *inode, struct file *file) return -EBUSY; } tmo = (count * HZ) / 3100; - current->timeout = tmo ? jiffies + tmo : 0; - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1370: midi timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->midi.owait, &wait); current->state = TASK_RUNNING; @@ -2242,8 +2237,11 @@ static /*const*/ struct file_operations es1370_midi_fops = { /* maximum number of devices */ #define NR_DEVICE 5 - +#ifdef CONFIG_SOUND_ES1370_JOYPORT_BOOT +static int joystick[NR_DEVICE] = { 1, 0, }; +#else static int joystick[NR_DEVICE] = { 0, }; +#endif static int lineout[NR_DEVICE] = { 0, }; static int micz[NR_DEVICE] = { 0, }; @@ -2337,8 +2335,6 @@ __initfunc(int init_es1370(void)) goto err_dev3; if ((s->dev_midi = register_sound_midi(&es1370_midi_fops)) < 0) goto err_dev4; - if (s->ctrl & CTRL_JYSTK_EN) - request_region(0x200, JOY_EXTENT, "es1370"); /* initialize the chips */ outl(s->ctrl, s->io+ES1370_REG_CONTROL); outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL); diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index 1c025fa2e..754aa443b 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -1462,11 +1462,8 @@ static int drain_dac1(struct es1371_state *s, int nonblock) } tmo = (count * HZ) / s->dac1rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT]; - current->timeout = jiffies + (tmo ? tmo : 1); - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1371: dma timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->dma_dac1.wait, &wait); current->state = TASK_RUNNING; @@ -1500,11 +1497,8 @@ static int drain_dac2(struct es1371_state *s, int nonblock) } tmo = (count * HZ) / s->dac2rate; tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT]; - current->timeout = jiffies + (tmo ? tmo : 1); - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1371: dma timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->dma_dac2.wait, &wait); current->state = TASK_RUNNING; @@ -2635,11 +2629,8 @@ static int es1371_midi_release(struct inode *inode, struct file *file) return -EBUSY; } tmo = (count * HZ) / 3100; - current->timeout = tmo ? jiffies + tmo : 0; - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "es1371: midi timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->midi.owait, &wait); current->state = TASK_RUNNING; diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index c73e6f06b..4bf4cd38d 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -863,7 +863,7 @@ static void pnp_mem_init(void) int bank, chunk, addr, total = 0; int bank_sizes[4]; - int i, j, bits = -1, nbanks = 0; + int i, j, bits = -1, testbits = -1, nbanks = 0; /* * This routine determines what kind of RAM is installed in each of the four @@ -974,28 +974,26 @@ static void pnp_mem_init(void) } } /* - * The last resort is to search for a combination where the last bank is - * smaller than the actual SIMM. This leaves some memory in the last bank - * unused but doesn't leave holes in the DRAM address space. - */ - if (bits == -1) /* No luck yet */ - { - for (i = 0; bits == -1 && i < 13; i++) - { - bits = i; - - for (j = 0; bits != -1 && j < nbanks - 1; j++) - if (mem_decode[i][j] != bank_sizes[j]) - bits = -1; /* No hit */ - } - if (bits != -1) - { + * The last resort is to search for a combination where the banks are + * smaller than the actual SIMMs. This leaves some memory in the banks + * unused but doesn't leave holes in the DRAM address space. + */ + if (bits == -1) /* No luck yet */ + { + for (i = 0; i < 13; i++) + { + testbits = i; + for (j = 0; testbits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] > bank_sizes[j]) { + testbits = -1; + } + if(testbits > bits) bits = testbits; + } + if (bits != -1) + { printk(KERN_INFO "Interwave: Can't use all installed RAM.\n"); printk(KERN_INFO "Interwave: Try reordering SIMMS.\n"); } - } - if (bits == -1) - { printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n"); printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); bits = 0; @@ -1929,11 +1927,8 @@ static int guswave_load_patch(int dev, int format, const char *addr, */ active_device = GUS_DEV_WAVE; - current->timeout = jiffies + HZ; - interruptible_sleep_on(&dram_sleeper); - if (!current->timeout) + if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ)) printk("GUS: DMA Transfer timed out\n"); - current->timeout = 0; restore_flags(flags); } diff --git a/drivers/sound/legacy.h b/drivers/sound/legacy.h index c9b39b1c9..cde5bc2fc 100644 --- a/drivers/sound/legacy.h +++ b/drivers/sound/legacy.h @@ -27,6 +27,7 @@ #define CONFIG_MPU401 #define CONFIG_MSS #define CONFIG_OPL3SA1 +#define CONFIG_OPL3SA2 #define CONFIG_PAS #define CONFIG_PSS #define CONFIG_SB diff --git a/drivers/sound/mad16.c b/drivers/sound/mad16.c index 607955d23..489c2c7c0 100644 --- a/drivers/sound/mad16.c +++ b/drivers/sound/mad16.c @@ -834,7 +834,6 @@ int probe_mad16_mpu(struct address_info *hw_config) void unload_mad16(struct address_info *hw_config) { - int mixer = audio_devs[hw_config->slots[0]]->mixer_dev; ad1848_unload(hw_config->io_base + 4, hw_config->irq, hw_config->dma, @@ -849,7 +848,7 @@ unload_mad16_mpu(struct address_info *hw_config) #if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD) if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { - sb_dsp_unload(hw_config); + sb_dsp_unload(hw_config, 0); return; } #endif diff --git a/drivers/sound/maui.c b/drivers/sound/maui.c index baf770a96..d6b12e07b 100644 --- a/drivers/sound/maui.c +++ b/drivers/sound/maui.c @@ -81,10 +81,8 @@ static int maui_wait(int mask) { if (inb(HOST_STAT_PORT) & mask) return 1; - current->timeout = jiffies + HZ / 10; current->state = TASK_INTERRUPTIBLE; - schedule(); - current->timeout = 0; + schedule_timeout(HZ / 10); if (signal_pending(current)) return 0; } diff --git a/drivers/sound/midibuf.c b/drivers/sound/midibuf.c index 23780b5a2..7adfeb89c 100644 --- a/drivers/sound/midibuf.c +++ b/drivers/sound/midibuf.c @@ -90,11 +90,8 @@ static void drain_midi_queue(int dev) if (midi_devs[dev]->buffer_status != NULL) while (!signal_pending(current) && midi_devs[dev]->buffer_status(dev)) - { - current->timeout = jiffies + HZ / 10; - interruptible_sleep_on(&midi_sleeper[dev]); - current->timeout = 0; - } + interruptible_sleep_on_timeout(&midi_sleeper[dev], + HZ/10); } static void midi_input_intr(int dev, unsigned char data) @@ -181,7 +178,7 @@ int MIDIbuf_open(int dev, struct file *file) midi_input_intr, midi_output_intr)) < 0) return err; - parms[dev].prech_timeout = 0; + parms[dev].prech_timeout = MAX_SCHEDULE_TIMEOUT; midi_in_buf[dev] = (struct midi_buf *) vmalloc(sizeof(struct midi_buf)); if (midi_in_buf[dev] == NULL) @@ -325,9 +322,9 @@ int MIDIbuf_read(int dev, struct file *file, char *buf, int count) if (!DATA_AVAIL(midi_in_buf[dev])) { /* * No data yet, wait */ - current->timeout = parms[dev].prech_timeout ? jiffies + parms[dev].prech_timeout : 0; - interruptible_sleep_on(&input_sleeper[dev]); - current->timeout = 0; + interruptible_sleep_on_timeout(&input_sleeper[dev], + parms[dev].prech_timeout); + if (signal_pending(current)) c = -EINTR; /* The user is getting restless */ } diff --git a/drivers/sound/msnd.c b/drivers/sound/msnd.c index ad7ceaa48..a3f73eded 100644 --- a/drivers/sound/msnd.c +++ b/drivers/sound/msnd.c @@ -20,7 +20,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd.c,v 1.9 1998/09/04 18:41:27 andrewtv Exp $ + * $Id: msnd.c,v 1.16 1998/09/08 04:05:56 andrewtv Exp $ * ********************************************************************/ @@ -46,6 +46,7 @@ # include <asm/uaccess.h> # include <asm/spinlock.h> #endif +#include <asm/irq.h> #include "msnd.h" #define LOGNAME "msnd" @@ -224,7 +225,7 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user) int msnd_wait_TXDE(multisound_dev_t *dev) { register unsigned int io = dev->io; - register int timeout = 100; + register int timeout = 1000; while(timeout-- > 0) if (inb(io + HP_ISR) & HPISR_TXDE) @@ -236,7 +237,7 @@ int msnd_wait_TXDE(multisound_dev_t *dev) int msnd_wait_HC0(multisound_dev_t *dev) { register unsigned int io = dev->io; - register int timeout = 100; + register int timeout = 1000; while(timeout-- > 0) if (!(inb(io + HP_CVR) & HPCVR_HC)) @@ -248,17 +249,16 @@ int msnd_wait_HC0(multisound_dev_t *dev) int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd) { unsigned long flags; - + spin_lock_irqsave(&dev->lock, flags); if (msnd_wait_HC0(dev) == 0) { - outb(cmd, dev->io + HP_CVR); spin_unlock_irqrestore(&dev->lock, flags); return 0; } spin_unlock_irqrestore(&dev->lock, flags); - printk(KERN_WARNING LOGNAME ": Send DSP command timeout\n"); + printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n"); return -EIO; } @@ -269,14 +269,13 @@ int msnd_send_word(multisound_dev_t *dev, unsigned char high, register unsigned int io = dev->io; if (msnd_wait_TXDE(dev) == 0) { - outb(high, io + HP_TXH); outb(mid, io + HP_TXM); outb(low, io + HP_TXL); return 0; } - printk(KERN_WARNING LOGNAME ": Send host word timeout\n"); + printk(KERN_DEBUG LOGNAME ": Send host word timeout\n"); return -EIO; } @@ -286,7 +285,6 @@ int msnd_upload_host(multisound_dev_t *dev, char *bin, int len) int i; if (len % 3 != 0) { - printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n"); return -EINVAL; } @@ -303,31 +301,27 @@ int msnd_upload_host(multisound_dev_t *dev, char *bin, int len) int msnd_enable_irq(multisound_dev_t *dev) { - printk(KERN_DEBUG LOGNAME ": enable_irq: count %d\n", dev->irq_ref); + unsigned long flags; - if (dev->irq_ref++ != 0) + if (dev->irq_ref++) return 0; printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n"); - + + spin_lock_irqsave(&dev->lock, flags); if (msnd_wait_TXDE(dev) == 0) { - - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR); - if (dev->type == msndClassic) outb(dev->irqid, dev->io + HP_IRQM); - outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR); outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR); - + enable_irq(dev->irq); spin_unlock_irqrestore(&dev->lock, flags); - return 0; } + spin_unlock_irqrestore(&dev->lock, flags); + + printk(KERN_DEBUG LOGNAME ": Enable IRQ failed\n"); return -EIO; } @@ -336,29 +330,28 @@ int msnd_disable_irq(multisound_dev_t *dev) { unsigned long flags; - printk(KERN_DEBUG LOGNAME ": disable_irq: count %d\n", dev->irq_ref); - if (--dev->irq_ref > 0) return 0; - if (dev->irq_ref < 0) { - printk(KERN_WARNING LOGNAME ": IRQ ref count is %d\n", dev->irq_ref); -/* dev->irq_ref = 0; */ - } + if (dev->irq_ref < 0) + printk(KERN_DEBUG LOGNAME ": IRQ ref count is %d\n", dev->irq_ref); printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n"); - - udelay(50); spin_lock_irqsave(&dev->lock, flags); - outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR); - - if (dev->type == msndClassic) - outb(HPIRQ_NONE, dev->io + HP_IRQM); - + if (msnd_wait_TXDE(dev) == 0) { + outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR); + if (dev->type == msndClassic) + outb(HPIRQ_NONE, dev->io + HP_IRQM); + disable_irq(dev->irq); + spin_unlock_irqrestore(&dev->lock, flags); + return 0; + } spin_unlock_irqrestore(&dev->lock, flags); - return 0; + printk(KERN_DEBUG LOGNAME ": Disable IRQ failed\n"); + + return -EIO; } #ifndef LINUX20 diff --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h index 804cff425..1dbdedf37 100644 --- a/drivers/sound/msnd.h +++ b/drivers/sound/msnd.h @@ -24,19 +24,19 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd.h,v 1.18 1998/09/04 18:43:40 andrewtv Exp $ + * $Id: msnd.h,v 1.32 1998/10/09 19:54:39 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_H #define __MSND_H -#define VERSION "0.7.13" +#define VERSION "0.8.2.1" #define DEFSAMPLERATE DSP_DEFAULT_SPEED #define DEFSAMPLESIZE AFMT_U8 #define DEFCHANNELS 1 -#define DEFFIFOSIZE 64 +#define DEFFIFOSIZE 128 #define SNDCARD_MSND 38 @@ -151,6 +151,7 @@ #define PCTODSP_OFFSET(w) (USHORT)((w)/2) #define PCTODSP_BASED(w) (USHORT)(((w)/2) + DSP_BASE_ADDR) +#define DSPTOPC_BASED(w) (((w) - DSP_BASE_ADDR) * 2) #ifdef SLOWIO # undef outb @@ -207,14 +208,10 @@ typedef struct multisound_dev { int memid, irqid; int irq, irq_ref; unsigned char info; - char *base; -#ifndef LINUX20 - spinlock_t lock; -#endif + volatile BYTE *base; /* Motorola 56k DSP SMA */ volatile BYTE *SMA; - volatile BYTE *CurDAQD, *CurDARQD; volatile BYTE *DAPQ, *DARQ, *MODQ, *MIDQ, *DSPQ; volatile WORD *pwDSPQData, *pwMIDQData, *pwMODQData; @@ -222,27 +219,33 @@ typedef struct multisound_dev { enum { msndClassic, msndPinnacle } type; mode_t mode; unsigned long flags; -#define F_BANKONE 0 -#define F_INTERRUPT 1 -#define F_WRITING 2 -#define F_WRITEBLOCK 3 -#define F_READING 4 -#define F_READBLOCK 5 -#define F_AUDIO_INUSE 6 -#define F_EXT_MIDI_INUSE 7 -#define F_INT_MIDI_INUSE 8 -#define F_WRITEFLUSH 9 -#define F_HAVEDIGITAL 10 +#define F_RESETTING 0 +#define F_HAVEDIGITAL 1 +#define F_AUDIO_WRITE_INUSE 2 +#define F_WRITING 3 +#define F_WRITEBLOCK 4 +#define F_WRITEFLUSH 5 +#define F_AUDIO_READ_INUSE 6 +#define F_READING 7 +#define F_READBLOCK 8 +#define F_EXT_MIDI_INUSE 9 +#define F_INT_MIDI_INUSE 10 +#define F_DISABLE_WRITE_NDELAY 11 struct wait_queue *writeblock, *readblock; struct wait_queue *writeflush; +#ifndef LINUX20 + spinlock_t lock; +#endif + int nresets; unsigned long recsrc; int left_levels[16]; int right_levels[16]; int mixer_mod_count; int calibrate_signal; - int sample_size; - int sample_rate; - int channels; + int play_sample_size, play_sample_rate, play_channels; + int play_ndelay; + int rec_sample_size, rec_sample_rate, rec_channels; + int rec_ndelay; BYTE bCurrentMidiPatch; void (*inc_ref)(void); void (*dec_ref)(void); @@ -250,7 +253,7 @@ typedef struct multisound_dev { /* Digital audio FIFOs */ msnd_fifo DAPF, DARF; int fifosize; - int lastbank; + int last_playbank, last_recbank; /* MIDI in callback */ void (*midi_in_interrupt)(struct multisound_dev *); diff --git a/drivers/sound/msnd_classic.h b/drivers/sound/msnd_classic.h index bdc28ffd0..25898f8e0 100644 --- a/drivers/sound/msnd_classic.h +++ b/drivers/sound/msnd_classic.h @@ -24,7 +24,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_classic.h,v 1.7 1998/09/03 06:39:47 andrewtv Exp $ + * $Id: msnd_classic.h,v 1.9 1998/09/10 04:11:18 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_CLASSIC_H diff --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c index bebb5d49c..8f0b6de86 100644 --- a/drivers/sound/msnd_pinnacle.c +++ b/drivers/sound/msnd_pinnacle.c @@ -29,7 +29,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_pinnacle.c,v 1.17 1998/09/04 18:41:27 andrewtv Exp $ + * $Id: msnd_pinnacle.c,v 1.66 1998/10/09 19:54:39 andrewtv Exp $ * ********************************************************************/ @@ -45,6 +45,7 @@ #ifndef LINUX20 # include <linux/init.h> #endif +#include <asm/irq.h> #include "sound_config.h" #include "sound_firmware.h" #ifdef MSND_CLASSIC @@ -52,13 +53,33 @@ #endif #include "msnd.h" #ifdef MSND_CLASSIC +# ifdef CONFIG_MSNDCLAS_HAVE_BOOT +# define HAVE_DSPCODEH +# endif # include "msnd_classic.h" # define LOGNAME "msnd_classic" #else +# ifdef CONFIG_MSNDPIN_HAVE_BOOT +# define HAVE_DSPCODEH +# endif # include "msnd_pinnacle.h" # define LOGNAME "msnd_pinnacle" #endif +#ifndef CONFIG_MSND_WRITE_NDELAY +# define CONFIG_MSND_WRITE_NDELAY 0 +#endif + +#define get_play_delay_jiffies(size) ((size) * HZ * \ + dev.play_sample_size / 8 / \ + dev.play_sample_rate / \ + dev.play_channels) + +#define get_rec_delay_jiffies(size) ((size) * HZ * \ + dev.rec_sample_size / 8 / \ + dev.rec_sample_rate / \ + dev.rec_channels) + static multisound_dev_t dev; #ifndef HAVE_DSPCODEH @@ -66,71 +87,86 @@ static char *dspini, *permini; static int sizeof_dspini, sizeof_permini; #endif +static int dsp_full_reset(void); +static void dsp_write_flush(void); + +static __inline__ int chk_send_dsp_cmd(multisound_dev_t *dev, register BYTE cmd) +{ + if (msnd_send_dsp_cmd(dev, cmd) == 0) + return 0; + dsp_full_reset(); + return msnd_send_dsp_cmd(dev, cmd); +} + static void reset_play_queue(void) { int n; LPDAQD lpDAQ; - msnd_fifo_make_empty(&dev.DAPF); - writew(0, dev.DAPQ + JQS_wHead); - writew(PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE), dev.DAPQ + JQS_wTail); - dev.CurDAQD = (LPDAQD)(dev.base + 1 * DAPQ_DATA_BUFF); - outb(HPBLKSEL_0, dev.io + HP_BLKS); - memset_io(dev.base, 0, DAP_BUFF_SIZE * 3); + dev.last_playbank = -1; + writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead); + writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail); - for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, lpDAQ += DAQDS__size) { + for (n = 0, lpDAQ = dev.base + DAPQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) { writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart); - writew(DAP_BUFF_SIZE, lpDAQ + DAQDS_wSize); + writew(0, lpDAQ + DAQDS_wSize); writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.channels, lpDAQ + DAQDS_wChannels); - writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate); + writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize); + writew(dev.play_channels, lpDAQ + DAQDS_wChannels); + writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate); writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n + 1, lpDAQ + DAQDS_wFlags); + writew(n, lpDAQ + DAQDS_wFlags); } - dev.lastbank = -1; } static void reset_record_queue(void) { int n; LPDAQD lpDAQ; + unsigned long flags; + + dev.last_recbank = 2; + writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead); + writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail); - msnd_fifo_make_empty(&dev.DARF); - writew(0, dev.DARQ + JQS_wHead); - writew(PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE), dev.DARQ + JQS_wTail); - dev.CurDARQD = (LPDAQD)(dev.base + 1 * DARQ_DATA_BUFF); + /* Critical section: bank 1 access */ + spin_lock_irqsave(&dev.lock, flags); outb(HPBLKSEL_1, dev.io + HP_BLKS); memset_io(dev.base, 0, DAR_BUFF_SIZE * 3); outb(HPBLKSEL_0, dev.io + HP_BLKS); + spin_unlock_irqrestore(&dev.lock, flags); - for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, lpDAQ += DAQDS__size) { + for (n = 0, lpDAQ = dev.base + DARQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) { writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart); writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize); writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.channels, lpDAQ + DAQDS_wChannels); - writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate); + writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize); + writew(dev.rec_channels, lpDAQ + DAQDS_wChannels); + writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate); writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n + 1, lpDAQ + DAQDS_wFlags); + writew(n, lpDAQ + DAQDS_wFlags); } } static void reset_queues(void) { - writew(0, dev.DSPQ + JQS_wHead); - writew(0, dev.DSPQ + JQS_wTail); - reset_play_queue(); - reset_record_queue(); + if (dev.mode & FMODE_WRITE) { + msnd_fifo_make_empty(&dev.DAPF); + reset_play_queue(); + } + if (dev.mode & FMODE_READ) { + msnd_fifo_make_empty(&dev.DARF); + reset_record_queue(); + } } -static int dsp_set_format(int val) +static int dsp_set_format(struct file *file, int val) { int data, i; LPDAQD lpDAQ, lpDARQ; - lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF); - lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF); + lpDAQ = dev.base + DAPQ_DATA_BUFF; + lpDARQ = dev.base + DARQ_DATA_BUFF; switch (val) { case AFMT_U8: @@ -143,28 +179,43 @@ static int dsp_set_format(int val) } for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - - writew(data, lpDAQ + DAQDS_wSampleSize); - writew(data, lpDARQ + DAQDS_wSampleSize); + if (file->f_mode & FMODE_WRITE) + writew(data, lpDAQ + DAQDS_wSampleSize); + if (file->f_mode & FMODE_READ) + writew(data, lpDARQ + DAQDS_wSampleSize); } - - dev.sample_size = data; + if (file->f_mode & FMODE_WRITE) + dev.play_sample_size = data; + if (file->f_mode & FMODE_READ) + dev.rec_sample_size = data; return data; } -static int dsp_ioctl(unsigned int cmd, unsigned long arg) +static int dsp_get_frag_size(void) +{ + int size; + size = dev.fifosize / 4; + if (size > 32 * 1024) + size = 32 * 1024; + return size; +} + +static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int val, i, data, tmp; LPDAQD lpDAQ, lpDARQ; + audio_buf_info abinfo; + unsigned long flags; - lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF); - lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF); + lpDAQ = dev.base + DAPQ_DATA_BUFF; + lpDARQ = dev.base + DARQ_DATA_BUFF; switch (cmd) { case SNDCTL_DSP_SUBDIVIDE: case SNDCTL_DSP_SETFRAGMENT: case SNDCTL_DSP_SETDUPLEX: + case SNDCTL_DSP_POST: return 0; case SNDCTL_DSP_GETIPTR: @@ -173,14 +224,39 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg) case SNDCTL_DSP_MAPOUTBUF: return -EINVAL; - case SNDCTL_DSP_SYNC: + case SNDCTL_DSP_GETOSPACE: + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + spin_lock_irqsave(&dev.lock, flags); + abinfo.fragsize = dsp_get_frag_size(); + abinfo.bytes = dev.DAPF.n - dev.DAPF.len; + abinfo.fragstotal = dev.DAPF.n / abinfo.fragsize; + abinfo.fragments = abinfo.bytes / abinfo.fragsize; + spin_unlock_irqrestore(&dev.lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + + case SNDCTL_DSP_GETISPACE: + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + spin_lock_irqsave(&dev.lock, flags); + abinfo.fragsize = dsp_get_frag_size(); + abinfo.bytes = dev.DARF.n - dev.DARF.len; + abinfo.fragstotal = dev.DARF.n / abinfo.fragsize; + abinfo.fragments = abinfo.bytes / abinfo.fragsize; + spin_unlock_irqrestore(&dev.lock, flags); + return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; + case SNDCTL_DSP_RESET: - reset_play_queue(); - reset_record_queue(); + dev.nresets = 0; + reset_queues(); + return 0; + + case SNDCTL_DSP_SYNC: + dsp_write_flush(); return 0; case SNDCTL_DSP_GETBLKSIZE: - tmp = dev.fifosize / 4; + tmp = dsp_get_frag_size(); if (put_user(tmp, (int *)arg)) return -EFAULT; return 0; @@ -195,14 +271,25 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg) if (get_user(val, (int *)arg)) return -EFAULT; - data = (val == AFMT_QUERY) ? dev.sample_size : dsp_set_format(val); + if (file->f_mode & FMODE_WRITE) + data = val == AFMT_QUERY + ? dev.play_sample_size + : dsp_set_format(file, val); + else + data = val == AFMT_QUERY + ? dev.rec_sample_size + : dsp_set_format(file, val); if (put_user(data, (int *)arg)) return -EFAULT; return 0; case SNDCTL_DSP_NONBLOCK: - dev.mode |= O_NONBLOCK; + if (!test_bit(F_DISABLE_WRITE_NDELAY, &dev.flags) && + file->f_mode & FMODE_WRITE) + dev.play_ndelay = 1; + if (file->f_mode & FMODE_READ) + dev.rec_ndelay = 1; return 0; case SNDCTL_DSP_GETCAPS: @@ -224,65 +311,58 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg) data = val; for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - - writew(data, lpDAQ + DAQDS_wSampleRate); - writew(data, lpDARQ + DAQDS_wSampleRate); + if (file->f_mode & FMODE_WRITE) + writew(data, lpDAQ + DAQDS_wSampleRate); + if (file->f_mode & FMODE_READ) + writew(data, lpDARQ + DAQDS_wSampleRate); } - - dev.sample_rate = data; + if (file->f_mode & FMODE_WRITE) + dev.play_sample_rate = data; + if (file->f_mode & FMODE_READ) + dev.rec_sample_rate = data; if (put_user(data, (int *)arg)) return -EFAULT; return 0; case SNDCTL_DSP_CHANNELS: - if (get_user(val, (int *)arg)) - return -EFAULT; - - switch (val) { - case 1: - case 2: - data = val; - break; - default: - val = data = 2; - break; - } - - for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - - writew(data, lpDAQ + DAQDS_wChannels); - writew(data, lpDARQ + DAQDS_wChannels); - } - - dev.channels = data; - - if (put_user(val, (int *)arg)) - return -EFAULT; - return 0; - case SNDCTL_DSP_STEREO: if (get_user(val, (int *)arg)) return -EFAULT; - - switch (val) { - case 0: - data = 1; - break; - default: - val = 1; - case 1: - data = 2; - break; + + if (cmd == SNDCTL_DSP_CHANNELS) { + switch (val) { + case 1: + case 2: + data = val; + break; + default: + val = data = 2; + break; + } + } else { + switch (val) { + case 0: + data = 1; + break; + default: + val = 1; + case 1: + data = 2; + break; + } } for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - - writew(data, lpDAQ + DAQDS_wChannels); - writew(data, lpDARQ + DAQDS_wChannels); + if (file->f_mode & FMODE_WRITE) + writew(data, lpDAQ + DAQDS_wChannels); + if (file->f_mode & FMODE_READ) + writew(data, lpDARQ + DAQDS_wChannels); } - - dev.channels = data; + if (file->f_mode & FMODE_WRITE) + dev.play_channels = data; + if (file->f_mode & FMODE_READ) + dev.rec_channels = data; if (put_user(val, (int *)arg)) return -EFAULT; @@ -320,6 +400,12 @@ static int mixer_get(int d) writew(dev.right_levels[a] * readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff / s, \ dev.SMA + SMA_##b##Right); +#define update_pot(d,s,ar) \ + writeb(dev.left_levels[d] >> 8, dev.SMA + SMA_##s##Left); \ + writeb(dev.right_levels[d] >> 8, dev.SMA + SMA_##s##Right); \ + if (msnd_send_word(&dev, 0, 0, ar) == 0) \ + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); + static int mixer_set(int d, int value) { int left = value & 0x000000ff; @@ -350,7 +436,7 @@ static int mixer_set(int d, int value) writeb(bLeft, dev.SMA + SMA_bInPotPosLeft); writeb(bRight, dev.SMA + SMA_bInPotPosRight); if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); break; #ifndef MSND_CLASSIC @@ -358,7 +444,7 @@ static int mixer_set(int d, int value) writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft); writeb(bRight, dev.SMA + SMA_bMicPotPosRight); if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); break; #endif @@ -366,7 +452,7 @@ static int mixer_set(int d, int value) writeb(bLeft, dev.SMA + SMA_bAuxPotPosLeft); writeb(bRight, dev.SMA + SMA_bAuxPotPosRight); if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); break; /* digital controls */ @@ -389,6 +475,20 @@ static int mixer_set(int d, int value) return mixer_get(d); } +static void mixer_setup(void) +{ + update_pot(SOUND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS); +#ifndef MSND_CLASSIC + update_pot(SOUND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS); +#endif + update_pot(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS); + update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1); + update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1); +#ifndef MSND_CLASSIC + update_vol(SOUND_MIXER_SYNTH, wCurrMHdrVol, 1); +#endif +} + static unsigned long set_recsrc(unsigned long recsrc) { if (dev.recsrc == recsrc) @@ -403,17 +503,15 @@ static unsigned long set_recsrc(unsigned long recsrc) #ifndef MSND_CLASSIC if (dev.recsrc & SOUND_MASK_LINE) { if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); } else if (dev.recsrc & SOUND_MASK_SYNTH) { if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_SYNTH_IN) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); } else if ((dev.recsrc & SOUND_MASK_DIGITAL1) && test_bit(F_HAVEDIGITAL, &dev.flags)) { - if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0) { - udelay(50); - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); - } + if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0) + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); } else { #ifdef HAVE_NORECSRC @@ -422,7 +520,7 @@ static unsigned long set_recsrc(unsigned long recsrc) #else dev.recsrc = SOUND_MASK_LINE; if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0) - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ); + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ); #endif } #endif /* MSND_CLASSIC */ @@ -430,6 +528,12 @@ static unsigned long set_recsrc(unsigned long recsrc) return dev.recsrc; } +static unsigned long force_recsrc(unsigned long recsrc) +{ + dev.recsrc = 0; + return set_recsrc(recsrc); +} + #define set_mixer_info() \ strncpy(info.id, "MSNDMIXER", sizeof(info.id)); \ strncpy(info.name, "MultiSound Mixer", sizeof(info.name)); @@ -447,10 +551,6 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) set_mixer_info(); return copy_to_user((void *)arg, &info, sizeof(info)); } - else if (cmd == OSS_GETVERSION) { - int sound_version = SOUND_VERSION; - return put_user(sound_version, (int *)arg); - } else if (((cmd >> 8) & 0xff) == 'M') { int val = 0; @@ -521,77 +621,138 @@ static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u { int minor = MINOR(inode->i_rdev); + if (cmd == OSS_GETVERSION) { + int sound_version = SOUND_VERSION; + return put_user(sound_version, (int *)arg); + } + if (minor == dev.dsp_minor) - return dsp_ioctl(cmd, arg); + return dsp_ioctl(file, cmd, arg); else if (minor == dev.mixer_minor) return mixer_ioctl(cmd, arg); return -EINVAL; } -static void dsp_halt(void) +static void dsp_write_flush(void) { - mdelay(1); -#ifdef LINUX20 - if (test_bit(F_READING, &dev.flags)) { + if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags)) + return; + set_bit(F_WRITEFLUSH, &dev.flags); + interruptible_sleep_on_timeout(&dev.writeflush, get_play_delay_jiffies(dev.DAPF.len) + HZ / 8); + clear_bit(F_WRITEFLUSH, &dev.flags); + if (!signal_pending(current)) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(get_play_delay_jiffies(DAP_BUFF_SIZE)); + } + clear_bit(F_WRITING, &dev.flags); +} + +static void dsp_halt(struct file *file) +{ + if ((file ? file->f_mode : dev.mode) & FMODE_READ) { clear_bit(F_READING, &dev.flags); -#else - if (test_and_clear_bit(F_READING, &dev.flags)) { -#endif - msnd_send_dsp_cmd(&dev, HDEX_RECORD_STOP); + chk_send_dsp_cmd(&dev, HDEX_RECORD_STOP); msnd_disable_irq(&dev); - + if (file) { + printk(KERN_DEBUG LOGNAME ": Stopping read for %p\n", file); + dev.mode &= ~FMODE_READ; + } + clear_bit(F_AUDIO_READ_INUSE, &dev.flags); } - mdelay(1); -#ifdef LINUX20 - if (test_bit(F_WRITING, &dev.flags)) { - clear_bit(F_WRITING, &dev.flags); -#else - if (test_and_clear_bit(F_WRITING, &dev.flags)) { -#endif - set_bit(F_WRITEFLUSH, &dev.flags); - interruptible_sleep_on(&dev.writeflush); - current->state = TASK_INTERRUPTIBLE; - current->timeout = - jiffies + DAP_BUFF_SIZE / 2 * HZ / - dev.sample_rate / dev.channels; - schedule(); - current->timeout = 0; - msnd_send_dsp_cmd(&dev, HDEX_PLAY_STOP); + if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) { + if (test_bit(F_WRITING, &dev.flags)) { + dsp_write_flush(); + chk_send_dsp_cmd(&dev, HDEX_PLAY_STOP); + } msnd_disable_irq(&dev); - memset_io(dev.base, 0, DAP_BUFF_SIZE * 3); - + if (file) { + printk(KERN_DEBUG LOGNAME ": Stopping write for %p\n", file); + dev.mode &= ~FMODE_WRITE; + } + clear_bit(F_AUDIO_WRITE_INUSE, &dev.flags); } - mdelay(1); - reset_queues(); } -static int dsp_open(struct file *file) +static int dsp_release(struct file *file) { - dev.mode = file->f_mode; - set_bit(F_AUDIO_INUSE, &dev.flags); - reset_queues(); + dsp_halt(file); return 0; } -static int dsp_close(void) +static int dsp_open(struct file *file) { - dsp_halt(); - clear_bit(F_AUDIO_INUSE, &dev.flags); + if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) { + set_bit(F_AUDIO_WRITE_INUSE, &dev.flags); + clear_bit(F_WRITING, &dev.flags); + msnd_fifo_make_empty(&dev.DAPF); + reset_play_queue(); + if (file) { + printk(KERN_DEBUG LOGNAME ": Starting write for %p\n", file); + dev.mode |= FMODE_WRITE; + } + msnd_enable_irq(&dev); + } + if ((file ? file->f_mode : dev.mode) & FMODE_READ) { + set_bit(F_AUDIO_READ_INUSE, &dev.flags); + clear_bit(F_READING, &dev.flags); + msnd_fifo_make_empty(&dev.DARF); + reset_record_queue(); + if (file) { + printk(KERN_DEBUG LOGNAME ": Starting read for %p\n", file); + dev.mode |= FMODE_READ; + } + msnd_enable_irq(&dev); + } return 0; } +static void set_default_play_audio_parameters(void) +{ + dev.play_sample_size = DEFSAMPLESIZE; + dev.play_sample_rate = DEFSAMPLERATE; + dev.play_channels = DEFCHANNELS; +} + +static void set_default_rec_audio_parameters(void) +{ + dev.rec_sample_size = DEFSAMPLESIZE; + dev.rec_sample_rate = DEFSAMPLERATE; + dev.rec_channels = DEFCHANNELS; +} + +static void set_default_audio_parameters(void) +{ + set_default_play_audio_parameters(); + set_default_rec_audio_parameters(); +} + static int dev_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); int err = 0; if (minor == dev.dsp_minor) { - - if (test_bit(F_AUDIO_INUSE, &dev.flags)) + if ((file->f_mode & FMODE_WRITE && + test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) || + (file->f_mode & FMODE_READ && + test_bit(F_AUDIO_READ_INUSE, &dev.flags))) return -EBUSY; - err = dsp_open(file); + if ((err = dsp_open(file)) >= 0) { + dev.nresets = 0; + if (file->f_mode & FMODE_WRITE) { + set_default_play_audio_parameters(); + if (!test_bit(F_DISABLE_WRITE_NDELAY, &dev.flags)) + dev.play_ndelay = (file->f_flags & O_NDELAY) ? 1 : 0; + else + dev.play_ndelay = 0; + } + if (file->f_mode & FMODE_READ) { + set_default_rec_audio_parameters(); + dev.rec_ndelay = (file->f_flags & O_NDELAY) ? 1 : 0; + } + } } else if (minor == dev.mixer_minor) { /* nothing */ @@ -605,9 +766,9 @@ static int dev_open(struct inode *inode, struct file *file) } #ifdef LINUX20 -static void dev_close(struct inode *inode, struct file *file) +static void dev_release(struct inode *inode, struct file *file) #else -static int dev_close(struct inode *inode, struct file *file) +static int dev_release(struct inode *inode, struct file *file) #endif { int minor = MINOR(inode->i_rdev); @@ -619,7 +780,7 @@ static int dev_close(struct inode *inode, struct file *file) #ifndef LINUX20 err = #endif - dsp_close(); + dsp_release(file); } else if (minor == dev.mixer_minor) { /* nothing */ @@ -637,62 +798,133 @@ static int dev_close(struct inode *inode, struct file *file) #endif } -static int DAPF_to_bank(int bank) +static __inline__ int pack_DARQ_to_DARF(register int bank) { - return msnd_fifo_read(&dev.DAPF, dev.base + bank * DAP_BUFF_SIZE, DAP_BUFF_SIZE, 0); + register int size, n, timeout = 3; + register WORD wTmp; + LPDAQD DAQD; + + /* Increment the tail and check for queue wrap */ + wTmp = readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size); + if (wTmp > readw(dev.DARQ + JQS_wSize)) + wTmp = 0; + while (wTmp == readw(dev.DARQ + JQS_wHead) && timeout--) + udelay(1); + writew(wTmp, dev.DARQ + JQS_wTail); + + /* Get our digital audio queue struct */ + DAQD = bank * DAQDS__size + dev.base + DARQ_DATA_BUFF; + + /* Get length of data */ + size = readw(DAQD + DAQDS_wSize); + + /* Read data from the head (unprotected bank 1 access okay + since this is only called inside an interrupt) */ + outb(HPBLKSEL_1, dev.io + HP_BLKS); + if ((n = msnd_fifo_write( + &dev.DARF, + (char *)(dev.base + bank * DAR_BUFF_SIZE), + size, 0)) <= 0) { + outb(HPBLKSEL_0, dev.io + HP_BLKS); + return n; + } + outb(HPBLKSEL_0, dev.io + HP_BLKS); + + return 1; } -static int bank_to_DARF(int bank) +static __inline__ int pack_DAPF_to_DAPQ(register int start) { - return msnd_fifo_write(&dev.DARF, dev.base + bank * DAR_BUFF_SIZE, DAR_BUFF_SIZE, 0); + register WORD DAPQ_tail; + register int protect = start, nbanks = 0; + LPDAQD DAQD; + + DAPQ_tail = readw(dev.DAPQ + JQS_wTail); + while (DAPQ_tail != readw(dev.DAPQ + JQS_wHead) || start) { + register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size); + register int n; + unsigned long flags; + + /* Write the data to the new tail */ + if (protect) { + /* Critical section: protect fifo in non-interrupt */ + spin_lock_irqsave(&dev.lock, flags); + if ((n = msnd_fifo_read( + &dev.DAPF, + (char *)(dev.base + bank_num * DAP_BUFF_SIZE), + DAP_BUFF_SIZE, 0)) < 0) { + spin_unlock_irqrestore(&dev.lock, flags); + return n; + } + spin_unlock_irqrestore(&dev.lock, flags); + } else { + if ((n = msnd_fifo_read( + &dev.DAPF, + (char *)(dev.base + bank_num * DAP_BUFF_SIZE), + DAP_BUFF_SIZE, 0)) < 0) { + return n; + } + } + if (!n) + break; + + if (start) + start = 0; + + /* Get our digital audio queue struct */ + DAQD = bank_num * DAQDS__size + dev.base + DAPQ_DATA_BUFF; + + /* Write size of this bank */ + writew(n, DAQD + DAQDS_wSize); + ++nbanks; + + /* Then advance the tail */ + DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size); + writew(DAPQ_tail, dev.DAPQ + JQS_wTail); + + /* Tell the DSP to play the bank */ + msnd_send_dsp_cmd(&dev, HDEX_PLAY_START); + } + + return nbanks; } static int dsp_read(char *buf, size_t len) { - int err = 0; int count = len; while (count > 0) { - int n; + unsigned long flags; + /* Critical section: protect fifo in non-interrupt */ + spin_lock_irqsave(&dev.lock, flags); if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) { - printk(KERN_WARNING LOGNAME ": FIFO read error\n"); + spin_unlock_irqrestore(&dev.lock, flags); return n; } - + spin_unlock_irqrestore(&dev.lock, flags); buf += n; count -= n; -#ifdef LINUX20 - if (!test_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) { - set_bit(F_READING, &dev.flags); -#else - if (!test_and_set_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) { -#endif - reset_record_queue(); - msnd_enable_irq(&dev); - msnd_send_dsp_cmd(&dev, HDEX_RECORD_START); - + if (!test_bit(F_READING, &dev.flags) && dev.mode & FMODE_READ) { + dev.last_recbank = -1; + if (chk_send_dsp_cmd(&dev, HDEX_RECORD_START) == 0) + set_bit(F_READING, &dev.flags); } - if (dev.mode & O_NONBLOCK) + if (dev.rec_ndelay) return count == len ? -EAGAIN : len - count; if (count > 0) { - set_bit(F_READBLOCK, &dev.flags); - interruptible_sleep_on(&dev.readblock); + if (!interruptible_sleep_on_timeout(&dev.readblock, get_rec_delay_jiffies(DAR_BUFF_SIZE))) + clear_bit(F_READING, &dev.flags); clear_bit(F_READBLOCK, &dev.flags); - if (signal_pending(current)) - err = -EINTR; - + return -EINTR; } - - if (err != 0) - return err; } return len - count; @@ -700,50 +932,39 @@ static int dsp_read(char *buf, size_t len) static int dsp_write(const char *buf, size_t len) { - int err = 0; int count = len; while (count > 0) { - int n; + unsigned long flags; + /* Critical section: protect fifo in non-interrupt */ + spin_lock_irqsave(&dev.lock, flags); if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) { - printk(KERN_WARNING LOGNAME ": FIFO write error\n"); + spin_unlock_irqrestore(&dev.lock, flags); return n; } - + spin_unlock_irqrestore(&dev.lock, flags); buf += n; count -= n; -#ifdef LINUX20 if (!test_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) { - set_bit(F_WRITING, &dev.flags); -#else - if (!test_and_set_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) { -#endif - reset_play_queue(); - msnd_enable_irq(&dev); - msnd_send_dsp_cmd(&dev, HDEX_PLAY_START); - + dev.last_playbank = -1; + if (pack_DAPF_to_DAPQ(1) > 0) + set_bit(F_WRITING, &dev.flags); } - if (dev.mode & O_NONBLOCK) + if (dev.play_ndelay) return count == len ? -EAGAIN : len - count; if (count > 0) { - set_bit(F_WRITEBLOCK, &dev.flags); - interruptible_sleep_on(&dev.writeblock); + interruptible_sleep_on_timeout(&dev.writeblock, get_play_delay_jiffies(DAP_BUFF_SIZE)); clear_bit(F_WRITEBLOCK, &dev.flags); - if (signal_pending(current)) - err = -EINTR; - + return -EINTR; } - - if (err != 0) - return err; } return len - count; @@ -758,12 +979,9 @@ static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off) { int minor = MINOR(file->f_dentry->d_inode->i_rdev); #endif - - if (minor == dev.dsp_minor) { - + if (minor == dev.dsp_minor) return dsp_read(buf, count); - - } else + else return -EINVAL; } @@ -776,44 +994,22 @@ static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_ { int minor = MINOR(file->f_dentry->d_inode->i_rdev); #endif - - if (minor == dev.dsp_minor) { - + if (minor == dev.dsp_minor) return dsp_write(buf, count); - - } else + else return -EINVAL; } -static void eval_dsp_msg(WORD wMessage) +static __inline__ void eval_dsp_msg(register WORD wMessage) { - WORD wTmp; - switch (HIBYTE(wMessage)) { case HIMT_PLAY_DONE: - if (dev.lastbank == LOBYTE(wMessage)) + if (dev.last_playbank == LOBYTE(wMessage) || !test_bit(F_WRITING, &dev.flags)) break; - - dev.lastbank = LOBYTE(wMessage); - - writew(DAP_BUFF_SIZE, dev.CurDAQD + DAQDS_wSize); + dev.last_playbank = LOBYTE(wMessage); - wTmp = readw(dev.DAPQ + JQS_wTail) + PCTODSP_OFFSET(DAPQ_STRUCT_SIZE); - if (wTmp > readw(dev.DAPQ + JQS_wSize)) - writew(0, dev.DAPQ + JQS_wTail); - else - writew(wTmp, dev.DAPQ + JQS_wTail); - - if ((dev.CurDAQD += DAQDS__size) > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE)) - dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF); - - if (dev.lastbank < 3) { - if (DAPF_to_bank(dev.lastbank) > 0) { - mdelay(1); - msnd_send_dsp_cmd(&dev, HDEX_PLAY_START); - } - else if (!test_bit(F_WRITEBLOCK, &dev.flags)) { - clear_bit(F_WRITING, &dev.flags); + if (pack_DAPF_to_DAPQ(0) <= 0) { + if (!test_bit(F_WRITEBLOCK, &dev.flags)) { #ifdef LINUX20 if (test_bit(F_WRITEFLUSH, &dev.flags)) { clear_bit(F_WRITEFLUSH, &dev.flags); @@ -824,6 +1020,7 @@ static void eval_dsp_msg(WORD wMessage) wake_up_interruptible(&dev.writeflush); #endif } + clear_bit(F_WRITING, &dev.flags); } if (test_bit(F_WRITEBLOCK, &dev.flags)) @@ -831,21 +1028,11 @@ static void eval_dsp_msg(WORD wMessage) break; case HIMT_RECORD_DONE: - wTmp = readw(dev.DARQ + JQS_wTail) + DARQ_STRUCT_SIZE / 2; - - if (wTmp > readw(dev.DARQ + JQS_wSize)) - wTmp = 0; - - while (wTmp == readw(dev.DARQ + JQS_wHead)); - - writew(wTmp, dev.DARQ + JQS_wTail); + if (dev.last_recbank == LOBYTE(wMessage)) + break; + dev.last_recbank = LOBYTE(wMessage); - outb(HPBLKSEL_1, dev.io + HP_BLKS); - if (bank_to_DARF(LOBYTE(wMessage)) == 0 && !test_bit(F_READBLOCK, &dev.flags)) { - memset_io(dev.base, 0, DAR_BUFF_SIZE * 3); - clear_bit(F_READING, &dev.flags); - } - outb(HPBLKSEL_0, dev.io + HP_BLKS); + pack_DARQ_to_DARF(dev.last_recbank); if (test_bit(F_READBLOCK, &dev.flags)) wake_up_interruptible(&dev.readblock); @@ -857,17 +1044,17 @@ static void eval_dsp_msg(WORD wMessage) case HIDSP_PLAY_UNDER: #endif case HIDSP_INT_PLAY_UNDER: -/* printk(KERN_INFO LOGNAME ": Write underflow\n"); */ - reset_play_queue(); +/* printk(KERN_DEBUG LOGNAME ": Play underflow\n"); */ + clear_bit(F_WRITING, &dev.flags); break; case HIDSP_INT_RECORD_OVER: -/* printk(KERN_INFO LOGNAME ": Read overflow\n"); */ - reset_record_queue(); +/* printk(KERN_DEBUG LOGNAME ": Record overflow\n"); */ + clear_bit(F_READING, &dev.flags); break; default: - printk(KERN_DEBUG LOGNAME ": DSP message %u\n", LOBYTE(wMessage)); +/* printk(KERN_DEBUG LOGNAME ": DSP message %d 0x%02x\n", LOBYTE(wMessage), LOBYTE(wMessage)); */ break; } break; @@ -877,85 +1064,68 @@ static void eval_dsp_msg(WORD wMessage) (*dev.midi_in_interrupt)(&dev); break; - case HIMT_MIDI_OUT: - printk(KERN_DEBUG LOGNAME ": MIDI out event\n"); - break; - default: - printk(KERN_DEBUG LOGNAME ": HIMT message %u\n", HIBYTE(wMessage)); +/* printk(KERN_DEBUG LOGNAME ": HIMT message %d 0x%02x\n", HIBYTE(wMessage), HIBYTE(wMessage)); */ break; } } static void intr(int irq, void *dev_id, struct pt_regs *regs) { - if (test_bit(F_INTERRUPT, &dev.flags)) - return; - - set_bit(F_INTERRUPT, &dev.flags); - - if (test_bit(F_BANKONE, &dev.flags)) - outb(HPBLKSEL_0, dev.io + HP_BLKS); - + /* Send ack to DSP */ inb(dev.io + HP_RXL); - + + /* Evaluate queued DSP messages */ while (readw(dev.DSPQ + JQS_wTail) != readw(dev.DSPQ + JQS_wHead)) { - WORD wTmp; + register WORD wTmp; - eval_dsp_msg(*(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead))); - - wTmp = readw(dev.DSPQ + JQS_wHead) + 1; - if (wTmp > readw(dev.DSPQ + JQS_wSize)) + eval_dsp_msg(readw(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead))); + + if ((wTmp = readw(dev.DSPQ + JQS_wHead) + 1) > readw(dev.DSPQ + JQS_wSize)) writew(0, dev.DSPQ + JQS_wHead); else writew(wTmp, dev.DSPQ + JQS_wHead); } - - if (test_bit(F_BANKONE, &dev.flags)) - outb(HPBLKSEL_1, dev.io + HP_BLKS); - - clear_bit(F_INTERRUPT, &dev.flags); } static struct file_operations dev_fileops = { - NULL, - dev_read, - dev_write, - NULL, - NULL, - dev_ioctl, - NULL, - dev_open, + NULL, /* llseek */ + dev_read, /* read */ + dev_write, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + dev_ioctl, /* ioctl */ + NULL, /* mmap */ + dev_open, /* open */ +#ifndef LINUX20 + NULL, /* flush */ +#endif + dev_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ #ifndef LINUX20 -# if LINUX_VERSION_CODE >= 0x020100 + 118 - NULL, -# endif /* >= 2.1.118 */ + NULL, /* lock */ #endif - dev_close, }; -__initfunc(static int reset_dsp(void)) +static int reset_dsp(void) { int timeout = 100; outb(HPDSPRESET_ON, dev.io + HP_DSPR); - mdelay(1); - +#ifndef MSND_CLASSIC dev.info = inb(dev.io + HP_INFO); - +#endif outb(HPDSPRESET_OFF, dev.io + HP_DSPR); - mdelay(1); - while (timeout-- > 0) { - if (inb(dev.io + HP_CVR) == HP_CVR_DEF) return 0; - mdelay(1); } - printk(KERN_ERR LOGNAME ": Cannot reset DSP\n"); return -EIO; @@ -973,7 +1143,6 @@ __initfunc(static int probe_multisound(void)) printk(KERN_ERR LOGNAME ": I/O port conflict\n"); return -ENODEV; } - request_region(dev.io, dev.numio, "probing"); if (reset_dsp() < 0) { @@ -1024,127 +1193,82 @@ __initfunc(static int probe_multisound(void)) return 0; } -__initfunc(static int init_sma(void)) +static void msnd_init_queue(volatile BYTE *base, int start, int size) { - int n; - LPDAQD lpDAQ; + writew(PCTODSP_BASED(start), base + JQS_wStart); + writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize); + writew(0, base + JQS_wHead); + writew(0, base + JQS_wTail); +} + +static int init_sma(void) +{ + static int initted; + WORD mastVolLeft, mastVolRight; + unsigned long flags; #ifdef MSND_CLASSIC outb(dev.memid, dev.io + HP_MEMM); #endif outb(HPBLKSEL_0, dev.io + HP_BLKS); + if (initted) { + mastVolLeft = readw(dev.SMA + SMA_wCurrMastVolLeft); + mastVolRight = readw(dev.SMA + SMA_wCurrMastVolRight); + } else + mastVolLeft = mastVolRight = 0; memset_io(dev.base, 0, 0x8000); - + + /* Critical section: bank 1 access */ + spin_lock_irqsave(&dev.lock, flags); outb(HPBLKSEL_1, dev.io + HP_BLKS); memset_io(dev.base, 0, 0x8000); - outb(HPBLKSEL_0, dev.io + HP_BLKS); + spin_unlock_irqrestore(&dev.lock, flags); - dev.DAPQ = (BYTE *)(dev.base + DAPQ_OFFSET); - dev.DARQ = (BYTE *)(dev.base + DARQ_OFFSET); - dev.MODQ = (BYTE *)(dev.base + MODQ_OFFSET); - dev.MIDQ = (BYTE *)(dev.base + MIDQ_OFFSET); - dev.DSPQ = (BYTE *)(dev.base + DSPQ_OFFSET); - dev.SMA = (BYTE *)(dev.base + SMA_STRUCT_START); - - dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF); - dev.CurDARQD = (LPDAQD)(dev.base + DARQ_DATA_BUFF); - - dev.sample_size = DEFSAMPLESIZE; - dev.sample_rate = DEFSAMPLERATE; - dev.channels = DEFCHANNELS; - - for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, lpDAQ += DAQDS__size) { - - writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart); - writew(DAP_BUFF_SIZE, lpDAQ + DAQDS_wSize); - writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.channels, lpDAQ + DAQDS_wChannels); - writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate); - writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n + 1, lpDAQ + DAQDS_wFlags); - } - - for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, lpDAQ += DAQDS__size) { - - writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart); - writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize); - writew(1, lpDAQ + DAQDS_wFormat); - writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize); - writew(dev.channels, lpDAQ + DAQDS_wChannels); - writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate); - writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg); - writew(n + 1, lpDAQ + DAQDS_wFlags); - - } - - dev.pwDSPQData = (WORD *)(dev.base + DSPQ_DATA_BUFF); - dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF); - dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF); - - writew(PCTODSP_BASED(MIDQ_DATA_BUFF), dev.MIDQ + JQS_wStart); - writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, dev.MIDQ + JQS_wSize); - writew(0, dev.MIDQ + JQS_wHead); - writew(0, dev.MIDQ + JQS_wTail); + dev.pwDSPQData = (volatile WORD *)(dev.base + DSPQ_DATA_BUFF); + dev.pwMODQData = (volatile WORD *)(dev.base + MODQ_DATA_BUFF); + dev.pwMIDQData = (volatile WORD *)(dev.base + MIDQ_DATA_BUFF); - writew(PCTODSP_BASED(MODQ_DATA_BUFF), dev.MODQ + JQS_wStart); - writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, dev.MODQ + JQS_wSize); - writew(0, dev.MODQ + JQS_wHead); - writew(0, dev.MODQ + JQS_wTail); + /* Motorola 56k shared memory base */ + dev.SMA = dev.base + SMA_STRUCT_START; - writew(PCTODSP_BASED(DAPQ_DATA_BUFF), dev.DAPQ + JQS_wStart); - writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, dev.DAPQ + JQS_wSize); - writew(0, dev.DAPQ + JQS_wHead); - writew(0, dev.DAPQ + JQS_wTail); + /* Digital audio play queue */ + dev.DAPQ = dev.base + DAPQ_OFFSET; + msnd_init_queue(dev.DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE); - writew(PCTODSP_BASED(DARQ_DATA_BUFF), dev.DARQ + JQS_wStart); - writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, dev.DARQ + JQS_wSize); - writew(0, dev.DARQ + JQS_wHead); - writew(0, dev.DARQ + JQS_wTail); + /* Digital audio record queue */ + dev.DARQ = dev.base + DARQ_OFFSET; + msnd_init_queue(dev.DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE); - writew(PCTODSP_BASED(DSPQ_DATA_BUFF), dev.DSPQ + JQS_wStart); - writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, dev.DSPQ + JQS_wSize); - writew(0, dev.DSPQ + JQS_wHead); - writew(0, dev.DSPQ + JQS_wTail); + /* MIDI out queue */ + dev.MODQ = dev.base + MODQ_OFFSET; + msnd_init_queue(dev.MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE); - writew(0, dev.SMA + SMA_wCurrPlayBytes); - writew(0, dev.SMA + SMA_wCurrRecordBytes); + /* MIDI in queue */ + dev.MIDQ = dev.base + MIDQ_OFFSET; + msnd_init_queue(dev.MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE); - writew(0, dev.SMA + SMA_wCurrPlayVolLeft); - writew(0, dev.SMA + SMA_wCurrPlayVolRight); - - writew(0, dev.SMA + SMA_wCurrInVolLeft); - writew(0, dev.SMA + SMA_wCurrInVolRight); - - writew(0, dev.SMA + SMA_wCurrMastVolLeft); - writew(0, dev.SMA + SMA_wCurrMastVolRight); + /* DSP -> host message queue */ + dev.DSPQ = dev.base + DSPQ_OFFSET; + msnd_init_queue(dev.DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE); + /* Setup some DSP values */ +#ifndef MSND_CLASSIC + writew(1, dev.SMA + SMA_wCurrPlayFormat); + writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize); + writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels); + writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate); +#endif + writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD); + writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft); + writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight); #ifndef MSND_CLASSIC writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch); writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate); #endif - - writew(0x0000, dev.SMA + SMA_wCurrDSPStatusFlags); - writew(0x0000, dev.SMA + SMA_wCurrHostStatusFlags); - writew(0x303, dev.SMA + SMA_wCurrInputTagBits); - writew(0, dev.SMA + SMA_wCurrLeftPeak); - writew(0, dev.SMA + SMA_wCurrRightPeak); - - writeb(0, dev.SMA + SMA_bInPotPosRight); - writeb(0, dev.SMA + SMA_bInPotPosLeft); - - writeb(0, dev.SMA + SMA_bAuxPotPosRight); - writeb(0, dev.SMA + SMA_bAuxPotPosLeft); -#ifndef MSND_CLASSIC - writew(1, dev.SMA + SMA_wCurrPlayFormat); - writew(dev.sample_size, dev.SMA + SMA_wCurrPlaySampleSize); - writew(dev.channels, dev.SMA + SMA_wCurrPlayChannels); - writew(dev.sample_rate, dev.SMA + SMA_wCurrPlaySampleRate); -#endif - writew(dev.sample_rate, dev.SMA + SMA_wCalFreqAtoD); + initted = 1; return 0; } @@ -1164,21 +1288,18 @@ __initfunc(static int calibrate_adc(WORD srate)) writew(srate, dev.SMA + SMA_wCalFreqAtoD); if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 && - msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) { + chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ / 3; - schedule(); - current->timeout = 0; + schedule_timeout(HZ / 3); printk("successful\n"); return 0; } - printk("failed\n"); return -EIO; } -__initfunc(static int upload_dsp_code(void)) +static int upload_dsp_code(void) { outb(HPBLKSEL_0, dev.io + HP_BLKS); @@ -1214,7 +1335,7 @@ __initfunc(static int upload_dsp_code(void)) } #ifdef MSND_CLASSIC -__initfunc(static void reset_proteus(void)) +static void reset_proteus(void) { outb(HPPRORESET_ON, dev.io + HP_PROR); mdelay(TIME_PRO_RESET); @@ -1223,7 +1344,7 @@ __initfunc(static void reset_proteus(void)) } #endif -__initfunc(static int initialize(void)) +static int initialize(void) { int err, timeout; @@ -1233,7 +1354,6 @@ __initfunc(static int initialize(void)) reset_proteus(); #endif - if ((err = init_sma()) < 0) { printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n"); return err; @@ -1250,36 +1370,52 @@ __initfunc(static int initialize(void)) printk(KERN_INFO LOGNAME ": DSP upload successful\n"); timeout = 200; - while (readw(dev.base)) { mdelay(1); - if (--timeout < 0) + if (!timeout--) { + printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n"); return -EIO; + } } + mixer_setup(); + return 0; } +static int dsp_full_reset(void) +{ + int rv; + + if (test_bit(F_RESETTING, &dev.flags) || ++dev.nresets > 10) + return 0; + + printk(KERN_INFO LOGNAME ": Resetting DSP\n"); + set_bit(F_RESETTING, &dev.flags); + dsp_halt(NULL); /* Unconditionally halt */ + if ((rv = initialize())) + printk(KERN_WARNING LOGNAME ": DSP reset failed\n"); + force_recsrc(dev.recsrc); + dsp_open(NULL); + clear_bit(F_RESETTING, &dev.flags); + + return rv; +} + __initfunc(static int attach_multisound(void)) { int err; - printk(KERN_DEBUG LOGNAME ": Intializing DSP\n"); - - if ((err = request_irq(dev.irq, intr, SA_SHIRQ, dev.name, &dev)) < 0) { + if ((err = request_irq(dev.irq, intr, 0, dev.name, &dev)) < 0) { printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq); return err; - } - request_region(dev.io, dev.numio, dev.name); - if ((err = initialize()) < 0) { - printk(KERN_WARNING LOGNAME ": Initialization failure\n"); + if ((err = dsp_full_reset()) < 0) { release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); return err; - } if ((err = msnd_register(&dev)) < 0) { @@ -1307,15 +1443,17 @@ __initfunc(static int attach_multisound(void)) } printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", dev.dsp_minor, dev.mixer_minor); - calibrate_adc(dev.sample_rate); + disable_irq(dev.irq); + calibrate_adc(dev.play_sample_rate); #ifndef MSND_CLASSIC printk(KERN_INFO LOGNAME ": Setting initial recording source to Line In\n"); - set_recsrc(SOUND_MASK_LINE); + force_recsrc(SOUND_MASK_LINE); #endif return 0; } +#ifdef MODULE static void unload_multisound(void) { release_region(dev.io, dev.numio); @@ -1324,6 +1462,7 @@ static void unload_multisound(void) unregister_sound_dsp(dev.dsp_minor); msnd_unregister(&dev); } +#endif static void mod_inc_ref(void) { @@ -1490,6 +1629,7 @@ MODULE_DESCRIPTION ("Turtle Beach " LONGNAME " Linux Driver"); MODULE_PARM (io, "i"); MODULE_PARM (irq, "i"); MODULE_PARM (mem, "i"); +MODULE_PARM (write_ndelay, "i"); MODULE_PARM (major, "i"); MODULE_PARM (fifosize, "i"); MODULE_PARM (calibrate_signal, "i"); @@ -1508,6 +1648,7 @@ MODULE_PARM (joystick_io, "i"); static int io __initdata = -1; static int irq __initdata = -1; static int mem __initdata = -1; +static int write_ndelay __initdata = -1; #ifndef MSND_CLASSIC /* Pinnacle/Fiji non-PnP Config Port */ @@ -1535,6 +1676,8 @@ int init_module(void) #else /* not a module */ +static int write_ndelay __initdata = -1; + #ifdef MSND_CLASSIC static int io __initdata = CONFIG_MSNDCLAS_IO; static int irq __initdata = CONFIG_MSNDCLAS_IRQ; @@ -1558,7 +1701,7 @@ static int mem __initdata = CONFIG_MSNDPIN_MEM; #endif static int cfg __initdata = CONFIG_MSNDPIN_CFG; /* If not a module, we don't need to bother with reset=1 */ -static int reset __initdata; +static int reset; /* Extra Peripheral Configuration (Default: Disable) */ #ifndef CONFIG_MSNDPIN_MPU_IO @@ -1626,10 +1769,8 @@ __initfunc(int msnd_pinnacle_init(void)) printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version " VERSION ", Copyright (C) 1998 Andrew Veliath\n"); - if (io == -1 || irq == -1 || mem == -1) { - + if (io == -1 || irq == -1 || mem == -1) printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n"); - } if (io == -1 || !(io == 0x290 || @@ -1640,7 +1781,6 @@ __initfunc(int msnd_pinnacle_init(void)) io == 0x220 || io == 0x210 || io == 0x3e0)) { - printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, or 0x3E0\n"); return -EINVAL; } @@ -1652,7 +1792,6 @@ __initfunc(int msnd_pinnacle_init(void)) irq == 10 || irq == 11 || irq == 12)) { - printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n"); return -EINVAL; } @@ -1664,7 +1803,6 @@ __initfunc(int msnd_pinnacle_init(void)) mem == 0xd8000 || mem == 0xe0000 || mem == 0xe8000)) { - printk(KERN_ERR LOGNAME ": \"mem\" - must be set to " "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n"); return -EINVAL; @@ -1734,9 +1872,10 @@ __initfunc(int msnd_pinnacle_init(void)) if (fifosize < 16) fifosize = 16; - if (fifosize > 768) - fifosize = 768; + if (fifosize > 1024) + fifosize = 1024; + set_default_audio_parameters(); #ifdef MSND_CLASSIC dev.type = msndClassic; #else @@ -1751,6 +1890,12 @@ __initfunc(int msnd_pinnacle_init(void)) dev.recsrc = 0; dev.inc_ref = mod_inc_ref; dev.dec_ref = mod_dec_ref; + if (write_ndelay == -1) + write_ndelay = CONFIG_MSND_WRITE_NDELAY; + if (write_ndelay) + clear_bit(F_DISABLE_WRITE_NDELAY, &dev.flags); + else + set_bit(F_DISABLE_WRITE_NDELAY, &dev.flags); #ifndef MSND_CLASSIC if (digital) { @@ -1771,34 +1916,28 @@ __initfunc(int msnd_pinnacle_init(void)) printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize); if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) { - printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n"); return err; } if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) { - printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n"); msnd_fifo_free(&dev.DAPF); return err; } if ((err = probe_multisound()) < 0) { - printk(KERN_ERR LOGNAME ": Probe failed\n"); msnd_fifo_free(&dev.DAPF); msnd_fifo_free(&dev.DARF); return err; - } if ((err = attach_multisound()) < 0) { - printk(KERN_ERR LOGNAME ": Attach failed\n"); msnd_fifo_free(&dev.DAPF); msnd_fifo_free(&dev.DARF); return err; - } return 0; @@ -1813,6 +1952,5 @@ void cleanup_module(void) msnd_fifo_free(&dev.DAPF); msnd_fifo_free(&dev.DARF); - } #endif diff --git a/drivers/sound/msnd_pinnacle.h b/drivers/sound/msnd_pinnacle.h index 0ae9a1026..2f572af2c 100644 --- a/drivers/sound/msnd_pinnacle.h +++ b/drivers/sound/msnd_pinnacle.h @@ -24,7 +24,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: msnd_pinnacle.h,v 1.8 1998/09/03 06:39:47 andrewtv Exp $ + * $Id: msnd_pinnacle.h,v 1.10 1998/09/10 04:11:18 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_PINNACLE_H diff --git a/drivers/sound/opl3sa2.c b/drivers/sound/opl3sa2.c new file mode 100644 index 000000000..d9d95c278 --- /dev/null +++ b/drivers/sound/opl3sa2.c @@ -0,0 +1,241 @@ +/* + * sound/opl3sa2.c + * + * A low level driver for Yamaha OPL3-SA[2,3,x] based cards. + * + * Scott Murray, Jun 14, 1998 + * + */ + +/* Based on the CS4232 driver: + * + * Copyright (C) by Hannu Savolainen 1993-1997 + * + * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) + * Version 2 (June 1991). See the "COPYING" file distributed with this software + * for more info. + */ + +#include <linux/config.h> +#include <linux/module.h> + +#include "sound_config.h" +#include "soundmodule.h" + +#ifdef CONFIG_OPL3SA2 + +int probe_opl3sa2_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + return probe_mpu401(hw_config); +#else + return 0; +#endif +} + + +void attach_opl3sa2_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + attach_mpu401(hw_config); +#endif +} + + +void unload_opl3sa2_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + unload_mpu401(hw_config); +#endif +} + + +int probe_opl3sa2_mss(struct address_info *hw_config) +{ + return probe_ms_sound(hw_config); +} + + +void attach_opl3sa2_mss(struct address_info *hw_config) +{ + printk(KERN_INFO "opl3sa2.c: trying to init WSS\n"); + + attach_ms_sound(hw_config); + + /* request_region(hw_config->io_base, 4, "Yamaha 7xx WSS Config"); */ + + if (hw_config->slots[0] != -1 && + audio_devs[hw_config->slots[0]]->mixer_dev != -1) + { + AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD); + AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH); + /* GSM! test the following: */ + AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE); + } +} + + +void unload_opl3sa2_mss(struct address_info *hw_config) +{ + int mixer; + + /* Find mixer */ + mixer = audio_devs[hw_config->slots[0]]->mixer_dev; + + /* Unload MSS audio codec */ + unload_ms_sound(hw_config); + + sound_unload_audiodev(hw_config->slots[0]); + + /* Unload mixer if there */ + if(mixer >= 0) + { + sound_unload_mixerdev(mixer); + } + + /* Release MSS config ports */ + release_region(hw_config->io_base, 4); +} + + +int probe_opl3sa2(struct address_info *hw_config) +{ + /* + * Verify that the I/O port range is free. + */ + + printk(KERN_INFO "opl3sa2.c: Control using I/O port 0x%03x\n", hw_config->io_base); + + if (check_region(hw_config->io_base, 2)) + { + printk(KERN_ERR "opl3sa2.c: Control I/O port 0x%03x not free\n", hw_config->io_base); + return 0; + } + + /* GSM!: Add some kind of other test here... */ + + return 1; +} + + +void attach_opl3sa2(struct address_info *hw_config) +{ + printk(KERN_INFO "opl3sa2.c: trying to init!\n"); + + request_region(hw_config->io_base, 2, "Yamaha 7xx Control"); + + /* GSM! Mixer stuff should go here... */ +} + + +void unload_opl3sa2(struct address_info *hw_config) +{ + /* Release control ports */ + release_region(hw_config->io_base, 2); + + /* GSM! Mixer stuff should go here... */ +} + + +#ifdef MODULE + +int io = -1; +int mss_io = -1; +int mpu_io = -1; +int irq = -1; +int dma = -1; +int dma2 = -1; + +MODULE_PARM(io,"i"); +MODULE_PARM(mss_io,"i"); +MODULE_PARM(mpu_io,"i"); +MODULE_PARM(irq,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(dma2,"i"); + +EXPORT_NO_SYMBOLS; + +struct address_info cfg; +struct address_info mss_cfg; +struct address_info mpu_cfg; + +/* + * Install a OPL3SA2 based card. Need to have ad1848 and mpu401 + * loaded ready. + */ +int init_module(void) +{ + int i; + + if (io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1) + { + printk(KERN_ERR "opl3sa2: io, mss_io, irq, dma, and dma2 must be set.\n"); + return -EINVAL; + } + + /* Our own config: */ + cfg.io_base = io; + cfg.irq = irq; + cfg.dma = dma; + cfg.dma2 = dma2; + + /* The MSS config: */ + mss_cfg.io_base = mss_io; + mss_cfg.irq = irq; + mss_cfg.dma = dma; + mss_cfg.dma2 = dma2; + mss_cfg.card_subtype = 1; /* No IRQ or DMA setup */ + + /* Call me paranoid: */ + for(i = 0; i < 6; i++) + { + cfg.slots[i] = mss_cfg.slots[i] = mpu_cfg.slots[i] = -1; + } + + if (probe_opl3sa2(&cfg) == 0) + { + return -ENODEV; + } + attach_opl3sa2(&cfg); + + if (probe_opl3sa2_mss(&mss_cfg) == 0) + { + return -ENODEV; + } + attach_opl3sa2_mss(&mss_cfg); + +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + if(mpu_io != -1) + { + /* MPU config: */ + mpu_cfg.io_base = mpu_io; + mpu_cfg.irq = irq; + mpu_cfg.dma = dma; + mpu_cfg.always_detect = 1; /* It's there, so use shared IRQs */ + + if (probe_opl3sa2_mpu(&mpu_cfg)) + { + attach_opl3sa2_mpu(&mpu_cfg); + } + } +#endif + SOUND_LOCK; + return 0; +} + + +void cleanup_module(void) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + if(mpu_cfg.slots[1] != -1) + { + unload_opl3sa2_mpu(&mpu_cfg); + } +#endif + unload_opl3sa2_mss(&mss_cfg); + unload_opl3sa2(&cfg); + SOUND_LOCK_END; +} + +#endif +#endif diff --git a/drivers/sound/os.h b/drivers/sound/os.h index 794036b81..2b2be83d5 100644 --- a/drivers/sound/os.h +++ b/drivers/sound/os.h @@ -48,7 +48,6 @@ extern void sound_close_dma(int chn); extern void reprogram_timer(void); -#define RUNTIME_DMA_ALLOC #define USE_AUTOINIT_DMA extern caddr_t sound_mem_blocks[1024]; diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index fd6e0b6f5..701be5289 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -796,7 +796,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int l data = (unsigned short *)mbuf->data; save_flags(flags); cli(); - for (i = 0; i < mbuf->len; i++) { + for (i = 0; i < sizeof(mbuf->data)/sizeof(unsigned short); i++) { mbuf->len = i; /* feed back number of WORDs read */ if (!pss_get_dspword(devc, data++)) { if (i == 0) diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h index 19f8ee825..dc864646e 100644 --- a/drivers/sound/sb.h +++ b/drivers/sound/sb.h @@ -87,15 +87,20 @@ typedef struct sb_devc { /* State variables */ int opened; + /* new audio fields for full duplex support */ + int fullduplex; + int duplex; int speed, bits, channels; volatile int irq_ok; volatile int intr_active, irq_mode; + /* duplicate audio fields for full duplex support */ + volatile int intr_active_16, irq_mode_16; /* Mixer fields */ int *levels; mixer_tab *iomap; - int mixer_caps, recmask, supported_devices; - int supported_rec_devices; + int mixer_caps, recmask, outmask, supported_devices; + int supported_rec_devices, supported_out_devices; int my_mixerdev; int sbmixnum; @@ -105,6 +110,13 @@ typedef struct sb_devc { int trg_bytes; int trg_intrflag; int trg_restart; + /* duplicate audio fields for full duplex support */ + unsigned long trg_buf_16; + int trigger_bits_16; + int trg_bytes_16; + int trg_intrflag_16; + int trg_restart_16; + unsigned char tconst; int my_dev; @@ -122,7 +134,7 @@ void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); unsigned int sb_getmixer (sb_devc *devc, unsigned int port); int sb_dsp_detect (struct address_info *hw_config); int sb_dsp_init (struct address_info *hw_config); -void sb_dsp_unload(struct address_info *hw_config); +void sb_dsp_unload(struct address_info *hw_config, int sbmpu); int sb_mixer_init(sb_devc *devc); void sb_mixer_set_stereo (sb_devc *devc, int mode); void smw_mixer_init(sb_devc *devc); diff --git a/drivers/sound/sb_audio.c b/drivers/sound/sb_audio.c index 971a7414f..b14924e4e 100644 --- a/drivers/sound/sb_audio.c +++ b/drivers/sound/sb_audio.c @@ -15,6 +15,10 @@ * * Status * Mostly working. Weird uart bug causing irq storms + * + * Daniel J. Rodriksson: Changes to make sb16 work full duplex. + * Maybe other 16 bit cards in this code could behave + * the same. */ #include <linux/config.h> @@ -47,7 +51,7 @@ static int sb_audio_open(int dev, int mode) restore_flags(flags); return -EBUSY; } - if (devc->dma16 != -1 && devc->dma16 != devc->dma8) + if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex) { if (sound_open_dma(devc->dma16, "Sound Blaster 16 bit")) { @@ -59,6 +63,9 @@ static int sb_audio_open(int dev, int mode) restore_flags(flags); devc->irq_mode = IMODE_NONE; + devc->irq_mode_16 = IMODE_NONE; + devc->fullduplex = devc->duplex && + ((mode & OPEN_READ) && (mode & OPEN_WRITE)); sb_dsp_reset(devc); /* The ALS007 seems to require that the DSP be removed from the output */ @@ -84,9 +91,11 @@ static void sb_audio_close(int dev) { sb_devc *devc = audio_devs[dev]->devc; - audio_devs[dev]->dmap_in->dma = audio_devs[dev]->dmap_out->dma = devc->dma8; + audio_devs[dev]->dmap_out->dma = devc->dma8; + audio_devs[dev]->dmap_in->dma = ( devc->duplex ) ? + devc->dma16 : devc->dma8; - if (devc->dma16 != -1 && devc->dma16 != devc->dma8) + if (devc->dma16 != -1 && devc->dma16 != devc->dma8 && !devc->duplex) sound_close_dma(devc->dma16); /* For ALS007, turn DSP output back on if closing the device for read */ @@ -104,20 +113,40 @@ static void sb_set_output_parms(int dev, unsigned long buf, int nr_bytes, { sb_devc *devc = audio_devs[dev]->devc; - devc->trg_buf = buf; - devc->trg_bytes = nr_bytes; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_OUTPUT; + if (!devc->fullduplex || devc->bits == AFMT_S16_LE) + { + devc->trg_buf = buf; + devc->trg_bytes = nr_bytes; + devc->trg_intrflag = intrflag; + devc->irq_mode = IMODE_OUTPUT; + } + else + { + devc->trg_buf_16 = buf; + devc->trg_bytes_16 = nr_bytes; + devc->trg_intrflag_16 = intrflag; + devc->irq_mode_16 = IMODE_OUTPUT; + } } static void sb_set_input_parms(int dev, unsigned long buf, int count, int intrflag) { sb_devc *devc = audio_devs[dev]->devc; - devc->trg_buf = buf; - devc->trg_bytes = count; - devc->trg_intrflag = intrflag; - devc->irq_mode = IMODE_INPUT; + if (!devc->fullduplex || devc->bits != AFMT_S16_LE) + { + devc->trg_buf = buf; + devc->trg_bytes = count; + devc->trg_intrflag = intrflag; + devc->irq_mode = IMODE_INPUT; + } + else + { + devc->trg_buf_16 = buf; + devc->trg_bytes_16 = count; + devc->trg_intrflag_16 = intrflag; + devc->irq_mode_16 = IMODE_INPUT; + } } /* @@ -830,9 +859,23 @@ static int sb16_audio_prepare_for_input(int dev, int bsize, int bcount) { sb_devc *devc = audio_devs[dev]->devc; - audio_devs[dev]->dmap_out->dma = - audio_devs[dev]->dmap_in->dma = - devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; + if (!devc->fullduplex) + { + audio_devs[dev]->dmap_out->dma = + audio_devs[dev]->dmap_in->dma = + devc->bits == AFMT_S16_LE ? + devc->dma16 : devc->dma8; + } + else if (devc->bits == AFMT_S16_LE) + { + audio_devs[dev]->dmap_out->dma = devc->dma8; + audio_devs[dev]->dmap_in->dma = devc->dma16; + } + else + { + audio_devs[dev]->dmap_out->dma = devc->dma16; + audio_devs[dev]->dmap_in->dma = devc->dma8; + } devc->trigger_bits = 0; return 0; @@ -842,8 +885,23 @@ static int sb16_audio_prepare_for_output(int dev, int bsize, int bcount) { sb_devc *devc = audio_devs[dev]->devc; - audio_devs[dev]->dmap_out->dma = audio_devs[dev]->dmap_in->dma = - devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; + if (!devc->fullduplex) + { + audio_devs[dev]->dmap_out->dma = + audio_devs[dev]->dmap_in->dma = + devc->bits == AFMT_S16_LE ? + devc->dma16 : devc->dma8; + } + else if (devc->bits == AFMT_S16_LE) + { + audio_devs[dev]->dmap_out->dma = devc->dma8; + audio_devs[dev]->dmap_in->dma = devc->dma16; + } + else + { + audio_devs[dev]->dmap_out->dma = devc->dma16; + audio_devs[dev]->dmap_in->dma = devc->dma8; + } devc->trigger_bits = 0; return 0; @@ -854,9 +912,27 @@ static void sb16_audio_output_block(int dev, unsigned long buf, int count, { unsigned long flags, cnt; sb_devc *devc = audio_devs[dev]->devc; + unsigned long bits; - devc->irq_mode = IMODE_OUTPUT; - devc->intr_active = 1; + if (!devc->fullduplex || devc->bits == AFMT_S16_LE) + { + devc->irq_mode = IMODE_OUTPUT; + devc->intr_active = 1; + } + else + { + devc->irq_mode_16 = IMODE_OUTPUT; + devc->intr_active_16 = 1; + } + + /* save value */ + save_flags (flags); + cli (); + bits = devc->bits; + if (devc->fullduplex) + devc->bits = (devc->bits == AFMT_S16_LE) ? + AFMT_U8 : AFMT_S16_LE; + restore_flags (flags); cnt = count; if (devc->bits == AFMT_S16_LE) @@ -878,6 +954,8 @@ static void sb16_audio_output_block(int dev, unsigned long buf, int count, sb_dsp_command(devc, (unsigned char) (cnt & 0xff)); sb_dsp_command(devc, (unsigned char) (cnt >> 8)); + /* restore real value after all programming */ + devc->bits = bits; restore_flags(flags); } @@ -886,8 +964,16 @@ static void sb16_audio_start_input(int dev, unsigned long buf, int count, int in unsigned long flags, cnt; sb_devc *devc = audio_devs[dev]->devc; - devc->irq_mode = IMODE_INPUT; - devc->intr_active = 1; + if (!devc->fullduplex || devc->bits != AFMT_S16_LE) + { + devc->irq_mode = IMODE_INPUT; + devc->intr_active = 1; + } + else + { + devc->irq_mode_16 = IMODE_INPUT; + devc->intr_active_16 = 1; + } cnt = count; if (devc->bits == AFMT_S16_LE) @@ -916,29 +1002,141 @@ static void sb16_audio_trigger(int dev, int bits) { sb_devc *devc = audio_devs[dev]->devc; + int bits_16 = bits & devc->irq_mode_16; bits &= devc->irq_mode; - if (!bits) + if (!bits && !bits_16) sb_dsp_command(devc, 0xd0); /* Halt DMA */ else { - switch (devc->irq_mode) + if (bits) { - case IMODE_INPUT: - sb16_audio_start_input(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; - - case IMODE_OUTPUT: - sb16_audio_output_block(dev, devc->trg_buf, devc->trg_bytes, - devc->trg_intrflag); - break; + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb16_audio_start_input(dev, + devc->trg_buf, + devc->trg_bytes, + devc->trg_intrflag); + break; + + case IMODE_OUTPUT: + sb16_audio_output_block(dev, + devc->trg_buf, + devc->trg_bytes, + devc->trg_intrflag); + break; + } + } + if (bits_16) + { + switch (devc->irq_mode_16) + { + case IMODE_INPUT: + sb16_audio_start_input(dev, + devc->trg_buf_16, + devc->trg_bytes_16, + devc->trg_intrflag_16); + break; + + case IMODE_OUTPUT: + sb16_audio_output_block(dev, + devc->trg_buf_16, + devc->trg_bytes_16, + devc->trg_intrflag_16); + break; + } } } - devc->trigger_bits = bits; + devc->trigger_bits = bits | bits_16; } +static unsigned char lbuf8[2048]; +static signed short *lbuf16 = (signed short *)lbuf8; +#define LBUFCOPYSIZE 1024 +static void +sb16_copy_from_user(int dev, + char *localbuf, int localoffs, + const char *userbuf, int useroffs, + int max_in, int max_out, + int *used, int *returned, + int len) +{ + sb_devc *devc = audio_devs[dev]->devc; + int i, c, p, locallen; + unsigned char *buf8; + signed short *buf16; + + /* if not duplex no conversion */ + if (!devc->fullduplex) + { + copy_from_user (localbuf + localoffs, userbuf + useroffs, len); + *used = len; + *returned = len; + } + else if (devc->bits == AFMT_S16_LE) + { + /* 16 -> 8 */ + /* max_in >> 1, max number of samples in ( 16 bits ) */ + /* max_out, max number of samples out ( 8 bits ) */ + /* len, number of samples that will be taken ( 16 bits )*/ + /* c, count of samples remaining in buffer ( 16 bits )*/ + /* p, count of samples already processed ( 16 bits )*/ + len = ( (max_in >> 1) > max_out) ? max_out : (max_in >> 1); + c = len; + p = 0; + buf8 = (unsigned char *)(localbuf + localoffs); + while (c) + { + locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); + /* << 1 in order to get 16 bit samples */ + copy_from_user (lbuf16, + userbuf+useroffs + (p << 1), + locallen << 1); + for (i = 0; i < locallen; i++) + { + buf8[p+i] = ~((lbuf16[i] >> 8) & 0xff) ^ 0x80; + } + c -= locallen; p += locallen; + } + /* used = ( samples * 16 bits size ) */ + *used = len << 1; + /* returned = ( samples * 8 bits size ) */ + *returned = len; + } + else + { + /* 8 -> 16 */ + /* max_in, max number of samples in ( 8 bits ) */ + /* max_out >> 1, max number of samples out ( 16 bits ) */ + /* len, number of samples that will be taken ( 8 bits )*/ + /* c, count of samples remaining in buffer ( 8 bits )*/ + /* p, count of samples already processed ( 8 bits )*/ + len = max_in > (max_out >> 1) ? (max_out >> 1) : max_in; + c = len; + p = 0; + buf16 = (signed short *)(localbuf + localoffs); + while (c) + { + locallen = (c >= LBUFCOPYSIZE ? LBUFCOPYSIZE : c); + copy_from_user (lbuf8, + userbuf+useroffs + p, + locallen); + for (i = 0; i < locallen; i++) + { + buf16[p+i] = (~lbuf8[i] ^ 0x80) << 8; + } + c -= locallen; p += locallen; + } + /* used = ( samples * 8 bits size ) */ + *used = len; + /* returned = ( samples * 16 bits size ) */ + *returned = len << 1; + } +} + + static struct audio_driver sb1_audio_driver = /* SB1.x */ { sb_audio_open, @@ -1050,7 +1248,7 @@ static struct audio_driver sb16_audio_driver = /* SB16 */ sb16_audio_prepare_for_output, sb1_audio_halt_xfer, NULL, /* local_qlen */ - NULL, /* copy_from_user */ + sb16_copy_from_user, /* copy_from_user */ NULL, NULL, sb16_audio_trigger, @@ -1124,6 +1322,11 @@ void sb_audio_init(sb_devc * devc, char *name) DDB(printk("Will use SB16 driver\n")); audio_flags = DMA_AUTOMODE; format_mask |= AFMT_S16_LE; + if (devc->dma8 != devc->dma16 && devc->dma16 != -1) + { + audio_flags |= DMA_DUPLEX; + devc->duplex = 1; + } driver = &sb16_audio_driver; break; @@ -1136,7 +1339,8 @@ void sb_audio_init(sb_devc * devc, char *name) if ((devc->my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, name,driver, sizeof(struct audio_driver), audio_flags, format_mask, devc, - devc->dma8, devc->dma8)) < 0) + devc->dma8, + devc->duplex ? devc->dma16 : devc->dma8) < 0)) { printk(KERN_ERR "Sound Blaster: unable to install audio.\n"); return; diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index 2fc88cb24..24a3aa829 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -12,6 +12,9 @@ */ #include <linux/config.h> +#ifdef CONFIG_MCA +#include <linux/mca.h> +#endif #include <linux/module.h> #include "sound_config.h" @@ -22,6 +25,8 @@ #include "sb_mixer.h" #include "sb.h" +static int sbmpu = 0; + void attach_sb_card(struct address_info *hw_config) { #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) @@ -32,6 +37,67 @@ void attach_sb_card(struct address_info *hw_config) int probe_sb(struct address_info *hw_config) { +#ifdef CONFIG_MCA + /* MCA code added by ZP Gu (zpg@castle.net) */ + if (MCA_bus) { /* no multiple REPLY card probing */ + int slot; + u8 pos2, pos3, pos4; + + slot = mca_find_adapter( 0x5138, 0 ); + if( slot == MCA_NOTFOUND ) + { + slot = mca_find_adapter( 0x5137, 0 ); + + if (slot != MCA_NOTFOUND) + mca_set_adapter_name( slot, "REPLY SB16 & SCSI Adapter" ); + } + else + { + mca_set_adapter_name( slot, "REPLY SB16 Adapter" ); + } + + if (slot != MCA_NOTFOUND) + { + mca_mark_as_used(slot); + pos2 = mca_read_stored_pos( slot, 2 ); + pos3 = mca_read_stored_pos( slot, 3 ); + pos4 = mca_read_stored_pos( slot, 4 ); + + if (pos2 & 0x4) + { + /* enabled? */ + static unsigned short irq[] = { 0, 5, 7, 10 }; + /* + static unsigned short midiaddr[] = {0, 0x330, 0, 0x300 }; + */ + + hw_config->io_base = 0x220 + 0x20 * (pos2 >> 6); + hw_config->irq = irq[(pos4 >> 5) & 0x3]; + hw_config->dma = pos3 & 0xf; + /* Reply ADF wrong on High DMA, pos[1] should start w/ 00 */ + hw_config->dma2 = (pos3 >> 4) & 0x3; + if (hw_config->dma2 == 0) + hw_config->dma2 = hw_config->dma; + else + hw_config->dma2 += 4; + /* + hw_config->driver_use_2 = midiaddr[(pos2 >> 3) & 0x3]; + */ + + printk("SB: Reply MCA SB at slot=%d \ +iobase=0x%x irq=%d lo_dma=%d hi_dma=%d\n", + slot+1, + hw_config->io_base, hw_config->irq, + hw_config->dma, hw_config->dma2); + } + else + { + printk ("Reply SB Base I/O address disabled\n"); + } + } + } +#endif + if (check_region(hw_config->io_base, 16)) { printk(KERN_ERR "sb_card: I/O port %x is already in use\n\n", hw_config->io_base); @@ -43,7 +109,7 @@ int probe_sb(struct address_info *hw_config) void unload_sb(struct address_info *hw_config) { if(hw_config->slots[0]!=-1) - sb_dsp_unload(hw_config); + sb_dsp_unload(hw_config, sbmpu); } int sb_be_quiet=0; @@ -82,8 +148,6 @@ MODULE_PARM(trix, "i"); MODULE_PARM(pas2, "i"); MODULE_PARM(sm_games, "i"); -static int sbmpu = 0; - void *smw_free = NULL; int init_module(void) @@ -113,8 +177,6 @@ int init_module(void) config_mpu.io_base = mpu_io; if (mpu_io && probe_sbmpu(&config_mpu)) sbmpu = 1; -#endif -#ifdef CONFIG_MIDI if (sbmpu) attach_sbmpu(&config_mpu); #endif diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 04b3d7854..34f82ff70 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -10,7 +10,10 @@ * Version 2 (June 1991). See the "COPYING" file distributed with this software * for more info. */ - +/* + * Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts + * for full duplex support ( only sb16 by now ) + */ #include <linux/config.h> #include <linux/delay.h> #include <asm/init.h> @@ -140,7 +143,7 @@ static void sbintr(int irq, void *dev_id, struct pt_regs *dummy) if (!(src & 3)) return; /* Not a DSP interrupt */ } - if (devc->intr_active) + if (devc->intr_active && (!devc->fullduplex || (src & 0x01))) { switch (devc->irq_mode) { @@ -166,6 +169,26 @@ static void sbintr(int irq, void *dev_id, struct pt_regs *dummy) ; } } + else if (devc->intr_active_16 && (src & 0x02)) + { + switch (devc->irq_mode_16) + { + case IMODE_OUTPUT: + DMAbuf_outputintr(devc->dev, 1); + break; + + case IMODE_INPUT: + DMAbuf_inputintr(devc->dev); + break; + + case IMODE_INIT: + break; + + default: + /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */ + ; + } + } /* * Acknowledge interrupts */ @@ -592,6 +615,7 @@ int sb_dsp_detect(struct address_info *hw_config) sb_devc sb_info; sb_devc *devc = &sb_info; + memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */ sb_info.my_mididev = -1; sb_info.my_mixerdev = -1; sb_info.my_dev = -1; @@ -608,7 +632,6 @@ int sb_dsp_detect(struct address_info *hw_config) #endif return 0; } - memset((char *) &sb_info, 0, sizeof(sb_info)); /* Zero everything */ devc->type = hw_config->card_subtype; @@ -855,6 +878,7 @@ int sb_dsp_init(struct address_info *hw_config) if(!sb16_set_dma_hw(devc)) { free_irq(devc->irq, devc); + release_region(hw_config->io_base, 16); return 0; } @@ -932,7 +956,10 @@ void sb_dsp_disable_recording(int io_base) { } -void sb_dsp_unload(struct address_info *hw_config) +/* if (sbmpu) below we allow mpu401 to manage the midi devs + otherwise we have to unload them. (Andrzej Krzysztofowicz) */ + +void sb_dsp_unload(struct address_info *hw_config, int sbmpu) { sb_devc *devc; @@ -954,7 +981,9 @@ void sb_dsp_unload(struct address_info *hw_config) sound_unload_mixerdev(devc->my_mixerdev); /* We don't have to do this bit any more the UART401 is its own master -- Krzysztof Halasa */ - /* sound_unload_mididev(devc->my_mididev); */ + /* But we have to do it, if UART401 is not detected */ + if (!sbmpu) + sound_unload_mididev(devc->my_mididev); sound_unload_audiodev(devc->my_dev); } kfree(devc); @@ -1301,10 +1330,8 @@ int probe_sbmpu(struct address_info *hw_config) } hw_config->name = "Sound Blaster 16"; hw_config->irq = -devc->irq; -#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) if (devc->minor > 12) /* What is Vibra's version??? */ sb16_set_mpu_port(devc, hw_config); -#endif break; case MDL_ESS: diff --git a/drivers/sound/sb_midi.c b/drivers/sound/sb_midi.c index 970ec4a0b..31a299a96 100644 --- a/drivers/sound/sb_midi.c +++ b/drivers/sound/sb_midi.c @@ -182,8 +182,6 @@ void sb_dsp_midi_init(sb_devc * devc) printk(KERN_ERR "sb_midi: too many MIDI devices detected\n"); return; } - std_midi_synth.midi_dev = dev; - devc->my_mididev = dev; std_midi_synth.midi_dev = devc->my_mididev = dev; midi_devs[dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL); if (midi_devs[dev] == NULL) diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c index 7c4af3d03..aaab4907d 100644 --- a/drivers/sound/sb_mixer.c +++ b/drivers/sound/sb_mixer.c @@ -294,6 +294,39 @@ static int set_recmask(sb_devc * devc, int mask) return devc->recmask; } +static int set_outmask(sb_devc * devc, int mask) +{ + int devmask, i; + unsigned char regimage; + + devmask = mask & devc->supported_out_devices; + + switch (devc->model) + { + case MDL_SB16: + if (devc->submodel == SUBMDL_ALS007) + break; + else + { + regimage = 0; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + { + if ((1 << i) & devmask) + { + regimage |= (sb16_recmasks_L[i] | sb16_recmasks_R[i]); + } + sb_setmixer (devc, SB16_OMASK, regimage); + } + } + break; + default: + break; + } + + devc->outmask = devmask; + return devc->outmask; +} + static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) { sb_devc *devc = mixer_devs[dev]->devc; @@ -321,6 +354,10 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) ret = set_recmask(devc, val); break; + case SOUND_MIXER_OUTSRC: + ret = set_outmask(devc, val); + break; + default: ret = sb_mixer_set(devc, cmd & 0xff, val); } @@ -331,13 +368,20 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) ret = devc->recmask; break; + case SOUND_MIXER_OUTSRC: + ret = devc->outmask; + break; + case SOUND_MIXER_DEVMASK: ret = devc->supported_devices; break; case SOUND_MIXER_STEREODEVS: ret = devc->supported_devices; - if (devc->model != MDL_JAZZ && devc->model != MDL_SMW) + /* The ESS seems to have stereo mic controls */ + if (devc->model == MDL_ESS) + ret &= ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX); + else if (devc->model != MDL_JAZZ && devc->model != MDL_SMW) ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); break; @@ -345,6 +389,10 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) ret = devc->supported_rec_devices; break; + case SOUND_MIXER_OUTMASK: + ret = devc->supported_out_devices; + break; + case SOUND_MIXER_CAPS: ret = devc->mixer_caps; break; @@ -432,6 +480,7 @@ int sb_mixer_init(sb_devc * devc) case MDL_SB16: devc->mixer_caps = 0; devc->supported_rec_devices = SB16_RECORDING_DEVICES; + devc->supported_out_devices = SB16_OUTFILTER_DEVICES; if (devc->submodel != SUBMDL_ALS007) { devc->supported_devices = SB16_MIXER_DEVICES; diff --git a/drivers/sound/sb_mixer.h b/drivers/sound/sb_mixer.h index 714b8a4d8..7f61e6e0c 100644 --- a/drivers/sound/sb_mixer.h +++ b/drivers/sound/sb_mixer.h @@ -41,6 +41,9 @@ #define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ SOUND_MASK_CD) +#define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD) + #define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES #define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER) @@ -99,6 +102,7 @@ /* * Mixer registers of SB16 */ +#define SB16_OMASK 0x3c #define SB16_IMASK_L 0x3d #define SB16_IMASK_R 0x3e @@ -197,7 +201,7 @@ MIX_ENT(SOUND_MIXER_SYNTH, 0x66, 7, 4, 0x66, 3, 4), MIX_ENT(SOUND_MIXER_PCM, 0x64, 7, 4, 0x64, 3, 4), MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_LINE, 0x6e, 7, 4, 0x6e, 3, 4), -MIX_ENT(SOUND_MIXER_MIC, 0x6a, 6, 3, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_MIC, 0x6a, 2, 3, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_CD, 0x68, 7, 4, 0x68, 3, 4), MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index 514333512..b5cb59cdf 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -113,9 +113,9 @@ int sequencer_read(int dev, struct file *file, char *buf, int count) restore_flags(flags); return -EAGAIN; } - current->timeout = pre_event_timeout ? jiffies + pre_event_timeout : 0; - interruptible_sleep_on(&midi_sleeper); - current->timeout = 0; + + interruptible_sleep_on_timeout(&midi_sleeper, + pre_event_timeout); if (!iqlen) { restore_flags(flags); @@ -355,7 +355,6 @@ static int seq_queue(unsigned char *note, char nonblock) /* * Sleep until there is enough space on the queue */ - current->timeout = 0; interruptible_sleep_on(&seq_sleeper); } if (qlen >= SEQ_MAX_QUEUE) @@ -1026,7 +1025,7 @@ int sequencer_open(int dev, struct file *file) max_mididev = num_midis; max_synthdev = num_synths; - pre_event_timeout = 0; + pre_event_timeout = MAX_SCHEDULE_TIMEOUT; seq_mode = SEQ_1; if (pending_timer != -1) @@ -1153,11 +1152,9 @@ void seq_drain_midi_queues(void) * Let's have a delay */ - if (n) { - current->timeout = jiffies + HZ / 10; - interruptible_sleep_on(&seq_sleeper); - current->timeout = 0; - } + if (n) + interruptible_sleep_on_timeout(&seq_sleeper, + HZ/10); } } @@ -1179,9 +1176,8 @@ void sequencer_release(int dev, struct file *file) while (!signal_pending(current) && qlen > 0) { seq_sync(); - current->timeout = jiffies + 3 * HZ; - interruptible_sleep_on(&seq_sleeper); - current->timeout = 0; + interruptible_sleep_on_timeout(&seq_sleeper, + 3*HZ); /* Extra delay */ } } @@ -1233,11 +1229,8 @@ static int seq_sync(void) save_flags(flags); cli(); - if (qlen > 0) { - current->timeout = jiffies + HZ; - interruptible_sleep_on(&seq_sleeper); - current->timeout = 0; - } + if (qlen > 0) + interruptible_sleep_on_timeout(&seq_sleeper, HZ); restore_flags(flags); return qlen; } @@ -1262,9 +1255,7 @@ static void midi_outc(int dev, unsigned char data) save_flags(flags); cli(); while (n && !midi_devs[dev]->outputc(dev, data)) { - current->timeout = jiffies + 4; - interruptible_sleep_on(&seq_sleeper); - current->timeout = 0; + interruptible_sleep_on_timeout(&seq_sleeper, HZ/25); n--; } restore_flags(flags); @@ -1540,12 +1531,12 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) return 0; case SNDCTL_MIDI_INFO: - if (get_user(dev, (int *)(&(((struct synth_info *)arg)->device)))) + if (get_user(dev, (int *)(&(((struct midi_info *)arg)->device)))) return -EFAULT; if (dev < 0 || dev >= max_mididev) return -ENXIO; midi_devs[dev]->info.device = dev; - return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct synth_info))?-EFAULT:0; + return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct midi_info))?-EFAULT:0; case SNDCTL_SEQ_THRESHOLD: if (get_user(val, (int *)arg)) diff --git a/drivers/sound/sgalaxy.c b/drivers/sound/sgalaxy.c index 4e5cb870e..baff3e5cc 100644 --- a/drivers/sound/sgalaxy.c +++ b/drivers/sound/sgalaxy.c @@ -29,9 +29,7 @@ static void sleep( unsigned howlong ) { current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + howlong; - schedule(); - current->timeout = 0; + schedule_timeout(howlong); } #define DPORT 0x80 @@ -93,7 +91,7 @@ int probe_sgalaxy( struct address_info *ai ) } if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) ) - return 1; /* The card is already active */ + return probe_ms_sound(ai); /* The card is already active, check irq etc... */ if ( check_region( ai->ai_sgbase, 0x10 ) ) { @@ -110,9 +108,7 @@ int probe_sgalaxy( struct address_info *ai ) sleep( HZ/10 ); - if ( ad1848_detect( ai->io_base+4, NULL, ai->osp ) ) - return 1; - return 0; + return probe_ms_sound(ai); } void attach_sgalaxy( struct address_info *ai ) diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index 82d0461a4..b57cd186a 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -1245,11 +1245,8 @@ static int drain_dac(struct sv_state *s, int nonblock) } tmo = (count * HZ) / s->ratedac; tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK]; - current->timeout = jiffies + (tmo ? tmo : 1); - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "sv: dma timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->dma_dac.wait, &wait); current->state = TASK_RUNNING; @@ -2025,11 +2022,8 @@ static int sv_midi_release(struct inode *inode, struct file *file) return -EBUSY; } tmo = (count * HZ) / 3100; - current->timeout = tmo ? jiffies + tmo : 0; - schedule(); - if (tmo && !current->timeout) + if (!schedule_timeout(tmo ? : 1) && tmo) printk(KERN_DEBUG "sv: midi timed out??\n"); - current->timeout = 0; } remove_wait_queue(&s->midi.owait, &wait); current->state = TASK_RUNNING; diff --git a/drivers/sound/sound_calls.h b/drivers/sound/sound_calls.h index a5d2272b4..8c91cb72d 100644 --- a/drivers/sound/sound_calls.h +++ b/drivers/sound/sound_calls.h @@ -251,6 +251,8 @@ void unload_trix_sb(struct address_info *hw_info); void unload_trix_mpu(struct address_info *hw_info); void unload_cs4232(struct address_info *hw_info); void unload_cs4232_mpu(struct address_info *hw_info); +void unload_opl3sa2(struct address_info *hw_info); +void unload_opl3sa2_mpu(struct address_info *hw_info); /* From cs4232.c */ @@ -259,6 +261,12 @@ void attach_cs4232 (struct address_info *hw_config); int probe_cs4232_mpu (struct address_info *hw_config); void attach_cs4232_mpu (struct address_info *hw_config); +/* From opl3sa2.c */ +int probe_opl3sa2 (struct address_info *hw_config); +void attach_opl3sa2 (struct address_info *hw_config); +int probe_opl3sa2_mpu (struct address_info *hw_config); +void attach_opl3sa2_mpu (struct address_info *hw_config); + /* From maui.c */ void attach_maui(struct address_info * hw_config); int probe_maui(struct address_info *hw_config); diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 1fbb368d8..b830afdd2 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -15,6 +15,8 @@ * integrated sound_switch.c * Stefan Reinauer : integrated /proc/sound (equals to /dev/sndstat, * which should disappear in the near future) + * + * Rob Riggs Added persistent DMA buffers support (1998/10/17) */ #include <linux/config.h> @@ -64,6 +66,9 @@ static int is_unloading = 0; caddr_t sound_mem_blocks[1024]; int sound_nblocks = 0; +/* Persistent DMA buffers */ +int sound_dmap_flag = 0; /* Off by default */ + static int soundcard_configured = 0; static char dma_alloc_map[MAX_DMA_CHANNELS] = @@ -287,11 +292,13 @@ static int sound_proc_get_info(char *buffer, char **start, off_t offset, int len return len; } +#ifdef CONFIG_PROC_FS static struct proc_dir_entry proc_root_sound = { PROC_SOUND, 5, "sound", S_IFREG | S_IRUGO, 1, 0, 0, 0, NULL, sound_proc_get_info }; +#endif #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) @@ -837,8 +844,10 @@ soundcard_init(void) audio_init_devices(); } #endif +#ifdef CONFIG_PROC_FS if (proc_register(&proc_root, &proc_root_sound)) printk(KERN_ERR "sound: registering /proc/sound failed\n"); +#endif } static int sound[20] = { @@ -848,7 +857,9 @@ static int sound[20] = { #ifdef MODULE int traceinit = 0; +static int dmabuf = 0; MODULE_PARM(traceinit, "i"); +MODULE_PARM(dmabuf, "i"); int init_module(void) { @@ -874,6 +885,10 @@ int init_module(void) printk(KERN_ERR "sound: driver already loaded/included in kernel\n"); return err; } + + /* Protecting the innocent */ + sound_dmap_flag = (dmabuf > 0 ? 1 : 0); + chrdev_registered = 1; soundcard_init(); diff --git a/drivers/sound/sscape.c b/drivers/sound/sscape.c index 1b823692c..48017eeed 100644 --- a/drivers/sound/sscape.c +++ b/drivers/sound/sscape.c @@ -124,10 +124,8 @@ static char old_hardware = 0; static void sleep(unsigned howlong) { - current->timeout = jiffies + 1; current->state = TASK_INTERRUPTIBLE; - schedule(); - current->timeout = 0; + schedule_timeout(1); } static unsigned char sscape_read(struct sscape_info *devc, int reg) diff --git a/drivers/sound/trix.c b/drivers/sound/trix.c index 1ed1b8d78..97113a838 100644 --- a/drivers/sound/trix.c +++ b/drivers/sound/trix.c @@ -39,6 +39,8 @@ static int mpu_initialized = 0; static int *trix_osp = NULL; +static int mpu = 0; + static unsigned char trix_read(int addr) { outb(((unsigned char) addr), 0x390); /* MT-0002-PC ASIC address */ @@ -445,7 +447,7 @@ void unload_trix_mpu(struct address_info *hw_config) void unload_trix_sb(struct address_info *hw_config) { #ifdef CONFIG_SBDSP - sb_dsp_unload(hw_config); + sb_dsp_unload(hw_config, mpu); #endif } @@ -479,7 +481,6 @@ struct address_info config; struct address_info sb_config; struct address_info mpu_config; -static int mpu = 0; static int sb = 0; static int fw_load; diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c index 3740dd263..b2e33ab1a 100644 --- a/drivers/sound/wavfront.c +++ b/drivers/sound/wavfront.c @@ -49,7 +49,7 @@ * aspects of configuring a WaveFront soundcard, particularly the * effects processor. * - * $Id: wavfront.c,v 0.4 1998/07/22 02:12:11 pbd Exp $ + * $Id: wavfront.c,v 0.5 1998/07/22 16:16:41 pbd Exp $ * * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) * Version 2 (June 1991). See the "COPYING" file distributed with this software @@ -343,11 +343,8 @@ static int wavefront_sleep (wf_config *hw, int limit) { - current->timeout = jiffies + limit; current->state = TASK_INTERRUPTIBLE; - schedule(); - current->timeout = 0; - + schedule_timeout(limit); return signal_pending(current); } @@ -667,16 +664,16 @@ wavefront_cmd (wf_config *hw, int cmd, /*********************************************************************** WaveFront: data munging -Things here are weird. All data written to the board cannot -have its most significant bit set. Any data item with values +Things here are wierd. All data written to the board cannot +have its most significant bit set. Any data item with values potentially > 0x7F (127) must be split across multiple bytes. Sometimes, we need to munge numeric values that are represented on -the x86 side as 8- to 32-bit values. Sometimes, we need to munge data -that is represented on the x86 side as an array of bytes. The most +the x86 side as 8-32 bit values. Sometimes, we need to munge data +that is represented on the x86 side as an array of bytes. The most efficient approach to handling both cases seems to be to use 2 -different functions for munging and 2 for de-munging. This avoids -weird casting and worrying about bit-level offsets. +different functions for munging and 2 for de-munging. This avoids +wierd casting and worrying about bit-level offsets. **********************************************************************/ @@ -1198,14 +1195,14 @@ wavefront_send_sample (wf_config *hw, shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset), shptr, 4); - /* This one is truly weird. What kind of weirdo decided that in - a system dominated by 16- and 32-bit integers, they would use - just 12 bits ? + /* This one is truly wierd. What kind of wierdo decided that in + a system dominated by 16 and 32 bit integers, they would use + a just 12 bits ? */ shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); - /* Why is this nybblified, when the MSB is *always* zero? + /* Why is this nybblified, when the MSB is *always* zero ? Anyway, we can't take address of bitfield, so make a good-faith guess at where it starts. */ @@ -2058,14 +2055,12 @@ wavefront_open (int dev, int mode) return (0); } -static void -wavefront_close (int dev) - +static void wavefront_close (int dev) { struct wf_config *hw = &wavefront_configuration; - int i; #ifdef WF_STATS + int i; printk ("Status during loop: %ld\n", hw->status_found_during_loop); for (i = 0; i < 4; i++) { printk ("Status during sleep[%d]: %ld\n", @@ -2078,42 +2073,36 @@ wavefront_close (int dev) return; } -static void -wavefront_aftertouch (int dev, int channel, int pressure) +static void wavefront_aftertouch (int dev, int channel, int pressure) { midi_synth_aftertouch (wavefront_configuration.mididev,channel,pressure); }; -static void -wavefront_bender (int dev, int chn, int value) +static void wavefront_bender (int dev, int chn, int value) { midi_synth_bender (wavefront_configuration.mididev, chn, value); }; -static void -wavefront_controller (int dev, int channel, int ctrl_num, int value) +static void wavefront_controller (int dev, int channel, int ctrl_num, int value) { if(ctrl_num==CTRL_PITCH_BENDER) wavefront_bender(0,channel,value); midi_synth_controller (wavefront_configuration.mididev, channel,ctrl_num,value); }; -static void -wavefront_panning(int dev, int channel, int pressure) +static void wavefront_panning(int dev, int channel, int pressure) { midi_synth_controller (wavefront_configuration.mididev, channel,CTL_PAN,pressure); }; -static int -wavefront_set_instr (int dev, int channel, int instr_no) +static int wavefront_set_instr (int dev, int channel, int instr_no) { return(midi_synth_set_instr (wavefront_configuration.mididev, channel,instr_no)); }; -static int -wavefront_kill_note (int dev, int channel, int note, int volume) +static int wavefront_kill_note (int dev, int channel, int note, int volume) { if (note==255) return (midi_synth_start_note (wavefront_configuration.mididev, @@ -2122,8 +2111,7 @@ wavefront_kill_note (int dev, int channel, int note, int volume) channel, note, volume)); }; -static int -wavefront_start_note (int dev, int channel, int note, int volume) +static int wavefront_start_note (int dev, int channel, int note, int volume) { if (note==255) { midi_synth_aftertouch (wavefront_configuration.mididev, @@ -2143,13 +2131,11 @@ wavefront_start_note (int dev, int channel, int note, int volume) return(0); }; -static void -wavefront_setup_voice (int dev, int voice, int chn) +static void wavefront_setup_voice (int dev, int voice, int chn) { }; static void wavefront_reset (int dev) - { int i; @@ -2266,8 +2252,7 @@ wavefront_should_cause_interrupt (wf_config *hw, int val, int port, int timeout) cli(); hw->irq_ok = 0; outb (val,port); - current->timeout = jiffies + timeout; - interruptible_sleep_on (&hw->interrupt_sleeper); + interruptible_sleep_on_timeout(&hw->interrupt_sleeper, timeout); restore_flags (flags); } @@ -2278,6 +2263,12 @@ wavefront_hw_reset (wf_config *hw) int bits; int hwv[2]; + /* Check IRQ is legal */ + + if ((bits = wavefront_interrupt_bits (hw->irq)) < 0) { + return 1; + } + if (request_irq (hw->irq, wavefrontintr, 0, "WaveFront", (void *) hw) < 0) { printk (KERN_WARNING "WaveFront: IRQ %d not available!\n", @@ -2325,10 +2316,6 @@ wavefront_hw_reset (wf_config *hw) plus external 9-pin MIDI interface selected */ - if ((bits = wavefront_interrupt_bits (hw->irq)) < 0) { - return 1; - } - outb (0x80 | 0x40 | bits, hw->data_port); /* CONTROL REGISTER @@ -2350,7 +2337,6 @@ wavefront_hw_reset (wf_config *hw) wait till it gets back to use. After a cold boot, this can take some time. - I think this is because its only after a cold boot that the onboard ROM does its memory check, which can take "up to 4 seconds" according to the WaveFront SDK. So, since sleeping @@ -2797,51 +2783,50 @@ wavefront_do_reset (wf_config *hw, int atboot) if (hw->israw || wf_raw) { if (wavefront_download_firmware (hw, ospath)) { goto gone_bad; - return 1; } - } - - if (fx_raw) { - wffx_init (hw); - } - - /* If we loaded the OS, we now have to wait for it to be ready - to roll. We can't guarantee that interrupts are enabled, - because we might be reloading the module without forcing a - reset/reload of the firmware. - - Rather than busy-wait, lets just turn interrupts on. - */ - outb (0x80|0x40|0x10|0x1, hw->control_port); + /* Wait for the OS to get running. The protocol for + this is non-obvious, and was determined by + using port-IO tracing in DOSemu and some + experimentation here. + + Rather than busy-wait, use interrupts creatively. + */ - wavefront_should_cause_interrupt (hw, WFC_NOOP, + wavefront_should_cause_interrupt (hw, WFC_NOOP, hw->data_port, (10*HZ)); - - if (!hw->irq_ok) { - printk (KERN_WARNING "WaveFront: no post-OS interrupt.\n"); - goto gone_bad; - } - - /* Now, do it again ! */ + + if (!hw->irq_ok) { + printk (KERN_WARNING + "WaveFront: no post-OS interrupt.\n"); + goto gone_bad; + } + + /* Now, do it again ! */ + + wavefront_should_cause_interrupt (hw, WFC_NOOP, + hw->data_port, (10*HZ)); + + if (!hw->irq_ok) { + printk (KERN_WARNING + "WaveFront: no post-OS interrupt(2).\n"); + goto gone_bad; + } - wavefront_should_cause_interrupt (hw, WFC_NOOP, - hw->data_port, (10*HZ)); - - if (!hw->irq_ok) { - printk (KERN_WARNING "WaveFront: no post-OS interrupt(2).\n"); - goto gone_bad; + /* OK, no (RX/TX) interrupts any more, but leave mute + on. Master interrupts get enabled when we're done here. + */ + + outb (0x80, hw->control_port); + + /* No need for the IRQ anymore */ + + free_irq (hw->irq, hw); } - - /* OK, no (RX/TX) interrupts any more, but leave mute - on. Master interrupts get enabled when we're done here. - */ - - outb (0x80, hw->control_port); - /* No need for the IRQ anymore */ - - free_irq (hw->irq, hw); + if (/*XXX has_fx_device() && */ fx_raw) { + wffx_init (hw); + } /* SETUPSND.EXE asks for sample memory config here, but since i have no idea how to interpret the result, we'll forget @@ -3109,14 +3094,14 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r) /* YSS225 initialization. - This code was developed using DOSEmu. The Turtle Beach SETUPSND - utility was run with I/O tracing in DOSEmu enabled, and a reconstruction + This code was developed using DOSEMU. The Turtle Beach SETUPSND + utility was run with I/O tracing in DOSEMU enabled, and a reconstruction of the port I/O done, using the Yamaha faxback document as a guide - to add more logic to the code. It's really pretty weird. + to add more logic to the code. Its really pretty wierd. There was an alternative approach of just dumping the whole I/O sequence as a series of port/value pairs and a simple loop - that output it. However, I hope that eventually I'll get more + that output it. However, I hope that eventually I'll get more control over what this code does, and so I tried to stick with a somewhat "algorithmic" approach. */ @@ -3592,7 +3577,7 @@ int init_module (void) { printk ("Turtle Beach WaveFront Driver\n" - "Copyright (C) by Hannu Savolainen, " + "Copyright (C) by Hannu Solvainen, " "Paul Barton-Davis 1993-1998.\n"); if (io == -1 || irq == -1) { diff --git a/drivers/sound/wf_midi.c b/drivers/sound/wf_midi.c index 2333fd118..ee26fb1ec 100644 --- a/drivers/sound/wf_midi.c +++ b/drivers/sound/wf_midi.c @@ -375,24 +375,25 @@ wf_mpu_input_scanner (struct wf_mpu_config *devc, unsigned char midic) return 1; } -void -wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy) +void wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy) { struct wf_mpu_config *devc; - int dev; + int dev; static struct wf_mpu_config *isrc = 0; - int n; + int n; struct midi_input_info *mi; - static int cnt = 0; - if (irq < 0 || irq > 15) { + if (irq < 0 || irq > 15) + { printk (KERN_ERR "WF-MPU: bogus interrupt #%d", irq); return; } dev = irq2dev[irq]; mi = &midi_devs[dev]->in_info; - if (mi->m_busy) return; + if (mi->m_busy) + return; mi->m_busy = 1; + sti (); n = 50; @@ -445,8 +446,7 @@ wf_mpuintr (int irq, void *dev_id, struct pt_regs *dummy) mi->m_busy = 0; } -static int -wf_mpu_open (int dev, int mode, +static int wf_mpu_open (int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev) ) |