diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-13 16:29:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-13 16:29:25 +0000 |
commit | db7d4daea91e105e3859cf461d7e53b9b77454b2 (patch) | |
tree | 9bb65b95440af09e8aca63abe56970dd3360cc57 /drivers/sound/sonicvibes.c | |
parent | 9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff) |
Merge with Linux 2.2.8.
Diffstat (limited to 'drivers/sound/sonicvibes.c')
-rw-r--r-- | drivers/sound/sonicvibes.c | 88 |
1 files changed, 68 insertions, 20 deletions
diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index b1899e143..c6d30d43f 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -3,7 +3,7 @@ /* * sonicvibes.c -- S3 Sonic Vibes audio driver. * - * Copyright (C) 1998 Thomas Sailer (sailer@ife.ee.ethz.ch) + * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -51,6 +51,23 @@ * 16.12.98 0.9 Fix a few f_file & FMODE_ bugs * 06.01.99 0.10 remove the silly SA_INTERRUPT flag. * hopefully killed the egcs section type conflict + * 12.03.99 0.11 cinfo.blocks should be reset after GETxPTR ioctl. + * reported by Johan Maes <joma@telindus.be> + * 22.03.99 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK + * read/write cannot be executed + * 05.04.99 0.13 added code to sv_read and sv_write which should detect + * lockups of the sound chip and revive it. This is basically + * an ugly hack, but at least applications using this driver + * won't hang forever. I don't know why these lockups happen, + * it might well be the motherboard chipset (an early 486 PCI + * board with ALI chipset), since every busmastering 100MB + * ethernet card I've tried (Realtek 8139 and Macronix tulip clone) + * exhibit similar behaviour (they work for a couple of packets + * and then lock up and can be revived by ifconfig down/up). + * 07.04.99 0.14 implemented the following ioctl's: SOUND_PCM_READ_RATE, + * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; + * Alpha fixes reported by Peter Jones <pjones@redhat.com> + * Note: dmaio hack might still be wrong on archs other than i386 * */ @@ -251,7 +268,8 @@ struct sv_state { int dev_dmfm; /* hardware resources */ - unsigned int iosb, ioenh, iosynth, iomidi, iogame, iodmaa, iodmac, irq; + unsigned long iosb, ioenh, iosynth, iomidi, iogame; /* long for SPARC */ + unsigned int iodmaa, iodmac, irq; /* mixer stuff */ struct { @@ -1293,8 +1311,20 @@ static ssize_t sv_read(struct file *file, char *buffer, size_t count, loff_t *pp if (cnt <= 0) { start_adc(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; - interruptible_sleep_on(&s->dma_adc.wait); + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) { + printk(KERN_DEBUG "sv: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, + s->dma_adc.hwptr, s->dma_adc.swptr); + stop_adc(s); + spin_lock_irqsave(&s->lock, flags); + set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift); + /* program enhanced mode registers */ + wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8); + wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); + s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; @@ -1353,8 +1383,20 @@ static ssize_t sv_write(struct file *file, const char *buffer, size_t count, lof if (cnt <= 0) { start_dac(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; - interruptible_sleep_on(&s->dma_dac.wait); + return ret ? ret : -EAGAIN; + if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) { + printk(KERN_DEBUG "sv: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n", + s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, + s->dma_dac.hwptr, s->dma_dac.swptr); + stop_dac(s); + spin_lock_irqsave(&s->lock, flags); + set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift); + /* program enhanced mode registers */ + wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8); + wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); + s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0; + spin_unlock_irqrestore(&s->lock, flags); + } if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; continue; @@ -1431,8 +1473,6 @@ static int sv_mmap(struct file *file, struct vm_area_struct *vma) if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) return -EAGAIN; db->mapped = 1; - vma->vm_file = file; - file->f_count++; return 0; } @@ -1648,7 +1688,7 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_adc.total_bytes; - cinfo.blocks = s->dma_adc.total_bytes >> s->dma_adc.fragshift; + cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift; cinfo.ptr = s->dma_adc.hwptr; if (s->dma_adc.mapped) s->dma_adc.count &= s->dma_adc.fragsize-1; @@ -1661,7 +1701,7 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un spin_lock_irqsave(&s->lock, flags); sv_update_ptr(s); cinfo.bytes = s->dma_dac.total_bytes; - cinfo.blocks = s->dma_dac.total_bytes >> s->dma_dac.fragshift; + cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift; cinfo.ptr = s->dma_dac.hwptr; if (s->dma_dac.mapped) s->dma_dac.count &= s->dma_dac.fragsize-1; @@ -1715,11 +1755,19 @@ static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un s->dma_dac.subdivision = val; return 0; - case SOUND_PCM_WRITE_FILTER: - case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_RATE: + return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, (int *)arg); + case SOUND_PCM_READ_CHANNELS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT) + : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, (int *)arg); + case SOUND_PCM_READ_BITS: + return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT) + : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? 16 : 8, (int *)arg); + + case SOUND_PCM_WRITE_FILTER: + case SNDCTL_DSP_SETSYNCRO: case SOUND_PCM_READ_FILTER: return -EINVAL; @@ -1841,7 +1889,7 @@ static ssize_t sv_midi_read(struct file *file, char *buffer, size_t count, loff_ cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.iwait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -1888,7 +1936,7 @@ static ssize_t sv_midi_write(struct file *file, const char *buffer, size_t count cnt = count; if (cnt <= 0) { if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EBUSY; + return ret ? ret : -EAGAIN; interruptible_sleep_on(&s->midi.owait); if (signal_pending(current)) return ret ? ret : -ERESTARTSYS; @@ -2273,7 +2321,7 @@ __initfunc(int init_sonicvibes(void)) if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - printk(KERN_INFO "sv: version v0.10 time " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "sv: version v0.14 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"); @@ -2327,7 +2375,7 @@ __initfunc(int init_sonicvibes(void)) } pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */ pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */ - printk(KERN_DEBUG "sv: io ports: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#lx %#x %#x\n", s->iosb, s->ioenh, s->iosynth, s->iomidi, s->iogame, s->iodmaa, s->iodmac); if (s->ioenh == 0 || s->iodmaa == 0 || s->iodmac == 0) continue; @@ -2337,7 +2385,7 @@ __initfunc(int init_sonicvibes(void)) 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); + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1); goto err_region5; } request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM"); @@ -2352,12 +2400,12 @@ __initfunc(int init_sonicvibes(void)) } request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC"); if (check_region(s->iomidi, SV_EXTENT_MIDI)) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1); + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1); goto err_region2; } request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi"); if (check_region(s->iosynth, SV_EXTENT_SYNTH)) { - printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); + printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1); goto err_region1; } request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth"); @@ -2388,7 +2436,7 @@ __initfunc(int init_sonicvibes(void)) printk(KERN_ERR "sv: irq %u in use\n", s->irq); goto err_irq; } - printk(KERN_INFO "sv: found adapter at io %#06x irq %u dmaa %#06x dmac %#06x revision %u\n", + printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n", s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION)); /* register devices */ if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0) |