diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-09-19 19:15:08 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-09-19 19:15:08 +0000 |
commit | 03ba4131783cc9e872f8bb26a03f15bc11f27564 (patch) | |
tree | 88db8dba75ae06ba3bad08e42c5e52efc162535c /drivers/sound | |
parent | 257730f99381dd26e10b832fce4c94cae7ac1176 (diff) |
- Merge with Linux 2.1.121.
- Bugfixes.
Diffstat (limited to 'drivers/sound')
32 files changed, 2092 insertions, 1435 deletions
diff --git a/drivers/sound/Config.in b/drivers/sound/Config.in index 4f511f3ab..b23a61f74 100644 --- a/drivers/sound/Config.in +++ b/drivers/sound/Config.in @@ -35,6 +35,18 @@ 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 I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDPIN_IO 290 + 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 + 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 + fi fi dep_tristate 'OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND @@ -156,7 +168,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then dep_tristate 'Support for Crystal CS4232 based (PnP) cards' CONFIG_SOUND_CS4232 $CONFIG_SOUND_OSS if [ "$CONFIG_SOUND_CS4232" = "y" ]; then - hex 'CS4232 audio I/O base 530, 604, E80 or F40' CONFIG_CS4232_BASE 530 + hex 'CS4232 audio I/O base (normally 530, 604, E80 or F40)' CONFIG_CS4232_BASE 530 int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CONFIG_CS4232_IRQ 11 int 'CS4232 audio DMA 0, 1 or 3' CONFIG_CS4232_DMA 0 int 'CS4232 second (duplex) DMA 0, 1 or 3' CONFIG_CS4232_DMA2 3 @@ -205,7 +217,7 @@ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then dep_tristate 'Loopback MIDI device support' CONFIG_SOUND_VMIDI $CONFIG_SOUND_OSS dep_tristate '6850 UART support' CONFIG_SOUND_UART6850 $CONFIG_SOUND_OSS - if [ "$CONFIG_UART6850" = "y" ]; then + if [ "$CONFIG_SOUND_UART6850" = "y" ]; then hex 'I/O base for UART 6850 MIDI port (Unknown)' CONFIG_U6850_BASE 0 int 'UART6850 IRQ (Unknown)' CONFIG_U6850_IRQ -1 fi diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index d04efe300..f072b7fad 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -79,7 +79,7 @@ obj-$(CONFIG_SOUND_SOFTOSS) += softoss2.o obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb.o uart401.o -obj-$(CONFIG_SOUND_UART6850) += uart6850.c +obj-$(CONFIG_SOUND_UART6850) += uart6850.o obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_YM3812) += adlib_card.o opl3.o obj-$(CONFIG_VIDC_SOUND) += vidc_mod.o @@ -92,7 +92,6 @@ 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 \ diff --git a/drivers/sound/README.FIRST b/drivers/sound/README.FIRST index 3a6b60483..85ecccdfc 100644 --- a/drivers/sound/README.FIRST +++ b/drivers/sound/README.FIRST @@ -1,4 +1,4 @@ -The modular sound driver patches where funded by Red Hat Software +The modular sound driver patches were funded by Red Hat Software (www.redhat.com). The sound driver here is thus a modified version of Hannu's code. Please bear that in mind when considering the appropriate forums for bug reporting. diff --git a/drivers/sound/audio.c b/drivers/sound/audio.c index f08f6aaca..54d8e5f5b 100644 --- a/drivers/sound/audio.c +++ b/drivers/sound/audio.c @@ -17,6 +17,7 @@ * (which is grossly misnamed btw.) because they have the same * lifetime as the rest in there and dynamic allocation saves * 12k or so + * Thomas Sailer : use more logical O_NONBLOCK semantics */ #include <linux/config.h> @@ -99,7 +100,6 @@ int audio_open(int dev, struct file *file) set_format(dev, bits); audio_devs[dev]->audio_mode = AM_NONE; - audio_devs[dev]->dev_nblock = 0; return ret; @@ -203,10 +203,10 @@ int audio_write(int dev, struct file *file, const char *buf, int count) while (c) { - if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, audio_devs[dev]->dev_nblock)) < 0) + if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, !!(file->f_flags & O_NONBLOCK))) < 0) { /* Handle nonblocking mode */ - if (audio_devs[dev]->dev_nblock && err == -EAGAIN) + if ((file->f_flags & O_NONBLOCK) && err == -EAGAIN) return p; /* No more space. Return # of accepted bytes */ return err; } @@ -273,14 +273,13 @@ int audio_read(int dev, struct file *file, char *buf, int count) while(c) { - if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l, - audio_devs[dev]->dev_nblock)) < 0) + if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l, !!(file->f_flags & O_NONBLOCK))) < 0) { /* * Nonblocking mode handling. Return current # of bytes */ - if (audio_devs[dev]->dev_nblock && buf_no == -EAGAIN) + if (file->f_flags & O_NONBLOCK && buf_no == -EAGAIN) return p; if (p > 0) /* Avoid throwing away data */ @@ -388,7 +387,7 @@ int audio_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg) return dma_ioctl(dev, cmd, arg); case SNDCTL_DSP_NONBLOCK: - audio_devs[dev]->dev_nblock = 1; + file->f_flags |= O_NONBLOCK; return 0; case SNDCTL_DSP_GETCAPS: diff --git a/drivers/sound/dev_table.h b/drivers/sound/dev_table.h index bf5d62bff..215df408a 100644 --- a/drivers/sound/dev_table.h +++ b/drivers/sound/dev_table.h @@ -230,8 +230,6 @@ struct audio_operations /* fields formerly in audio.c */ int audio_mode; - /* why don't we use file->f_flags & O_NONBLOCK for the following? - ts */ - int dev_nblock; /* 1 if in nonblocking mode */ #define AM_NONE 0 #define AM_WRITE OPEN_WRITE diff --git a/drivers/sound/dmabuf.c b/drivers/sound/dmabuf.c index ecabf72ab..51b9d87de 100644 --- a/drivers/sound/dmabuf.c +++ b/drivers/sound/dmabuf.c @@ -206,6 +206,7 @@ static void close_dmap(struct audio_operations *adev, struct dma_buffparms *dmap dmap->dma_mode = DMODE_NONE; dmap->flags &= ~DMA_BUSY; disable_dma(dmap->dma); + sound_free_dmap(dmap); } diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c index f944252bf..b351c73db 100644 --- a/drivers/sound/dmasound.c +++ b/drivers/sound/dmasound.c @@ -3808,6 +3808,7 @@ static struct file_operations mixer_fops = mixer_ioctl, NULL, /* mixer_mmap */ mixer_open, + NULL, /* flush */ mixer_release, }; @@ -4169,6 +4170,7 @@ static struct file_operations sq_fops = sq_ioctl, NULL, /* sq_mmap */ sq_open, + NULL, /* flush */ sq_release, }; @@ -4363,6 +4365,7 @@ static struct file_operations state_fops = NULL, /* state_ioctl */ NULL, /* state_mmap */ state_open, + NULL, /* flush */ state_release, }; diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index 5a9b4ec9e..00794bf39 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -1,7 +1,7 @@ /*****************************************************************************/ /* - * es1370.c -- Ensoniq ES1370/Ashai Kasei AK4531 audio driver. + * es1370.c -- Ensoniq ES1370/Asahi Kasei AK4531 audio driver. * * Copyright (C) 1998 Thomas Sailer (sailer@ife.ee.ethz.ch) * @@ -67,6 +67,15 @@ * settings (not sure if this should be standard) * Fixed many references: f_flags should be f_mode * -- Gerald Britton <gbritton@mit.edu> + * 03.08.98 0.11 Now mixer behaviour can basically be selected between + * "OSS documented" and "OSS actual" behaviour + * Fixed mixer table thanks to Hakan.Lennestal@lu.erisoft.se + * On module startup, set DAC2 to 11kSPS instead of 5.5kSPS, + * as it produces an annoying ssssh in the lower sampling rate + * Do not include modversions.h + * 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 * * some important things missing in Ensoniq documentation: * @@ -91,7 +100,6 @@ #include <linux/version.h> #include <linux/module.h> -#include <linux/modversions.h> #include <linux/string.h> #include <linux/ioport.h> #include <linux/sched.h> @@ -110,6 +118,10 @@ /* --------------------------------------------------------------------- */ +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +/* --------------------------------------------------------------------- */ + #ifndef PCI_VENDOR_ID_ENSONIQ #define PCI_VENDOR_ID_ENSONIQ 0x1274 #endif @@ -316,7 +328,7 @@ struct es1370_state { /* --------------------------------------------------------------------- */ -struct es1370_state *devs = NULL; +static struct es1370_state *devs = NULL; /* --------------------------------------------------------------------- */ @@ -446,7 +458,7 @@ static void start_adc(struct es1370_state *s) unsigned fragremain, fshift; spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < s->dma_adc.dmasize - 2*s->dma_adc.fragsize) + if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) && s->dma_adc.ready) { s->ctrl |= CTRL_ADC_EN; s->sctrl = (s->sctrl & ~SCTRL_R1LOOPSEL) | SCTRL_R1INTEN; @@ -464,10 +476,9 @@ static void start_adc(struct es1370_state *s) /* --------------------------------------------------------------------- */ -#define DMABUF_DEFAULTORDER 8 +#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 - extern inline void dealloc_dmabuf(struct dmabuf *db) { unsigned long map, mapend; @@ -588,10 +599,10 @@ static void es1370_update_ptr(struct es1370_state *s) s->dma_adc.total_bytes += diff; s->dma_adc.count += diff; if (s->dma_adc.mapped) { - if (s->dma_adc.count >= s->dma_adc.fragsize) + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) wake_up(&s->dma_adc.wait); } else { - if (s->dma_adc.count > s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1)) { + if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { s->ctrl &= ~CTRL_ADC_EN; outl(s->ctrl, s->io+ES1370_REG_CONTROL); s->dma_adc.error++; @@ -606,7 +617,7 @@ static void es1370_update_ptr(struct es1370_state *s) s->dma_dac1.total_bytes += diff; if (s->dma_dac1.mapped) { s->dma_dac1.count += diff; - if (s->dma_dac1.count >= s->dma_dac1.fragsize) + if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize) wake_up(&s->dma_dac1.wait); } else { s->dma_dac1.count -= diff; @@ -614,12 +625,12 @@ static void es1370_update_ptr(struct es1370_state *s) s->ctrl &= ~CTRL_DAC1_EN; outl(s->ctrl, s->io+ES1370_REG_CONTROL); s->dma_dac1.error++; - } else if (s->dma_dac1.count <= s->dma_dac1.fragsize && !s->dma_dac1.endcleared) { + } else if (s->dma_dac1.count <= (signed)s->dma_dac1.fragsize && !s->dma_dac1.endcleared) { clear_advance(s->dma_dac1.rawbuf, s->dma_dac1.dmasize, s->dma_dac1.swptr, s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80); s->dma_dac1.endcleared = 1; } - if (s->dma_dac1.count < s->dma_dac1.dmasize) + if (s->dma_dac1.count < (signed)s->dma_dac1.dmasize) wake_up(&s->dma_dac1.wait); } } @@ -629,7 +640,7 @@ static void es1370_update_ptr(struct es1370_state *s) s->dma_dac2.total_bytes += diff; if (s->dma_dac2.mapped) { s->dma_dac2.count += diff; - if (s->dma_dac2.count >= s->dma_dac2.fragsize) + if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) wake_up(&s->dma_dac2.wait); } else { s->dma_dac2.count -= diff; @@ -637,12 +648,12 @@ static void es1370_update_ptr(struct es1370_state *s) s->ctrl &= ~CTRL_DAC2_EN; outl(s->ctrl, s->io+ES1370_REG_CONTROL); s->dma_dac2.error++; - } else if (s->dma_dac2.count <= s->dma_dac2.fragsize && !s->dma_dac2.endcleared) { + } else if (s->dma_dac2.count <= (signed)s->dma_dac2.fragsize && !s->dma_dac2.endcleared) { clear_advance(s->dma_dac2.rawbuf, s->dma_dac2.dmasize, s->dma_dac2.swptr, s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80); s->dma_dac2.endcleared = 1; } - if (s->dma_dac2.count < s->dma_dac2.dmasize) + if (s->dma_dac2.count < (signed)s->dma_dac2.dmasize) wake_up(&s->dma_dac2.wait); } } @@ -734,20 +745,21 @@ static const struct { [SOUND_MIXER_CD] = { 3, 0x6, 0x7, 1, 0x0006, 1 }, /* CD */ [SOUND_MIXER_LINE] = { 4, 0x8, 0x9, 1, 0x0018, 1 }, /* Line */ [SOUND_MIXER_LINE1] = { 5, 0xa, 0xb, 1, 0x1800, 1 }, /* AUX */ - [SOUND_MIXER_LINE2] = { 6, 0xc, 0x0, 1, 0x0100, 1 }, /* Mono1 */ - [SOUND_MIXER_LINE3] = { 7, 0xd, 0x0, 1, 0x0200, 1 }, /* Mono2 */ - [SOUND_MIXER_MIC] = { 8, 0xe, 0x0, 1, 0x0001, 1 }, /* Mic */ - [SOUND_MIXER_OGAIN] = { 9, 0xf, 0x0, 1, 0x0000, 1 } /* mono out */ + [SOUND_MIXER_LINE2] = { 6, 0xc, 0x0, 0, 0x0100, 1 }, /* Mono1 */ + [SOUND_MIXER_LINE3] = { 7, 0xd, 0x0, 0, 0x0200, 1 }, /* Mono2 */ + [SOUND_MIXER_MIC] = { 8, 0xe, 0x0, 0, 0x0001, 1 }, /* Mic */ + [SOUND_MIXER_OGAIN] = { 9, 0xf, 0x0, 0, 0x0000, 1 } /* mono out */ }; static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg) { + unsigned long flags; int i, val, j; - unsigned char l, r, rl, rr, sr, sl; + unsigned char l, r, rl, rr; VALIDATE_STATE(s); - if (cmd == SOUND_MIXER_PRIVATE1) { + /* enable/disable/query mixer preamp */ get_user_ret(val, (int *)arg, -EFAULT); if (val != -1) { s->mix.micpreamp = !!val; @@ -755,6 +767,34 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a } return put_user(s->mix.micpreamp, (int *)arg); } + if (cmd == SOUND_MIXER_PRIVATE2) { + /* enable/disable/query use of linein as second lineout */ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != -1) { + spin_lock_irqsave(&s->lock, flags); + if (val) + s->ctrl |= CTRL_XCTL0; + else + s->ctrl &= ~CTRL_XCTL0; + outl(s->ctrl, s->io+ES1370_REG_CONTROL); + spin_unlock_irqrestore(&s->lock, flags); + } + return put_user((s->ctrl & CTRL_XCTL0) ? 1 : 0, (int *)arg); + } + if (cmd == SOUND_MIXER_PRIVATE3) { + /* enable/disable/query microphone impedance setting */ + get_user_ret(val, (int *)arg, -EFAULT); + if (val != -1) { + spin_lock_irqsave(&s->lock, flags); + if (val) + s->ctrl |= CTRL_XCTL1; + else + s->ctrl &= ~CTRL_XCTL1; + outl(s->ctrl, s->io+ES1370_REG_CONTROL); + spin_unlock_irqrestore(&s->lock, flags); + } + return put_user((s->ctrl & CTRL_XCTL1) ? 1 : 0, (int *)arg); + } if (cmd == SOUND_MIXER_INFO) { mixer_info info; strncpy(info.id, "ES1370", sizeof(info.id)); @@ -842,25 +882,23 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a l = val & 0xff; if (l > 100) l = 100; - sl = sr = l; if (mixtable[i].stereo) { r = (val >> 8) & 0xff; if (r > 100) r = 100; - sr = r; - if (l < 10) { + if (l < 7) { rl = 0x80; l = 0; } else { - rl = 15 - ((l - 10) / 6); - l = (15 - rl) * 6 + 10; + rl = 31 - ((l - 7) / 3); + l = (31 - rl) * 3 + 7; } - if (r < 10) { + if (r < 7) { rr = 0x80; r = 0; } else { - rr = 15 - ((r - 10) / 6); - r = (15 - rr) * 6 + 10; + rr = 31 - ((r - 7) / 3); + r = (31 - rr) * 3 + 7; } wrcodec(s, mixtable[i].right, rr); } else { @@ -873,17 +911,21 @@ static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long a r = l = (7 - rl) * 14 + 2; } } else { - if (l < 10) { + if (l < 7) { rl = 0x80; r = l = 0; } else { - rl = 15 - ((l - 10) / 6); - r = l = (15 - rl) * 6 + 10; + rl = 31 - ((l - 7) / 3); + r = l = (31 - rl) * 3 + 7; } } - } + } wrcodec(s, mixtable[i].left, rl); - s->mix.vol[mixtable[i].volidx] = ((unsigned int)sr << 8) | sl; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + s->mix.vol[mixtable[i].volidx] = ((unsigned int)r << 8) | l; +#else + s->mix.vol[mixtable[i].volidx] = val; +#endif return put_user(s->mix.vol[mixtable[i].volidx], (int *)arg); } } @@ -935,14 +977,13 @@ static /*const*/ struct file_operations es1370_mixer_fops = { &es1370_ioctl_mixdev, NULL, /* mmap */ &es1370_open_mixdev, + NULL, /* flush */ &es1370_release_mixdev, NULL, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ -#if 0 NULL, /* revalidate */ NULL, /* lock */ -#endif }; /* --------------------------------------------------------------------- */ @@ -1147,7 +1188,7 @@ static unsigned int es1370_poll(struct file *file, struct poll_table_struct *wai es1370_update_ptr(s); if (file->f_mode & FMODE_READ) { if (s->dma_adc.mapped) { - if (s->dma_adc.count >= s->dma_adc.fragsize) + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) mask |= POLLIN | POLLRDNORM; } else { if (s->dma_adc.count > 0) @@ -1156,10 +1197,10 @@ static unsigned int es1370_poll(struct file *file, struct poll_table_struct *wai } if (file->f_mode & FMODE_WRITE) { if (s->dma_dac2.mapped) { - if (s->dma_dac2.count >= s->dma_dac2.fragsize) + if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) mask |= POLLOUT | POLLWRNORM; } else { - if (s->dma_dac2.dmasize > s->dma_dac2.count) + if ((signed)s->dma_dac2.dmasize > s->dma_dac2.count) mask |= POLLOUT | POLLWRNORM; } } @@ -1584,6 +1625,7 @@ static /*const*/ struct file_operations es1370_audio_fops = { &es1370_ioctl, &es1370_mmap, &es1370_open, + NULL, /* flush */ &es1370_release, NULL, /* fsync */ NULL, /* fasync */ @@ -1660,10 +1702,10 @@ static unsigned int es1370_poll_dac(struct file *file, struct poll_table_struct spin_lock_irqsave(&s->lock, flags); es1370_update_ptr(s); if (s->dma_dac1.mapped) { - if (s->dma_dac1.count >= s->dma_dac1.fragsize) + if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize) mask |= POLLOUT | POLLWRNORM; } else { - if (s->dma_dac1.dmasize > s->dma_dac1.count) + if ((signed)s->dma_dac1.dmasize > s->dma_dac1.count) mask |= POLLOUT | POLLWRNORM; } spin_unlock_irqrestore(&s->lock, flags); @@ -1950,6 +1992,7 @@ static /*const*/ struct file_operations es1370_dac_fops = { &es1370_ioctl_dac, &es1370_mmap_dac, &es1370_open_dac, + NULL, /* flush */ &es1370_release_dac, NULL, /* fsync */ NULL, /* fasync */ @@ -2186,6 +2229,7 @@ static /*const*/ struct file_operations es1370_midi_fops = { NULL, /* ioctl */ NULL, /* mmap */ &es1370_midi_open, + NULL, /* flush */ &es1370_midi_release, NULL, /* fsync */ NULL, /* fasync */ @@ -2234,7 +2278,7 @@ __initfunc(int init_es1370(void)) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1370: version v0.10 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1370: version v0.13 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) { if (pcidev->base_address[0] == 0 || @@ -2267,7 +2311,7 @@ __initfunc(int init_es1370(void)) goto err_irq; } /* initialize codec registers */ - s->ctrl = CTRL_CDC_EN | CTRL_SERR_DIS | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV); + s->ctrl = CTRL_CDC_EN | CTRL_SERR_DIS | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL); if (joystick[index]) { if (check_region(0x200, JOY_EXTENT)) printk(KERN_ERR "es1370: io port 0x200 in use\n"); @@ -2356,7 +2400,7 @@ void cleanup_module(void) while ((s = devs)) { devs = devs->next; - outl(CTRL_SERR_DIS, s->io+ES1370_REG_CONTROL); /* switch everything off */ + outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */ outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */ synchronize_irq(); free_irq(s->irq, s); diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index 8fcc03541..1c025fa2e 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -45,8 +45,10 @@ * should be detected. This results in strange behaviour of some mixer * settings, like master volume and mic. * 08.06.98 0.2 First release using Alan Cox' soundcore instead of miscdevice - * - * + * 03.08.98 0.3 Do not include modversions.h + * Now mixer behaviour can basically be selected between + * "OSS documented" and "OSS actual" behaviour + * 31.08.98 0.4 Fix realplayer problems - dac.count issues * */ @@ -54,7 +56,6 @@ #include <linux/version.h> #include <linux/module.h> -#include <linux/modversions.h> #include <linux/string.h> #include <linux/ioport.h> #include <linux/sched.h> @@ -73,6 +74,10 @@ /* --------------------------------------------------------------------- */ +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +/* --------------------------------------------------------------------- */ + #ifndef PCI_VENDOR_ID_ENSONIQ #define PCI_VENDOR_ID_ENSONIQ 0x1274 #endif @@ -325,6 +330,9 @@ struct es1371_state { struct { unsigned short codec_id; unsigned int modcnt; +#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS + unsigned short vol[13]; +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } mix; /* wave stuff */ @@ -373,7 +381,7 @@ struct es1371_state { /* --------------------------------------------------------------------- */ -struct es1371_state *devs = NULL; +static struct es1371_state *devs = NULL; /* --------------------------------------------------------------------- */ @@ -686,7 +694,7 @@ static void start_adc(struct es1371_state *s) unsigned fragremain, fshift; spin_lock_irqsave(&s->lock, flags); - if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < s->dma_adc.dmasize - 2*s->dma_adc.fragsize) + if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) && s->dma_adc.ready) { s->ctrl |= CTRL_ADC_EN; s->sctrl = (s->sctrl & ~SCTRL_R1LOOPSEL) | SCTRL_R1INTEN; @@ -704,7 +712,7 @@ static void start_adc(struct es1371_state *s) /* --------------------------------------------------------------------- */ -#define DMABUF_DEFAULTORDER 8 +#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 @@ -831,7 +839,7 @@ static void es1371_update_ptr(struct es1371_state *s) if (s->dma_adc.count >= s->dma_adc.fragsize) wake_up(&s->dma_adc.wait); } else { - if (s->dma_adc.count > s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1)) { + if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { s->ctrl &= ~CTRL_ADC_EN; outl(s->ctrl, s->io+ES1371_REG_CONTROL); s->dma_adc.error++; @@ -846,7 +854,7 @@ static void es1371_update_ptr(struct es1371_state *s) s->dma_dac1.total_bytes += diff; if (s->dma_dac1.mapped) { s->dma_dac1.count += diff; - if (s->dma_dac1.count >= s->dma_dac1.fragsize) + if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize) wake_up(&s->dma_dac1.wait); } else { s->dma_dac1.count -= diff; @@ -854,12 +862,12 @@ static void es1371_update_ptr(struct es1371_state *s) s->ctrl &= ~CTRL_DAC1_EN; outl(s->ctrl, s->io+ES1371_REG_CONTROL); s->dma_dac1.error++; - } else if (s->dma_dac1.count <= s->dma_dac1.fragsize && !s->dma_dac1.endcleared) { + } else if (s->dma_dac1.count <= (signed)s->dma_dac1.fragsize && !s->dma_dac1.endcleared) { clear_advance(s->dma_dac1.rawbuf, s->dma_dac1.dmasize, s->dma_dac1.swptr, s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80); s->dma_dac1.endcleared = 1; } - if (s->dma_dac1.count < s->dma_dac1.dmasize) + if (s->dma_dac1.count < (signed)s->dma_dac1.dmasize) wake_up(&s->dma_dac1.wait); } } @@ -869,7 +877,7 @@ static void es1371_update_ptr(struct es1371_state *s) s->dma_dac2.total_bytes += diff; if (s->dma_dac2.mapped) { s->dma_dac2.count += diff; - if (s->dma_dac2.count >= s->dma_dac2.fragsize) + if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) wake_up(&s->dma_dac2.wait); } else { s->dma_dac2.count -= diff; @@ -877,12 +885,12 @@ static void es1371_update_ptr(struct es1371_state *s) s->ctrl &= ~CTRL_DAC2_EN; outl(s->ctrl, s->io+ES1371_REG_CONTROL); s->dma_dac2.error++; - } else if (s->dma_dac2.count <= s->dma_dac2.fragsize && !s->dma_dac2.endcleared) { + } else if (s->dma_dac2.count <= (signed)s->dma_dac2.fragsize && !s->dma_dac2.endcleared) { clear_advance(s->dma_dac2.rawbuf, s->dma_dac2.dmasize, s->dma_dac2.swptr, s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80); s->dma_dac2.endcleared = 1; } - if (s->dma_dac2.count < s->dma_dac2.dmasize) + if (s->dma_dac2.count < (signed)s->dma_dac2.dmasize) wake_up(&s->dma_dac2.wait); } } @@ -982,7 +990,7 @@ static const unsigned int recsrc[8] = SOUND_MASK_PHONEIN }; -static const unsigned char volreg[] = +static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = { /* 5 bit stereo */ [SOUND_MIXER_LINE] = 0x10, @@ -1006,6 +1014,8 @@ static const unsigned char volreg[] = [SOUND_MIXER_IGAIN] = 0x1e }; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + #define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00)) static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg) @@ -1093,6 +1103,34 @@ static int mixer_rdch(struct es1371_state *s, unsigned int ch, int *arg) } } +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = +{ + /* 5 bit stereo */ + [SOUND_MIXER_LINE] = 1, + [SOUND_MIXER_CD] = 2, + [SOUND_MIXER_VIDEO] = 3, + [SOUND_MIXER_LINE1] = 4, + [SOUND_MIXER_PCM] = 5, + /* 6 bit stereo */ + [SOUND_MIXER_VOLUME] = 6, + [SOUND_MIXER_PHONEOUT] = 7, + /* 6 bit mono */ + [SOUND_MIXER_OGAIN] = 8, + [SOUND_MIXER_PHONEIN] = 9, + /* 4 bit mono but shifted by 1 */ + [SOUND_MIXER_SPEAKER] = 10, + /* 6 bit mono + preamp */ + [SOUND_MIXER_MIC] = 11, + /* 4 bit stereo */ + [SOUND_MIXER_RECLEV] = 12, + /* 4 bit mono */ + [SOUND_MIXER_IGAIN] = 13 +}; + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + static int mixer_wrch(struct es1371_state *s, unsigned int ch, int val) { int i; @@ -1295,7 +1333,13 @@ static int mixer_ioctl(struct es1371_state *s, unsigned int cmd, unsigned long a i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES) return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS return mixer_rdch(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) @@ -1324,7 +1368,14 @@ static int mixer_ioctl(struct es1371_state *s, unsigned int cmd, unsigned long a get_user_ret(val, (int *)arg, -EFAULT); if (mixer_wrch(s, i, val)) return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS return mixer_rdch(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + s->mix.vol[volidx[i]-1] = val; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } @@ -1375,6 +1426,7 @@ static /*const*/ struct file_operations es1371_mixer_fops = { &es1371_ioctl_mixdev, NULL, /* mmap */ &es1371_open_mixdev, + NULL, /* flush */ &es1371_release_mixdev, NULL, /* fsync */ NULL, /* fasync */ @@ -1585,7 +1637,7 @@ static unsigned int es1371_poll(struct file *file, struct poll_table_struct *wai es1371_update_ptr(s); if (file->f_flags & FMODE_READ) { if (s->dma_adc.mapped) { - if (s->dma_adc.count >= s->dma_adc.fragsize) + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) mask |= POLLIN | POLLRDNORM; } else { if (s->dma_adc.count > 0) @@ -1594,10 +1646,10 @@ static unsigned int es1371_poll(struct file *file, struct poll_table_struct *wai } if (file->f_flags & FMODE_WRITE) { if (s->dma_dac2.mapped) { - if (s->dma_dac2.count >= s->dma_dac2.fragsize) + if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) mask |= POLLOUT | POLLWRNORM; } else { - if (s->dma_dac2.dmasize > s->dma_dac2.count) + if ((signed)s->dma_dac2.dmasize > s->dma_dac2.count) mask |= POLLOUT | POLLWRNORM; } } @@ -2022,6 +2074,7 @@ static /*const*/ struct file_operations es1371_audio_fops = { &es1371_ioctl, &es1371_mmap, &es1371_open, + NULL, /* flush */ &es1371_release, NULL, /* fsync */ NULL, /* fasync */ @@ -2098,10 +2151,10 @@ static unsigned int es1371_poll_dac(struct file *file, struct poll_table_struct spin_lock_irqsave(&s->lock, flags); es1371_update_ptr(s); if (s->dma_dac1.mapped) { - if (s->dma_dac1.count >= s->dma_dac1.fragsize) + if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize) mask |= POLLOUT | POLLWRNORM; } else { - if (s->dma_dac1.dmasize > s->dma_dac1.count) + if ((signed)s->dma_dac1.dmasize > s->dma_dac1.count) mask |= POLLOUT | POLLWRNORM; } spin_unlock_irqrestore(&s->lock, flags); @@ -2378,6 +2431,7 @@ static /*const*/ struct file_operations es1371_dac_fops = { &es1371_ioctl_dac, &es1371_mmap_dac, &es1371_open_dac, + NULL, /* flush */ &es1371_release_dac, NULL, /* fsync */ NULL, /* fasync */ @@ -2613,6 +2667,7 @@ static /*const*/ struct file_operations es1371_midi_fops = { NULL, /* ioctl */ NULL, /* mmap */ &es1371_midi_open, + NULL, /* flush */ &es1371_midi_release, NULL, /* fsync */ NULL, /* fasync */ @@ -2662,7 +2717,7 @@ __initfunc(int init_es1371(void)) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "es1371: version v0.2 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "es1371: version v0.4 time " __TIME__ " " __DATE__ "\n"); while (index < NR_DEVICE && (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) { if (pcidev->base_address[0] == 0 || @@ -2818,11 +2873,7 @@ __initfunc(int init_es1371(void)) #ifdef MODULE MODULE_PARM(joystick, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(joystick, "if 1 enables joystick interface (still need separate driver)"); -MODULE_PARM(lineout, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out"); -MODULE_PARM(micz, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(micz, "changes (??) the microphone impedance"); +MODULE_PARM_DESC(joystick, "sets address and enables joystick interface (still need separate driver)"); MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); MODULE_DESCRIPTION("ES1371 AudioPCI97 Driver"); diff --git a/drivers/sound/gus_wave.c b/drivers/sound/gus_wave.c index c15bced88..c73e6f06b 100644 --- a/drivers/sound/gus_wave.c +++ b/drivers/sound/gus_wave.c @@ -3142,6 +3142,7 @@ void gus_wave_init(struct address_info *hw_config) return; } + hw_config->slots[4] = gus_devnum; audio_devs[gus_devnum]->min_fragment = 9; /* 512k */ audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */ audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */ diff --git a/drivers/sound/lowlevel/README b/drivers/sound/lowlevel/README index 86c93b55b..76fba8dee 100644 --- a/drivers/sound/lowlevel/README +++ b/drivers/sound/lowlevel/README @@ -11,7 +11,8 @@ Hannu Savolainen (hannu@voxware.pp.fi) for more info. The following low level drivers are included: - ACI MIXER for miroPCM12 by Markus Kuhn -(mskuhn@cip.informatik.uni-erlangen.de). + (mskuhn@cip.informatik.uni-erlangen.de). +- Audio Excel DSP 16 initialization driver by Riccardo Facchetti + (fizban@tin.it) - SB32/AWE synthesizer driver (Emu8000) by Takashi Iwai -(iwai@dragon.mm.t.u-tokyo.ac.jp). See README.awe for more -info. + (iwai@dragon.mm.t.u-tokyo.ac.jp). See README.awe for more info. diff --git a/drivers/sound/lowlevel/README.aedsp16 b/drivers/sound/lowlevel/README.aedsp16 deleted file mode 100644 index 8f5b05afd..000000000 --- a/drivers/sound/lowlevel/README.aedsp16 +++ /dev/null @@ -1,137 +0,0 @@ -Driver ------- - -Informations about Audio Excel DSP 16 driver can be found in the source -file lowlevel/aedsp16.c -Please, read the head of the source before using it. It contain useful -informations. - -Configuration -------------- - -The Audio Excel configuration, is now done with the standard Linux setup. -You have to configure the sound card (Sound Blaster or Microsoft Sound System) -and, if you want it, the Roland MPU-401 (do not use the Sound Blaster MPU-401, -SB-MPU401) in the main driver menu. Activate the lowlevel drivers then select -the Audio Excel hardware that you want to initialize. Check the IRQ/DMA/MIRQ -of the Audio Excel initialization: it must be the same as the SBPRO (or MSS) -setup. If the parameters are different, correct it. -I you own a Gallant's audio card based on SC-6600, activate the SC-6600 support. -If you want to change the configuration of the sound board, be sure to -check off all the configuration items before re-configure it. - -Module parameters ------------------ -To use this driver as a module, you must configure some module parameters, to -set up I/O addresses, IRQ lines and DMA channels. Some parameters are -mandatory while some others are optional. Here a list of parameters you can -use with this module: - -Name Description -==== =========== -MANDATORY -io I/O base address (0x220 or 0x240) -irq irq line (5, 7, 9, 10 or 11) -dma dma channel (0, 1 or 3) - -OPTIONAL -mss_base I/O base address for activate MSS mode (default SBPRO) - (0x530 or 0xE80) -mpu_base I/O base address for activate MPU-401 mode - (0x300, 0x310, 0x320 or 0x330) -mpu_irq MPU-401 irq line (5, 7, 9, 10 or 0) - -The /etc/conf.modules will have a line like this: - -options aedsp16 io=0x220 irq=10 dma=3 mss_base=0x530 - -Of course, you must write the 'options' for all other subsequent modules, -opl3, ad1848, adlib_card, sb - -Then you must load the sound modules stack in this order: -sound -> aedsp16 -> [ ad1848, opl3 ] - -Sound cards supported ---------------------- -This driver supports the SC-6000 and SC-6600 based Gallant's sound card. -It don't support the Audio Excel DSP 16 III (try the SC-6600 code). -I'm working on the III version of the card: if someone have useful -informations about it, please let me know. -For all the non-supported audio cards, you have to boot MS-DOS (or WIN95) -activating the audio card with the MS-DOS device driver, then you have to -<ctrl>-<alt>-<del> and boot Linux. -Follow these steps: - -1) Compile Linux kernel with standard sound driver, using the emulation - you want, with the parameters of your audio card, - e.g. Microsoft Sound System irq10 dma3 -2) Install your new kernel as the default boot kernel. -3) Boot MS-DOS and configure the audio card with the boot time device - driver, for MSS irq10 dma3 in our example. -4) <ctrl>-<alt>-<del> and boot Linux. This will mantain the DOS configuration - and will boot the new kernel with sound driver. The sound driver will find - the audio card and will recognize and attach it. - -Reports on User successes -------------------------- - -[--------------------------------------------------------------------------] - -From POPmail Mon Jul 29 18:23:12 1996 -Received: from cdc8g5.cdc.polimi.it by mbox.vol.it with SMTP - (1.39.111.2/16.2) id AA257995686; Mon, 29 Jul 1996 09:34:46 +0200 -Return-Path: <sjg95@unixfe.rl.ac.uk> -Received: from [130.246.12.16] by cdc8g5.cdc.polimi.it with SMTP - (1.38.193.4/15.6) id AA27426; Mon, 29 Jul 1996 09:42:49 +0200 -Posted-Date: Mon, 29 Jul 1996 08:35:40 +0100 -Received-Date: Mon, 29 Jul 1996 09:42:49 +0200 -Received: (from sjg95@localhost) by unixfe.rl.ac.uk (8.7.3/8.7.3) - id IAA58788 for riccardo@cdc8g5.cdc.polimi.it; Mon, 29 Jul 1996 08:35:40 +0100 -Date: Mon, 29 Jul 1996 08:35:40 +0100 -From: Mr S J Greenaway <sjg95@unixfe.rl.ac.uk> -Message-Id: <199607290735.IAA58788@unixfe.rl.ac.uk> -To: riccardo@cdc8g5.cdc.polimi.it (Riccardo Facchetti) -Subject: Re: Audio Excel DSP 16 initialization code -Newsgroups: comp.os.linux.announce -X-Newsreader: TIN [version 1.2 PL2] -Status: RO -X-Status: A - -Just to let you know got my Audio Excel (emulating a MSS) working -with my original SB16, thanks for the driver! - -/dev/sndstat: - -Linux huey 2.0.9 #10 Sat Jul 27 11:41:42 BST 1996 i586) -Kernel: Linux huey 2.0.9 #14 Sun Jul 28 12:50:43 BST 1996 i586 -Config options: c0202 - -Installed drivers: -Type 10: MS Sound System -Type 24: MS Sound System (AXP) -Type 27: Compaq Deskpro XL -Type 2: Sound Blaster - -Card config: -MS Sound System at 0x530 irq 11 drq 3 -Sound Blaster at 0x240 irq 5 drq 1,5 - -Audio devices: -0: MSS audio codec (CS4231A) -1: Sound Blaster 16 (4.12) - -Synth devices: - -Midi devices: NOT ENABLED IN CONFIG - -Timers: -0: System clock -1: MSS audio codec (CS4231A) - -Mixers: -0: MSS audio codec (CS4231A) -1: Sound Blaster - -[--------------------------------------------------------------------------] - - Riccardo diff --git a/drivers/sound/lowlevel/aci.c b/drivers/sound/lowlevel/aci.c index d46088b8e..c65fbd84a 100644 --- a/drivers/sound/lowlevel/aci.c +++ b/drivers/sound/lowlevel/aci.c @@ -4,17 +4,25 @@ * ACI is a protocol used to communicate with the microcontroller on * some sound cards produced by miro, e.g. the miroSOUND PCM12 and * PCM20. The ACI has been developed for miro by Norberto Pellicci - * <pellicci@ix.netcom.com>. Special thanks to both him and miro for + * <pellicci@home.com>. Special thanks to both him and miro for * providing the ACI specification. * * The main function of the ACI is to control the mixer and to get a * product identification. On the PCM20, ACI also controls the radio - * tuner on this card, however this is not yet supported in this - * software. + * tuner on this card, this is supported in the Video for Linux + * radio-miropcm20 driver. * * This Voxware ACI driver currently only supports the ACI functions - * on the miroSOUND PCM12 card. Support for miro sound cards with - * additional ACI functions can easily be added later. + * on the miroSOUND PCM12 and PCM20 card. Support for miro sound cards + * with additional ACI functions can easily be added later. + * + * / NOTE / When compiling as a module, make sure to load the module + * after loading the mad16 module. The initialisation code expects the + * MAD16 default mixer to be already available. + * + * / NOTE / When compiling as a module, make sure to load the module + * after loading the mad16 module. The initialisation code expects the + * MAD16 default mixer to be already available. * * Revision history: * @@ -27,6 +35,9 @@ * 1996-05-28 Markus Kuhn * Initialize CS4231A mixer, make ACI first mixer, * use new private mixer API for solo mode. + * 1998-08-18 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> + * Small modification to export ACI functions and + * complete modularisation. */ /* @@ -59,10 +70,11 @@ */ #include <linux/config.h> /* for CONFIG_ACI_MIXER */ +#include <linux/module.h> #include "lowlevel.h" #include "../sound_config.h" -#include "lowlevel.h" -#ifdef CONFIG_ACI_MIXER + +#if defined(CONFIG_ACI_MIXER) || defined(CONFIG_ACI_MIXER_MODULE) #undef DEBUG /* if defined, produce a verbose report via syslog */ @@ -77,7 +89,7 @@ static int aci_present = 0; #ifdef MODULE /* Whether the aci mixer is to be reset. */ int aci_reset = 0; /* Default: don't reset if the driver is a */ MODULE_PARM(aci_reset,"i"); -#else /* module; use "insmod sound.o aci_reset=1" */ +#else /* module; use "insmod aci.o aci_reset=1" */ int aci_reset = 1; /* to override. */ #endif @@ -143,12 +155,12 @@ static int read_general_status(void) * If a problem occurred, they return -1. */ -static int implied_cmd(unsigned char opcode) +int aci_implied_cmd(unsigned char opcode) { unsigned long flags; #ifdef DEBUG - printk("ACI: implied_cmd(0x%02x)\n", opcode); + printk("ACI: aci_implied_cmd(0x%02x)\n", opcode); #endif save_flags(flags); @@ -165,13 +177,13 @@ static int implied_cmd(unsigned char opcode) } -static int write_cmd(unsigned char opcode, unsigned char parameter) +int aci_write_cmd(unsigned char opcode, unsigned char parameter) { unsigned long flags; int status; #ifdef DEBUG - printk("ACI: write_cmd(0x%02x, 0x%02x)\n", opcode, parameter); + printk("ACI: aci_write_cmd(0x%02x, 0x%02x)\n", opcode, parameter); #endif save_flags(flags); @@ -202,8 +214,53 @@ static int write_cmd(unsigned char opcode, unsigned char parameter) return 0; } +/* + * This write command send 2 parameters instead of one. + * Only used in PCM20 radio frequency tuning control + */ + +int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2) +{ + unsigned long flags; + int status; + +#ifdef DEBUG + printk("ACI: aci_write_cmd_d(0x%02x, 0x%02x)\n", opcode, parameter, parameter2); +#endif + + save_flags(flags); + cli(); + + if (read_general_status() < 0 || busy_wait()) { + restore_flags(flags); + return -1; + } + outb_p(opcode, COMMAND_REGISTER); + if (busy_wait()) { restore_flags(flags); return -1; } + outb_p(parameter, COMMAND_REGISTER); + if (busy_wait()) { restore_flags(flags); return -1; } + outb_p(parameter2, COMMAND_REGISTER); + + if ((status = read_general_status()) < 0) { + restore_flags(flags); + return -1; + } + /* polarity of the INVALID flag depends on ACI version */ + if ((aci_version < 0xb0 && (status & 0x40) != 0) || + (aci_version >= 0xb0 && (status & 0x40) == 0)) { + restore_flags(flags); +#if 0 /* Frequency tuning works, but the INVALID flag is set ??? */ + printk("ACI: invalid write (double) command 0x%02x, 0x%02x, 0x%02x.\n", + opcode, parameter, parameter2); +#endif + return -1; + } + + restore_flags(flags); + return 0; +} -static int read_cmd(unsigned char opcode, int length, unsigned char *parameter) +int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter) { unsigned long flags; int i = 0; @@ -219,10 +276,10 @@ static int read_cmd(unsigned char opcode, int length, unsigned char *parameter) parameter[i++] = inb_p(STATUS_REGISTER); #ifdef DEBUG if (i == 1) - printk("ACI: read_cmd(0x%02x, %d) = 0x%02x\n", opcode, length, + printk("ACI: aci_read_cmd(0x%02x, %d) = 0x%02x\n", opcode, length, parameter[i-1]); else - printk("ACI: read_cmd cont.: 0x%02x\n", parameter[i-1]); + printk("ACI: aci_read_cmd cont.: 0x%02x\n", parameter[i-1]); #endif } @@ -231,7 +288,7 @@ static int read_cmd(unsigned char opcode, int length, unsigned char *parameter) } -static int indexed_cmd(unsigned char opcode, unsigned char index, +int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter) { unsigned long flags; @@ -249,7 +306,7 @@ static int indexed_cmd(unsigned char opcode, unsigned char index, if (busy_wait()) { restore_flags(flags); return -1; } *parameter = inb_p(STATUS_REGISTER); #ifdef DEBUG - printk("ACI: indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index, + printk("ACI: aci_indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index, *parameter); #endif @@ -285,10 +342,10 @@ static int getvolume(caddr_t arg, unsigned char buf; /* left channel */ - if (indexed_cmd(0xf0, left_index, &buf)) return -EIO; + if (aci_indexed_cmd(0xf0, left_index, &buf)) return -EIO; vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0); /* right channel */ - if (indexed_cmd(0xf0, right_index, &buf)) return -EIO; + if (aci_indexed_cmd(0xf0, right_index, &buf)) return -EIO; vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8; return (*(int *) arg = vol); @@ -304,13 +361,13 @@ static int setvolume(caddr_t arg, vol = *(int *)arg & 0xff; if (vol > 100) vol = 100; vol = SCALE(100, 0x20, vol); - if (write_cmd(left_index, 0x20 - vol)) return -EIO; + if (aci_write_cmd(left_index, 0x20 - vol)) return -EIO; ret = SCALE(0x20, 100, vol); /* right channel */ vol = (*(int *)arg >> 8) & 0xff; if (vol > 100) vol = 100; vol = SCALE(100, 0x20, vol); - if (write_cmd(right_index, 0x20 - vol)) return -EIO; + if (aci_write_cmd(right_index, 0x20 - vol)) return -EIO; ret |= SCALE(0x20, 100, vol) << 8; return (*(int *) arg = ret); @@ -327,7 +384,7 @@ aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) if (cmd == SOUND_MIXER_PRIVATE1) { if (*(int *) arg >= 0) { aci_solo = !!*(int *) arg; - if (write_cmd(0xd2, aci_solo)) return -EIO; + if (aci_write_cmd(0xd2, aci_solo)) return -EIO; } else if (aci_version >= 0xb0) { if ((status = read_general_status()) < 0) return -EIO; return (*(int *) arg = (status & 0x20) == 0); @@ -359,7 +416,7 @@ aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) vol = *(int *) arg & 0xff; if (vol > 100) vol = 100; vol = SCALE(100, 3, vol); - if (write_cmd(0x03, vol)) return -EIO; + if (aci_write_cmd(0x03, vol)) return -EIO; vol = SCALE(3, 100, vol); return (*(int *) arg = vol | (vol << 8)); case SOUND_MIXER_RECSRC: @@ -414,7 +471,7 @@ aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) case SOUND_MIXER_LINE2: /* AUX2 */ return getvolume(arg, 0x13, 0x12); case SOUND_MIXER_IGAIN: /* MIC pre-amp */ - if (indexed_cmd(0xf0, 0x21, &buf)) return -EIO; + if (aci_indexed_cmd(0xf0, 0x21, &buf)) return -EIO; vol = SCALE(3, 100, buf <= 3 ? buf : 3); vol |= vol << 8; return (*(int *) arg = vol); @@ -478,13 +535,13 @@ int attach_aci(void) return 0; } - if (read_cmd(0xf2, 2, aci_idcode)) { + if (aci_read_cmd(0xf2, 2, aci_idcode)) { #ifdef DEBUG printk("ACI: Failed to read idcode.\n"); #endif return 0; } - if (read_cmd(0xf1, 1, &aci_version)) { + if (aci_read_cmd(0xf1, 1, &aci_version)) { #ifdef DEBUG printk("ACI: Failed to read version.\n"); #endif @@ -516,7 +573,7 @@ int attach_aci(void) if (aci_reset) { /* initialize ACI mixer */ - implied_cmd(0xff); + aci_implied_cmd(0xff); aci_solo = 0; } @@ -606,3 +663,17 @@ void unload_aci(void) } #endif + +#if defined(MODULE) + +int init_module(void) { + attach_aci(); + return(0); +} + +void cleanup_module(void) { + unload_aci(); +} + +#endif /* MODULE */ + diff --git a/drivers/sound/lowlevel/aedsp16.c b/drivers/sound/lowlevel/aedsp16.c index cb919507e..48ef93f19 100644 --- a/drivers/sound/lowlevel/aedsp16.c +++ b/drivers/sound/lowlevel/aedsp16.c @@ -26,6 +26,7 @@ #include <linux/config.h> #include <linux/delay.h> #include <linux/module.h> +#include <linux/init.h> #include "../sound_config.h" #include "../soundmodule.h" @@ -248,6 +249,10 @@ the flexibility of modular version, I have removed all the conditional compilation for SBPRO, MPU and MSS code. Now it is all managed with the ae_config structure. + v1.2 + - Module informations added. + - Removed aedsp16_delay_10msec(), now using mdelay(10) + - All data and funcs moved to .*.init section. Known Problems: - Audio Excel DSP 16 III don't work with this driver. @@ -259,7 +264,7 @@ */ -#define VERSION "1.1" /* Version of Audio Excel DSP 16 driver */ +#define VERSION "1.2" /* Version of Audio Excel DSP 16 driver */ #undef AEDSP16_DEBUG 1 /* Define this to enable debug code */ #undef AEDSP16_DEBUG_MORE 1 /* Define this to enable more debug */ @@ -421,14 +426,14 @@ #define INIT_MSS (1<<1) #define INIT_MPU401 (1<<2) -static int soft_cfg = 0; /* Will contain or'ed values of soft cf */ -static int soft_cfg_1 = 0; /* Will contain or'ed values of some cf */ -static int gc = 0; /* generic counter (utility counter) */ -static int ver[3]; /* DSP Version, hi<-ver[0], lo<-ver[1] */ +static int soft_cfg __initdata = 0; /* bitmapped config */ +static int soft_cfg_mss __initdata = 0; /* bitmapped mss config */ +static int ver[CARDVERLEN] __initdata = {0, 0}; /* DSP Ver: + hi->ver[0] lo->ver[1] */ #if defined(CONFIG_SC6600) static int hard_cfg[2] /* lo<-hard_cfg[0] hi<-hard_cfg[1] */ - = { 0, 0}; + __initdata = { 0, 0}; #endif /* CONFIG_SC6600 */ #if defined(CONFIG_SC6600) @@ -440,7 +445,10 @@ struct d_hcfg { int wssbase; int cdrom; int cdrombase; -} decoded_hcfg; +}; + +struct d_hcfg decoded_hcfg __initdata = {0, }; + #endif /* CONFIG_SC6600 */ /* orVals contain the values to be or'ed */ @@ -464,7 +472,7 @@ struct aedsp16_info { * Magic values that the DSP will eat when configuring irq/mirq/dma */ /* DSP IRQ conversion array */ -static struct orVals orIRQ[] = { +static struct orVals orIRQ[] __initdata = { {0x05, 0x28}, {0x07, 0x08}, {0x09, 0x10}, @@ -474,7 +482,7 @@ static struct orVals orIRQ[] = { }; /* MPU-401 IRQ conversion array */ -static struct orVals orMIRQ[] = { +static struct orVals orMIRQ[] __initdata = { {0x05, 0x04}, {0x07, 0x44}, {0x09, 0x84}, @@ -483,14 +491,14 @@ static struct orVals orMIRQ[] = { }; /* DMA Channels conversion array */ -static struct orVals orDMA[] = { +static struct orVals orDMA[] __initdata = { {0x00, 0x01}, {0x01, 0x02}, {0x03, 0x03}, {0x00, 0x00} }; -static struct aedsp16_info ae_config = { +static struct aedsp16_info ae_config __initdata = { DEF_AEDSP16_IOB, DEF_AEDSP16_IRQ, DEF_AEDSP16_MRQ, @@ -503,16 +511,10 @@ static struct aedsp16_info ae_config = { /* * Buffers to store audio card informations */ -static char DSPCopyright[CARDNAMELEN + 1]; -static char DSPVersion[CARDVERLEN + 1]; +static char DSPCopyright[CARDNAMELEN + 1] __initdata = {0, }; +static char DSPVersion[CARDVERLEN + 1] __initdata = {0, }; -static void aedsp16_delay_10msec(void) -{ - for (gc = 0; gc < 1000; gc++) - udelay(10); -} - -static int aedsp16_wait_data(int port) +static int __init aedsp16_wait_data(int port) { int loop = STATUSRETRY; unsigned char ret = 0; @@ -535,7 +537,7 @@ static int aedsp16_wait_data(int port) return FALSE; } -static int aedsp16_read(int port) +static int __init aedsp16_read(int port) { int inbyte; @@ -553,12 +555,12 @@ static int aedsp16_read(int port) return inbyte; } -static int aedsp16_test_dsp(int port) +static int __init aedsp16_test_dsp(int port) { return ((aedsp16_read(port) == 0xaa) ? TRUE : FALSE); } -static int aedsp16_dsp_reset(int port) +static int __init aedsp16_dsp_reset(int port) { /* * Reset DSP @@ -579,7 +581,7 @@ static int aedsp16_dsp_reset(int port) return FALSE; } -static int aedsp16_write(int port, int cmd) +static int __init aedsp16_write(int port, int cmd) { unsigned char ret; int loop = HARDRETRY; @@ -607,7 +609,7 @@ static int aedsp16_write(int port, int cmd) #if defined(CONFIG_SC6600) #if defined(AEDSP16_INFO) || defined(AEDSP16_DEBUG) -void aedsp16_pinfo(void) { +void __init aedsp16_pinfo(void) { DBG(("\n Base address: %x\n", decoded_hcfg.iobase)); DBG((" Joystick : %s present\n", decoded_hcfg.joystick?"":" not")); DBG((" WSS addr : %x\n", decoded_hcfg.wssbase)); @@ -617,7 +619,7 @@ void aedsp16_pinfo(void) { } #endif -void aedsp16_hard_decode(void) { +void __init aedsp16_hard_decode(void) { DBG((" aedsp16_hard_decode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1])); @@ -661,7 +663,7 @@ void aedsp16_hard_decode(void) { DBG(("success.\n")); } -void aedsp16_hard_encode(void) { +void __init aedsp16_hard_encode(void) { DBG((" aedsp16_hard_encode: 0x%x, 0x%x\n", hard_cfg[0], hard_cfg[1])); @@ -686,7 +688,7 @@ void aedsp16_hard_encode(void) { } -static int aedsp16_hard_write(int port) { +static int __init aedsp16_hard_write(int port) { DBG(("aedsp16_hard_write:\n")); @@ -721,7 +723,7 @@ static int aedsp16_hard_write(int port) { return TRUE; } -static int aedsp16_hard_read(int port) { +static int __init aedsp16_hard_read(int port) { DBG(("aedsp16_hard_read:\n")); @@ -755,7 +757,7 @@ static int aedsp16_hard_read(int port) { return TRUE; } -static int aedsp16_ext_cfg_write(int port) { +static int __init aedsp16_ext_cfg_write(int port) { int extcfg, val; @@ -809,7 +811,7 @@ static int aedsp16_ext_cfg_write(int port) { #endif /* CONFIG_SC6600 */ -static int aedsp16_cfg_write(int port) { +static int __init aedsp16_cfg_write(int port) { if (aedsp16_write(port, WRITE_MDIRQ_CFG)) { printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); return FALSE; @@ -821,11 +823,11 @@ static int aedsp16_cfg_write(int port) { return TRUE; } -static int aedsp16_init_mss(int port) +static int __init aedsp16_init_mss(int port) { DBG(("aedsp16_init_mss:\n")); - aedsp16_delay_10msec(); + mdelay(10); if (aedsp16_write(port, DSP_INIT_MSS)) { printk("[AEDSP16] aedsp16_init_mss [0x%x]: failed!\n", @@ -833,19 +835,20 @@ static int aedsp16_init_mss(int port) DBG(("failure.\n")); return FALSE; } - aedsp16_delay_10msec(); + + mdelay(10); if (aedsp16_cfg_write(port) == FALSE) return FALSE; - outb(soft_cfg_1, ae_config.mss_base); + outb(soft_cfg_mss, ae_config.mss_base); DBG(("success.\n")); return TRUE; } -static int aedsp16_setup_board(int port) { +static int __init aedsp16_setup_board(int port) { int loop = RETRY; #if defined(CONFIG_SC6600) @@ -873,7 +876,7 @@ static int aedsp16_setup_board(int port) { printk("[AEDSP16] CMD 0x%x: failed!\n", COMMAND_88); return FALSE; } - aedsp16_delay_10msec(); + mdelay(10); } while ((aedsp16_wait_data(port) == FALSE) && loop--); if (aedsp16_read(port) == -1) { @@ -934,7 +937,7 @@ static int aedsp16_setup_board(int port) { return TRUE; } -static int aedsp16_stdcfg(int port) { +static int __init aedsp16_stdcfg(int port) { if (aedsp16_write(port, WRITE_MDIRQ_CFG)) { printk("[AEDSP16] CMD 0x%x: failed!\n", WRITE_MDIRQ_CFG); return FALSE; @@ -949,7 +952,7 @@ static int aedsp16_stdcfg(int port) { return TRUE; } -static int aedsp16_dsp_version(int port) +static int __init aedsp16_dsp_version(int port) { int len = 0; int ret; @@ -980,7 +983,7 @@ static int aedsp16_dsp_version(int port) return TRUE; } -static int aedsp16_dsp_copyright(int port) +static int __init aedsp16_dsp_copyright(int port) { int len = 0; int ret; @@ -1016,29 +1019,31 @@ static int aedsp16_dsp_copyright(int port) return TRUE; } -static void aedsp16_init_tables(void) +static void __init aedsp16_init_tables(void) { + int i = 0; + memset(DSPCopyright, 0, CARDNAMELEN + 1); memset(DSPVersion, 0, CARDVERLEN + 1); - for (gc = 0; orIRQ[gc].or; gc++) - if (orIRQ[gc].val == ae_config.irq) { - soft_cfg |= orIRQ[gc].or; - soft_cfg_1 |= orIRQ[gc].or; + for (i = 0; orIRQ[i].or; i++) + if (orIRQ[i].val == ae_config.irq) { + soft_cfg |= orIRQ[i].or; + soft_cfg_mss |= orIRQ[i].or; } - for (gc = 0; orMIRQ[gc].or; gc++) - if (orMIRQ[gc].or == ae_config.mpu_irq) - soft_cfg |= orMIRQ[gc].or; + for (i = 0; orMIRQ[i].or; i++) + if (orMIRQ[i].or == ae_config.mpu_irq) + soft_cfg |= orMIRQ[i].or; - for (gc = 0; orDMA[gc].or; gc++) - if (orDMA[gc].val == ae_config.dma) { - soft_cfg |= orDMA[gc].or; - soft_cfg_1 |= orDMA[gc].or; + for (i = 0; orDMA[i].or; i++) + if (orDMA[i].val == ae_config.dma) { + soft_cfg |= orDMA[i].or; + soft_cfg_mss |= orDMA[i].or; } } -static int aedsp16_init_board(void) +static int __init aedsp16_init_board(void) { aedsp16_init_tables(); @@ -1134,12 +1139,12 @@ static int aedsp16_init_board(void) printk("]\n"); #endif /* MODULE || AEDSP16_INFO || AEDSP16_DEBUG */ - aedsp16_delay_10msec(); + mdelay(10); return TRUE; } -static int init_aedsp16_sb(void) +static int __init init_aedsp16_sb(void) { DBG(("init_aedsp16_sb: ")); @@ -1159,7 +1164,7 @@ static int init_aedsp16_sb(void) return TRUE; } -static void uninit_aedsp16_sb(void) +static void __init uninit_aedsp16_sb(void) { DBG(("uninit_aedsp16_sb: ")); @@ -1168,7 +1173,7 @@ static void uninit_aedsp16_sb(void) DBG(("done.\n")); } -static int init_aedsp16_mss(void) +static int __init init_aedsp16_mss(void) { DBG(("init_aedsp16_mss: ")); @@ -1207,7 +1212,7 @@ static int init_aedsp16_mss(void) return TRUE; } -static void uninit_aedsp16_mss(void) +static void __init uninit_aedsp16_mss(void) { DBG(("uninit_aedsp16_mss: ")); @@ -1221,7 +1226,7 @@ static void uninit_aedsp16_mss(void) DBG(("done.\n")); } -static int init_aedsp16_mpu(void) +static int __init init_aedsp16_mpu(void) { DBG(("init_aedsp16_mpu: ")); @@ -1251,7 +1256,7 @@ static int init_aedsp16_mpu(void) return TRUE; } -static void uninit_aedsp16_mpu(void) +static void __init uninit_aedsp16_mpu(void) { DBG(("uninit_aedsp16_mpu: ")); @@ -1266,7 +1271,7 @@ static void uninit_aedsp16_mpu(void) DBG(("done.\n")); } -int init_aedsp16(void) +int __init init_aedsp16(void) { int initialized = FALSE; @@ -1324,7 +1329,7 @@ int init_aedsp16(void) return initialized; } -void uninit_aedsp16(void) +void __init uninit_aedsp16(void) { if (ae_config.mss_base != -1) uninit_aedsp16_mss(); @@ -1344,12 +1349,20 @@ int mss_base = -1; int mpu_base = -1; -MODULE_PARM(io,"i"); -MODULE_PARM(irq,"i"); -MODULE_PARM(dma,"i"); -MODULE_PARM(mpu_irq,"i"); -MODULE_PARM(mss_base,"i"); -MODULE_PARM(mpu_base,"i"); +MODULE_PARM(io, "i"); +MODULE_PARM_DESC(io, "I/O base address (0x220 0x240)"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "IRQ line (5 7 9 10 11)"); +MODULE_PARM(dma, "i"); +MODULE_PARM_DESC(dma, "dma line (0 1 3)"); +MODULE_PARM(mpu_irq, "i"); +MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ line (5 7 9 10 0)"); +MODULE_PARM(mss_base, "i"); +MODULE_PARM_DESC(mss_base, "MSS emulation I/O base address (0x530 0xE80)"); +MODULE_PARM(mpu_base, "i"); +MODULE_PARM_DESC(mpu_base,"MPU-401 I/O base address (0x300 0x310 0x320 0x330)"); +MODULE_AUTHOR("Riccardo Facchetti <fizban@tin.it>"); +MODULE_DESCRIPTION("Audio Excel DSP 16 Driver Version " VERSION); int init_module(void) { printk("Audio Excel DSP 16 init driver Copyright (C) Riccardo Facchetti 1995-98\n"); diff --git a/drivers/sound/lowlevel/awe_compat.h b/drivers/sound/lowlevel/awe_compat.h index d0c34a1fa..0107bd2c1 100644 --- a/drivers/sound/lowlevel/awe_compat.h +++ b/drivers/sound/lowlevel/awe_compat.h @@ -92,7 +92,7 @@ static void *my_realloc(void *buf, int oldsize, int size) get_user(target, (unsigned char*)&((addr)[offs])) #define GET_SHORT_FROM_USER(target,addr,offs) \ get_user(target, (unsigned short*)&((addr)[offs])) -#ifdef AWE_OSS38 +#ifdef AWE_OSS38_AND_IM_A_BANANA #define IOCTL_TO_USER(target,offs,source,count) \ memcpy(target, (source)+(offs), count) #define IO_WRITE_CHECK(cmd) (_SIOC_DIR(cmd) & _IOC_WRITE) diff --git a/drivers/sound/lowlevel/miroaci.h b/drivers/sound/lowlevel/miroaci.h new file mode 100644 index 000000000..9d64eaa1e --- /dev/null +++ b/drivers/sound/lowlevel/miroaci.h @@ -0,0 +1,6 @@ +extern int aci_implied_cmd(unsigned char opcode); +extern int aci_write_cmd(unsigned char opcode, unsigned char parameter); +extern int aci_write_cmd_d(unsigned char opcode, unsigned char parameter, unsigned char parameter2); +extern int aci_read_cmd(unsigned char opcode, int length, unsigned char *parameter); +extern int aci_indexed_cmd(unsigned char opcode, unsigned char index, unsigned char *parameter); + diff --git a/drivers/sound/lowlevel/soundlow.c b/drivers/sound/lowlevel/soundlow.c index 64ac00ccd..96fdb94be 100644 --- a/drivers/sound/lowlevel/soundlow.c +++ b/drivers/sound/lowlevel/soundlow.c @@ -5,6 +5,7 @@ #include "lowlevel.h" #include <linux/config.h> #include <linux/module.h> +#include <linux/init.h> #include "../soundvers.h" #ifdef LOWLEVEL_MODULE @@ -15,8 +16,8 @@ extern int attach_aci(void); extern void unload_aci(void); extern int attach_awe(void); extern void unload_awe(void); -extern int init_aedsp16(void); -extern void uninit_aedsp16(void); +extern int init_aedsp16(void) __init; +extern void uninit_aedsp16(void) __init; /* * There are two places where you can insert initialization calls of diff --git a/drivers/sound/msnd.c b/drivers/sound/msnd.c index 8c0f99ed8..ad7ceaa48 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.5 1998/07/18 00:12:15 andrewtv Exp $ + * $Id: msnd.c,v 1.9 1998/09/04 18:41:27 andrewtv Exp $ * ********************************************************************/ @@ -168,16 +168,8 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user) } if (user) { -#ifdef LINUX20 - if (verify_area(VERIFY_READ, buf , nwritten)) - return nwritten; - - memcpy_fromfs(f->data + f->tail, buf, nwritten); -#else if (copy_from_user(f->data + f->tail, buf, nwritten)) return -EFAULT; -#endif - } else memcpy(f->data + f->tail, buf, nwritten); @@ -214,15 +206,8 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user) } if (user) { -#ifdef LINUX20 - if (verify_area(VERIFY_WRITE, buf, nread)) - return nread; - - memcpy_tofs(buf, f->data + f->head, nread); -#else if (copy_to_user(buf, f->data + f->head, nread)) return -EFAULT; -#endif } else memcpy(buf, f->data + f->head, nread); @@ -356,8 +341,10 @@ int msnd_disable_irq(multisound_dev_t *dev) if (--dev->irq_ref > 0) return 0; - if (dev->irq_ref < 0) - dev->irq_ref = 0; + if (dev->irq_ref < 0) { + printk(KERN_WARNING LOGNAME ": IRQ ref count is %d\n", dev->irq_ref); +/* dev->irq_ref = 0; */ + } printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n"); diff --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h index b0a330ca4..804cff425 100644 --- a/drivers/sound/msnd.h +++ b/drivers/sound/msnd.h @@ -24,16 +24,16 @@ * 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.6 1998/07/18 00:12:15 andrewtv Exp $ + * $Id: msnd.h,v 1.18 1998/09/04 18:43:40 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_H #define __MSND_H -#define VERSION "0.7.0" +#define VERSION "0.7.13" #define DEFSAMPLERATE DSP_DEFAULT_SPEED -#define DEFSAMPLESIZE 8 +#define DEFSAMPLESIZE AFMT_U8 #define DEFCHANNELS 1 #define DEFFIFOSIZE 64 @@ -142,9 +142,9 @@ #define HDEX_MIDI_OUT_STOP (9 + HDEX_BASE) #define HDEX_AUX_REQ (10 + HDEX_BASE) -#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF )) +#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF)) #define LOWORD(l) ((WORD)(DWORD)(l)) -#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8 ) & 0xFF )) +#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF)) #define LOBYTE(w) ((BYTE)(w)) #define MAKELONG(low,hi) ((long)(((WORD)(low))|(((DWORD)((WORD)(hi)))<<16))) #define MAKEWORD(low,hi) ((WORD)(((BYTE)(low))|(((WORD)((BYTE)(hi)))<<8))) @@ -166,33 +166,31 @@ # define spin_unlock_irqrestore(junk,flags) do { restore_flags(flags); } while (0) #endif -typedef unsigned char BYTE; -typedef unsigned short USHORT; -typedef unsigned short WORD; -typedef unsigned int DWORD; -typedef -struct DAQueueDataStruct * LPDAQD; - -#define GCC_PACKED __attribute__ ((packed)) - -struct JobQueueStruct { - WORD wStart; - WORD wSize; - WORD wHead; - WORD wTail; -} GCC_PACKED; - -struct DAQueueDataStruct { - WORD wStart; - WORD wSize; - WORD wFormat; - WORD wSampleSize; - WORD wChannels; - WORD wSampleRate; - WORD wIntMsg; - WORD wFlags; -} GCC_PACKED; - +/* JobQueueStruct */ +#define JQS_wStart 0x00 +#define JQS_wSize 0x02 +#define JQS_wHead 0x04 +#define JQS_wTail 0x06 +#define JQS__size 0x08 + +/* DAQueueDataStruct */ +#define DAQDS_wStart 0x00 +#define DAQDS_wSize 0x02 +#define DAQDS_wFormat 0x04 +#define DAQDS_wSampleSize 0x06 +#define DAQDS_wChannels 0x08 +#define DAQDS_wSampleRate 0x0A +#define DAQDS_wIntMsg 0x0C +#define DAQDS_wFlags 0x0E +#define DAQDS__size 0x10 + +typedef u8 BYTE; +typedef u16 USHORT; +typedef u16 WORD; +typedef u32 DWORD; +typedef volatile BYTE * LPDAQD; + +/* Generic FIFO */ typedef struct { size_t n, len; char *data; @@ -200,12 +198,12 @@ typedef struct { } msnd_fifo; typedef struct multisound_dev { - + /* Linux device info */ char *name; int dsp_minor, mixer_minor; /* Hardware resources */ - unsigned int io, numio; + int io, numio; int memid, irqid; int irq, irq_ref; unsigned char info; @@ -214,16 +212,14 @@ typedef struct multisound_dev { spinlock_t lock; #endif - /* MultiSound DDK variables */ - enum { msndClassic, msndPinnacle } type; - struct SMA0_CommonData *SMA; /* diff. structure for classic vs. pinnacle */ - struct DAQueueDataStruct *CurDAQD; - struct DAQueueDataStruct *CurDARQD; - volatile WORD *pwDSPQData , *pwMIDQData , *pwMODQData; - volatile struct JobQueueStruct *DAPQ , *DARQ , *MODQ , *MIDQ , *DSPQ; - BYTE bCurrentMidiPatch; + /* Motorola 56k DSP SMA */ + volatile BYTE *SMA; + volatile BYTE *CurDAQD, *CurDARQD; + volatile BYTE *DAPQ, *DARQ, *MODQ, *MIDQ, *DSPQ; + volatile WORD *pwDSPQData, *pwMIDQData, *pwMODQData; /* State variables */ + enum { msndClassic, msndPinnacle } type; mode_t mode; unsigned long flags; #define F_BANKONE 0 @@ -236,27 +232,28 @@ typedef struct multisound_dev { #define F_EXT_MIDI_INUSE 7 #define F_INT_MIDI_INUSE 8 #define F_WRITEFLUSH 9 - +#define F_HAVEDIGITAL 10 struct wait_queue *writeblock, *readblock; struct wait_queue *writeflush; 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; + BYTE bCurrentMidiPatch; void (*inc_ref)(void); void (*dec_ref)(void); /* Digital audio FIFOs */ - int fifosize; msnd_fifo DAPF, DARF; + int fifosize; int lastbank; /* MIDI in callback */ void (*midi_in_interrupt)(struct multisound_dev *); - } multisound_dev_t; #ifndef mdelay diff --git a/drivers/sound/msnd_classic.h b/drivers/sound/msnd_classic.h index 3ae0e0b3b..bdc28ffd0 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.5 1998/07/18 00:12:15 andrewtv Exp $ + * $Id: msnd_classic.h,v 1.7 1998/09/03 06:39:47 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_CLASSIC_H @@ -32,133 +32,133 @@ #include <linux/config.h> -#define DSP_NUMIO 0x10 +#define DSP_NUMIO 0x10 -#define HP_MEMM 0x08 +#define HP_MEMM 0x08 -#define HP_BITM 0x0E -#define HP_WAIT 0x0D -#define HP_DSPR 0x0A -#define HP_PROR 0x0B -#define HP_BLKS 0x0C +#define HP_BITM 0x0E +#define HP_WAIT 0x0D +#define HP_DSPR 0x0A +#define HP_PROR 0x0B +#define HP_BLKS 0x0C -#define HPPRORESET_OFF 0 -#define HPPRORESET_ON 1 +#define HPPRORESET_OFF 0 +#define HPPRORESET_ON 1 -#define HPDSPRESET_OFF 0 -#define HPDSPRESET_ON 1 +#define HPDSPRESET_OFF 0 +#define HPDSPRESET_ON 1 -#define HPBLKSEL_0 0 -#define HPBLKSEL_1 1 +#define HPBLKSEL_0 0 +#define HPBLKSEL_1 1 -#define HPWAITSTATE_0 0 -#define HPWAITSTATE_1 1 +#define HPWAITSTATE_0 0 +#define HPWAITSTATE_1 1 -#define HPBITMODE_16 0 -#define HPBITMODE_8 1 +#define HPBITMODE_16 0 +#define HPBITMODE_8 1 -#define HIDSP_INT_PLAY_UNDER 0x00 -#define HIDSP_INT_RECORD_OVER 0x01 -#define HIDSP_INPUT_CLIPPING 0x02 -#define HIDSP_MIDI_IN_OVER 0x10 +#define HIDSP_INT_PLAY_UNDER 0x00 +#define HIDSP_INT_RECORD_OVER 0x01 +#define HIDSP_INPUT_CLIPPING 0x02 +#define HIDSP_MIDI_IN_OVER 0x10 #define HIDSP_MIDI_OVERRUN_ERR 0x13 -#define HDEXAR_CLEAR_PEAKS 1 -#define HDEXAR_IN_SET_POTS 2 -#define HDEXAR_AUX_SET_POTS 3 -#define HDEXAR_CAL_A_TO_D 4 -#define HDEXAR_RD_EXT_DSP_BITS 5 - -#define TIME_PRO_RESET_DONE 0x028A -#define TIME_PRO_SYSEX 0x0040 -#define TIME_PRO_RESET 0x0032 - -#define AGND 0x01 -#define SIGNAL 0x02 - -#define EXT_DSP_BIT_DCAL 0x0001 -#define EXT_DSP_BIT_MIDI_CON 0x0002 - -#define BUFFSIZE 0x8000 -#define HOSTQ_SIZE 0x40 - -#define SRAM_CNTL_START 0x7F00 -#define SMA_STRUCT_START 0x7F40 - -#define DAP_BUFF_SIZE 0x2400 -#define DAR_BUFF_SIZE 0x2000 - -#define DAPQ_STRUCT_SIZE 0x10 -#define DARQ_STRUCT_SIZE 0x10 -#define DAPQ_BUFF_SIZE (3 * 0x10) -#define DARQ_BUFF_SIZE (3 * 0x10) -#define MODQ_BUFF_SIZE 0x400 -#define MIDQ_BUFF_SIZE 0x200 -#define DSPQ_BUFF_SIZE 0x40 - -#define DAPQ_DATA_BUFF 0x6C00 -#define DARQ_DATA_BUFF 0x6C30 -#define MODQ_DATA_BUFF 0x6C60 -#define MIDQ_DATA_BUFF 0x7060 -#define DSPQ_DATA_BUFF 0x7260 - -#define DAPQ_OFFSET SRAM_CNTL_START -#define DARQ_OFFSET (SRAM_CNTL_START + 0x08) -#define MODQ_OFFSET (SRAM_CNTL_START + 0x10) -#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18) -#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20) - -#define MOP_PROTEUS 0x10 -#define MOP_EXTOUT 0x32 -#define MOP_EXTTHRU 0x02 -#define MOP_OUTMASK 0x01 - -#define MIP_EXTIN 0x01 -#define MIP_PROTEUS 0x00 -#define MIP_INMASK 0x32 - -struct SMA0_CommonData { - WORD wCurrPlayBytes; - WORD wCurrRecordBytes; - WORD wCurrPlayVolLeft; - WORD wCurrPlayVolRight; - WORD wCurrInVolLeft; - WORD wCurrInVolRight; - WORD wUser_3; - WORD wUser_4; - DWORD dwUser_5; - DWORD dwUser_6; - WORD wUser_7; - WORD wReserved_A; - WORD wReserved_B; - WORD wReserved_C; - WORD wReserved_D; - WORD wReserved_E; - WORD wReserved_F; - WORD wReserved_G; - WORD wReserved_H; - WORD wCurrDSPStatusFlags; - WORD wCurrHostStatusFlags; - WORD wCurrInputTagBits; - WORD wCurrLeftPeak; - WORD wCurrRightPeak; - WORD wExtDSPbits; - BYTE bExtHostbits; - BYTE bBoardLevel; - BYTE bInPotPosRight; - BYTE bInPotPosLeft; - BYTE bAuxPotPosRight; - BYTE bAuxPotPosLeft; - WORD wCurrMastVolLeft; - WORD wCurrMastVolRight; - BYTE bUser_12; - BYTE bUser_13; - WORD wUser_14; - WORD wUser_15; - WORD wCalFreqAtoD; - WORD wUser_16; - WORD wUser_17; -} GCC_PACKED; +#define HDEXAR_CLEAR_PEAKS 1 +#define HDEXAR_IN_SET_POTS 2 +#define HDEXAR_AUX_SET_POTS 3 +#define HDEXAR_CAL_A_TO_D 4 +#define HDEXAR_RD_EXT_DSP_BITS 5 + +#define TIME_PRO_RESET_DONE 0x028A +#define TIME_PRO_SYSEX 0x0040 +#define TIME_PRO_RESET 0x0032 + +#define AGND 0x01 +#define SIGNAL 0x02 + +#define EXT_DSP_BIT_DCAL 0x0001 +#define EXT_DSP_BIT_MIDI_CON 0x0002 + +#define BUFFSIZE 0x8000 +#define HOSTQ_SIZE 0x40 + +#define SRAM_CNTL_START 0x7F00 +#define SMA_STRUCT_START 0x7F40 + +#define DAP_BUFF_SIZE 0x2400 +#define DAR_BUFF_SIZE 0x2000 + +#define DAPQ_STRUCT_SIZE 0x10 +#define DARQ_STRUCT_SIZE 0x10 +#define DAPQ_BUFF_SIZE (3 * 0x10) +#define DARQ_BUFF_SIZE (3 * 0x10) +#define MODQ_BUFF_SIZE 0x400 +#define MIDQ_BUFF_SIZE 0x200 +#define DSPQ_BUFF_SIZE 0x40 + +#define DAPQ_DATA_BUFF 0x6C00 +#define DARQ_DATA_BUFF 0x6C30 +#define MODQ_DATA_BUFF 0x6C60 +#define MIDQ_DATA_BUFF 0x7060 +#define DSPQ_DATA_BUFF 0x7260 + +#define DAPQ_OFFSET SRAM_CNTL_START +#define DARQ_OFFSET (SRAM_CNTL_START + 0x08) +#define MODQ_OFFSET (SRAM_CNTL_START + 0x10) +#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18) +#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20) + +#define MOP_PROTEUS 0x10 +#define MOP_EXTOUT 0x32 +#define MOP_EXTTHRU 0x02 +#define MOP_OUTMASK 0x01 + +#define MIP_EXTIN 0x01 +#define MIP_PROTEUS 0x00 +#define MIP_INMASK 0x32 + +/* Classic SMA Common Data */ +#define SMA_wCurrPlayBytes 0x0000 +#define SMA_wCurrRecordBytes 0x0002 +#define SMA_wCurrPlayVolLeft 0x0004 +#define SMA_wCurrPlayVolRight 0x0006 +#define SMA_wCurrInVolLeft 0x0008 +#define SMA_wCurrInVolRight 0x000a +#define SMA_wUser_3 0x000c +#define SMA_wUser_4 0x000e +#define SMA_dwUser_5 0x0010 +#define SMA_dwUser_6 0x0014 +#define SMA_wUser_7 0x0018 +#define SMA_wReserved_A 0x001a +#define SMA_wReserved_B 0x001c +#define SMA_wReserved_C 0x001e +#define SMA_wReserved_D 0x0020 +#define SMA_wReserved_E 0x0022 +#define SMA_wReserved_F 0x0024 +#define SMA_wReserved_G 0x0026 +#define SMA_wReserved_H 0x0028 +#define SMA_wCurrDSPStatusFlags 0x002a +#define SMA_wCurrHostStatusFlags 0x002c +#define SMA_wCurrInputTagBits 0x002e +#define SMA_wCurrLeftPeak 0x0030 +#define SMA_wCurrRightPeak 0x0032 +#define SMA_wExtDSPbits 0x0034 +#define SMA_bExtHostbits 0x0036 +#define SMA_bBoardLevel 0x0037 +#define SMA_bInPotPosRight 0x0038 +#define SMA_bInPotPosLeft 0x0039 +#define SMA_bAuxPotPosRight 0x003a +#define SMA_bAuxPotPosLeft 0x003b +#define SMA_wCurrMastVolLeft 0x003c +#define SMA_wCurrMastVolRight 0x003e +#define SMA_bUser_12 0x0040 +#define SMA_bUser_13 0x0041 +#define SMA_wUser_14 0x0042 +#define SMA_wUser_15 0x0044 +#define SMA_wCalFreqAtoD 0x0046 +#define SMA_wUser_16 0x0048 +#define SMA_wUser_17 0x004a +#define SMA__size 0x004c #ifdef HAVE_DSPCODEH # include "msndperm.c" diff --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c index ac33dcab8..bebb5d49c 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.5 1998/07/18 00:12:16 andrewtv Exp $ + * $Id: msnd_pinnacle.c,v 1.17 1998/09/04 18:41:27 andrewtv Exp $ * ********************************************************************/ @@ -59,11 +59,7 @@ # define LOGNAME "msnd_pinnacle" #endif -#define DEVNAME dev.name -#define MIXERMINOR dev.mixer_minor -#define DSPMINOR dev.dsp_minor - -multisound_dev_t dev; +static multisound_dev_t dev; #ifndef HAVE_DSPCODEH static char *dspini, *permini; @@ -76,25 +72,22 @@ static void reset_play_queue(void) LPDAQD lpDAQ; msnd_fifo_make_empty(&dev.DAPF); - dev.DAPQ->wHead = 0; - dev.DAPQ->wTail = PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE); + 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); - for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) { - - writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart); - writew(DAP_BUFF_SIZE, &lpDAQ->wSize); - writew(1, &lpDAQ->wFormat); - writew(dev.sample_size, &lpDAQ->wSampleSize); - writew(dev.channels, &lpDAQ->wChannels); - writew(dev.sample_rate, &lpDAQ->wSampleRate); - writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg); - writew(n + 1, &lpDAQ->wFlags); - + 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); } - dev.lastbank = -1; } @@ -104,34 +97,62 @@ static void reset_record_queue(void) LPDAQD lpDAQ; msnd_fifo_make_empty(&dev.DARF); - dev.DARQ->wHead = 0; - dev.DARQ->wTail = PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE); + 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); outb(HPBLKSEL_1, dev.io + HP_BLKS); memset_io(dev.base, 0, DAR_BUFF_SIZE * 3); outb(HPBLKSEL_0, dev.io + HP_BLKS); - for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, ++lpDAQ) { - - writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart); - writew(DAR_BUFF_SIZE, &lpDAQ->wSize); - writew(1, &lpDAQ->wFormat); - writew(dev.sample_size, &lpDAQ->wSampleSize); - writew(dev.channels, &lpDAQ->wChannels); - writew(dev.sample_rate, &lpDAQ->wSampleRate); - writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg); - writew(n + 1, &lpDAQ->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); } } static void reset_queues(void) { - dev.DSPQ->wHead = dev.DSPQ->wTail = 0; + writew(0, dev.DSPQ + JQS_wHead); + writew(0, dev.DSPQ + JQS_wTail); reset_play_queue(); reset_record_queue(); } +static int dsp_set_format(int val) +{ + int data, i; + LPDAQD lpDAQ, lpDARQ; + + lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF); + lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF); + + switch (val) { + case AFMT_U8: + case AFMT_S16_LE: + data = val; + break; + default: + data = DEFSAMPLESIZE; + break; + } + + for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { + + writew(data, lpDAQ + DAQDS_wSampleSize); + writew(data, lpDARQ + DAQDS_wSampleSize); + } + + dev.sample_size = data; + + return data; +} + static int dsp_ioctl(unsigned int cmd, unsigned long arg) { int val, i, data, tmp; @@ -154,64 +175,43 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg) case SNDCTL_DSP_SYNC: case SNDCTL_DSP_RESET: - reset_play_queue(); reset_record_queue(); - return 0; case SNDCTL_DSP_GETBLKSIZE: - tmp = dev.fifosize / 4; if (put_user(tmp, (int *)arg)) return -EFAULT; - return 0; - case SNDCTL_DSP_NONBLOCK: - - dev.mode |= O_NONBLOCK; - - return 0; - - case SNDCTL_DSP_GETCAPS: - - val = DSP_CAP_DUPLEX | DSP_CAP_BATCH; + case SNDCTL_DSP_GETFMTS: + val = AFMT_S16_LE | AFMT_U8; if (put_user(val, (int *)arg)) return -EFAULT; - return 0; - case SNDCTL_DSP_SAMPLESIZE: - + case SNDCTL_DSP_SETFMT: if (get_user(val, (int *)arg)) return -EFAULT; - switch (val) { - case 16: - case 8: - data = val; - break; - default: - data = DEFSAMPLESIZE; - break; - } - - for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) { + data = (val == AFMT_QUERY) ? dev.sample_size : dsp_set_format(val); - lpDAQ->wSampleSize = data; - lpDARQ->wSampleSize = data; - } - - dev.sample_size = data; - if (put_user(data, (int *)arg)) return -EFAULT; + return 0; + + case SNDCTL_DSP_NONBLOCK: + dev.mode |= O_NONBLOCK; + return 0; + case SNDCTL_DSP_GETCAPS: + val = DSP_CAP_DUPLEX | DSP_CAP_BATCH; + if (put_user(val, (int *)arg)) + return -EFAULT; return 0; case SNDCTL_DSP_SPEED: - if (get_user(val, (int *)arg)) return -EFAULT; @@ -223,21 +223,19 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg) data = val; - for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) { - - lpDAQ->wSampleRate = data; - lpDARQ->wSampleRate = data; + for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { + + writew(data, lpDAQ + DAQDS_wSampleRate); + writew(data, lpDARQ + DAQDS_wSampleRate); } dev.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; @@ -251,21 +249,19 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg) break; } - for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) { + for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - lpDAQ->wChannels = data; - lpDARQ->wChannels = data; + 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; @@ -280,17 +276,16 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg) break; } - for (i = 0; i < 3; ++i, ++lpDAQ, ++lpDARQ) { + for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) { - lpDAQ->wChannels = data; - lpDARQ->wChannels = data; + writew(data, lpDAQ + DAQDS_wChannels); + writew(data, lpDARQ + DAQDS_wChannels); } dev.channels = data; if (put_user(val, (int *)arg)) return -EFAULT; - return 0; } @@ -319,11 +314,11 @@ static int mixer_get(int d) } } -#define update_vol(a,b,s) \ - writew(dev.left_levels[a] * readw(&dev.SMA->wCurrMastVolLeft) / 0xffff / s, \ - &dev.SMA->b##Left); \ - writew(dev.right_levels[a] * readw(&dev.SMA->wCurrMastVolRight) / 0xffff / s, \ - &dev.SMA->b##Right); +#define update_vol(a,b,s) \ + writew(dev.left_levels[a] * readw(dev.SMA + SMA_wCurrMastVolLeft) / 0xffff / s, \ + dev.SMA + SMA_##b##Left); \ + writew(dev.right_levels[a] * readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff / s, \ + dev.SMA + SMA_##b##Right); static int mixer_set(int d, int value) { @@ -346,30 +341,30 @@ static int mixer_set(int d, int value) switch (d) { case SOUND_MIXER_VOLUME: /* master volume */ - writew(wLeft / 2, &dev.SMA->wCurrMastVolLeft); - writew(wRight / 2, &dev.SMA->wCurrMastVolRight); + writew(wLeft / 2, dev.SMA + SMA_wCurrMastVolLeft); + writew(wRight / 2, dev.SMA + SMA_wCurrMastVolRight); break; /* pot controls */ case SOUND_MIXER_LINE: /* aux pot control */ - writeb(bLeft, &dev.SMA->bInPotPosLeft); - writeb(bRight, &dev.SMA->bInPotPosRight); + 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); break; #ifndef MSND_CLASSIC case SOUND_MIXER_MIC: /* mic pot control */ - writeb(bLeft, &dev.SMA->bMicPotPosLeft); - writeb(bRight, &dev.SMA->bMicPotPosRight); + 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); break; #endif case SOUND_MIXER_LINE1: /* line pot control */ - writeb(bLeft, &dev.SMA->bAuxPotPosLeft); - writeb(bRight, &dev.SMA->bAuxPotPosRight); + 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); break; @@ -396,25 +391,29 @@ static int mixer_set(int d, int value) static unsigned long set_recsrc(unsigned long recsrc) { + if (dev.recsrc == recsrc) + return dev.recsrc; #ifdef HAVE_NORECSRC - if (recsrc == 0) + else if (recsrc == 0) dev.recsrc = 0; - else #endif + else dev.recsrc ^= 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); - } 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); - + } + 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); + } } else { #ifdef HAVE_NORECSRC @@ -431,14 +430,31 @@ static unsigned long set_recsrc(unsigned long recsrc) return dev.recsrc; } +#define set_mixer_info() \ + strncpy(info.id, "MSNDMIXER", sizeof(info.id)); \ + strncpy(info.name, "MultiSound Mixer", sizeof(info.name)); + static int mixer_ioctl(unsigned int cmd, unsigned long arg) { - int val = 0; - - if (((cmd >> 8) & 0xff) == 'M') { + if (cmd == SOUND_MIXER_INFO) { + mixer_info info; + set_mixer_info(); + info.modify_counter = dev.mixer_mod_count; + return copy_to_user((void *)arg, &info, sizeof(info)); + } + else if (cmd == SOUND_OLD_MIXER_INFO) { + _old_mixer_info info; + 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; if (_SIOC_DIR(cmd) & _SIOC_WRITE) { - switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: if (get_user(val, (int *)arg)) @@ -452,7 +468,7 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) val = mixer_set(cmd & 0xff, val); break; } - + ++dev.mixer_mod_count; return put_user(val, (int *)arg); } else { @@ -479,6 +495,8 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg) #else val = SOUND_MASK_LINE | SOUND_MASK_SYNTH; + if (test_bit(F_HAVEDIGITAL, &dev.flags)) + val |= SOUND_MASK_DIGITAL1; #endif break; @@ -503,9 +521,9 @@ static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u { int minor = MINOR(inode->i_rdev); - if (minor == DSPMINOR) + if (minor == dev.dsp_minor) return dsp_ioctl(cmd, arg); - else if (minor == MIXERMINOR) + else if (minor == dev.mixer_minor) return mixer_ioctl(cmd, arg); return -EINVAL; @@ -568,14 +586,14 @@ static int dev_open(struct inode *inode, struct file *file) int minor = MINOR(inode->i_rdev); int err = 0; - if (minor == DSPMINOR) { + if (minor == dev.dsp_minor) { if (test_bit(F_AUDIO_INUSE, &dev.flags)) return -EBUSY; err = dsp_open(file); } - else if (minor == MIXERMINOR) { + else if (minor == dev.mixer_minor) { /* nothing */ } else err = -EINVAL; @@ -597,13 +615,13 @@ static int dev_close(struct inode *inode, struct file *file) int err = 0; #endif - if (minor == DSPMINOR) { + if (minor == dev.dsp_minor) { #ifndef LINUX20 err = #endif dsp_close(); } - else if (minor == MIXERMINOR) { + else if (minor == dev.mixer_minor) { /* nothing */ } #ifndef LINUX20 @@ -741,7 +759,7 @@ 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 == DSPMINOR) { + if (minor == dev.dsp_minor) { return dsp_read(buf, count); @@ -759,7 +777,7 @@ 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 == DSPMINOR) { + if (minor == dev.dsp_minor) { return dsp_write(buf, count); @@ -769,32 +787,32 @@ static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_ static void eval_dsp_msg(WORD wMessage) { + WORD wTmp; + switch (HIBYTE(wMessage)) { case HIMT_PLAY_DONE: - if (dev.lastbank == LOBYTE(wMessage)) break; dev.lastbank = LOBYTE(wMessage); - dev.CurDAQD->wSize = DAP_BUFF_SIZE; + writew(DAP_BUFF_SIZE, dev.CurDAQD + DAQDS_wSize); - if ((dev.DAPQ->wTail += PCTODSP_OFFSET(DAPQ_STRUCT_SIZE)) > dev.DAPQ->wSize) - dev.DAPQ->wTail = 0; + 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 > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE)) + 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); #ifdef LINUX20 if (test_bit(F_WRITEFLUSH, &dev.flags)) { @@ -805,44 +823,33 @@ static void eval_dsp_msg(WORD wMessage) if (test_and_clear_bit(F_WRITEFLUSH, &dev.flags)) wake_up_interruptible(&dev.writeflush); #endif - msnd_disable_irq(&dev); - } } if (test_bit(F_WRITEBLOCK, &dev.flags)) wake_up_interruptible(&dev.writeblock); - break; - case HIMT_RECORD_DONE: { - - WORD wTemp; - - wTemp = dev.DARQ->wTail + (DARQ_STRUCT_SIZE / 2); + case HIMT_RECORD_DONE: + wTmp = readw(dev.DARQ + JQS_wTail) + DARQ_STRUCT_SIZE / 2; - if (wTemp > dev.DARQ->wSize) - wTemp = 0; + if (wTmp > readw(dev.DARQ + JQS_wSize)) + wTmp = 0; - while (wTemp == dev.DARQ->wHead); + while (wTmp == readw(dev.DARQ + JQS_wHead)); - dev.DARQ->wTail = wTemp; + writew(wTmp, dev.DARQ + JQS_wTail); outb(HPBLKSEL_1, dev.io + HP_BLKS); - if (bank_to_DARF(LOBYTE(wMessage)) == 0 && - !test_bit(F_READBLOCK, &dev.flags)) { - + 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); - msnd_disable_irq(&dev); - } outb(HPBLKSEL_0, dev.io + HP_BLKS); if (test_bit(F_READBLOCK, &dev.flags)) wake_up_interruptible(&dev.readblock); - - } break; + break; case HIMT_DSP: switch (LOBYTE(wMessage)) { @@ -850,12 +857,12 @@ static void eval_dsp_msg(WORD wMessage) case HIDSP_PLAY_UNDER: #endif case HIDSP_INT_PLAY_UNDER: - printk(KERN_INFO LOGNAME ": Write underflow\n"); +/* printk(KERN_INFO LOGNAME ": Write underflow\n"); */ reset_play_queue(); break; case HIDSP_INT_RECORD_OVER: - printk(KERN_INFO LOGNAME ": Read overflow\n"); +/* printk(KERN_INFO LOGNAME ": Read overflow\n"); */ reset_record_queue(); break; @@ -892,12 +899,16 @@ static void intr(int irq, void *dev_id, struct pt_regs *regs) inb(dev.io + HP_RXL); - while (dev.DSPQ->wTail != dev.DSPQ->wHead) { - - eval_dsp_msg(*(dev.pwDSPQData + dev.DSPQ->wHead)); + while (readw(dev.DSPQ + JQS_wTail) != readw(dev.DSPQ + JQS_wHead)) { + WORD wTmp; - if (++dev.DSPQ->wHead > dev.DSPQ->wSize) - dev.DSPQ->wHead = 0; + eval_dsp_msg(*(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead))); + + wTmp = readw(dev.DSPQ + JQS_wHead) + 1; + if (wTmp > 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)) @@ -915,12 +926,17 @@ static struct file_operations dev_fileops = { dev_ioctl, NULL, dev_open, +#ifndef LINUX20 +# if LINUX_VERSION_CODE >= 0x020100 + 118 + NULL, +# endif /* >= 2.1.118 */ +#endif dev_close, }; __initfunc(static int reset_dsp(void)) { - int timeout = 20000; + int timeout = 100; outb(HPDSPRESET_ON, dev.io + HP_DSPR); @@ -954,7 +970,6 @@ __initfunc(static int probe_multisound(void)) #endif if (check_region(dev.io, dev.numio)) { - printk(KERN_ERR LOGNAME ": I/O port conflict\n"); return -ENODEV; } @@ -962,7 +977,6 @@ __initfunc(static int probe_multisound(void)) request_region(dev.io, dev.numio, "probing"); if (reset_dsp() < 0) { - release_region(dev.io, dev.numio); return -ENODEV; } @@ -1026,13 +1040,12 @@ __initfunc(static int init_sma(void)) outb(HPBLKSEL_0, dev.io + HP_BLKS); - dev.DAPQ = (struct JobQueueStruct *)(dev.base + DAPQ_OFFSET); - dev.DARQ = (struct JobQueueStruct *)(dev.base + DARQ_OFFSET); - dev.MODQ = (struct JobQueueStruct *)(dev.base + MODQ_OFFSET); - dev.MIDQ = (struct JobQueueStruct *)(dev.base + MIDQ_OFFSET); - dev.DSPQ = (struct JobQueueStruct *)(dev.base + DSPQ_OFFSET); - - dev.SMA = (struct SMA0_CommonData *)(dev.base + SMA_STRUCT_START); + 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); @@ -1041,28 +1054,28 @@ __initfunc(static int init_sma(void)) dev.sample_rate = DEFSAMPLERATE; dev.channels = DEFCHANNELS; - for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, ++lpDAQ) { + for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, lpDAQ += DAQDS__size) { - writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), &lpDAQ->wStart); - writew(DAP_BUFF_SIZE, &lpDAQ->wSize); - writew(1, &lpDAQ->wFormat); - writew(dev.sample_size, &lpDAQ->wSampleSize); - writew(dev.channels, &lpDAQ->wChannels); - writew(dev.sample_rate, &lpDAQ->wSampleRate); - writew(HIMT_PLAY_DONE * 0x100 + n, &lpDAQ->wIntMsg); - writew(n + 1, &lpDAQ->wFlags); + 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) { + for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, lpDAQ += DAQDS__size) { - writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, &lpDAQ->wStart); - writew(DAR_BUFF_SIZE, &lpDAQ->wSize); - writew(1, &lpDAQ->wFormat); - writew(dev.sample_size, &lpDAQ->wSampleSize); - writew(dev.channels, &lpDAQ->wChannels); - writew(dev.sample_rate, &lpDAQ->wSampleRate); - writew(HIMT_RECORD_DONE * 0x100 + n, &lpDAQ->wIntMsg); - writew(n + 1, &lpDAQ->wFlags); + 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); } @@ -1070,68 +1083,68 @@ __initfunc(static int init_sma(void)) dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF); dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF); - writew(PCTODSP_BASED(MIDQ_DATA_BUFF), &dev.MIDQ->wStart); - writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, &dev.MIDQ->wSize); - writew(0, &dev.MIDQ->wHead); - writew(0, &dev.MIDQ->wTail); + 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); - writew(PCTODSP_BASED(MODQ_DATA_BUFF), &dev.MODQ->wStart); - writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, &dev.MODQ->wSize); - writew(0, &dev.MODQ->wHead); - writew(0, &dev.MODQ->wTail); + 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); - writew(PCTODSP_BASED(DAPQ_DATA_BUFF), &dev.DAPQ->wStart); - writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, &dev.DAPQ->wSize); - writew(0, &dev.DAPQ->wHead); - writew(0, &dev.DAPQ->wTail); + 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); - writew(PCTODSP_BASED(DARQ_DATA_BUFF), &dev.DARQ->wStart); - writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, &dev.DARQ->wSize); - writew(0, &dev.DARQ->wHead); - writew(0, &dev.DARQ->wTail); + 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); - writew(PCTODSP_BASED(DSPQ_DATA_BUFF), &dev.DSPQ->wStart); - writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, &dev.DSPQ->wSize); - writew(0, &dev.DSPQ->wHead); - writew(0, &dev.DSPQ->wTail); + 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); - writew(0, &dev.SMA->wCurrPlayBytes); - writew(0, &dev.SMA->wCurrRecordBytes); + writew(0, dev.SMA + SMA_wCurrPlayBytes); + writew(0, dev.SMA + SMA_wCurrRecordBytes); - writew(0, &dev.SMA->wCurrPlayVolLeft); - writew(0, &dev.SMA->wCurrPlayVolRight); + writew(0, dev.SMA + SMA_wCurrPlayVolLeft); + writew(0, dev.SMA + SMA_wCurrPlayVolRight); - writew(0, &dev.SMA->wCurrInVolLeft); - writew(0, &dev.SMA->wCurrInVolRight); + writew(0, dev.SMA + SMA_wCurrInVolLeft); + writew(0, dev.SMA + SMA_wCurrInVolRight); - writew(0, &dev.SMA->wCurrMastVolLeft); - writew(0, &dev.SMA->wCurrMastVolRight); + writew(0, dev.SMA + SMA_wCurrMastVolLeft); + writew(0, dev.SMA + SMA_wCurrMastVolRight); #ifndef MSND_CLASSIC - writel(0x00010000, &dev.SMA->dwCurrPlayPitch); - writel(0x00000001, &dev.SMA->dwCurrPlayRate); + writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch); + writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate); #endif - writew(0x0000, &dev.SMA->wCurrDSPStatusFlags); - writew(0x0000, &dev.SMA->wCurrHostStatusFlags); + writew(0x0000, dev.SMA + SMA_wCurrDSPStatusFlags); + writew(0x0000, dev.SMA + SMA_wCurrHostStatusFlags); - writew(0x303, &dev.SMA->wCurrInputTagBits); - writew(0, &dev.SMA->wCurrLeftPeak); - writew(0, &dev.SMA->wCurrRightPeak); + writew(0x303, dev.SMA + SMA_wCurrInputTagBits); + writew(0, dev.SMA + SMA_wCurrLeftPeak); + writew(0, dev.SMA + SMA_wCurrRightPeak); - writeb(0, &dev.SMA->bInPotPosRight); - writeb(0, &dev.SMA->bInPotPosLeft); + writeb(0, dev.SMA + SMA_bInPotPosRight); + writeb(0, dev.SMA + SMA_bInPotPosLeft); - writeb(0, &dev.SMA->bAuxPotPosRight); - writeb(0, &dev.SMA->bAuxPotPosLeft); + writeb(0, dev.SMA + SMA_bAuxPotPosRight); + writeb(0, dev.SMA + SMA_bAuxPotPosLeft); #ifndef MSND_CLASSIC - writew(1, &dev.SMA->wCurrPlayFormat); - writew(dev.sample_size, &dev.SMA->wCurrPlaySampleSize); - writew(dev.channels, &dev.SMA->wCurrPlayChannels); - writew(dev.sample_rate, &dev.SMA->wCurrPlaySampleRate); + 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->wCalFreqAtoD); + writew(dev.sample_rate, dev.SMA + SMA_wCalFreqAtoD); return 0; } @@ -1139,25 +1152,21 @@ __initfunc(static int init_sma(void)) __initfunc(static int calibrate_adc(WORD srate)) { if (!dev.calibrate_signal) { - printk(KERN_INFO LOGNAME ": ADC calibration to board ground "); - writew(readw(&dev.SMA->wCurrHostStatusFlags) - | 0x0001, &dev.SMA->wCurrHostStatusFlags); - } - else { - + writew(readw(dev.SMA + SMA_wCurrHostStatusFlags) + | 0x0001, dev.SMA + SMA_wCurrHostStatusFlags); + } else { printk(KERN_INFO LOGNAME ": ADC calibration to signal ground "); - writew(readw(&dev.SMA->wCurrHostStatusFlags) - & ~0x0001, &dev.SMA->wCurrHostStatusFlags); + writew(readw(dev.SMA + SMA_wCurrHostStatusFlags) + & ~0x0001, dev.SMA + SMA_wCurrHostStatusFlags); } - writew(srate, &dev.SMA->wCalFreqAtoD); + 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) { - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ; + current->timeout = jiffies + HZ / 3; schedule(); current->timeout = 0; printk("successful\n"); @@ -1191,9 +1200,7 @@ __initfunc(static int upload_dsp_code(void)) } #endif memcpy_toio(dev.base, PERMCODE, PERMCODESIZE); - if (msnd_upload_host(&dev, INITCODE, INITCODESIZE) < 0) { - printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n"); return -ENODEV; } @@ -1228,7 +1235,6 @@ __initfunc(static int initialize(void)) #endif if ((err = init_sma()) < 0) { - printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n"); return err; } @@ -1237,17 +1243,15 @@ __initfunc(static int initialize(void)) return err; if ((err = upload_dsp_code()) < 0) { - printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n"); return err; } else printk(KERN_INFO LOGNAME ": DSP upload successful\n"); - timeout = 2000; + timeout = 200; while (readw(dev.base)) { - mdelay(1); if (--timeout < 0) return -EIO; @@ -1262,17 +1266,15 @@ __initfunc(static int attach_multisound(void)) printk(KERN_DEBUG LOGNAME ": Intializing DSP\n"); - if ((err = request_irq(dev.irq, intr, SA_SHIRQ, DEVNAME, &dev)) < 0) { - + if ((err = request_irq(dev.irq, intr, SA_SHIRQ, dev.name, &dev)) < 0) { printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq); return err; } - request_region(dev.io, dev.numio, DEVNAME); + request_region(dev.io, dev.numio, dev.name); if ((err = initialize()) < 0) { - printk(KERN_WARNING LOGNAME ": Initialization failure\n"); release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); @@ -1281,35 +1283,35 @@ __initfunc(static int attach_multisound(void)) } if ((err = msnd_register(&dev)) < 0) { - printk(KERN_ERR LOGNAME ": Unable to register MultiSound\n"); release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); return err; } - if ((DSPMINOR = register_sound_dsp(&dev_fileops)) < 0) { - + if ((dev.dsp_minor = register_sound_dsp(&dev_fileops)) < 0) { printk(KERN_ERR LOGNAME ": Unable to register DSP operations\n"); msnd_unregister(&dev); release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); - return DSPMINOR; + return dev.dsp_minor; } - if ((MIXERMINOR = register_sound_mixer(&dev_fileops)) < 0) { - + if ((dev.mixer_minor = register_sound_mixer(&dev_fileops)) < 0) { printk(KERN_ERR LOGNAME ": Unable to register mixer operations\n"); - unregister_sound_mixer(MIXERMINOR); + unregister_sound_mixer(dev.mixer_minor); msnd_unregister(&dev); release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); - return MIXERMINOR; + return dev.mixer_minor; } - printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", MIXERMINOR, DSPMINOR); + printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", dev.dsp_minor, dev.mixer_minor); calibrate_adc(dev.sample_rate); - set_recsrc(0); +#ifndef MSND_CLASSIC + printk(KERN_INFO LOGNAME ": Setting initial recording source to Line In\n"); + set_recsrc(SOUND_MASK_LINE); +#endif return 0; } @@ -1318,8 +1320,8 @@ static void unload_multisound(void) { release_region(dev.io, dev.numio); free_irq(dev.irq, &dev); - unregister_sound_mixer(MIXERMINOR); - unregister_sound_dsp(DSPMINOR); + unregister_sound_mixer(dev.mixer_minor); + unregister_sound_dsp(dev.dsp_minor); msnd_unregister(&dev); } @@ -1333,6 +1335,155 @@ static void mod_dec_ref(void) MOD_DEC_USE_COUNT; } +#ifndef MSND_CLASSIC + +/* Pinnacle/Fiji Logical Device Configuration */ + +__initfunc(static int msnd_write_cfg(int cfg, int reg, int value)) +{ + outb(reg, cfg); + outb(value, cfg + 1); + if (value != inb(cfg + 1)) { + printk(KERN_ERR LOGNAME ": msnd_write_cfg: I/O error\n"); + return -EIO; + } + return 0; +} + +__initfunc(static int msnd_write_cfg_io0(int cfg, int num, WORD io)) +{ + if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) + return -EIO; + if (msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io))) + return -EIO; + if (msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io))) + return -EIO; + return 0; +} + +__initfunc(static int msnd_write_cfg_io1(int cfg, int num, WORD io)) +{ + if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) + return -EIO; + if (msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io))) + return -EIO; + if (msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io))) + return -EIO; + return 0; +} + +__initfunc(static int msnd_write_cfg_irq(int cfg, int num, WORD irq)) +{ + if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) + return -EIO; + if (msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq))) + return -EIO; + if (msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE)) + return -EIO; + return 0; +} + +__initfunc(static int msnd_write_cfg_mem(int cfg, int num, int mem)) +{ + WORD wmem; + + mem >>= 8; + mem &= 0xfff; + wmem = (WORD)mem; + if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) + return -EIO; + if (msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem))) + return -EIO; + if (msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem))) + return -EIO; + if (wmem && msnd_write_cfg(cfg, IREG_MEMCONTROL, (MEMTYPE_HIADDR | MEMTYPE_16BIT))) + return -EIO; + return 0; +} + +__initfunc(static int msnd_activate_logical(int cfg, int num)) +{ + if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) + return -EIO; + if (msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE)) + return -EIO; + return 0; +} + +__initfunc(static int msnd_write_cfg_logical(int cfg, int num, WORD io0, WORD io1, WORD irq, int mem)) +{ + if (msnd_write_cfg(cfg, IREG_LOGDEVICE, num)) + return -EIO; + if (msnd_write_cfg_io0(cfg, num, io0)) + return -EIO; + if (msnd_write_cfg_io1(cfg, num, io1)) + return -EIO; + if (msnd_write_cfg_irq(cfg, num, irq)) + return -EIO; + if (msnd_write_cfg_mem(cfg, num, mem)) + return -EIO; + if (msnd_activate_logical(cfg, num)) + return -EIO; + return 0; +} + +typedef struct msnd_pinnacle_cfg_device { + WORD io0, io1, irq; + int mem; +} msnd_pinnacle_cfg_t[4]; + +__initfunc(static int msnd_pinnacle_cfg_devices(int cfg, int reset, msnd_pinnacle_cfg_t device)) +{ + int i; + + /* Reset devices if told to */ + if (reset) { + printk(KERN_INFO LOGNAME ": Resetting all devices\n"); + for (i = 0; i < 4; ++i) + if (msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0)) + return -EIO; + } + + /* Configure specified devices */ + for (i = 0; i < 4; ++i) { + + switch (i) { + case 0: /* DSP */ + if (!(device[i].io0 && device[i].irq && device[i].mem)) + continue; + break; + case 1: /* MPU */ + if (!(device[i].io0 && device[i].irq)) + continue; + printk(KERN_INFO LOGNAME + ": Configuring MPU to I/O 0x%x IRQ %d\n", + device[i].io0, device[i].irq); + break; + case 2: /* IDE */ + if (!(device[i].io0 && device[i].io1 && device[i].irq)) + continue; + printk(KERN_INFO LOGNAME + ": Configuring IDE to I/O 0x%x, 0x%x IRQ %d\n", + device[i].io0, device[i].io1, device[i].irq); + break; + case 3: /* Joystick */ + if (!(device[i].io0)) + continue; + printk(KERN_INFO LOGNAME + ": Configuring joystick to I/O 0x%x\n", + device[i].io0); + break; + } + + /* Configure the device */ + if (msnd_write_cfg_logical(cfg, i, device[i].io0, device[i].io1, device[i].irq, device[i].mem)) + return -EIO; + } + + return 0; +} +#endif + #ifdef MODULE MODULE_AUTHOR ("Andrew Veliath <andrewtv@usa.net>"); MODULE_DESCRIPTION ("Turtle Beach " LONGNAME " Linux Driver"); @@ -1342,35 +1493,135 @@ MODULE_PARM (mem, "i"); MODULE_PARM (major, "i"); MODULE_PARM (fifosize, "i"); MODULE_PARM (calibrate_signal, "i"); +#ifndef MSND_CLASSIC +MODULE_PARM (digital, "i"); +MODULE_PARM (cfg, "i"); +MODULE_PARM (reset, "i"); +MODULE_PARM (mpu_io, "i"); +MODULE_PARM (mpu_irq, "i"); +MODULE_PARM (ide_io0, "i"); +MODULE_PARM (ide_io1, "i"); +MODULE_PARM (ide_irq, "i"); +MODULE_PARM (joystick_io, "i"); +#endif static int io __initdata = -1; static int irq __initdata = -1; static int mem __initdata = -1; + +#ifndef MSND_CLASSIC +/* Pinnacle/Fiji non-PnP Config Port */ +static int cfg __initdata = -1; + +/* Extra Peripheral Configuration */ +static int reset __initdata; +static int mpu_io __initdata; +static int mpu_irq __initdata; +static int ide_io0 __initdata; +static int ide_io1 __initdata; +static int ide_irq __initdata; +static int joystick_io __initdata; + +/* If we have the digital daugherboard... */ +static int digital __initdata; +#endif + static int fifosize __initdata = DEFFIFOSIZE; static int calibrate_signal __initdata; +/* If we're a module, this is just init_module */ + int init_module(void) + #else /* not a module */ + #ifdef MSND_CLASSIC static int io __initdata = CONFIG_MSNDCLAS_IO; static int irq __initdata = CONFIG_MSNDCLAS_IRQ; static int mem __initdata = CONFIG_MSNDCLAS_MEM; -#else +#else /* Pinnacle/Fiji */ + static int io __initdata = CONFIG_MSNDPIN_IO; static int irq __initdata = CONFIG_MSNDPIN_IRQ; static int mem __initdata = CONFIG_MSNDPIN_MEM; + +/* Pinnacle/Fiji non-PnP Config Port */ +#ifdef CONFIG_MSNDPIN_NONPNP +# ifndef CONFIG_MSNDPIN_CFG +# define CONFIG_MSNDPIN_CFG 0x250 +# endif +#else +# ifdef CONFIG_MSNDPIN_CFG +# undef CONFIG_MSNDPIN_CFG +# endif +# define CONFIG_MSNDPIN_CFG -1 #endif -static int fifosize __initdata = DEFFIFOSIZE; -static int calibrate_signal __initdata; +static int cfg __initdata = CONFIG_MSNDPIN_CFG; +/* If not a module, we don't need to bother with reset=1 */ +static int reset __initdata; + +/* Extra Peripheral Configuration (Default: Disable) */ +#ifndef CONFIG_MSNDPIN_MPU_IO +# define CONFIG_MSNDPIN_MPU_IO 0 +#endif +static int mpu_io __initdata = CONFIG_MSNDPIN_MPU_IO; + +#ifndef CONFIG_MSNDPIN_MPU_IRQ +# define CONFIG_MSNDPIN_MPU_IRQ 0 +#endif +static int mpu_irq __initdata = CONFIG_MSNDPIN_MPU_IRQ; + +#ifndef CONFIG_MSNDPIN_IDE_IO0 +# define CONFIG_MSNDPIN_IDE_IO0 0 +#endif +static int ide_io0 __initdata = CONFIG_MSNDPIN_IDE_IO0; + +#ifndef CONFIG_MSNDPIN_IDE_IO1 +# define CONFIG_MSNDPIN_IDE_IO1 0 +#endif +static int ide_io1 __initdata = CONFIG_MSNDPIN_IDE_IO1; + +#ifndef CONFIG_MSNDPIN_IDE_IRQ +# define CONFIG_MSNDPIN_IDE_IRQ 0 +#endif +static int ide_irq __initdata = CONFIG_MSNDPIN_IDE_IRQ; + +#ifndef CONFIG_MSNDPIN_JOYSTICK_IO +# define CONFIG_MSNDPIN_JOYSTICK_IO 0 +#endif +static int joystick_io __initdata = CONFIG_MSNDPIN_JOYSTICK_IO; + +/* Have SPDIF (Digital) Daughterboard */ +#ifndef CONFIG_MSNDPIN_DIGITAL +# define CONFIG_MSNDPIN_DIGITAL 0 +#endif +static int digital __initdata = CONFIG_MSNDPIN_DIGITAL; + +#endif /* MSND_CLASSIC */ + +#ifndef CONFIG_MSND_FIFOSIZE +# define CONFIG_MSND_FIFOSIZE DEFFIFOSIZE +#endif +static int fifosize __initdata = CONFIG_MSND_FIFOSIZE; + +#ifndef CONFIG_MSND_CALSIGNAL +# define CONFIG_MSND_CALSIGNAL 0 +#endif +static int +calibrate_signal __initdata = CONFIG_MSND_CALSIGNAL; #ifdef MSND_CLASSIC __initfunc(int msnd_classic_init(void)) #else __initfunc(int msnd_pinnacle_init(void)) #endif /* MSND_CLASSIC */ -#endif + +#endif /* MODULE */ { int err; +#ifndef MSND_CLASSIC + static msnd_pinnacle_cfg_t pinnacle_devs; +#endif /* MSND_CLASSIC */ printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version " VERSION ", Copyright (C) 1998 Andrew Veliath\n"); @@ -1379,7 +1630,7 @@ __initfunc(int msnd_pinnacle_init(void)) printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n"); } - + if (io == -1 || !(io == 0x290 || io == 0x260 || @@ -1390,7 +1641,7 @@ __initfunc(int msnd_pinnacle_init(void)) io == 0x210 || io == 0x3e0)) { - printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set\n"); + 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; } @@ -1437,6 +1688,47 @@ __initfunc(int msnd_pinnacle_init(void)) case 0xe0000: dev.memid = HPMEM_E000; break; case 0xe8000: dev.memid = HPMEM_E800; break; } +#else + if (cfg == -1) { + printk(KERN_INFO LOGNAME ": Assuming PnP mode\n"); + } else if (cfg != 0x250 && cfg != 0x260 && cfg != 0x270) { + printk(KERN_INFO LOGNAME ": Config port must be 0x250, 0x260 or 0x270 (or unspecified for PnP mode)\n"); + return -EINVAL; + } else { + printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%x\n", cfg); + + /* DSP */ + pinnacle_devs[0].io0 = io; + pinnacle_devs[0].irq = irq; + pinnacle_devs[0].mem = mem; + + /* The following are Pinnacle specific */ + + /* MPU */ + pinnacle_devs[1].io0 = mpu_io; + pinnacle_devs[1].irq = mpu_irq; + + /* IDE */ + pinnacle_devs[2].io0 = ide_io0; + pinnacle_devs[2].io1 = ide_io1; + pinnacle_devs[2].irq = ide_irq; + + /* Joystick */ + pinnacle_devs[3].io0 = joystick_io; + + if (check_region(cfg, 2)) { + printk(KERN_ERR LOGNAME ": Config port 0x%x conflict\n", cfg); + return -EIO; + } + + request_region(cfg, 2, "Pinnacle/Fiji Config"); + if (msnd_pinnacle_cfg_devices(cfg, reset, pinnacle_devs)) { + printk(KERN_ERR LOGNAME ": Device configuration error\n"); + release_region(cfg, 2); + return -EIO; + } + release_region(cfg, 2); + } #endif /* MSND_CLASSIC */ if (fifosize < 16) @@ -1460,6 +1752,13 @@ __initfunc(int msnd_pinnacle_init(void)) dev.inc_ref = mod_inc_ref; dev.dec_ref = mod_dec_ref; +#ifndef MSND_CLASSIC + if (digital) { + set_bit(F_HAVEDIGITAL, &dev.flags); + printk(KERN_INFO LOGNAME ": Digital I/O access enabled\n"); + } +#endif + init_waitqueue(&dev.writeblock); init_waitqueue(&dev.readblock); init_waitqueue(&dev.writeflush); diff --git a/drivers/sound/msnd_pinnacle.h b/drivers/sound/msnd_pinnacle.h index f6971c949..0ae9a1026 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.5 1998/07/18 00:12:16 andrewtv Exp $ + * $Id: msnd_pinnacle.h,v 1.8 1998/09/03 06:39:47 andrewtv Exp $ * ********************************************************************/ #ifndef __MSND_PINNACLE_H @@ -32,189 +32,196 @@ #include <linux/config.h> -#define DSP_NUMIO 0x08 - -#define HP_DSPR 0x04 -#define HP_BLKS 0x04 - -#define HPDSPRESET_OFF 2 -#define HPDSPRESET_ON 0 - -#define HPBLKSEL_0 2 -#define HPBLKSEL_1 3 - -#define HIMT_DAT_OFF 0x03 - -#define HIDSP_PLAY_UNDER 0x00 -#define HIDSP_INT_PLAY_UNDER 0x01 -#define HIDSP_SSI_TX_UNDER 0x02 -#define HIDSP_RECQ_OVERFLOW 0x08 -#define HIDSP_INT_RECORD_OVER 0x09 -#define HIDSP_SSI_RX_OVERFLOW 0x0a - -#define HIDSP_MIDI_IN_OVER 0x10 - -#define HIDSP_MIDI_FRAME_ERR 0x11 -#define HIDSP_MIDI_PARITY_ERR 0x12 -#define HIDSP_MIDI_OVERRUN_ERR 0x13 - -#define HIDSP_INPUT_CLIPPING 0x20 -#define HIDSP_MIX_CLIPPING 0x30 -#define HIDSP_DAT_IN_OFF 0x21 - -#define HDEXAR_SET_ANA_IN 0 -#define HDEXAR_CLEAR_PEAKS 1 -#define HDEXAR_IN_SET_POTS 2 -#define HDEXAR_AUX_SET_POTS 3 -#define HDEXAR_CAL_A_TO_D 4 -#define HDEXAR_RD_EXT_DSP_BITS 5 - -#define HDEXAR_SET_SYNTH_IN 4 -#define HDEXAR_READ_DAT_IN 5 -#define HDEXAR_MIC_SET_POTS 6 -#define HDEXAR_SET_DAT_IN 7 - -#define HDEXAR_SET_SYNTH_48 8 -#define HDEXAR_SET_SYNTH_44 9 - -#define TIME_PRO_RESET_DONE 0x028A -#define TIME_PRO_SYSEX 0x001E -#define TIME_PRO_RESET 0x0032 - -#define AGND 0x01 -#define SIGNAL 0x02 - -#define EXT_DSP_BIT_DCAL 0x0001 -#define EXT_DSP_BIT_MIDI_CON 0x0002 - -#define BUFFSIZE 0x8000 -#define HOSTQ_SIZE 0x40 - -#define SRAM_CNTL_START 0x7F00 -#define SMA_STRUCT_START 0x7F40 - -#define DAP_BUFF_SIZE 0x2400 -#define DAR_BUFF_SIZE 0x2000 - -#define DAPQ_STRUCT_SIZE 0x10 -#define DARQ_STRUCT_SIZE 0x10 -#define DAPQ_BUFF_SIZE (3 * 0x10) -#define DARQ_BUFF_SIZE (3 * 0x10) -#define MODQ_BUFF_SIZE 0x400 -#define MIDQ_BUFF_SIZE 0x800 -#define DSPQ_BUFF_SIZE 0x5A0 - -#define DAPQ_DATA_BUFF 0x6C00 -#define DARQ_DATA_BUFF 0x6C30 -#define MODQ_DATA_BUFF 0x6C60 -#define MIDQ_DATA_BUFF 0x7060 -#define DSPQ_DATA_BUFF 0x7860 - -#define DAPQ_OFFSET SRAM_CNTL_START -#define DARQ_OFFSET (SRAM_CNTL_START + 0x08) -#define MODQ_OFFSET (SRAM_CNTL_START + 0x10) -#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18) -#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20) - -#define WAVEHDR_MOP 0 -#define EXTOUT_MOP 1 -#define HWINIT_MOP 0xFE -#define NO_MOP 0xFF - -#define MAX_MOP 1 - -#define EXTIN_MIP 0 -#define WAVEHDR_MIP 1 -#define HWINIT_MIP 0xFE - -#define MAX_MIP 1 - -struct SMA0_CommonData { - WORD wCurrPlayBytes; - WORD wCurrRecordBytes; - WORD wCurrPlayVolLeft; - WORD wCurrPlayVolRight; - - WORD wCurrInVolLeft; - WORD wCurrInVolRight; - WORD wCurrMHdrVolLeft; - WORD wCurrMHdrVolRight; - - DWORD dwCurrPlayPitch; - DWORD dwCurrPlayRate; - - WORD wCurrMIDIIOPatch; - - WORD wCurrPlayFormat; - WORD wCurrPlaySampleSize; - WORD wCurrPlayChannels; - WORD wCurrPlaySampleRate; - - WORD wCurrRecordFormat; - WORD wCurrRecordSampleSize; - WORD wCurrRecordChannels; - WORD wCurrRecordSampleRate; - - WORD wCurrDSPStatusFlags; - WORD wCurrHostStatusFlags; - - WORD wCurrInputTagBits; - WORD wCurrLeftPeak; - WORD wCurrRightPeak; - - BYTE bMicPotPosLeft; - BYTE bMicPotPosRight; - - BYTE bMicPotMaxLeft; - BYTE bMicPotMaxRight; - - BYTE bInPotPosLeft; - BYTE bInPotPosRight; - - BYTE bAuxPotPosLeft; - BYTE bAuxPotPosRight; - - BYTE bInPotMaxLeft; - BYTE bInPotMaxRight; - BYTE bAuxPotMaxLeft; - BYTE bAuxPotMaxRight; - BYTE bInPotMaxMethod; - BYTE bAuxPotMaxMethod; - - WORD wCurrMastVolLeft; - WORD wCurrMastVolRight; - - WORD wCalFreqAtoD; - - WORD wCurrAuxVolLeft; - WORD wCurrAuxVolRight; - - WORD wCurrPlay1VolLeft; - WORD wCurrPlay1VolRight; - WORD wCurrPlay2VolLeft; - WORD wCurrPlay2VolRight; - WORD wCurrPlay3VolLeft; - WORD wCurrPlay3VolRight; - WORD wCurrPlay4VolLeft; - WORD wCurrPlay4VolRight; - WORD wCurrPlay1PeakLeft; - WORD wCurrPlay1PeakRight; - WORD wCurrPlay2PeakLeft; - WORD wCurrPlay2PeakRight; - WORD wCurrPlay3PeakLeft; - WORD wCurrPlay3PeakRight; - WORD wCurrPlay4PeakLeft; - WORD wCurrPlay4PeakRight; - WORD wCurrPlayPeakLeft; - WORD wCurrPlayPeakRight; - - WORD wCurrDATSR; - WORD wCurrDATRXCHNL; - WORD wCurrDATTXCHNL; - WORD wCurrDATRXRate; - - DWORD dwDSPPlayCount; -} GCC_PACKED; +#define DSP_NUMIO 0x08 + +#define IREG_LOGDEVICE 0x07 +#define IREG_ACTIVATE 0x30 +#define LD_ACTIVATE 0x01 +#define LD_DISACTIVATE 0x00 +#define IREG_EECONTROL 0x3F +#define IREG_MEMBASEHI 0x40 +#define IREG_MEMBASELO 0x41 +#define IREG_MEMCONTROL 0x42 +#define IREG_MEMRANGEHI 0x43 +#define IREG_MEMRANGELO 0x44 +#define MEMTYPE_8BIT 0x00 +#define MEMTYPE_16BIT 0x02 +#define MEMTYPE_RANGE 0x00 +#define MEMTYPE_HIADDR 0x01 +#define IREG_IO0_BASEHI 0x60 +#define IREG_IO0_BASELO 0x61 +#define IREG_IO1_BASEHI 0x62 +#define IREG_IO1_BASELO 0x63 +#define IREG_IRQ_NUMBER 0x70 +#define IREG_IRQ_TYPE 0x71 +#define IRQTYPE_HIGH 0x02 +#define IRQTYPE_LOW 0x00 +#define IRQTYPE_LEVEL 0x01 +#define IRQTYPE_EDGE 0x00 + +#define HP_DSPR 0x04 +#define HP_BLKS 0x04 + +#define HPDSPRESET_OFF 2 +#define HPDSPRESET_ON 0 + +#define HPBLKSEL_0 2 +#define HPBLKSEL_1 3 + +#define HIMT_DAT_OFF 0x03 + +#define HIDSP_PLAY_UNDER 0x00 +#define HIDSP_INT_PLAY_UNDER 0x01 +#define HIDSP_SSI_TX_UNDER 0x02 +#define HIDSP_RECQ_OVERFLOW 0x08 +#define HIDSP_INT_RECORD_OVER 0x09 +#define HIDSP_SSI_RX_OVERFLOW 0x0a + +#define HIDSP_MIDI_IN_OVER 0x10 + +#define HIDSP_MIDI_FRAME_ERR 0x11 +#define HIDSP_MIDI_PARITY_ERR 0x12 +#define HIDSP_MIDI_OVERRUN_ERR 0x13 + +#define HIDSP_INPUT_CLIPPING 0x20 +#define HIDSP_MIX_CLIPPING 0x30 +#define HIDSP_DAT_IN_OFF 0x21 + +#define HDEXAR_SET_ANA_IN 0 +#define HDEXAR_CLEAR_PEAKS 1 +#define HDEXAR_IN_SET_POTS 2 +#define HDEXAR_AUX_SET_POTS 3 +#define HDEXAR_CAL_A_TO_D 4 +#define HDEXAR_RD_EXT_DSP_BITS 5 + +#define HDEXAR_SET_SYNTH_IN 4 +#define HDEXAR_READ_DAT_IN 5 +#define HDEXAR_MIC_SET_POTS 6 +#define HDEXAR_SET_DAT_IN 7 + +#define HDEXAR_SET_SYNTH_48 8 +#define HDEXAR_SET_SYNTH_44 9 + +#define TIME_PRO_RESET_DONE 0x028A +#define TIME_PRO_SYSEX 0x001E +#define TIME_PRO_RESET 0x0032 + +#define AGND 0x01 +#define SIGNAL 0x02 + +#define EXT_DSP_BIT_DCAL 0x0001 +#define EXT_DSP_BIT_MIDI_CON 0x0002 + +#define BUFFSIZE 0x8000 +#define HOSTQ_SIZE 0x40 + +#define SRAM_CNTL_START 0x7F00 +#define SMA_STRUCT_START 0x7F40 + +#define DAP_BUFF_SIZE 0x2400 +#define DAR_BUFF_SIZE 0x2000 + +#define DAPQ_STRUCT_SIZE 0x10 +#define DARQ_STRUCT_SIZE 0x10 +#define DAPQ_BUFF_SIZE (3 * 0x10) +#define DARQ_BUFF_SIZE (3 * 0x10) +#define MODQ_BUFF_SIZE 0x400 +#define MIDQ_BUFF_SIZE 0x800 +#define DSPQ_BUFF_SIZE 0x5A0 + +#define DAPQ_DATA_BUFF 0x6C00 +#define DARQ_DATA_BUFF 0x6C30 +#define MODQ_DATA_BUFF 0x6C60 +#define MIDQ_DATA_BUFF 0x7060 +#define DSPQ_DATA_BUFF 0x7860 + +#define DAPQ_OFFSET SRAM_CNTL_START +#define DARQ_OFFSET (SRAM_CNTL_START + 0x08) +#define MODQ_OFFSET (SRAM_CNTL_START + 0x10) +#define MIDQ_OFFSET (SRAM_CNTL_START + 0x18) +#define DSPQ_OFFSET (SRAM_CNTL_START + 0x20) + +#define WAVEHDR_MOP 0 +#define EXTOUT_MOP 1 +#define HWINIT_MOP 0xFE +#define NO_MOP 0xFF + +#define MAX_MOP 1 + +#define EXTIN_MIP 0 +#define WAVEHDR_MIP 1 +#define HWINIT_MIP 0xFE + +#define MAX_MIP 1 + +/* Pinnacle/Fiji SMA Common Data */ +#define SMA_wCurrPlayBytes 0x0000 +#define SMA_wCurrRecordBytes 0x0002 +#define SMA_wCurrPlayVolLeft 0x0004 +#define SMA_wCurrPlayVolRight 0x0006 +#define SMA_wCurrInVolLeft 0x0008 +#define SMA_wCurrInVolRight 0x000a +#define SMA_wCurrMHdrVolLeft 0x000c +#define SMA_wCurrMHdrVolRight 0x000e +#define SMA_dwCurrPlayPitch 0x0010 +#define SMA_dwCurrPlayRate 0x0014 +#define SMA_wCurrMIDIIOPatch 0x0018 +#define SMA_wCurrPlayFormat 0x001a +#define SMA_wCurrPlaySampleSize 0x001c +#define SMA_wCurrPlayChannels 0x001e +#define SMA_wCurrPlaySampleRate 0x0020 +#define SMA_wCurrRecordFormat 0x0022 +#define SMA_wCurrRecordSampleSize 0x0024 +#define SMA_wCurrRecordChannels 0x0026 +#define SMA_wCurrRecordSampleRate 0x0028 +#define SMA_wCurrDSPStatusFlags 0x002a +#define SMA_wCurrHostStatusFlags 0x002c +#define SMA_wCurrInputTagBits 0x002e +#define SMA_wCurrLeftPeak 0x0030 +#define SMA_wCurrRightPeak 0x0032 +#define SMA_bMicPotPosLeft 0x0034 +#define SMA_bMicPotPosRight 0x0035 +#define SMA_bMicPotMaxLeft 0x0036 +#define SMA_bMicPotMaxRight 0x0037 +#define SMA_bInPotPosLeft 0x0038 +#define SMA_bInPotPosRight 0x0039 +#define SMA_bAuxPotPosLeft 0x003a +#define SMA_bAuxPotPosRight 0x003b +#define SMA_bInPotMaxLeft 0x003c +#define SMA_bInPotMaxRight 0x003d +#define SMA_bAuxPotMaxLeft 0x003e +#define SMA_bAuxPotMaxRight 0x003f +#define SMA_bInPotMaxMethod 0x0040 +#define SMA_bAuxPotMaxMethod 0x0041 +#define SMA_wCurrMastVolLeft 0x0042 +#define SMA_wCurrMastVolRight 0x0044 +#define SMA_wCalFreqAtoD 0x0046 +#define SMA_wCurrAuxVolLeft 0x0048 +#define SMA_wCurrAuxVolRight 0x004a +#define SMA_wCurrPlay1VolLeft 0x004c +#define SMA_wCurrPlay1VolRight 0x004e +#define SMA_wCurrPlay2VolLeft 0x0050 +#define SMA_wCurrPlay2VolRight 0x0052 +#define SMA_wCurrPlay3VolLeft 0x0054 +#define SMA_wCurrPlay3VolRight 0x0056 +#define SMA_wCurrPlay4VolLeft 0x0058 +#define SMA_wCurrPlay4VolRight 0x005a +#define SMA_wCurrPlay1PeakLeft 0x005c +#define SMA_wCurrPlay1PeakRight 0x005e +#define SMA_wCurrPlay2PeakLeft 0x0060 +#define SMA_wCurrPlay2PeakRight 0x0062 +#define SMA_wCurrPlay3PeakLeft 0x0064 +#define SMA_wCurrPlay3PeakRight 0x0066 +#define SMA_wCurrPlay4PeakLeft 0x0068 +#define SMA_wCurrPlay4PeakRight 0x006a +#define SMA_wCurrPlayPeakLeft 0x006c +#define SMA_wCurrPlayPeakRight 0x006e +#define SMA_wCurrDATSR 0x0070 +#define SMA_wCurrDATRXCHNL 0x0072 +#define SMA_wCurrDATTXCHNL 0x0074 +#define SMA_wCurrDATRXRate 0x0076 +#define SMA_dwDSPPlayCount 0x0078 +#define SMA__size 0x007c #ifdef HAVE_DSPCODEH # include "pndsperm.c" diff --git a/drivers/sound/opl3.c b/drivers/sound/opl3.c index bc6382f99..8898c655a 100644 --- a/drivers/sound/opl3.c +++ b/drivers/sound/opl3.c @@ -169,7 +169,7 @@ int opl3_detect(int ioaddr, int *osp) if (devc == NULL) { - printk(KERN_ERR "OPL3: Can't allocate memory for the device control " + printk(KERN_ERR "opl3: Can't allocate memory for the device control " "structure \n "); return 0; } @@ -495,7 +495,7 @@ static int opl3_start_note (int dev, int voice, int note, int volume) if (instr->channel < 0) { - printk(KERN_WARNING "OPL3: Initializing voice %d with undefined instrument\n", voice); + printk(KERN_WARNING "opl3: Initializing voice %d with undefined instrument\n", voice); return 0; } @@ -1091,7 +1091,7 @@ int opl3_init(int ioaddr, int *osp) if (devc == NULL) { - printk(KERN_ERR "opl3_init: Device control structure not initialized.\n"); + printk(KERN_ERR "opl3: Device control structure not initialized.\n"); return -1; } @@ -1137,16 +1137,15 @@ int opl3_init(int ioaddr, int *osp) if (devc->model == 2) { - if (devc->is_opl4) - conf_printf2("Yamaha OPL4/OPL3 FM", ioaddr, 0, -1, -1); - else - conf_printf2("Yamaha OPL3 FM", ioaddr, 0, -1, -1); + if (devc->is_opl4) + strcpy(devc->fm_info.name, "Yamaha OPL4/OPL3 FM"); + else + strcpy(devc->fm_info.name, "Yamaha OPL3"); devc->v_alloc->max_voice = devc->nr_voice = 18; devc->fm_info.nr_drums = 0; devc->fm_info.synth_subtype = FM_TYPE_OPL3; devc->fm_info.capabilities |= SYNTH_CAP_OPL3; - strcpy(devc->fm_info.name, "Yamaha OPL-3"); for (i = 0; i < 18; i++) { @@ -1160,13 +1159,14 @@ int opl3_init(int ioaddr, int *osp) } else { - conf_printf2("Yamaha OPL2 FM", ioaddr, 0, -1, -1); + strcpy(devc->fm_info.name, "Yamaha OPL2"); devc->v_alloc->max_voice = devc->nr_voice = 9; devc->fm_info.nr_drums = 0; for (i = 0; i < 18; i++) pv_map[i].ioaddr = devc->left_io; }; + conf_printf2(devc->fm_info.name, ioaddr, 0, -1, -1); for (i = 0; i < SBFM_MAXINSTR; i++) devc->i_map[i].channel = -1; @@ -1185,14 +1185,21 @@ int me; int init_module (void) { - printk("YM3812 and OPL-3 driver Copyright (C) by Hannu Savolainen, Rob Hooft 1993-1996\n"); + printk(KERN_INFO "YM3812 and OPL-3 driver Copyright (C) by Hannu Savolainen, Rob Hooft 1993-1996\n"); if (io != -1) /* User loading pure OPL3 module */ { + if (check_region(io, 4)) + { + printk(KERN_WARNING "opl3: I/O port 0x%x already in use\n", io); + return 0; + } if (!opl3_detect(io, NULL)) { return -ENODEV; } me = opl3_init(io, NULL); + request_region(io,4,devc->fm_info.name); + } SOUND_LOCK; return 0; @@ -1202,6 +1209,8 @@ void cleanup_module(void) { if (devc) { + if(devc->base) + release_region(devc->base,4); kfree(devc); devc = NULL; sound_unload_synthdev(me); diff --git a/drivers/sound/sb.h b/drivers/sound/sb.h index 8d7ffe1a7..19f8ee825 100644 --- a/drivers/sound/sb.h +++ b/drivers/sound/sb.h @@ -121,7 +121,7 @@ int sb_dsp_reset (sb_devc *devc); 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); -void sb_dsp_init (struct address_info *hw_config); +int sb_dsp_init (struct address_info *hw_config); void sb_dsp_unload(struct address_info *hw_config); int sb_mixer_init(sb_devc *devc); void sb_mixer_set_stereo (sb_devc *devc, int mode); diff --git a/drivers/sound/sb_card.c b/drivers/sound/sb_card.c index 432501ebc..2fc88cb24 100644 --- a/drivers/sound/sb_card.c +++ b/drivers/sound/sb_card.c @@ -25,7 +25,8 @@ void attach_sb_card(struct address_info *hw_config) { #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) - sb_dsp_init(hw_config); + if(!sb_dsp_init(hw_config)) + hw_config->slots[0] = -1; #endif } @@ -41,7 +42,8 @@ int probe_sb(struct address_info *hw_config) void unload_sb(struct address_info *hw_config) { - sb_dsp_unload(hw_config); + if(hw_config->slots[0]!=-1) + sb_dsp_unload(hw_config); } int sb_be_quiet=0; @@ -92,7 +94,7 @@ int init_module(void) { if (io == -1 || dma == -1 || irq == -1) { - printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n"); + printk(KERN_ERR "sb_card: I/O, IRQ, and DMA are mandatory\n"); return -EINVAL; } config.io_base = io; @@ -104,6 +106,9 @@ int init_module(void) if (!probe_sb(&config)) return -ENODEV; attach_sb_card(&config); + + if(config.slots[0]==-1) + return -ENODEV; #ifdef CONFIG_MIDI config_mpu.io_base = mpu_io; if (mpu_io && probe_sbmpu(&config_mpu)) diff --git a/drivers/sound/sb_common.c b/drivers/sound/sb_common.c index 8fe5a44f0..04b3d7854 100644 --- a/drivers/sound/sb_common.c +++ b/drivers/sound/sb_common.c @@ -162,7 +162,7 @@ static void sbintr(int irq, void *dev_id, struct pt_regs *dummy) break; default: - /* printk( "Sound Blaster: Unexpected interrupt\n"); */ + /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */ ; } } @@ -242,7 +242,7 @@ static int sb16_set_dma_hw(sb_devc * devc) if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) { - printk(KERN_ERR "sb16: Invalid 8 bit DMA (%d)\n", devc->dma8); + printk(KERN_ERR "SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); return 0; } bits = (1 << devc->dma8); @@ -298,7 +298,7 @@ static int sb16_set_irq_hw(sb_devc * devc, int level) ival = 8; break; default: - printk(KERN_ERR "SB16 IRQ%d is not possible\n", level); + printk(KERN_ERR "SB16: Invalid IRQ%d\n", level); return 0; } sb_setmixer(devc, IRQ_NR, ival); @@ -694,7 +694,7 @@ int sb_dsp_detect(struct address_info *hw_config) return 1; } -void sb_dsp_init(struct address_info *hw_config) +int sb_dsp_init(struct address_info *hw_config) { sb_devc *devc; char name[100]; @@ -710,7 +710,7 @@ void sb_dsp_init(struct address_info *hw_config) if (detected_devc == NULL) { MDB(printk("No detected device\n")); - return; + return 0; } devc = detected_devc; detected_devc = NULL; @@ -718,7 +718,7 @@ void sb_dsp_init(struct address_info *hw_config) if (devc->base != hw_config->io_base) { DDB(printk("I/O port mismatch\n")); - return; + return 0; } /* * Now continue initialization of the device @@ -731,7 +731,7 @@ void sb_dsp_init(struct address_info *hw_config) if (request_irq(hw_config->irq, sbintr, 0, "soundblaster", devc) < 0) { printk(KERN_ERR "SB: Can't allocate IRQ%d\n", hw_config->irq); - return; + return 0; } devc->irq_ok = 0; @@ -739,7 +739,7 @@ void sb_dsp_init(struct address_info *hw_config) if (!sb16_set_irq_hw(devc, devc->irq)) /* Unsupported IRQ */ { free_irq(devc->irq, devc); - return; + return 0; } if ((devc->type == 0 || devc->type == MDL_ESS) && devc->major == 3 && devc->minor == 1) @@ -853,7 +853,11 @@ void sb_dsp_init(struct address_info *hw_config) else devc->dma16 = hw_config->dma2; - sb16_set_dma_hw(devc); + if(!sb16_set_dma_hw(devc)) { + free_irq(devc->irq, devc); + return 0; + } + devc->caps |= SB_NO_MIDI; } @@ -903,7 +907,7 @@ void sb_dsp_init(struct address_info *hw_config) { if (sound_alloc_dma(devc->dma8, "SoundBlaster8")) { - printk(KERN_WARNING "SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8); + printk(KERN_WARNING "Sound Blaster: Can't allocate 8 bit DMA channel %d\n", devc->dma8); } if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) { @@ -917,6 +921,7 @@ void sb_dsp_init(struct address_info *hw_config) { MDB(printk("Sound Blaster: no audio devices found.\n")); } + return 1; } void sb_dsp_disable_midi(int io_base) @@ -1160,7 +1165,9 @@ static int ess_midi_init(sb_devc * devc, struct address_info *hw_config) tmp = 1; /* MPU enabled without interrupts */ - switch (hw_config->irq) + /* May be shared: if so the value is -ve */ + + switch(abs(hw_config->irq)) { case 9: tmp = 0x4; diff --git a/drivers/sound/sequencer.c b/drivers/sound/sequencer.c index e4f962035..514333512 100644 --- a/drivers/sound/sequencer.c +++ b/drivers/sound/sequencer.c @@ -1061,7 +1061,10 @@ int sequencer_open(int dev, struct file *file) setup_mode2(); } if (!max_synthdev && !max_mididev) + { + sequencer_busy=0; return -ENXIO; + } synth_open_mask = 0; diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index 4f81fcdf3..82d0461a4 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -43,6 +43,10 @@ * Fix hwptr out of bounds (now mpg123 works) * 14.05.98 0.4 Don't allow excessive interrupt rates * 08.06.98 0.5 First release using Alan Cox' soundcore instead of miscdevice + * 03.08.98 0.6 Do not include modversions.h + * Now mixer behaviour can basically be selected between + * "OSS documented" and "OSS actual" behaviour + * 31.08.98 0.7 Fix realplayer problems - dac.count issues * */ @@ -50,7 +54,6 @@ #include <linux/version.h> #include <linux/module.h> -#include <linux/modversions.h> #include <linux/string.h> #include <linux/ioport.h> #include <linux/sched.h> @@ -71,6 +74,10 @@ /* --------------------------------------------------------------------- */ +#undef OSS_DOCUMENTED_MIXER_SEMANTICS + +/* --------------------------------------------------------------------- */ + #ifndef PCI_VENDOR_ID_S3 #define PCI_VENDOR_ID_S3 0x5333 #endif @@ -245,6 +252,9 @@ struct sv_state { /* mixer stuff */ struct { unsigned int modcnt; +#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS + unsigned short vol[13]; +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } mix; /* wave stuff */ @@ -471,6 +481,7 @@ static unsigned setpll(struct sv_state *s, unsigned char reg, unsigned rate) unsigned long flags; unsigned char r, m, n; unsigned xm, xn, xr, xd, metric = ~0U; + /* the warnings about m and n used uninitialized are bogus and may safely be ignored */ if (rate < 625000/ADCMULT) rate = 625000/ADCMULT; @@ -609,7 +620,7 @@ static void start_adc(struct sv_state *s) unsigned long flags; spin_lock_irqsave(&s->lock, flags); - if ((s->dma_adc.mapped || s->dma_adc.count < s->dma_adc.dmasize - 2*s->dma_adc.fragsize) + if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) && s->dma_adc.ready) { s->enable |= SV_CENABLE_RE; wrindir(s, SV_CIENABLE, s->enable); @@ -619,10 +630,9 @@ static void start_adc(struct sv_state *s) /* --------------------------------------------------------------------- */ -#define DMABUF_DEFAULTORDER 8 +#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT) #define DMABUF_MINORDER 1 - static void dealloc_dmabuf(struct dmabuf *db) { unsigned long map, mapend; @@ -754,10 +764,10 @@ static void sv_update_ptr(struct sv_state *s) s->dma_adc.total_bytes += diff; s->dma_adc.count += diff; if (s->dma_adc.mapped) { - if (s->dma_adc.count >= s->dma_adc.fragsize) + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) wake_up(&s->dma_adc.wait); } else { - if (s->dma_adc.count > s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1)) { + if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) { s->enable &= ~SV_CENABLE_RE; wrindir(s, SV_CIENABLE, s->enable); s->dma_adc.error++; @@ -774,7 +784,7 @@ static void sv_update_ptr(struct sv_state *s) s->dma_dac.total_bytes += diff; if (s->dma_dac.mapped) { s->dma_dac.count += diff; - if (s->dma_dac.count >= s->dma_dac.fragsize) + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) wake_up(&s->dma_dac.wait); } else { s->dma_dac.count -= diff; @@ -782,11 +792,11 @@ static void sv_update_ptr(struct sv_state *s) s->enable &= ~SV_CENABLE_PE; wrindir(s, SV_CIENABLE, s->enable); s->dma_dac.error++; - } else if (s->dma_dac.count <= s->dma_dac.fragsize && !s->dma_dac.endcleared) { + } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) { clear_advance(s); s->dma_dac.endcleared = 1; } - if (s->dma_dac.count < s->dma_dac.dmasize) + if (s->dma_dac.count < (signed)s->dma_dac.dmasize) wake_up(&s->dma_dac.wait); } } @@ -885,6 +895,8 @@ static const struct { [SOUND_MIXER_PCM] = { SV_CIMIX_PCMINL, SV_CIMIX_PCMINR, MT_6MUTE, 0 } }; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS + static int return_mixval(struct sv_state *s, unsigned i, int *arg) { unsigned long flags; @@ -928,6 +940,23 @@ static int return_mixval(struct sv_state *s, unsigned i, int *arg) return put_user((rr << 8) | rl, arg); } +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + +static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = +{ + [SOUND_MIXER_RECLEV] = 1, + [SOUND_MIXER_LINE1] = 2, + [SOUND_MIXER_CD] = 3, + [SOUND_MIXER_LINE] = 4, + [SOUND_MIXER_MIC] = 5, + [SOUND_MIXER_SYNTH] = 6, + [SOUND_MIXER_LINE2] = 7, + [SOUND_MIXER_VOLUME] = 8, + [SOUND_MIXER_PCM] = 9 +}; + +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + static unsigned mixer_recmask(struct sv_state *s) { unsigned long flags; @@ -1022,7 +1051,13 @@ static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg) i = _IOC_NR(cmd); if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type) return -EINVAL; +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } if (_IOC_DIR(cmd) != (_IOC_READ|_IOC_WRITE)) @@ -1116,7 +1151,14 @@ static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg) break; } spin_unlock_irqrestore(&s->lock, flags); +#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS return return_mixval(s, i, (int *)arg); +#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */ + if (!volidx[i]) + return -EINVAL; + s->mix.vol[volidx[i]-1] = val; + return put_user(s->mix.vol[volidx[i]-1], (int *)arg); +#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */ } } @@ -1167,6 +1209,7 @@ static /*const*/ struct file_operations sv_mixer_fops = { &sv_ioctl_mixdev, NULL, /* mmap */ &sv_open_mixdev, + NULL, /* flush */ &sv_release_mixdev, NULL, /* fsync */ NULL, /* fasync */ @@ -1349,7 +1392,7 @@ static unsigned int sv_poll(struct file *file, struct poll_table_struct *wait) sv_update_ptr(s); if (file->f_flags & FMODE_READ) { if (s->dma_adc.mapped) { - if (s->dma_adc.count >= s->dma_adc.fragsize) + if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) mask |= POLLIN | POLLRDNORM; } else { if (s->dma_adc.count > 0) @@ -1358,10 +1401,10 @@ static unsigned int sv_poll(struct file *file, struct poll_table_struct *wait) } if (file->f_flags & FMODE_WRITE) { if (s->dma_dac.mapped) { - if (s->dma_dac.count >= s->dma_dac.fragsize) + if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) mask |= POLLOUT | POLLWRNORM; } else { - if (s->dma_dac.dmasize > s->dma_dac.count) + if ((signed)s->dma_dac.dmasize > s->dma_dac.count) mask |= POLLOUT | POLLWRNORM; } } @@ -1769,6 +1812,7 @@ static /*const*/ struct file_operations sv_audio_fops = { &sv_ioctl, &sv_mmap, &sv_open, + NULL, /* flush */ &sv_release, NULL, /* fsync */ NULL, /* fasync */ @@ -2013,6 +2057,7 @@ static /*const*/ struct file_operations sv_midi_fops = { NULL, /* ioctl */ NULL, /* mmap */ &sv_midi_open, + NULL, /* flush */ &sv_midi_release, NULL, /* fsync */ NULL, /* fasync */ @@ -2186,6 +2231,7 @@ static /*const*/ struct file_operations sv_dmfm_fops = { &sv_dmfm_ioctl, NULL, /* mmap */ &sv_dmfm_open, + NULL, /* flush */ &sv_dmfm_release, NULL, /* fsync */ NULL, /* fasync */ @@ -2200,7 +2246,10 @@ static /*const*/ struct file_operations sv_dmfm_fops = { #define NR_DEVICE 5 static int reverb[NR_DEVICE] = { 0, }; + +#if 0 static int wavetable[NR_DEVICE] = { 0, }; +#endif static unsigned dmaio = 0xac00; @@ -2234,7 +2283,7 @@ __initfunc(int init_sonicvibes(void)) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.5 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.7 time " __TIME__ " " __DATE__ "\n"); #if 0 if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT))) printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n"); @@ -2297,7 +2346,6 @@ __initfunc(int init_sonicvibes(void)) /* hack */ pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */ - if (check_region(s->ioenh, SV_EXTENT_ENH)) { printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1); goto err_region5; @@ -2328,8 +2376,8 @@ __initfunc(int init_sonicvibes(void)) udelay(50); outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */ udelay(50); - outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE | SV_CCTRL_REVERB*/, - s->ioenh + SV_CODEC_CONTROL); + outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */ + | (reverb[index] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL); inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */ wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */ wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */ @@ -2412,9 +2460,11 @@ __initfunc(int init_sonicvibes(void)) #ifdef MODULE MODULE_PARM(reverb, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(reverb, "if 1 enables joystick interface (still need separate driver)"); +MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM"); +#if 0 MODULE_PARM(wavetable, "1-" __MODULE_STRING(NR_DEVICE) "i"); -MODULE_PARM_DESC(wavetable, "if 1 the LINE input is converted to LINE out"); +MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled"); +#endif MODULE_PARM(dmaio, "i"); MODULE_PARM_DESC(dmaio, "if the motherboard BIOS did not allocate DDMA io, allocate them starting at this address"); diff --git a/drivers/sound/sound_core.c b/drivers/sound/sound_core.c index 95ef40a0f..360028421 100644 --- a/drivers/sound/sound_core.c +++ b/drivers/sound/sound_core.c @@ -168,7 +168,7 @@ static void sound_remove_unit(struct sound_unit **list, int unit) * 6 -- sndstat (obsolete) * 7 *16 unused * 8 -- alternate sequencer (see above) - * 9 *16 unused + * 9 *16 raw synthesizer access * 10 *16 unused * 11 *16 unused * 12 *16 unused @@ -212,6 +212,13 @@ int register_sound_dsp(struct file_operations *fops) EXPORT_SYMBOL(register_sound_dsp); +int register_sound_synth(struct file_operations *fops) +{ + return sound_insert_unit(&chains[9], fops, 9, 137); +} + +EXPORT_SYMBOL(register_sound_synth); + void unregister_sound_special(int unit) { sound_remove_unit(&chains[unit&15], unit); @@ -240,6 +247,12 @@ void unregister_sound_dsp(int unit) EXPORT_SYMBOL(unregister_sound_dsp); +void unregister_sound_synth(int unit) +{ + return sound_remove_unit(&chains[9], unit); +} + +EXPORT_SYMBOL(unregister_sound_synth); /* * Now our file operations @@ -262,6 +275,7 @@ static struct file_operations soundcore_fops= NULL, NULL, NULL, + NULL, NULL }; diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 2abd7fa22..1fbb368d8 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -769,6 +769,7 @@ struct file_operations oss_sound_fops = sound_ioctl, sound_mmap, sound_open, + NULL, /* flush */ sound_release }; @@ -846,12 +847,16 @@ static int sound[20] = { #ifdef MODULE +int traceinit = 0; +MODULE_PARM(traceinit, "i"); + int init_module(void) { int err; int ints[21]; int i; + trace_init=traceinit; /* * "sound=" command line handling by Harald Milz. */ diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c index 735dcd93f..3740dd263 100644 --- a/drivers/sound/wavfront.c +++ b/drivers/sound/wavfront.c @@ -1,8 +1,8 @@ -/* - * sound/wavefront.c +/* -*- linux-c -*- * - * A low level driver for Turtle Beach WaveFront Series - * (Maui, Tropez, Tropez Plus, and perhaps the Monterey & Rio) + * sound/wavfront.c + * + * A Linux driver for Turtle Beach WaveFront Series (Maui, Tropez, Tropez Plus) * * This driver supports the onboard wavetable synthesizer (an ICS2115), * including patch, sample and program loading and unloading, conversion @@ -26,18 +26,6 @@ * This chip also controls the configuration of the card: the wavefront * synth is logical unit 4. * - * NOTE: this driver has been written to support multiple WaveFront - * cards, but without using PnP to configure the CS4232, all of them - * would end up with the same configuration. Further, the current - * module loading interface doesn't permit this, since it only allows - * once instance of a module (which happens to be equivalent to a - * single hardware configuration) to be installed at one time.In - * addition, there is a hard limit on the available DMA channels that - * also makes installing more than 1 card limited to purely MIDI/synth - * activities on the second card. Still, the coding style gets rid of - * virtually all globals, which I believe is a better way to code - * device drivers (or anything else, for that matter). - * ********************************************************************** * * Copyright (C) by Paul Barton-Davis 1998 @@ -61,9 +49,12 @@ * aspects of configuring a WaveFront soundcard, particularly the * effects processor. * + * $Id: wavfront.c,v 0.4 1998/07/22 02:12:11 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 - * for more info. */ + * for more info. + */ #include <linux/config.h> #include <linux/module.h> @@ -78,23 +69,26 @@ #define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT #include "midi_synth.h" -#define COPY_FROM_USER(a,b,c) copy_from_user ((a),(b),(c)) -#define COPY_TO_USER(a,b,c) copy_to_user ((a),(b),(c)) +/* This thing is meant to work as a module */ -#if defined(CONFIG_SOUND_WAVEFRONT) || defined(CONFIG_SOUND_WAVEFRONT_MODULE) +#if defined(CONFIG_SOUND_WAVEFRONT_MODULE) && defined(MODULE) -/* This thing is meant to work as a module */ +/* if WF_DEBUG not defined, no run-time debugging messages will + be available via the debug flag setting. Given the current + beta state of the driver, this will remain set until a future + version. +*/ -#ifdef MODULE +#define WF_DEBUG 1 /* bitmasks for WaveFront status port value */ #define STAT_INTR_WRITE 0x40 #define STAT_CAN_WRITE 0x20 -#define STAT_RINTR_ENABLED 0x10 +#define STAT_WINTR_ENABLED 0x10 #define STAT_INTR_READ 0x04 #define STAT_CAN_READ 0x02 -#define STAT_WINTR_ENABLED 0x01 +#define STAT_RINTR_ENABLED 0x01 /*** Module-accessible parameters ***************************************/ @@ -111,7 +105,7 @@ int fx_raw = 1; /* if this is zero, we'll leave the FX processor in operation, whatever that means. */ -int wf_debug_default = 0; /* you can set this to control debugging +int debug_default = 0; /* you can set this to control debugging during driver loading. it takes any combination of the WF_DEBUG_* flags defined in wavefront.h @@ -119,27 +113,33 @@ int wf_debug_default = 0; /* you can set this to control debugging /* XXX this needs to be made firmware and hardware version dependent */ -char *wf_ospath = "/etc/sound/wavefront.os"; /* where to find a processed - version of the WaveFront OS - */ +char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed + version of the WaveFront OS + */ -/* These three don't need to be messed with unless you're trying to - tweak the driver for optimal I/O performance. Read wavefront_wait() - and wavefront_sleep() to see what they do. You may need or want to - tweak them for CPU's different than the 486/66Mhz that I run on. -*/ +int sleep_interval = 100; /* HZ/sleep_interval seconds per sleep */ +int sleep_tries = 50; /* number of times we'll try to sleep */ + +int wait_usecs = 150; /* This magic number seems to give pretty optimal + throughput based on my limited experimentation. + If you want to play around with it and find a better + value, be my guest. Remember, the idea is to + get a number that causes us to just busy wait + for as many WaveFront commands as possible, without + coming up with a number so large that we hog the + whole CPU. -int wf_short_wait_count = 5000; /* loops, CPU dependent */ -int wf_sleep_interval = 50; /* HZ/wf_sleep_interval seconds per sleep */ -int wf_sleep_tries = 100; /*2sec*/ /* number of times we'll try to sleep */ + Specifically, with this number, out of about 134,000 + status waits, only about 250 result in a sleep. + */ MODULE_PARM(wf_raw,"i"); MODULE_PARM(fx_raw,"i"); -MODULE_PARM(wf_debug_default,"i"); -MODULE_PARM(wf_ospath,"s"); -MODULE_PARM(wf_short_wait_count,"i"); -MODULE_PARM(wf_sleep_interval,"i"); -MODULE_PARM(wf_sleep_tries,"i"); +MODULE_PARM(debug_default,"i"); +MODULE_PARM(sleep_interval,"i"); +MODULE_PARM(sleep_tries,"i"); +MODULE_PARM(wait_usecs,"i"); +MODULE_PARM(ospath,"s"); /***************************************************************************/ @@ -150,9 +150,7 @@ static struct synth_info wavefront_info = static int (*midi_load_patch) (int dev, int format, const char *addr, int offs, int count, int pmgr_flag) = NULL; - typedef struct wf_config { - int installed; /* well, is it ? note: doesn't mean "working" */ int devno; /* device number from kernel */ int irq; /* "you were one, one of the few ..." */ int base; /* low i/o port address */ @@ -185,7 +183,7 @@ typedef struct wf_config { volatile int irq_ok; /* set by interrupt handler */ int opened; /* flag, holds open(1) mode */ char debug; /* debugging flags */ - unsigned int freemem; /* installed RAM, in bytes */ + int freemem; /* installed RAM, in bytes */ int synthdev; /* OSS minor devnum for synth */ int mididev; /* OSS minor devno for internal MIDI */ int ext_mididev; /* OSS minor devno for external MIDI */ @@ -198,9 +196,20 @@ typedef struct wf_config { int samples_used; /* how many */ char interrupts_on; /* h/w MPU interrupts enabled ? */ char rom_samples_rdonly; /* can we write on ROM samples */ + struct wait_queue *interrupt_sleeper; +#ifdef WF_STATS + unsigned long status_found_during_loop; + unsigned long status_found_during_sleep[4]; +#endif WF_STATS + } wf_config; -static wf_config wfs[WAVEFRONT_MAX_DEVICES]; +/* Note: because this module doesn't export any symbols, this really isn't + a global variable, even if it looks like one. I was quite confused by + this when I started writing this as a (newer) module -- pbd. +*/ + +static wf_config wavefront_configuration; #define wavefront_status(hw) (inb (hw->status_port)) @@ -210,14 +219,6 @@ static int wffx_ioctl (struct wf_config *, wavefront_fx_info *); static int wffx_init (struct wf_config *hw); static int wavefront_delete_sample (struct wf_config *hw, int sampnum); -static volatile int irq2hw[17] = -{-1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1}; - -static volatile int dev2hw[17] = -{-1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1}; - typedef struct { int cmd; char *action; @@ -304,25 +305,10 @@ static wavefront_command wavefront_commands[] = { { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK }, { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers", 32, 0, 0 }, + { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK }, { 0x00 } }; -wf_config * -hw_from_dev (int dev) - -{ - int i; - - if ((i = dev2hw[dev]) == -1) { - printk (KERN_ERR - "WaveFront: no hardware associated with device %d.\n", - dev); - return 0; - } - - return &wfs[i]; -} - static const char * wavefront_errorstr (int errnum) @@ -370,21 +356,35 @@ wavefront_wait (wf_config *hw, int mask) { int i; + static int short_loop_cnt = 0; + + if (short_loop_cnt == 0) { + short_loop_cnt = (int) (((double) wait_usecs / 1000000.0) * + (double) current_cpu_data.loops_per_sec); + } - for (i = 0; i < wf_short_wait_count; i++) { + for (i = 0; i < short_loop_cnt; i++) { if (wavefront_status(hw) & mask) { +#ifdef WF_STATS + hw->status_found_during_loop++; +#endif WF_STATS return 1; } } - for (i = 0; i < wf_sleep_tries; i++) { + for (i = 0; i < sleep_tries; i++) { if (wavefront_status(hw) & mask) { +#ifdef WF_STATS + if (i < 4) { + hw->status_found_during_sleep[i]++; + } +#endif WF_STATS return 1; } - if (wavefront_sleep (hw, HZ/wf_sleep_interval)) { - return 0; + if (wavefront_sleep (hw, HZ/sleep_interval)) { + return (0); } } @@ -397,23 +397,30 @@ wavefront_read (wf_config *hw) if (wavefront_wait (hw, STAT_CAN_READ)) return inb (hw->data_port); +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: read timeout.\n"); } +#endif WF_DEBUG + return -1; } static int wavefront_write (wf_config *hw, unsigned char data) + { if (wavefront_wait (hw, STAT_CAN_WRITE)) { outb (data, hw->data_port); return 1; } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: write timeout.\n"); } +#endif WF_DEBUG + return 0; } @@ -444,60 +451,74 @@ wavefront_cmd (wf_config *hw, int cmd, rbuf = 0; } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_CMD) { printk (KERN_DEBUG "Wavefront: 0x%x [%s] (%d,%d,%d)\n", cmd, wfcmd->action, wfcmd->read_cnt, wfcmd->write_cnt, wfcmd->need_ack); } +#endif WF_DEBUG if (!wavefront_write (hw, cmd)) { +#ifdef WF_DEBUG if (hw->debug & (WF_DEBUG_IO|WF_DEBUG_CMD)) { printk (KERN_DEBUG "WaveFront: cannot request " "0x%x [%s].\n", cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } if (wfcmd->write_cnt > 0) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: writing %d bytes " "for 0x%x\n", wfcmd->write_cnt, cmd); } +#endif WF_DEBUG for (i = 0; i < wfcmd->write_cnt; i++) { if (!wavefront_write (hw, wbuf[i])) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: bad write for byte %d of 0x%x [%s].\n", i, cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: write[%d] = 0x%x\n", i, wbuf[i]); +#endif WF_DEBUG } } } if (wfcmd->read_cnt > 0) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: reading %d ints " "for 0x%x\n", wfcmd->read_cnt, cmd); } +#endif WF_DEBUG for (i = 0; i < wfcmd->read_cnt; i++) { if ((c = wavefront_read(hw)) == -1) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: bad read for byte %d of 0x%x [%s].\n", i, cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } @@ -505,12 +526,14 @@ wavefront_cmd (wf_config *hw, int cmd, if (c == 0xff) { if ((c = wavefront_read (hw)) == -1) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: bad read for error byte at " "read byte %d of 0x%x [%s].\n", i, cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } @@ -519,7 +542,7 @@ wavefront_cmd (wf_config *hw, int cmd, if (c == 1 && wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) { rbuf[0] = WF_ST_EMPTY; - return 0; + return (0); } else if (c == 3 && wfcmd->cmd == WFC_UPLOAD_PATCH) { @@ -533,6 +556,7 @@ wavefront_cmd (wf_config *hw, int cmd, } else { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: error %d (%s) during " @@ -542,6 +566,7 @@ wavefront_cmd (wf_config *hw, int cmd, wavefront_errorstr (c), i, cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } @@ -549,20 +574,24 @@ wavefront_cmd (wf_config *hw, int cmd, rbuf[i] = c; } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: read[%d] = 0x%x\n", i, rbuf[i]); } +#endif WF_DEBUG } } if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_CMD) { printk (KERN_DEBUG "WaveFront: reading ACK for 0x%x\n", cmd); } +#endif WF_DEBUG /* Some commands need an ACK, but return zero instead of the standard value. @@ -574,11 +603,13 @@ wavefront_cmd (wf_config *hw, int cmd, if (ack != WF_ACK) { if (ack == -1) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: cannot read ack for 0x%x [%s].\n", cmd, wfcmd->action); } +#endif WF_DEBUG return 1; } else { @@ -587,14 +618,17 @@ wavefront_cmd (wf_config *hw, int cmd, if (ack == 0xff) { /* explicit error */ if ((err = wavefront_read (hw)) == -1) { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: cannot read err for 0x%x [%s].\n", cmd, wfcmd->action); } +#endif WF_DEBUG } } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "WaveFront: 0x%x [%s] " @@ -602,22 +636,27 @@ wavefront_cmd (wf_config *hw, int cmd, cmd, wfcmd->action, ack, err, wavefront_errorstr (err)); } +#endif WF_DEBUG return -err; } } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: ack received " "for 0x%x [%s]\n", cmd, wfcmd->action); } +#endif WF_DEBUG } else { +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_CMD) { printk (KERN_DEBUG "Wavefront: 0x%x [%s] does not need " "ACK (%d,%d,%d)\n", cmd, wfcmd->action, wfcmd->read_cnt, wfcmd->write_cnt, wfcmd->need_ack); +#endif WF_DEBUG } } @@ -795,7 +834,7 @@ wavefront_get_sample_status (struct wf_config *hw, int assume_rom) WF_MAX_SAMPLE - hw->samples_used); - return 0; + return (0); } @@ -826,6 +865,7 @@ wavefront_get_patch_status (struct wf_config *hw) printk (KERN_ERR "WaveFront: upload patch " "error 0x%x\n", x); hw->patch_status[i] = 0; + return 1; } } @@ -843,7 +883,7 @@ wavefront_get_patch_status (struct wf_config *hw) printk (KERN_INFO "WaveFront: %d patch slots filled, %d in use\n", cnt, cnt2); - return 0; + return (0); } static int @@ -889,7 +929,7 @@ wavefront_get_program_status (struct wf_config *hw) printk (KERN_INFO "WaveFront: %d programs slots in use\n", cnt); - return 0; + return (0); } static int @@ -900,10 +940,12 @@ wavefront_send_patch (wf_config *hw, unsigned char buf[WF_PATCH_BYTES+2]; unsigned char *bptr; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: downloading patch %d\n", header->number); } +#endif WF_DEBUG hw->patch_status[header->number] |= WF_SLOT_FILLED; @@ -913,10 +955,10 @@ wavefront_send_patch (wf_config *hw, if (wavefront_cmd (hw, WFC_DOWNLOAD_PATCH, 0, buf)) { printk (KERN_ERR "WaveFront: download patch failed\n"); - return -EIO; + return -(EIO); } - return 0; + return (0); } static int @@ -927,10 +969,12 @@ wavefront_send_program (wf_config *hw, unsigned char buf[WF_PROGRAM_BYTES+1]; int i; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: downloading program %d\n", header->number); } +#endif WF_DEBUG hw->prog_status[header->number] = WF_SLOT_USED; @@ -954,10 +998,10 @@ wavefront_send_program (wf_config *hw, if (wavefront_cmd (hw, WFC_DOWNLOAD_PROGRAM, 0, buf)) { printk (KERN_WARNING "WaveFront: download patch failed\n"); - return -EIO; + return -(EIO); } - return 0; + return (0); } static int @@ -1004,6 +1048,7 @@ wavefront_send_sample (wf_config *hw, int skip = 0; int initial_skip = 0; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: sample %sdownload for slot %d, " "type %d, %d bytes from 0x%x\n", @@ -1011,6 +1056,7 @@ wavefront_send_sample (wf_config *hw, header->number, header->subkey, header->size, (int) header->dataptr); } +#endif WF_DEBUG if (header->size) { @@ -1032,10 +1078,9 @@ wavefront_send_sample (wf_config *hw, or theoretically some other configuration) is the responsibility of the user level library. - To try to do this in the kernel would be a little crazy: - we'd need 24 * 512 bytes (12K) of kernel space just to - hold copies of the original sample headers; the whole - patch/program/sample header data is about 158K!!! + To try to do this in the kernel would be a little + crazy: we'd need 158K of kernel space just to hold + a copy of the patch/program/sample header data. */ if (hw->rom_samples_rdonly) { @@ -1073,7 +1118,7 @@ wavefront_send_sample (wf_config *hw, printk (KERN_ERR "WaveFront: channel selection only possible " "on 16-bit samples"); - return -EINVAL; + return -(EINVAL); } } @@ -1108,11 +1153,13 @@ wavefront_send_sample (wf_config *hw, break; } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: channel selection: %d => " "initial skip = %d, skip = %d\n", WF_GET_CHANNEL (&header->hdr.s), initial_skip, skip); } +#endif WF_DEBUG /* Be safe, and zero the "Unused" bits ... */ @@ -1153,7 +1200,7 @@ wavefront_send_sample (wf_config *hw, /* This one is truly weird. What kind of weirdo decided that in a system dominated by 16- and 32-bit integers, they would use - a 12-bit transfer size ? + just 12 bits ? */ shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3); @@ -1171,7 +1218,7 @@ wavefront_send_sample (wf_config *hw, 0, sample_hdr)) { printk (KERN_WARNING "WaveFront: sample %sdownload refused.\n", header->size ? "" : "header "); - return -EIO; + return -(EIO); } if (header->size == 0) { @@ -1197,7 +1244,7 @@ wavefront_send_sample (wf_config *hw, if (wavefront_cmd (hw, WFC_DOWNLOAD_BLOCK, 0, 0)) { printk (KERN_WARNING "WaveFront: download block " "request refused.\n"); - return -EIO; + return -(EIO); } for (i = 0; i < blocksize; i++) { @@ -1207,7 +1254,7 @@ wavefront_send_sample (wf_config *hw, get_user (sample_short, dataptr); dataptr += skip; - if (data_is_unsigned) { + if (data_is_unsigned) { /* GUS ? */ if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) { @@ -1255,12 +1302,12 @@ wavefront_send_sample (wf_config *hw, if (dma_ack == -1) { printk (KERN_ERR "WaveFront: upload sample " "DMA ack timeout\n"); - return -EIO; + return -(EIO); } else { printk (KERN_ERR "WaveFront: upload sample " "DMA ack error 0x%x\n", dma_ack); - return -EIO; + return -(EIO); } } } @@ -1272,7 +1319,7 @@ wavefront_send_sample (wf_config *hw, */ sent: - return 0; + return (0); } static int @@ -1282,12 +1329,14 @@ wavefront_send_alias (struct wf_config *hw, { unsigned char alias_hdr[WF_ALIAS_BYTES]; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: download alias, %d is " "alias for %d\n", header->number, header->hdr.a.OriginalSample); } +#endif WF_DEBUG munge_int32 (header->number, &alias_hdr[0], 2); munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2); @@ -1304,12 +1353,12 @@ wavefront_send_alias (struct wf_config *hw, if (wavefront_cmd (hw, WFC_DOWNLOAD_SAMPLE_ALIAS, 0, alias_hdr)) { printk (KERN_ERR "WaveFront: download alias failed.\n"); - return -EIO; + return -(EIO); } hw->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS); - return 0; + return (0); } static int @@ -1330,17 +1379,21 @@ wavefront_send_multisample (struct wf_config *hw, num_samples = (1<<(header->hdr.ms.NumberOfSamples&7)); msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: multi %d with %d=%d samples\n", header->number, header->hdr.ms.NumberOfSamples, num_samples); } +#endif WF_DEBUG for (i = 0; i < num_samples; i++) { +#ifdef WF_DEBUG if ((hw->debug & (WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA)) == (WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA)) { printk (KERN_DEBUG "WaveFront: sample[%d] = %d\n", i, header->hdr.ms.SampleNumber[i]); } +#endif WF_DEBUG munge_int32 (header->hdr.ms.SampleNumber[i], &msample_hdr[3+(i*2)], 2); } @@ -1354,12 +1407,12 @@ wavefront_send_multisample (struct wf_config *hw, (unsigned char *) ((num_samples*2)+3), msample_hdr)) { printk (KERN_ERR "WaveFront: download of multisample failed.\n"); - return -EIO; + return -(EIO); } hw->sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE); - return 0; + return (0); } static int @@ -1375,13 +1428,15 @@ wavefront_fetch_multisample (struct wf_config *hw, if (wavefront_cmd (hw, WFC_UPLOAD_MULTISAMPLE, log_ns, number)) { printk (KERN_ERR "WaveFront: upload multisample failed.\n"); - return -EIO; + return -(EIO); } +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: msample %d has %d samples\n", header->number, log_ns[0]); } +#endif WF_DEBUG header->hdr.ms.NumberOfSamples = log_ns[0]; @@ -1395,26 +1450,28 @@ wavefront_fetch_multisample (struct wf_config *hw, if ((d[0] = wavefront_read (hw)) == -1) { printk (KERN_ERR "WaveFront: upload multisample failed " "during sample loop.\n"); - return -EIO; + return -(EIO); } if ((d[1] = wavefront_read (hw)) == -1) { printk (KERN_ERR "WaveFront: upload multisample failed " "during sample loop.\n"); - return -EIO; + return -(EIO); } header->hdr.ms.SampleNumber[i] = demunge_int32 ((unsigned char *) d, 2); +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_DATA) { printk (KERN_DEBUG "WaveFront: msample " "sample[%d] = %d\n", i, header->hdr.ms.SampleNumber[i]); } +#endif WF_DEBUG } - return 0; + return (0); } @@ -1426,12 +1483,14 @@ wavefront_send_drum (struct wf_config *hw, wavefront_patch_info *header) wavefront_drum *drum = &header->hdr.d; int i; +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: downloading edrum for MIDI " "note %d, patch = %d\n", header->number, drum->PatchNumber); } +#endif WF_DEBUG drumbuf[0] = header->number & 0x7f; @@ -1441,10 +1500,10 @@ wavefront_send_drum (struct wf_config *hw, wavefront_patch_info *header) if (wavefront_cmd (hw, WFC_DOWNLOAD_EDRUM_PROGRAM, 0, drumbuf)) { printk (KERN_ERR "WaveFront: download drum failed.\n"); - return -EIO; + return -(EIO); } - return 0; + return (0); } static int @@ -1468,7 +1527,7 @@ wavefront_find_free_patch (struct wf_config *hw) { int i; - for (i = 0; i < WF_MAX_SAMPLE; i++) { + for (i = 0; i < WF_MAX_PATCH; i++) { if (!(hw->patch_status[i] & WF_SLOT_FILLED)) { return i; } @@ -1522,7 +1581,7 @@ wavefront_load_gus_patch (struct wf_config *hw, /* Copy in the header of the GUS patch */ sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch; - COPY_FROM_USER (&((char *) &guspatch)[offs], + copy_from_user (&((char *) &guspatch)[offs], &(addr)[offs], sizeof_patch - offs); if ((i = wavefront_find_free_patch (hw)) == -1) { @@ -1656,19 +1715,15 @@ wavefront_load_patch (int dev, int format, const char *addr, int offs, int count, int pmgr_flag) { - struct wf_config *hw; + struct wf_config *hw = &wavefront_configuration; wavefront_patch_info header; - if ((hw = hw_from_dev (dev)) == 0) { - return -EINVAL; - } - if (format == SYSEX_PATCH) { /* Handled by midi_synth.c */ if (midi_load_patch == NULL) { printk (KERN_ERR "WaveFront: SYSEX not loadable: " "no midi patch loader!\n"); - return -EINVAL; + return -(EINVAL); } return midi_load_patch (dev, format, addr, offs, count, pmgr_flag); @@ -1679,12 +1734,12 @@ wavefront_load_patch (int dev, int format, const char *addr, } else if (format != WAVEFRONT_PATCH) { printk (KERN_ERR "WaveFront: unknown patch format %d\n", format); - return -EINVAL; + return -(EINVAL); } if (count < sizeof (wavefront_patch_info)) { printk (KERN_ERR "WaveFront: sample header too short\n"); - return -EINVAL; + return -(EINVAL); } /* copied in so far: `offs' bytes from `addr'. We shouldn't copy @@ -1694,10 +1749,11 @@ wavefront_load_patch (int dev, int format, const char *addr, through the 'hdrptr' field. */ - COPY_FROM_USER (&((char *) &header)[offs], &(addr)[offs], + copy_from_user (&((char *) &header)[offs], &(addr)[offs], sizeof(wavefront_patch_info) - sizeof(wavefront_any) - offs); +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_LOAD_PATCH) { printk (KERN_DEBUG "WaveFront: download " "Sample type: %d " @@ -1707,11 +1763,12 @@ wavefront_load_patch (int dev, int format, const char *addr, header.number, header.size); } +#endif WF_DEBUG switch (header.subkey) { case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */ - COPY_FROM_USER ((unsigned char *) &header.hdr.s, + copy_from_user ((unsigned char *) &header.hdr.s, (unsigned char *) header.hdrptr, sizeof (wavefront_sample)); @@ -1719,7 +1776,7 @@ wavefront_load_patch (int dev, int format, const char *addr, case WF_ST_MULTISAMPLE: - COPY_FROM_USER ((unsigned char *) &header.hdr.s, + copy_from_user ((unsigned char *) &header.hdr.s, (unsigned char *) header.hdrptr, sizeof (wavefront_multisample)); @@ -1728,28 +1785,28 @@ wavefront_load_patch (int dev, int format, const char *addr, case WF_ST_ALIAS: - COPY_FROM_USER ((unsigned char *) &header.hdr.a, + copy_from_user ((unsigned char *) &header.hdr.a, (unsigned char *) header.hdrptr, sizeof (wavefront_alias)); return wavefront_send_alias (hw, &header); case WF_ST_DRUM: - COPY_FROM_USER ((unsigned char *) &header.hdr.d, + copy_from_user ((unsigned char *) &header.hdr.d, (unsigned char *) header.hdrptr, sizeof (wavefront_drum)); return wavefront_send_drum (hw, &header); case WF_ST_PATCH: - COPY_FROM_USER ((unsigned char *) &header.hdr.p, + copy_from_user ((unsigned char *) &header.hdr.p, (unsigned char *) header.hdrptr, sizeof (wavefront_patch)); return wavefront_send_patch (hw, &header); case WF_ST_PROGRAM: - COPY_FROM_USER ((unsigned char *) &header.hdr.pr, + copy_from_user ((unsigned char *) &header.hdr.pr, (unsigned char *) header.hdrptr, sizeof (wavefront_program)); @@ -1758,7 +1815,7 @@ wavefront_load_patch (int dev, int format, const char *addr, default: printk (KERN_ERR "WaveFront: unknown patch type %d.\n", header.subkey); - return -EINVAL; + return -(EINVAL); } return 0; @@ -1804,24 +1861,19 @@ static int wavefront_synth_control (int dev, int cmd, caddr_t arg) { - struct wf_config *hw; + struct wf_config *hw = &wavefront_configuration; wavefront_control wc; unsigned char patchnumbuf[2]; int i; - if ((hw = hw_from_dev (dev)) == 0) { - printk (KERN_ERR - "WaveFront: synth_control with unknown " - "device number %d\n", dev); - return -EINVAL; - } - - COPY_FROM_USER (&wc, arg, sizeof (wc)); + copy_from_user (&wc, arg, sizeof (wc)); +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_CMD) { printk (KERN_DEBUG "WaveFront: synth control with " "cmd 0x%x\n", wc.cmd); } +#endif WF_DEBUG /* special case handling of or for various commands */ @@ -1940,7 +1992,7 @@ wavefront_synth_control (int dev, int cmd, caddr_t arg) is a low priority fix. */ - COPY_TO_USER (arg, &wc, sizeof (wc)); + copy_to_user (arg, &wc, sizeof (wc)); return 0; } @@ -1953,13 +2005,9 @@ WaveFront: MIDI synth interface static int wavefront_ioctl (int dev, unsigned int cmd, caddr_t arg) { - wf_config *hw; + wf_config *hw = &wavefront_configuration; unsigned char rbuf[4]; - if ((hw = hw_from_dev (dev)) == 0) { - return -EINVAL; - } - switch (cmd) { case SNDCTL_SYNTH_INFO: memcpy (&((char *) arg)[0], &wavefront_info, @@ -1992,7 +2040,7 @@ wavefront_ioctl (int dev, unsigned int cmd, caddr_t arg) return wavefront_synth_control (dev, cmd, arg); default: - return -EINVAL; + return -(EINVAL); } } @@ -2000,32 +2048,30 @@ static int wavefront_open (int dev, int mode) { - struct wf_config *hw; - - if ((hw = hw_from_dev (dev)) == 0) { - return -EINVAL; - } + struct wf_config *hw = &wavefront_configuration; if (hw->opened) { - printk (KERN_ERR "WaveFront: warning: device in use\n"); + printk (KERN_WARNING "WaveFront: warning: device in use\n"); } hw->opened = mode; - return 0; + return (0); } static void wavefront_close (int dev) { - struct wf_config *hw; + struct wf_config *hw = &wavefront_configuration; + int i; - if ((hw = hw_from_dev (dev)) == 0) { - printk (KERN_ERR - "WaveFront: close() called on non-existent dev %d", dev); - return; +#ifdef WF_STATS + printk ("Status during loop: %ld\n", hw->status_found_during_loop); + for (i = 0; i < 4; i++) { + printk ("Status during sleep[%d]: %ld\n", + i, hw->status_found_during_sleep[i]); } - +#endif WF_STATS hw->opened = 0; hw->debug = 0; @@ -2035,70 +2081,65 @@ wavefront_close (int dev) static void wavefront_aftertouch (int dev, int channel, int pressure) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return; - midi_synth_aftertouch (hw->mididev,channel,pressure); + midi_synth_aftertouch (wavefront_configuration.mididev,channel,pressure); }; static void wavefront_bender (int dev, int chn, int value) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return; - midi_synth_bender (hw->mididev, chn, value); + midi_synth_bender (wavefront_configuration.mididev, chn, value); }; static void wavefront_controller (int dev, int channel, int ctrl_num, int value) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return; if(ctrl_num==CTRL_PITCH_BENDER) wavefront_bender(0,channel,value); - midi_synth_controller (hw->mididev, channel,ctrl_num,value); + midi_synth_controller (wavefront_configuration.mididev, + channel,ctrl_num,value); }; static void wavefront_panning(int dev, int channel, int pressure) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return; - midi_synth_controller(hw->mididev,channel,CTL_PAN,pressure); + midi_synth_controller (wavefront_configuration.mididev, + channel,CTL_PAN,pressure); }; static int wavefront_set_instr (int dev, int channel, int instr_no) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return 1; - return(midi_synth_set_instr(hw->mididev,channel,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) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return 1; if (note==255) - return(midi_synth_start_note(hw->mididev, channel, 0, 0)); - return(midi_synth_kill_note(hw->mididev, channel, note, volume)); + return (midi_synth_start_note (wavefront_configuration.mididev, + channel, 0, 0)); + return(midi_synth_kill_note (wavefront_configuration.mididev, + channel, note, volume)); }; static int wavefront_start_note (int dev, int channel, int note, int volume) { - struct wf_config *hw = hw_from_dev (dev); - if (!hw) return 1; - if (note==255) { - /*midi_synth_controller(hw->mididev,channel,7,volume);*/ - midi_synth_aftertouch(hw->mididev,channel,volume); + midi_synth_aftertouch (wavefront_configuration.mididev, + channel,volume); return(0); }; + if (volume==0) { volume=127; - midi_synth_aftertouch(hw->mididev,channel,0); + midi_synth_aftertouch + (wavefront_configuration.mididev, + channel,0); }; - midi_synth_start_note (hw->mididev, channel, note, volume); + + midi_synth_start_note (wavefront_configuration.mididev, + channel, note, volume); return(0); }; @@ -2111,7 +2152,8 @@ static void wavefront_reset (int dev) { int i; - for(i=0;i<16;i++) { + + for (i = 0; i < 16; i++) { midi_synth_kill_note (dev,i,0,0); }; }; @@ -2149,16 +2191,18 @@ WaveFront: OSS/Free and/or Linux kernel installation interface void wavefrontintr (int irq, void *dev_id, struct pt_regs *dummy) { - int i; + /* We don't use this handler except during device + configuration. While the module is installed, the + interrupt is used to signal MIDI interrupts, and is + handled by the interrupt routine in wf_midi.c + */ + + wf_config *hw = (wf_config *) dev_id; + hw->irq_ok = 1; - if (irq < 0 || irq > 16) { - printk (KERN_WARNING "WaveFront: bogus interrupt %d recv'd\n", - irq); - } else if ((i = irq2hw[irq]) == -1) { - printk (KERN_ALERT - "WaveFront: interrupt from unknown hw (irq=%d).\n", irq); - } else { - wfs[i].irq_ok = 1; + if ((wavefront_status(hw) & STAT_INTR_WRITE) || + (wavefront_status(hw) & STAT_INTR_READ)) { + wake_up (&hw->interrupt_sleeper); } } @@ -2173,106 +2217,24 @@ wavefrontintr (int irq, void *dev_id, struct pt_regs *dummy) 6 Host Tx Interrupt Pending (1=Interrupt) 7 Unused -*/ +11111001 + Rx Intr enable + nothing to read from board + no rx interrupt pending + unused + tx interrupt enabled + space to transmit + tx interrupt pending -/* CONTROL REGISTER -0 Host Rx Interrupt Enable (1=Enabled) 0x1 -1 Unused 0x2 -2 Unused 0x4 -3 Unused 0x8 -4 Host Tx Interrupt Enable 0x10 -5 Mute (0=Mute; 1=Play) 0x20 -6 Master Interrupt Enable (1=Enabled) 0x40 -7 Master Reset (0=Reset; 1=Run) 0x80 */ int -probe_wavefront (struct address_info *hw_config) +wavefront_interrupt_bits (int irq) { - int i; - int tmp1, tmp2; - unsigned char bits; - unsigned char rbuf[32], wbuf[32]; - wf_config *hw; - - if (hw_config->irq < 0 || hw_config->irq > 16) { - printk (KERN_WARNING "WaveFront: impossible IRQ suggested(%d)\n", - hw_config->irq); - return 0; - } - - /* Yeah yeah, TB docs say 8, but the FX device on the Tropez Plus - takes up another 8 ... - */ - - if (check_region (hw_config->io_base, 16)) { - printk (KERN_ERR "WaveFront: IO address range 0x%x - 0x%x " - "already in use - ignored\n", hw_config->io_base, - hw_config->io_base+15); - return 0; - } - - for (i = 0; i < WAVEFRONT_MAX_DEVICES; i++) { - if (!wfs[i].installed) { - wfs[i].installed = 1; - break; - } - } - - if (i == WAVEFRONT_MAX_DEVICES) { - printk (KERN_WARNING "WaveFront: no device slots available (max = %d).\n", - WAVEFRONT_MAX_DEVICES); - return 0; - } - - hw = &wfs[i]; - - hw->irq = hw_config->irq; - hw->base = hw_config->io_base; - - hw->israw = 0; - hw->debug = wf_debug_default; - hw->interrupts_on = 0; - hw->rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */ - - hw_config->slots[WF_SYNTH_SLOT] = hw->synthdev = -1; - hw_config->slots[WF_INTERNAL_MIDI_SLOT] = hw->mididev = -1; - hw_config->slots[WF_EXTERNAL_MIDI_SLOT] = hw->ext_mididev = -1; + int bits; - irq2hw[hw_config->irq] = i; - - if (wavefront_cmd (hw, WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) { - hw->fw_version[0] = rbuf[0]; - hw->fw_version[1] = rbuf[1]; - printk (KERN_INFO "WaveFront: firmware %d.%d already loaded.\n", - rbuf[0], rbuf[1]); - - if (wavefront_cmd (hw, WFC_HARDWARE_VERSION, rbuf, wbuf) == 0) { - hw->hw_version[0] = rbuf[0]; - hw->hw_version[1] = rbuf[1]; - } else { - printk (KERN_INFO "WaveFront: not raw, but no hardware version!\n"); - return 0; - } - if (!wf_raw) { - return 1; - } - } else { - hw->israw = 1; - printk (KERN_INFO - "WaveFront: no response to firmware probe, " - "assume raw.\n"); - } - - if (request_irq (hw_config->irq, wavefrontintr, - 0, "WaveFront", NULL) < 0) { - printk (KERN_WARNING "WaveFront: IRQ %d not available!\n", - hw_config->irq); - return 0; - } - - switch (hw_config->irq) { + switch (irq) { case 9: bits = 0x00; break; @@ -2287,11 +2249,42 @@ probe_wavefront (struct address_info *hw_config) break; default: - printk (KERN_WARNING "WaveFront: invalid IRQ %d\n", - hw_config->irq); - return 0; + printk (KERN_WARNING "WaveFront: invalid IRQ %d\n", irq); + bits = -1; } - + + return bits; +} + +void +wavefront_should_cause_interrupt (wf_config *hw, int val, int port, int timeout) + +{ + unsigned long flags; + + save_flags (flags); + cli(); + hw->irq_ok = 0; + outb (val,port); + current->timeout = jiffies + timeout; + interruptible_sleep_on (&hw->interrupt_sleeper); + restore_flags (flags); +} + +static int +wavefront_hw_reset (wf_config *hw) + +{ + int bits; + int hwv[2]; + + if (request_irq (hw->irq, wavefrontintr, + 0, "WaveFront", (void *) hw) < 0) { + printk (KERN_WARNING "WaveFront: IRQ %d not available!\n", + hw->irq); + return 1; + } + /* try reset of port */ outb (0x0, hw->control_port); @@ -2305,9 +2298,6 @@ probe_wavefront (struct address_info *hw_config) Bit 6 - MIDI Interface Select - XXX PBD: I think this documentation is backwards. I leave bit - 6 unset, and get MIDI data from the 9 pin D connector. - 0 - Use the MIDI Input from the 26-pin WaveBlaster compatible header as the serial MIDI source 1 - Use the MIDI Input from the 9-pin D connector as the serial MIDI @@ -2331,101 +2321,270 @@ probe_wavefront (struct address_info *hw_config) */ - /* configure hardware: IRQ, plus external MIDI interface selected */ - - outb (bits | 0x80, hw->data_port); - - /* take us out of reset, unmute, master + TX + RX interrupts on */ - - outb (0x80|0x20|0x40|0x10|0x1, hw->control_port); - - for (i = 0; i < 1000000 && !hw->irq_ok; i++); - - /* Data port is now the data port, not the h/w initialization port - - The boot ROM will check the OSRAM, and will then - wait for the either the "download OS" or - "report h/w version" commands. - - Any other command will supposedly be ignored. + /* configure hardware: IRQ, enable interrupts, + 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 + + 0 Host Rx Interrupt Enable (1=Enabled) 0x1 + 1 Unused 0x2 + 2 Unused 0x4 + 3 Unused 0x8 + 4 Host Tx Interrupt Enable 0x10 + 5 Mute (0=Mute; 1=Play) 0x20 + 6 Master Interrupt Enable (1=Enabled) 0x40 + 7 Master Reset (0=Reset; 1=Run) 0x80 + + Take us out of reset, unmute, master + TX + RX interrupts on. + + We'll get an interrupt presumably to tell us that the TX + register is clear. However, this doesn't mean that the + board is ready. We actually have to send it a command, and + 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 + doesn't cost us much, we'll give it *plenty* of time. It + turns out that with 12MB of RAM, it can take up to 16 + seconds or so!! See the code after "ABOUT INTERRUPTS" + */ + + wavefront_should_cause_interrupt(hw, + 0x80|0x40|0x10|0x1, + hw->control_port, + (2*HZ)/100); + + /* Note: data port is now the data port, not the h/w initialization + port. + */ + if (!hw->irq_ok) { printk (KERN_WARNING "WaveFront: intr not received after h/w un-reset.\n"); - free_irq (hw_config->irq, NULL); - return 0; - } else { - hw->irq_ok = 0; - } + goto gone_bad; + } hw->interrupts_on = 1; - - /* WaveFront SDK says: - - "When the Master Reset is set to zero (0), the audio board is held - in reset, which is the power-up condition. Setting Master Reset to one - (1) allows the on-board processor to run. It takes approximately two - to four seconds, depending on the memory configuration, for the - on-board processor to complete it's initialization routine before it - will respond to commands after a reset." - - Actually, it seems that most of the time, even with 8MB of RAM, - its actually ready immediately. + + /* ABOUT INTERRUPTS: + ----------------- + + When we talk about interrupts, there are two kinds + generated by the ICS2115. The first is to signal MPU data + ready to read, and the second is to signal RX or TX status + changes. We *always* want interrupts for MPU stuff but we + generally avoid using RX/TX interrupts. + + In theory, we could use the TX and RX interrupts for all + communication with the card. However, there are 2 good + reasons not to do this. + + First of all, the MIDI interface is going to use the same + interrupt. This presents no practical problem since Linux + allows us to share IRQ's. However, there are times when it + makes sense for a user to ask the driver to disable + interrupts, to avoid bothering Linux with a stream of MIDI + interrupts that aren't going to be used because nothing + cares about them. If we rely on them for communication with + the WaveFront synth as well, this disabling would be + crippling. Since being able to disable them can save quite + a bit of overhead (consider the interrupt frequency of a + physical MIDI controller like a modwheel being shunted back + and forth - its higher than the mouse, and much of + the time is of absolutely no interest to the kernel or any + user space processes whatsoever), we don't want to do this. + + Secondly, much of the time, there's no reason to go to + sleep on a TX or RX status: the WaveFront gets back to us + quickly enough that its a lot more efficient to just busy + wait on the relevant status. Once we go to sleep, all is + lost anyway, and so interrupts don't really help us much anyway. + + Therefore, we don't use interrupts for communication with + the WaveFront synth. We just poll the relevant RX/TX status. + + However, there is one broad exception to this. During module + loading, to deal with several situations where timing would + be an issue, we use TX/RX interrupts to help us avoid busy + waiting for indeterminate and hard to manage periods of + time. So, TX/RX interrupts are enabled until the end of + wavefront_init(), and not used again after that. + + */ + + /* Note: data port is now the data port, not the h/w initialization + port. + + At this point, only "HW VERSION" or "DOWNLOAD OS" commands + will work. So, issue one of them, and wait for TX + interrupt. This can take a *long* time after a cold boot, + while the ISC ROM does its RAM test. The SDK says up to 4 + seconds - with 12MB of RAM on a Tropez+, it takes a lot + longer than that (~16secs). Note that the card understands + the difference between a warm and a cold boot, so + subsequent ISC2115 reboots (say, caused by module + reloading) will get through this much faster. + + Interesting question: why is no RX interrupt received first ? */ + + wavefront_should_cause_interrupt(hw, WFC_HARDWARE_VERSION, + hw->data_port, 20*HZ); - if (!wavefront_wait (hw, STAT_CAN_WRITE)) { - if (!wavefront_wait (hw, STAT_CAN_WRITE)) { - if (!wavefront_wait (hw, STAT_CAN_WRITE)) { - printk (KERN_WARNING - "WaveFront: OS not ready after " - "memory check.\n"); - free_irq (hw_config->irq, NULL); - return 0; - } - } + if (!hw->irq_ok) { + printk (KERN_WARNING + "WaveFront: post-RAM-check interrupt not received.\n"); + goto gone_bad; + } + + if (!(wavefront_status(hw) & STAT_CAN_READ)) { + printk (KERN_WARNING + "WaveFront: no response to HW version cmd.\n"); + goto gone_bad; + } + + if ((hwv[0] = wavefront_read (hw)) == -1) { + printk (KERN_WARNING + "WaveFront: board not responding correctly.\n"); + goto gone_bad; } - /* get H/W version, and check we get an interrupt */ - - outb (WFC_HARDWARE_VERSION, hw->data_port); - - for (i = 0; i < 1000000 && !hw->irq_ok; i++); - - /* We don't need the IRQ anymore for the WaveFront code, - and to allow an MPU-401 driver to attach to it later, lets - give it back .... + if (hwv[0] == 0xFF) { /* NAK */ - DO NOT alter irq2hw[], since we'll still use this to lookup - the config struct from an address_info struct. - */ + /* Board's RAM test failed. Try to read error code, + and tell us about it either way. + */ + + if ((hwv[0] = wavefront_read (hw)) == -1) { + printk (KERN_WARNING + "WaveFront: on-board RAM test failed " + "(bad error code).\n"); + } else { + printk (KERN_WARNING + "WaveFront: on-board RAM test failed " + "(error code: 0x%x).\n", + hwv[0]); + } + goto gone_bad; + } - free_irq (hw_config->irq, NULL); + /* We're OK, just get the next byte of the HW version response */ - if (!hw->irq_ok) { + if ((hwv[1] = wavefront_read (hw)) == -1) { printk (KERN_WARNING - "WaveFront: interrupt not received after " - "h/w version cmd.\n"); - return 0; - } else { - hw->irq_ok = 0; + "WaveFront: board not responding correctly(2).\n"); + goto gone_bad; + } + + printk (KERN_INFO "WaveFront: hardware version %d.%d\n", + hwv[0], hwv[1]); + + return 0; + + + gone_bad: + free_irq (hw->irq, hw); + return (1); + } + +int +probe_wavefront (struct address_info *hw_config) + +{ + unsigned char rbuf[4], wbuf[4]; + wf_config *hw; + + if (hw_config->irq < 0 || hw_config->irq > 16) { + printk (KERN_WARNING "WaveFront: impossible IRQ suggested(%d)\n", + hw_config->irq); + return 0; } - if ((tmp1 = wavefront_read(hw)) == -1) { - printk (KERN_WARNING - "WaveFront @ 0x%x not ready, ignoring\n", hw->base); + /* Yeah yeah, TB docs say 8, but the FX device on the Tropez Plus + takes up another 8 ... + */ + + if (check_region (hw_config->io_base, 16)) { + printk (KERN_ERR "WaveFront: IO address range 0x%x - 0x%x " + "already in use - ignored\n", hw_config->io_base, + hw_config->io_base+15); return 0; } - if ((tmp2 = wavefront_read(hw)) == -1) { - printk (KERN_WARNING - "WaveFront @ 0x%x not responding correctly, ignoring\n", - hw->base); + hw = &wavefront_configuration; + + hw->irq = hw_config->irq; + hw->base = hw_config->io_base; + + hw->israw = 0; + hw->debug = debug_default; + hw->interrupts_on = 0; + hw->rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */ + +#ifdef WF_STATS + hw->status_found_during_sleep[0] = 0; + hw->status_found_during_sleep[1] = 0; + hw->status_found_during_sleep[2] = 0; + hw->status_found_during_sleep[3] = 0; + hw->status_found_during_loop = 0; +#endif WF_STATS + + hw_config->slots[WF_SYNTH_SLOT] = hw->synthdev = -1; + hw_config->slots[WF_INTERNAL_MIDI_SLOT] = hw->mididev = -1; + hw_config->slots[WF_EXTERNAL_MIDI_SLOT] = hw->ext_mididev = -1; + + if (wavefront_cmd (hw, WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) { + + hw->fw_version[0] = rbuf[0]; + hw->fw_version[1] = rbuf[1]; + printk (KERN_INFO + "WaveFront: firmware %d.%d already loaded.\n", + rbuf[0], rbuf[1]); + + /* check that a command actually works */ + + if (wavefront_cmd (hw, WFC_HARDWARE_VERSION, + rbuf, wbuf) == 0) { + hw->hw_version[0] = rbuf[0]; + hw->hw_version[1] = rbuf[1]; + } else { + printk (KERN_INFO "WaveFront: not raw, but no " + "hardware version!\n"); + return 0; + } + + if (!wf_raw) { + return 1; + } else { + printk (KERN_INFO + "WaveFront: reloading firmware anyway.\n"); + } + + } else { + + hw->israw = 1; + printk (KERN_INFO "WaveFront: no response to firmware probe, " + "assume raw.\n"); + + } + + init_waitqueue (&hw->interrupt_sleeper); + + if (wavefront_hw_reset (hw)) { + printk (KERN_WARNING "WaveFront: hardware reset failed\n"); return 0; } - - printk (KERN_INFO "WaveFront: hardware version %d.%d\n", tmp1, tmp2); - + return 1; } @@ -2465,7 +2624,8 @@ wavefront_download_firmware (wf_config *hw, char *path) set_fs (get_ds()); if ((fd = open (path, 0, 0)) < 0) { - printk (KERN_WARNING "WaveFront: Unable to load \"%s\".\n", path); + printk (KERN_WARNING "WaveFront: Unable to load \"%s\".\n", + path); return 1; } @@ -2512,9 +2672,13 @@ wavefront_download_firmware (wf_config *hw, char *path) section_cnt_downloaded + 1, c); goto failure; - } else if ((hw->debug & WF_DEBUG_IO) && + } else { +#ifdef WF_DEBUG + if ((hw->debug & WF_DEBUG_IO) && !(++section_cnt_downloaded % 10)) { printk (KERN_DEBUG "."); + } +#endif WF_DEBUG } } else { @@ -2526,9 +2690,11 @@ wavefront_download_firmware (wf_config *hw, char *path) close (fd); set_fs (fs); +#ifdef WF_DEBUG if (hw->debug & WF_DEBUG_IO) { printk (KERN_DEBUG "\n"); } +#endif WF_DEBUG return 0; failure: @@ -2618,81 +2784,137 @@ wavefront_config_midi (wf_config *hw, struct address_info *hw_config) } static int -wavefront_init (wf_config *hw, struct address_info *hw_config) +wavefront_do_reset (wf_config *hw, int atboot) { - int samples_are_from_rom = 0; + char voices[1]; - /* XXX what state does the board need to be in before - I can download the firmware ? I think any state - after it acknowledges a hardware version command - post-booting. - */ + if (!atboot && wavefront_hw_reset (hw)) { + printk (KERN_WARNING "WaveFront: hw reset failed.\n"); + goto gone_bad; + } if (hw->israw || wf_raw) { - samples_are_from_rom = 1; - - if (wavefront_download_firmware (hw, wf_ospath)) { + if (wavefront_download_firmware (hw, ospath)) { + goto gone_bad; return 1; } - - /* enter normal operation: - bit 7: (on) reset 0x80 - bit 6: interrupts enabled 0x40 - bit 5: (on) mute (i.e. in play mode) 0x20 - bits 4-0: zero + } + + 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. - note: tx and rx interrupts turned off - */ + Rather than busy-wait, lets just turn interrupts on. + */ + + outb (0x80|0x40|0x10|0x1, hw->control_port); + + wavefront_should_cause_interrupt (hw, WFC_NOOP, + hw->data_port, (10*HZ)); - outb (0x80|0x40|0x20, hw->control_port); + 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)); - /* Set up MPU-401 emulation mode. For some reason, this always - fails the first time, and generates no ACK, so we'll - treat it as a special case by sleeping for a while, and then - trying again. - */ + if (!hw->irq_ok) { + printk (KERN_WARNING "WaveFront: no post-OS interrupt(2).\n"); + goto gone_bad; + } - wavefront_write (hw, 0xf0); - wavefront_write (hw, 1); - wavefront_sleep (hw, (HZ/wf_sleep_interval) * wf_sleep_tries); - wavefront_write (hw, 0xf0); - wavefront_write (hw, 1); - if (wavefront_read (hw) != 0x80) { - printk (KERN_ERR - "WaveFront: set MPU emulation mode " - "command failed.\n"); - return (1); + /* 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); + + /* SETUPSND.EXE asks for sample memory config here, but since i + have no idea how to interpret the result, we'll forget + about it. + */ + + if ((hw->freemem = wavefront_freemem (hw)) < 0) { + goto gone_bad; + } + + printk (KERN_INFO "WaveFront: available DRAM %dk\n", hw->freemem / 1024); + + if (!wavefront_write (hw, 0xf0) || + !wavefront_write (hw, 1) || + (wavefront_read (hw) < 0)) { + hw->debug = 0; + printk (KERN_WARNING "WaveFront: MPU emulation mode not set.\n"); + goto gone_bad; + } + + voices[0] = 32; + + if (wavefront_cmd (hw, WFC_SET_NVOICES, 0, voices)) { + printk (KERN_WARNING + "WaveFront: cannot set number of voices to 32.\n"); + } + + return 0; + + gone_bad: + /* reset that sucker so that it doesn't bother us. */ + + outb (0x0, hw->control_port); + free_irq (hw->irq, hw); + return 1; +} + +static int +wavefront_init (wf_config *hw, int atboot) + +{ + int samples_are_from_rom; + + if (hw->israw || wf_raw) { + samples_are_from_rom = 1; + } else { + samples_are_from_rom = 0; + } + + if (hw->israw || wf_raw || fx_raw) { + if (wavefront_do_reset (hw, atboot)) { + return 1; } } - hw->freemem = wavefront_freemem (hw); - printk (KERN_INFO "WaveFront: available DRAM %dk\n", hw->freemem / 1024); - wavefront_get_sample_status (hw, samples_are_from_rom); wavefront_get_program_status (hw); wavefront_get_patch_status (hw); - if (fx_raw) { - wffx_init (hw); - } - - return 0; + /* Start normal operation: unreset, master interrupt enable + (for MPU interrupts) no mute + */ + + outb (0x80|0x40|0x20, hw->control_port); + + return (0); } void attach_wavefront (struct address_info *hw_config) { int i; - struct wf_config *hw; - - if ((i = irq2hw[hw_config->irq]) == -1) { - printk (KERN_ERR "WaveFront: cannot attach unknown irq 0x%x.\n", - hw_config->irq); - return; - } - - hw = &wfs[i]; + struct wf_config *hw = &wavefront_configuration; if ((i = sound_alloc_synthdev()) == -1) { printk (KERN_ERR "WaveFront: Too many synthesizers\n"); @@ -2700,15 +2922,13 @@ attach_wavefront (struct address_info *hw_config) } else { hw_config->slots[WF_SYNTH_SLOT] = i; hw->synthdev = i; - dev2hw[hw->synthdev] = i; synth_devs[hw->synthdev] = &wavefront_operations; } - if (wavefront_init (hw, hw_config)) { + if (wavefront_init (hw, 1)) { printk (KERN_WARNING "WaveFront: board could not " "be initialized.\n"); sound_unload_synthdev (i); - hw->installed = 0; return; } @@ -2731,18 +2951,11 @@ attach_wavefront (struct address_info *hw_config) void unload_wavefront (struct address_info *hw_config) { - struct wf_config *hw; - int i; - - if ((i = irq2hw[hw_config->irq]) == -1) { - printk (KERN_ERR "WaveFront: unloading unrecognized device!\n"); - return; - } - hw = &wfs[i]; + struct wf_config *hw = &wavefront_configuration; /* the first two are freed by the wf_mpu code */ - release_region (hw_config->io_base+2, 6); - release_region (hw_config->io_base+8, 8); + release_region (hw->base+2, 6); + release_region (hw->base+8, 8); sound_unload_synthdev (hw->synthdev); #if defined(CONFIG_MIDI) unload_wf_mpu (hw_config); @@ -2802,13 +3015,13 @@ wffx_memset (struct wf_config *hw, int page, if (page < 0 || page > 7) { printk (KERN_ERR "WaveFront: FX memset: " "page must be >= 0 and <= 7\n"); - return -EINVAL; + return -(EINVAL); } if (addr < 0 || addr > 0x7f) { printk (KERN_ERR "WaveFront: FX memset: " "addr must be >= 0 and <= 7f\n"); - return -EINVAL; + return -(EINVAL); } if (cnt == 1) { @@ -2842,7 +3055,7 @@ wffx_memset (struct wf_config *hw, int page, "WaveFront: FX memset " "(0x%x, 0x%x, 0x%x, %d) incomplete\n", page, addr, (int) data, cnt); - return -EIO; + return -(EIO); } } @@ -2866,18 +3079,17 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r) if (r->data[2] <= 0) { printk (KERN_ERR "WaveFront: cannot write " "<= 0 bytes to FX\n"); - return -EINVAL; + return -(EINVAL); } else if (r->data[2] == 1) { pd = (unsigned short *) &r->data[3]; } else { if (r->data[2] > sizeof (page_data)) { - printk (KERN_ERR - "WaveFront: cannot write " + printk (KERN_ERR "WaveFront: cannot write " "> 255 bytes to FX\n"); - return -EINVAL; + return -(EINVAL); } - COPY_FROM_USER(page_data, (unsigned char *) r->data[3], - r->data[2]); + copy_from_user (page_data, (unsigned char *) r->data[3], + r->data[2]); pd = page_data; } @@ -2891,7 +3103,7 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r) printk (KERN_WARNING "WaveFront: FX: ioctl %d not yet supported\n", r->request); - return -EINVAL; + return -(EINVAL); } } @@ -3364,7 +3576,7 @@ wffx_init (struct wf_config *hw) outb (0x00, hw->fx_op); /* mute off */ - return 0; + return (0); } EXPORT_NO_SYMBOLS; @@ -3388,6 +3600,7 @@ int init_module (void) "options must be set.\n"); return -EINVAL; } + cfg.io_base = io; cfg.irq = irq; @@ -3406,7 +3619,6 @@ void cleanup_module (void) SOUND_LOCK_END; } -#endif MODULE -#endif CONFIG_SOUND_WAVEFRONT +#endif CONFIG_SOUND_WAVEFRONT_MODULE_AND_MODULE diff --git a/drivers/sound/wf_midi.c b/drivers/sound/wf_midi.c index c525abc97..2333fd118 100644 --- a/drivers/sound/wf_midi.c +++ b/drivers/sound/wf_midi.c @@ -454,12 +454,12 @@ wf_mpu_open (int dev, int mode, struct wf_mpu_config *devc; if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL) - return -ENXIO; + return -(ENXIO); devc = &dev_conf[dev]; if (devc->opened) { - return -EBUSY; + return -(EBUSY); } devc->mode = MODE_MIDI; @@ -678,8 +678,8 @@ static struct synth_operations wf_mpu_synth_proto = midi_synth_send_sysex }; -static struct synth_operations wf_mpu_synth_operations[WAVEFRONT_MAX_DEVICES*2]; -static struct midi_operations wf_mpu_midi_operations[WAVEFRONT_MAX_DEVICES*2]; +static struct synth_operations wf_mpu_synth_operations[2]; +static struct midi_operations wf_mpu_midi_operations[2]; static int wfmpu_cnt = 0; static struct midi_operations wf_mpu_midi_proto = @@ -707,9 +707,8 @@ config_wf_mpu (int dev, struct address_info *hw_config) struct wf_mpu_config *devc; int internal; - if (wfmpu_cnt >= WAVEFRONT_MAX_DEVICES * 2) { - printk (KERN_ERR "WF-MPU: eh ? more MPU devices " - "than cards ?!!\n"); + if (wfmpu_cnt >= 2) { + printk (KERN_ERR "WF-MPU: more MPU devices than cards ?!!\n"); return (-1); } |