diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-12-06 23:51:34 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-12-06 23:51:34 +0000 |
commit | 230e5ab6a084ed50470f101934782dbf54b0d06b (patch) | |
tree | 5dd821c8d33f450470588e7a543f74bf74306e9e /drivers/sound/pss.c | |
parent | c9b1c8a64c6444d189856f1e26bdcb8b4cd0113a (diff) |
Merge with Linux 2.1.67.
Diffstat (limited to 'drivers/sound/pss.c')
-rw-r--r-- | drivers/sound/pss.c | 1347 |
1 files changed, 687 insertions, 660 deletions
diff --git a/drivers/sound/pss.c b/drivers/sound/pss.c index 52374790f..2a9080a8f 100644 --- a/drivers/sound/pss.c +++ b/drivers/sound/pss.c @@ -11,11 +11,13 @@ * for more info. */ #include <linux/config.h> - +#include <linux/module.h> #include "sound_config.h" +#include "sound_firmware.h" +#include "soundmodule.h" -#if defined(CONFIG_PSS) && defined(CONFIG_AUDIO) +#if (defined(CONFIG_PSS) && defined(CONFIG_AUDIO))||defined(MODULE) /* * PSS registers. @@ -60,10 +62,10 @@ NULL; typedef struct pss_confdata { - int base; - int irq; - int dma; - int *osp; + int base; + int irq; + int dma; + int *osp; } pss_confdata; @@ -75,819 +77,844 @@ static int pss_initialized = 0; static int nonstandard_microcode = 0; static void -pss_write (int data) +pss_write(int data) { - int i, limit; - - limit = jiffies + 10; /* The timeout is 0.1 seconds */ - /* - * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 5000000 && jiffies < limit; i++) - { - if (inw (devc->base + PSS_STATUS) & PSS_WRITE_EMPTY) - { - outw (devc->base + PSS_DATA, data); - return; - } - } - printk ("PSS: DSP Command (%04x) Timeout.\n", data); + int i, limit; + + limit = jiffies + 10; /* The timeout is 0.1 seconds */ + /* + * Note! the i<5000000 is an emergency exit. The dsp_command() is sometimes + * called while interrupts are disabled. This means that the timer is + * disabled also. However the timeout situation is a abnormal condition. + * Normally the DSP should be ready to accept commands after just couple of + * loops. + */ + + for (i = 0; i < 5000000 && jiffies < limit; i++) + { + if (inw(devc->base + PSS_STATUS) & PSS_WRITE_EMPTY) + { + outw(devc->base + PSS_DATA, data); + return; + } + } + printk("PSS: DSP Command (%04x) Timeout.\n", data); } int -probe_pss (struct address_info *hw_config) +probe_pss(struct address_info *hw_config) { - unsigned short id; - int irq, dma; - - devc->base = hw_config->io_base; - irq = devc->irq = hw_config->irq; - dma = devc->dma = hw_config->dma; - devc->osp = hw_config->osp; - - if (devc->base != 0x220 && devc->base != 0x240) - if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ - return 0; - - if (check_region (devc->base, 16)) - { - printk ("PSS: I/O port conflict\n"); - return 0; - } - - id = inw (REG (PSS_ID)); - if ((id >> 8) != 'E') - { - /* printk ("No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); */ - return 0; - } - - return 1; + unsigned short id; + int irq, dma; + + devc->base = hw_config->io_base; + irq = devc->irq = hw_config->irq; + dma = devc->dma = hw_config->dma; + devc->osp = hw_config->osp; + + if (devc->base != 0x220 && devc->base != 0x240) + if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ + return 0; + + if (check_region(devc->base, 16)) + { + printk("PSS: I/O port conflict\n"); + return 0; + } + id = inw(REG(PSS_ID)); + if ((id >> 8) != 'E') + { + /* printk( "No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); */ + return 0; + } + return 1; } static int -set_irq (pss_confdata * devc, int dev, int irq) +set_irq(pss_confdata * devc, int dev, int irq) { - static unsigned short irq_bits[16] = - { - 0x0000, 0x0000, 0x0000, 0x0008, - 0x0000, 0x0010, 0x0000, 0x0018, - 0x0000, 0x0020, 0x0028, 0x0030, - 0x0038, 0x0000, 0x0000, 0x0000 - }; - - unsigned short tmp, bits; + static unsigned short irq_bits[16] = + { + 0x0000, 0x0000, 0x0000, 0x0008, + 0x0000, 0x0010, 0x0000, 0x0018, + 0x0000, 0x0020, 0x0028, 0x0030, + 0x0038, 0x0000, 0x0000, 0x0000 + }; - if (irq < 0 || irq > 15) - return 0; + unsigned short tmp, bits; - tmp = inw (REG (dev)) & ~0x38; /* Load confreg, mask IRQ bits out */ + if (irq < 0 || irq > 15) + return 0; - if ((bits = irq_bits[irq]) == 0 && irq != 0) - { - printk ("PSS: Invalid IRQ %d\n", irq); - return 0; - } + tmp = inw(REG(dev)) & ~0x38; /* Load confreg, mask IRQ bits out */ - outw (tmp | bits, REG (dev)); - return 1; + if ((bits = irq_bits[irq]) == 0 && irq != 0) + { + printk("PSS: Invalid IRQ %d\n", irq); + return 0; + } + outw(tmp | bits, REG(dev)); + return 1; } static int -set_io_base (pss_confdata * devc, int dev, int base) +set_io_base(pss_confdata * devc, int dev, int base) { - unsigned short tmp = inw (REG (dev)) & 0x003f; - unsigned short bits = (base & 0x0ffc) << 4; + unsigned short tmp = inw(REG(dev)) & 0x003f; + unsigned short bits = (base & 0x0ffc) << 4; - outw (bits | tmp, REG (dev)); + outw(bits | tmp, REG(dev)); - return 1; + return 1; } static int -set_dma (pss_confdata * devc, int dev, int dma) +set_dma(pss_confdata * devc, int dev, int dma) { - static unsigned short dma_bits[8] = - { - 0x0001, 0x0002, 0x0000, 0x0003, - 0x0000, 0x0005, 0x0006, 0x0007 - }; - - unsigned short tmp, bits; + static unsigned short dma_bits[8] = + { + 0x0001, 0x0002, 0x0000, 0x0003, + 0x0000, 0x0005, 0x0006, 0x0007 + }; - if (dma < 0 || dma > 7) - return 0; + unsigned short tmp, bits; - tmp = inw (REG (dev)) & ~0x07; /* Load confreg, mask DMA bits out */ + if (dma < 0 || dma > 7) + return 0; - if ((bits = dma_bits[dma]) == 0 && dma != 4) - { - printk ("PSS: Invalid DMA %d\n", dma); - return 0; - } + tmp = inw(REG(dev)) & ~0x07; /* Load confreg, mask DMA bits out */ - outw (tmp | bits, REG (dev)); - return 1; + if ((bits = dma_bits[dma]) == 0 && dma != 4) + { + printk("PSS: Invalid DMA %d\n", dma); + return 0; + } + outw(tmp | bits, REG(dev)); + return 1; } static int -pss_reset_dsp (pss_confdata * devc) +pss_reset_dsp(pss_confdata * devc) { - unsigned long i, limit = jiffies + 10; + unsigned long i, limit = jiffies + 10; - outw (0x2000, REG (PSS_CONTROL)); + outw(0x2000, REG(PSS_CONTROL)); - for (i = 0; i < 32768 && jiffies < limit; i++) - inw (REG (PSS_CONTROL)); + for (i = 0; i < 32768 && jiffies < limit; i++) + inw(REG(PSS_CONTROL)); - outw (0x0000, REG (PSS_CONTROL)); + outw(0x0000, REG(PSS_CONTROL)); - return 1; + return 1; } static int -pss_put_dspword (pss_confdata * devc, unsigned short word) +pss_put_dspword(pss_confdata * devc, unsigned short word) { - int i, val; + int i, val; - for (i = 0; i < 327680; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & PSS_WRITE_EMPTY) - { - outw (word, REG (PSS_DATA)); - return 1; - } - } - return 0; + for (i = 0; i < 327680; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_WRITE_EMPTY) + { + outw(word, REG(PSS_DATA)); + return 1; + } + } + return 0; } static int -pss_get_dspword (pss_confdata * devc, unsigned short *word) +pss_get_dspword(pss_confdata * devc, unsigned short *word) { - int i, val; + int i, val; - for (i = 0; i < 327680; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & PSS_READ_FULL) - { - *word = inw (REG (PSS_DATA)); - return 1; - } - } + for (i = 0; i < 327680; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_READ_FULL) + { + *word = inw(REG(PSS_DATA)); + return 1; + } + } - return 0; + return 0; } static int -pss_download_boot (pss_confdata * devc, unsigned char *block, int size, int flags) +pss_download_boot(pss_confdata * devc, unsigned char *block, int size, int flags) { - int i, limit, val, count; + int i, limit, val, count; - if (flags & CPF_FIRST) - { + if (flags & CPF_FIRST) + { /*_____ Warn DSP software that a boot is coming */ - outw (0x00fe, REG (PSS_DATA)); + outw(0x00fe, REG(PSS_DATA)); - limit = jiffies + 10; + limit = jiffies + 10; - for (i = 0; i < 32768 && jiffies < limit; i++) - if (inw (REG (PSS_DATA)) == 0x5500) - break; + for (i = 0; i < 32768 && jiffies < limit; i++) + if (inw(REG(PSS_DATA)) == 0x5500) + break; - outw (*block++, REG (PSS_DATA)); + outw(*block++, REG(PSS_DATA)); - pss_reset_dsp (devc); - } - - count = 1; - while (1) - { - int j; + pss_reset_dsp(devc); + } + count = 1; + while (1) + { + int j; - for (j = 0; j < 327670; j++) - { + for (j = 0; j < 327670; j++) + { /*_____ Wait for BG to appear */ - if (inw (REG (PSS_STATUS)) & PSS_FLAG3) - break; - } - - if (j == 327670) - { - /* It's ok we timed out when the file was empty */ - if (count >= size && flags & CPF_LAST) - break; - else - { - printk ("\nPSS: Download timeout problems, byte %d=%d\n", - count, size); - return 0; - } - } + if (inw(REG(PSS_STATUS)) & PSS_FLAG3) + break; + } + + if (j == 327670) + { + /* It's ok we timed out when the file was empty */ + if (count >= size && flags & CPF_LAST) + break; + else + { + printk("\nPSS: Download timeout problems, byte %d=%d\n", count, size); + return 0; + } + } /*_____ Send the next byte */ - outw (*block++, REG (PSS_DATA)); - count++; - } + outw(*block++, REG(PSS_DATA)); + count++; + } - if (flags & CPF_LAST) - { + if (flags & CPF_LAST) + { /*_____ Why */ - outw (0, REG (PSS_DATA)); - - limit = jiffies + 10; - for (i = 0; i < 32768 && jiffies < limit; i++) - val = inw (REG (PSS_STATUS)); - - limit = jiffies + 10; - for (i = 0; i < 32768 && jiffies < limit; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & 0x4000) - break; - } - - /* now read the version */ - for (i = 0; i < 32000; i++) - { - val = inw (REG (PSS_STATUS)); - if (val & PSS_READ_FULL) - break; - } - if (i == 32000) - return 0; - - val = inw (REG (PSS_DATA)); - /* printk("<PSS: microcode version %d.%d loaded>", val/16, val % 16); */ - } - - return 1; + outw(0, REG(PSS_DATA)); + + limit = jiffies + 10; + for (i = 0; i < 32768 && jiffies < limit; i++) + val = inw(REG(PSS_STATUS)); + + limit = jiffies + 10; + for (i = 0; i < 32768 && jiffies < limit; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & 0x4000) + break; + } + + /* now read the version */ + for (i = 0; i < 32000; i++) + { + val = inw(REG(PSS_STATUS)); + if (val & PSS_READ_FULL) + break; + } + if (i == 32000) + return 0; + + val = inw(REG(PSS_DATA)); + /* printk( "<PSS: microcode version %d.%d loaded>", val/16, val % 16); */ + } + return 1; } void -attach_pss (struct address_info *hw_config) +attach_pss(struct address_info *hw_config) { - unsigned short id; - char tmp[100]; + unsigned short id; + char tmp[100]; - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma = hw_config->dma; - devc->osp = hw_config->osp; + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma = hw_config->dma; + devc->osp = hw_config->osp; - if (!probe_pss (hw_config)) - return; + if (!probe_pss(hw_config)) + return; - id = inw (REG (PSS_ID)) & 0x00ff; + id = inw(REG(PSS_ID)) & 0x00ff; - /* - * Disable all emulations. Will be enabled later (if required). - */ - outw (0x0000, REG (CONF_PSS)); /* 0x0400 enables joystick */ - outw (0x0000, REG (CONF_WSS)); - outw (0x0000, REG (CONF_SB)); - outw (0x0000, REG (CONF_MIDI)); - outw (0x0000, REG (CONF_CDROM)); + /* + * Disable all emulations. Will be enabled later (if required). + */ + outw(0x0000, REG(CONF_PSS)); /* 0x0400 enables joystick */ + outw(0x0000, REG(CONF_WSS)); + outw(0x0000, REG(CONF_SB)); + outw(0x0000, REG(CONF_MIDI)); + outw(0x0000, REG(CONF_CDROM)); #if YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES - if (sound_alloc_dma (hw_config->dma, "PSS")) - { - printk ("pss.c: Can't allocate DMA channel\n"); - return; - } - - if (!set_irq (devc, CONF_PSS, devc->irq)) - { - printk ("PSS: IRQ error\n"); - return; - } - - if (!set_dma (devc, CONF_PSS, devc->dma)) - { - printk ("PSS: DRQ error\n"); - return; - } + if (sound_alloc_dma(hw_config->dma, "PSS")) + { + printk("pss.c: Can't allocate DMA channel\n"); + return; + } + if (!set_irq(devc, CONF_PSS, devc->irq)) + { + printk("PSS: IRQ error\n"); + return; + } + if (!set_dma(devc, CONF_PSS, devc->dma)) + { + printk("PSS: DRQ error\n"); + return; + } #endif - pss_initialized = 1; - sprintf (tmp, "ECHO-PSS Rev. %d", id); - conf_printf (tmp, hw_config); + pss_initialized = 1; + sprintf(tmp, "ECHO-PSS Rev. %d", id); + conf_printf(tmp, hw_config); } static void -pss_init_speaker (void) +pss_init_speaker(void) { /* Don't ask what are these commands. I really don't know */ - pss_write (0x0010); - pss_write (0x0000 | 252); /* Left master volume */ - pss_write (0x0010); - pss_write (0x0100 | 252); /* Right master volume */ - pss_write (0x0010); - pss_write (0x0200 | 246); /* Bass */ - pss_write (0x0010); - pss_write (0x0300 | 246); /* Treble */ - pss_write (0x0010); - pss_write (0x0800 | 0x00ce); /* Stereo switch? */ + pss_write(0x0010); + pss_write(0x0000 | 252); /* Left master volume */ + pss_write(0x0010); + pss_write(0x0100 | 252); /* Right master volume */ + pss_write(0x0010); + pss_write(0x0200 | 246); /* Bass */ + pss_write(0x0010); + pss_write(0x0300 | 246); /* Treble */ + pss_write(0x0010); + pss_write(0x0800 | 0x00ce); /* Stereo switch? */ } int -probe_pss_mpu (struct address_info *hw_config) +probe_pss_mpu(struct address_info *hw_config) { - int timeout; - - if (!pss_initialized) - return 0; - - if (check_region (hw_config->io_base, 2)) - { - printk ("PSS: MPU I/O port conflict\n"); - return 0; - } - - if (!set_io_base (devc, CONF_MIDI, hw_config->io_base)) - { - printk ("PSS: MIDI base error.\n"); - return 0; - } - - if (!set_irq (devc, CONF_MIDI, hw_config->irq)) - { - printk ("PSS: MIDI IRQ error.\n"); - return 0; - } - - if (!pss_synthLen) - { - printk ("PSS: Can't enable MPU. MIDI synth microcode not available.\n"); - return 0; - } - - if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - return 0; - } - - pss_init_speaker (); + int timeout; + + if (!pss_initialized) + return 0; + + if (check_region(hw_config->io_base, 2)) + { + printk("PSS: MPU I/O port conflict\n"); + return 0; + } + if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) + { + printk("PSS: MIDI base error.\n"); + return 0; + } + if (!set_irq(devc, CONF_MIDI, hw_config->irq)) + { + printk("PSS: MIDI IRQ error.\n"); + return 0; + } + if (!pss_synthLen) + { + printk("PSS: Can't enable MPU. MIDI synth microcode not available.\n"); + return 0; + } + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); + return 0; + } + pss_init_speaker(); /* * Finally wait until the DSP algorithm has initialized itself and * deactivates receive interrupt. */ - for (timeout = 900000; timeout > 0; timeout--) - { - if ((inb (hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */ - inb (hw_config->io_base); /* Discard it */ - else - break; /* No more input */ - } + for (timeout = 900000; timeout > 0; timeout--) + { + if ((inb(hw_config->io_base + 1) & 0x80) == 0) /* Input data avail */ + inb(hw_config->io_base); /* Discard it */ + else + break; /* No more input */ + } #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - return probe_mpu401 (hw_config); + return probe_mpu401(hw_config); #else - return 0; + return 0; #endif } static int -pss_coproc_open (void *dev_info, int sub_device) +pss_coproc_open(void *dev_info, int sub_device) { - switch (sub_device) - { - case COPR_MIDI: - - if (pss_synthLen == 0) - { - printk ("PSS: MIDI synth microcode not available.\n"); - return -EIO; - } - - if (nonstandard_microcode) - if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + switch (sub_device) { - printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - return -EIO; + case COPR_MIDI: + + if (pss_synthLen == 0) + { + printk("PSS: MIDI synth microcode not available.\n"); + return -EIO; + } + if (nonstandard_microcode) + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); + return -EIO; + } + nonstandard_microcode = 0; + break; + + default:; } - nonstandard_microcode = 0; - break; - - default:; - } - return 0; + return 0; } static void -pss_coproc_close (void *dev_info, int sub_device) +pss_coproc_close(void *dev_info, int sub_device) { - return; + return; } static void -pss_coproc_reset (void *dev_info) +pss_coproc_reset(void *dev_info) { - if (pss_synthLen) - if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { - printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - } - nonstandard_microcode = 0; + if (pss_synthLen) + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) + { + printk("PSS: Unable to load MIDI synth microcode to DSP.\n"); + } + nonstandard_microcode = 0; } static int -download_boot_block (void *dev_info, copr_buffer * buf) +download_boot_block(void *dev_info, copr_buffer * buf) { - if (buf->len <= 0 || buf->len > sizeof (buf->data)) - return -EINVAL; - - if (!pss_download_boot (devc, buf->data, buf->len, buf->flags)) - { - printk ("PSS: Unable to load microcode block to DSP.\n"); - return -EIO; - } - nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ - - return 0; -} + if (buf->len <= 0 || buf->len > sizeof(buf->data)) + return -EINVAL; -static int -pss_coproc_ioctl (void *dev_info, unsigned int cmd, caddr_t arg, int local) -{ - /* printk("PSS coproc ioctl %x %x %d\n", cmd, arg, local); */ - - switch (cmd) - { - case SNDCTL_COPR_RESET: - pss_coproc_reset (dev_info); - return 0; - break; - - case SNDCTL_COPR_LOAD: - { - copr_buffer *buf; - int err; - - buf = (copr_buffer *) vmalloc (sizeof (copr_buffer)); - if (buf == NULL) - return -ENOSPC; - - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); - err = download_boot_block (dev_info, buf); - vfree (buf); - return err; - } - break; - - case SNDCTL_COPR_SENDMSG: - { - copr_msg *buf; - unsigned long flags; - unsigned short *data; - int i; - - buf = (copr_msg *) vmalloc (sizeof (copr_msg)); - if (buf == NULL) - return -ENOSPC; - - memcpy ((char *) buf, (&((char *) arg)[0]), sizeof (*buf)); - - data = (unsigned short *) (buf->data); - - save_flags (flags); - cli (); - - for (i = 0; i < buf->len; i++) + if (!pss_download_boot(devc, buf->data, buf->len, buf->flags)) { - if (!pss_put_dspword (devc, *data++)) - { - restore_flags (flags); - buf->len = i; /* feed back number of WORDs sent */ - memcpy ((&((char *) arg)[0]), (char *) buf, sizeof (*buf)); - vfree (buf); - return -EIO; - } + printk("PSS: Unable to load microcode block to DSP.\n"); + return -EIO; } - - restore_flags (flags); - vfree (buf); + nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ return 0; - } - break; - - - case SNDCTL_COPR_RCVMSG: - { - copr_msg *buf; - unsigned long flags; - unsigned short *data; - unsigned int i; - int err = 0; - - buf = (copr_msg *) vmalloc (sizeof (copr_msg)); - if (buf == NULL) - return -ENOSPC; - - - data = (unsigned short *) buf->data; +} - save_flags (flags); - cli (); +static int +pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local) +{ + /* printk( "PSS coproc ioctl %x %x %d\n", cmd, arg, local); */ - for (i = 0; i < buf->len; i++) + switch (cmd) { - buf->len = i; /* feed back number of WORDs read */ - if (!pss_get_dspword (devc, data++)) - { - if (i == 0) - err = -EIO; - break; - } + case SNDCTL_COPR_RESET: + pss_coproc_reset(dev_info); + return 0; + break; + + case SNDCTL_COPR_LOAD: + { + copr_buffer *buf; + int err; + + buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); + if (buf == NULL) + return -ENOSPC; + + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); + err = download_boot_block(dev_info, buf); + vfree(buf); + return err; + } + break; + + case SNDCTL_COPR_SENDMSG: + { + copr_msg *buf; + unsigned long flags; + unsigned short *data; + int i; + + buf = (copr_msg *) vmalloc(sizeof(copr_msg)); + if (buf == NULL) + return -ENOSPC; + + memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf)); + + data = (unsigned short *) (buf->data); + + save_flags(flags); + cli(); + + for (i = 0; i < buf->len; i++) + { + if (!pss_put_dspword(devc, *data++)) + { + restore_flags(flags); + buf->len = i; /* feed back number of WORDs sent */ + memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf)); + vfree(buf); + return -EIO; + } + } + + restore_flags(flags); + vfree(buf); + + return 0; + } + break; + + + case SNDCTL_COPR_RCVMSG: + { + copr_msg *buf; + unsigned long flags; + unsigned short *data; + unsigned int i; + int err = 0; + + buf = (copr_msg *) vmalloc(sizeof(copr_msg)); + if (buf == NULL) + return -ENOSPC; + + + data = (unsigned short *) buf->data; + + save_flags(flags); + cli(); + + for (i = 0; i < buf->len; i++) + { + buf->len = i; /* feed back number of WORDs read */ + if (!pss_get_dspword(devc, data++)) + { + if (i == 0) + err = -EIO; + break; + } + } + + restore_flags(flags); + + memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf)); + vfree(buf); + + return err; + } + break; + + + case SNDCTL_COPR_RDATA: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d0)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + if (!pss_get_dspword(devc, &tmp)) + { + restore_flags(flags); + return -EIO; + } + buf.parm1 = tmp; + restore_flags(flags); + + memcpy((&((char *) arg)[0]), (char *) &buf, sizeof(buf)); + return 0; + } + break; + + case SNDCTL_COPR_WDATA: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d1)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + tmp = (unsigned int) buf.parm2 & 0xffff; + if (!pss_put_dspword(devc, tmp)) + { + restore_flags(flags); + return -EIO; + } + restore_flags(flags); + return 0; + } + break; + + case SNDCTL_COPR_WCODE: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d3)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + tmp = (unsigned int) buf.parm2 & 0x00ff; + if (!pss_put_dspword(devc, tmp)) + { + restore_flags(flags); + return -EIO; + } + tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff; + if (!pss_put_dspword(devc, tmp)) + { + restore_flags(flags); + return -EIO; + } + restore_flags(flags); + return 0; + } + break; + + case SNDCTL_COPR_RCODE: + { + copr_debug_buf buf; + unsigned long flags; + unsigned short tmp; + + memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf)); + + save_flags(flags); + cli(); + if (!pss_put_dspword(devc, 0x00d2)) + { + restore_flags(flags); + return -EIO; + } + if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff))) + { + restore_flags(flags); + return -EIO; + } + if (!pss_get_dspword(devc, &tmp)) /* Read MSB */ + { + restore_flags(flags); + return -EIO; + } + buf.parm1 = tmp << 8; + + if (!pss_get_dspword(devc, &tmp)) /* Read LSB */ + { + restore_flags(flags); + return -EIO; + } + buf.parm1 |= tmp & 0x00ff; + + restore_flags(flags); + + memcpy((&((char *) arg)[0]), (char *) &buf, sizeof(buf)); + return 0; + } + break; + + default: + return -EINVAL; } - restore_flags (flags); - - memcpy ((&((char *) arg)[0]), (char *) buf, sizeof (*buf)); - vfree (buf); - - return err; - } - break; + return -EINVAL; +} +static coproc_operations pss_coproc_operations = +{ + "ADSP-2115", + pss_coproc_open, + pss_coproc_close, + pss_coproc_ioctl, + pss_coproc_reset, + &pss_data +}; - case SNDCTL_COPR_RDATA: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; +void +attach_pss_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + { + attach_mpu401(hw_config); /* Slot 1 */ - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); + if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ + midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; + } +#endif +} - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d0)) - { - restore_flags (flags); - return -EIO; - } +int +probe_pss_mss(struct address_info *hw_config) +{ + volatile int timeout; - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) - { - restore_flags (flags); - return -EIO; - } + if (!pss_initialized) + return 0; - if (!pss_get_dspword (devc, &tmp)) + if (check_region(hw_config->io_base, 8)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS I/O port conflict\n"); + return 0; } - - buf.parm1 = tmp; - restore_flags (flags); - - memcpy ((&((char *) arg)[0]), (char *) &buf, sizeof (buf)); - return 0; - } - break; - - case SNDCTL_COPR_WDATA: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; - - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); - - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d1)) + if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS base error.\n"); + return 0; } - - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) + if (!set_irq(devc, CONF_WSS, hw_config->irq)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS IRQ error.\n"); + return 0; } - - tmp = (unsigned int) buf.parm2 & 0xffff; - if (!pss_put_dspword (devc, tmp)) + if (!set_dma(devc, CONF_WSS, hw_config->dma)) { - restore_flags (flags); - return -EIO; + printk("PSS: WSS DRQ error\n"); + return 0; } + /* + * For some reason the card returns 0xff in the WSS status register + * immediately after boot. Probably MIDI+SB emulation algorithm + * downloaded to the ADSP2115 spends some time initializing the card. + * Let's try to wait until it finishes this task. + */ + for (timeout = 0; + timeout < 100000 && (inb(hw_config->io_base + 3) & 0x3f) != 0x04; + timeout++); + + outb((0x0b), hw_config->io_base + 4); /* Required by some cards */ + + for (timeout = 0; + timeout < 100000; + timeout++); + return probe_ms_sound(hw_config); +} - restore_flags (flags); - return 0; - } - break; +void +attach_pss_mss(struct address_info *hw_config) +{ + attach_ms_sound(hw_config); /* Slot 0 */ - case SNDCTL_COPR_WCODE: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; + if (hw_config->slots[0] != -1) /* The MSS driver installed itself */ + audio_devs[hw_config->slots[0]]->coproc = &pss_coproc_operations; +} - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); +void +unload_pss(struct address_info *hw_config) +{ +} - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d3)) - { - restore_flags (flags); - return -EIO; - } +void +unload_pss_mpu(struct address_info *hw_config) +{ +#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + unload_mpu401(hw_config); +#endif +} - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) - { - restore_flags (flags); - return -EIO; - } +void +unload_pss_mss(struct address_info *hw_config) +{ + unload_ms_sound(hw_config); +} - tmp = (unsigned int) buf.parm2 & 0x00ff; - if (!pss_put_dspword (devc, tmp)) - { - restore_flags (flags); - return -EIO; - } +#ifdef MODULE - tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff; - if (!pss_put_dspword (devc, tmp)) - { - restore_flags (flags); - return -EIO; - } +int io = -1; +int irq = -1; +int dma = -1; - restore_flags (flags); - return 0; - } - break; +int pssmpu, pssmss; +struct address_info cfg; - case SNDCTL_COPR_RCODE: - { - copr_debug_buf buf; - unsigned long flags; - unsigned short tmp; +static int fw_load = 0; - memcpy ((char *) &buf, (&((char *) arg)[0]), sizeof (buf)); +/* + * Load a PSS sound card module + */ - save_flags (flags); - cli (); - if (!pss_put_dspword (devc, 0x00d2)) +int +init_module(void) +{ + if (io == -1 || irq == -1 || dma == -1) { - restore_flags (flags); - return -EIO; + printk("pss: dma, irq and io must be set.\n"); + return -EINVAL; } + cfg.io_base = io; + cfg.irq = irq; - if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) + if (!pss_synth) { - restore_flags (flags); - return -EIO; + fw_load = 1; + pss_synthLen = mod_firmware_load("/etc/sound/pss_synth", (void *) &pss_synth); } - - if (!pss_get_dspword (devc, &tmp)) /* Read MSB */ + if (probe_pss(&cfg)) + return -ENODEV; + /* + * Attach stuff + */ + if (probe_pss_mpu(&cfg)) { - restore_flags (flags); - return -EIO; + pssmpu = 1; + attach_pss_mpu(&cfg); } - - buf.parm1 = tmp << 8; - - if (!pss_get_dspword (devc, &tmp)) /* Read LSB */ + if (probe_pss_mss(&cfg)) { - restore_flags (flags); - return -EIO; + pssmss = 1; + attach_pss_mss(&cfg); } - - buf.parm1 |= tmp & 0x00ff; - - restore_flags (flags); - - memcpy ((&((char *) arg)[0]), (char *) &buf, sizeof (buf)); + SOUND_LOCK; return 0; - } - break; - - default: - return -EINVAL; - } - - return -EINVAL; -} - -static coproc_operations pss_coproc_operations = -{ - "ADSP-2115", - pss_coproc_open, - pss_coproc_close, - pss_coproc_ioctl, - pss_coproc_reset, - &pss_data -}; - -void -attach_pss_mpu (struct address_info *hw_config) -{ -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - { - int prev_devs; - - prev_devs = num_midis; - attach_mpu401 (hw_config); - - if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ - midi_devs[prev_devs]->coproc = &pss_coproc_operations; - } -#endif -} - -int -probe_pss_mss (struct address_info *hw_config) -{ - volatile int timeout; - - if (!pss_initialized) - return 0; - - if (check_region (hw_config->io_base, 8)) - { - printk ("PSS: WSS I/O port conflict\n"); - return 0; - } - - if (!set_io_base (devc, CONF_WSS, hw_config->io_base)) - { - printk ("PSS: WSS base error.\n"); - return 0; - } - - if (!set_irq (devc, CONF_WSS, hw_config->irq)) - { - printk ("PSS: WSS IRQ error.\n"); - return 0; - } - - if (!set_dma (devc, CONF_WSS, hw_config->dma)) - { - printk ("PSS: WSS DRQ error\n"); - return 0; - } - - /* - * For some reason the card returns 0xff in the WSS status register - * immediately after boot. Probably MIDI+SB emulation algorithm - * downloaded to the ADSP2115 spends some time initializing the card. - * Let's try to wait until it finishes this task. - */ - for (timeout = 0; - timeout < 100000 && (inb (hw_config->io_base + 3) & 0x3f) != 0x04; - timeout++); - - outb ((0x0b), hw_config->io_base + 4); /* Required by some cards */ - - for (timeout = 0; - timeout < 100000; - timeout++); - return probe_ms_sound (hw_config); -} - -void -attach_pss_mss (struct address_info *hw_config) -{ - int prev_devs; - - prev_devs = num_audiodevs; - attach_ms_sound (hw_config); - - if (num_audiodevs == (prev_devs + 1)) /* The MSS driver installed itself */ - audio_devs[prev_devs]->coproc = &pss_coproc_operations; } -void -unload_pss (struct address_info *hw_config) +void +cleanup_module(void) { + if (fw_load && pss_synth) + kfree(pss_synth); + if (pssmss) + unload_pss_mss(&cfg); + if (pssmpu) + unload_pss_mpu(&cfg); + unload_pss(&cfg); + SOUND_LOCK_END; } - -void -unload_pss_mpu (struct address_info *hw_config) -{ -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - unload_mpu401 (hw_config); #endif -} - -void -unload_pss_mss (struct address_info *hw_config) -{ - unload_ms_sound (hw_config); -} #endif |