From: Steve L. <slo...@us...> - 2002-04-12 21:59:19
|
Update of /cvsroot/linux-mips/linux/drivers/sound In directory usw-pr-cvs1:/tmp/cvs-serv14263/drivers/sound Modified Files: ite8172.c Log Message: PCI and sound fixes to IT8172 reference board. Index: ite8172.c =================================================================== RCS file: /cvsroot/linux-mips/linux/drivers/sound/ite8172.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- ite8172.c 18 Mar 2002 22:31:38 -0000 1.4 +++ ite8172.c 12 Apr 2002 21:59:15 -0000 1.5 @@ -51,6 +51,10 @@ * Revision history * 02.08.2001 Initial release * 06.22.2001 Added I2S support + * 03.20.2002 Added mutex locks around read/write methods, to prevent + * simultaneous access on SMP or preemptible kernels. Also + * removed the counter/pointer fragment aligning at the end + * of read/write methods [stevel]. */ #include <linux/version.h> #include <linux/module.h> @@ -292,6 +296,7 @@ spinlock_t lock; struct semaphore open_sem; + struct semaphore sem; mode_t open_mode; wait_queue_head_t open_wait; @@ -407,35 +412,31 @@ return sr; } +/* hold a spin-lock or stop the ADC before calling */ static void set_adc_rate(struct it8172_state *s, unsigned rate) { - unsigned long flags; unsigned short sr; sr = get_compat_rate(&rate); - spin_lock_irqsave(&s->lock, flags); s->capcc &= ~CC_SR_MASK; s->capcc |= sr; outw(s->capcc, s->io+IT_AC_CAPCC); - spin_unlock_irqrestore(&s->lock, flags); s->adcrate = rate; } +/* hold a spin-lock or stop the DAC before calling */ static void set_dac_rate(struct it8172_state *s, unsigned rate) { - unsigned long flags; unsigned short sr; sr = get_compat_rate(&rate); - spin_lock_irqsave(&s->lock, flags); s->pcc &= ~CC_SR_MASK; s->pcc |= sr; outw(s->pcc, s->io+IT_AC_PCC); - spin_unlock_irqrestore(&s->lock, flags); s->dacrate = rate; } @@ -768,8 +769,6 @@ unsigned short vol, mute; unsigned long newptr; - spin_lock(&s->lock); - isc = inb(s->io+IT_AC_ISC); /* fastpath out, to ease interrupt sharing */ @@ -778,6 +777,8 @@ return; } + spin_lock(&s->lock); + /* clear audio interrupts first */ outb(isc | ISC_VCI | ISC_CCI | ISC_PCI, s->io+IT_AC_ISC); @@ -802,9 +803,13 @@ if (isc & ISC_CCI) { if (adc->count > adc->dmasize - adc->fragsize) { // Overrun. Stop ADC and log the error + spin_unlock(&s->lock); stop_adc(s); + spin_lock(&s->lock); adc->error++; +#ifdef IT8172_VERBOSE_DEBUG dbg("adc overrun"); +#endif } else { newptr = virt_to_bus(adc->nextIn) + 2*adc->fragsize; if (newptr >= adc->dmaaddr + adc->dmasize) @@ -848,8 +853,16 @@ if (waitqueue_active(&dac->wait)) wake_up_interruptible(&dac->wait); - if (dac->count <= 0) + if (dac->count <= 0) { +#ifdef IT8172_VERBOSE_DEBUG + dbg("dac underrun"); +#endif + spin_unlock(&s->lock); stop_dac(s); + spin_lock(&s->lock); + dac->count = 0; + dac->nextIn = dac->nextOut; + } } spin_unlock(&s->lock); @@ -1090,7 +1103,7 @@ struct dmabuf *db = &s->dma_adc; ssize_t ret; unsigned long flags; - int cnt, remainder, avail; + int cnt, avail; if (ppos != &file->f_pos) return -ESPIPE; @@ -1100,26 +1113,30 @@ return -EFAULT; ret = 0; + down(&s->sem); + while (count > 0) { // wait for samples in capture buffer do { - spin_lock_irqsave(&s->lock, flags); if (db->stopped) start_adc(s); + spin_lock_irqsave(&s->lock, flags); avail = db->count; spin_unlock_irqrestore(&s->lock, flags); if (avail <= 0) { if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; - return ret; + goto out; } + up(&s->sem); interruptible_sleep_on(&db->wait); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; - return ret; + goto out; } + down(&s->sem); } } while (avail <= 0); @@ -1128,7 +1145,7 @@ avail : count, 1)) < 0) { if (!ret) ret = -EFAULT; - return ret; + goto out; } spin_lock_irqsave(&s->lock, flags); @@ -1144,25 +1161,8 @@ ret += cnt; } // while (count > 0) - /* - * See if the dma buffer count after this read call is - * aligned on a fragsize boundary. If not, read from - * buffer until we reach a boundary, and let's hope this - * is just the last remainder of an audio record. If not - * it means the user is not reading in fragsize chunks, in - * which case it's his/her fault that there are audio gaps - * in their record. - */ - spin_lock_irqsave(&s->lock, flags); - remainder = db->count % db->fragsize; - if (remainder) { - db->nextOut += remainder; - if (db->nextOut >= db->rawbuf + db->dmasize) - db->nextOut -= db->dmasize; - db->count -= remainder; - } - spin_unlock_irqrestore(&s->lock, flags); - + out: + up(&s->sem); return ret; } @@ -1173,7 +1173,7 @@ struct dmabuf *db = &s->dma_dac; ssize_t ret; unsigned long flags; - int cnt, remainder, avail; + int cnt, avail; if (ppos != &file->f_pos) return -ESPIPE; @@ -1182,7 +1182,9 @@ if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; ret = 0; - + + down(&s->sem); + while (count > 0) { // wait for space in playback buffer do { @@ -1193,14 +1195,16 @@ if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; - return ret; + goto out; } + up(&s->sem); interruptible_sleep_on(&db->wait); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; - return ret; + goto out; } + down(&s->sem); } } while (avail <= 0); @@ -1210,45 +1214,25 @@ avail : count, 0)) < 0) { if (!ret) ret = -EFAULT; - return ret; + goto out; } spin_lock_irqsave(&s->lock, flags); db->count += cnt; - if (db->stopped) - start_dac(s); - spin_unlock_irqrestore(&s->lock, flags); - db->nextIn += cnt; if (db->nextIn >= db->rawbuf + db->dmasize) db->nextIn -= db->dmasize; + spin_unlock_irqrestore(&s->lock, flags); + if (db->stopped) + start_dac(s); count -= cnt; buffer += cnt; ret += cnt; } // while (count > 0) - /* - * See if the dma buffer count after this write call is - * aligned on a fragsize boundary. If not, fill buffer - * with silence to the next boundary, and let's hope this - * is just the last remainder of an audio playback. If not - * it means the user is not sending us fragsize chunks, in - * which case it's his/her fault that there are audio gaps - * in their playback. - */ - spin_lock_irqsave(&s->lock, flags); - remainder = db->count % db->fragsize; - if (remainder) { - int fill_cnt = db->fragsize - remainder; - memset(db->nextIn, 0, fill_cnt); - db->nextIn += fill_cnt; - if (db->nextIn >= db->rawbuf + db->dmasize) - db->nextIn -= db->dmasize; - db->count += fill_cnt; - } - spin_unlock_irqrestore(&s->lock, flags); - + out: + up(&s->sem); return ret; } @@ -1295,31 +1279,37 @@ struct it8172_state *s = (struct it8172_state *)file->private_data; struct dmabuf *db; unsigned long size; - + int ret = 0; + lock_kernel(); + down(&s->sem); + if (vma->vm_flags & VM_WRITE) db = &s->dma_dac; else if (vma->vm_flags & VM_READ) db = &s->dma_adc; else { - unlock_kernel(); - return -EINVAL; + ret = -EINVAL; + goto out; } if (vma->vm_pgoff != 0) { - unlock_kernel(); - return -EINVAL; + ret = -EINVAL; + goto out; } size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) { - unlock_kernel(); - return -EINVAL; + ret = -EINVAL; + goto out; } if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) { - unlock_kernel(); - return -EAGAIN; + ret = -EAGAIN; + goto out; } + vma->vm_flags &= ~VM_IO; db->mapped = 1; + out: + up(&s->sem); unlock_kernel(); return 0; } @@ -1771,7 +1761,6 @@ { int minor = MINOR(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); - unsigned long flags; struct list_head *list; struct it8172_state *s; int ret; @@ -1809,7 +1798,8 @@ down(&s->open_sem); } - spin_lock_irqsave(&s->lock, flags); + stop_dac(s); + stop_adc(s); if (file->f_mode & FMODE_READ) { s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = @@ -1819,10 +1809,8 @@ if ((minor & 0xf) == SND_DEV_DSP16) s->capcc |= CC_DF; outw(s->capcc, s->io+IT_AC_CAPCC); - if ((ret = prog_dmabuf_adc(s))) { - spin_unlock_irqrestore(&s->lock, flags); + if ((ret = prog_dmabuf_adc(s))) return ret; - } } if (file->f_mode & FMODE_WRITE) { s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = @@ -1832,16 +1820,13 @@ if ((minor & 0xf) == SND_DEV_DSP16) s->pcc |= CC_DF; outw(s->pcc, s->io+IT_AC_PCC); - if ((ret = prog_dmabuf_dac(s))) { - spin_unlock_irqrestore(&s->lock, flags); + if ((ret = prog_dmabuf_dac(s))) return ret; - } } - spin_unlock_irqrestore(&s->lock, flags); - s->open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE)); up(&s->open_sem); + init_MUTEX(&s->sem); return 0; } @@ -2052,7 +2037,7 @@ if (pci_enable_device(pcidev)) goto err_dev3; pci_set_master(pcidev); - + /* get out of legacy mode */ pci_read_config_byte (pcidev, 0x40, &legacy); pci_write_config_byte (pcidev, 0x40, legacy & ~1); @@ -2078,7 +2063,7 @@ /* cold reset the AC97 */ outw(CODECC_CR, s->io+IT_AC_CODECC); - udelay(1000); + it8172_delay(10); outw(0, s->io+IT_AC_CODECC); /* need to delay around 500msec(bleech) to give some CODECs enough time to wakeup */ @@ -2092,7 +2077,7 @@ /* codec init */ if (!ac97_probe_codec(&s->codec)) goto err_dev3; - + /* add I2S as allowable recording source */ s->codec.record_sources |= SOUND_MASK_I2S; @@ -2198,7 +2183,7 @@ { if (!pci_present()) /* No PCI bus in this machine! */ return -ENODEV; - info("version v0.5 time " __TIME__ " " __DATE__); + info("version v1.0 time " __TIME__ " " __DATE__); return pci_module_init(&it8172_driver); } |