X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=sound%2Foss%2Fau1550_ac97.c;h=4191acccbcdb93fab12373847688b91103d52c65;hb=db1dd4d376134eba0e08af523b61cc566a4ea1cd;hp=a78e48d412d29562a92b8488bdbe0dc780c7b7ba;hpb=1da177e4c3f41524e886b7f1b8a0c1fc7321cac2;p=safe%2Fjmp%2Flinux-2.6 diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index a78e48d..4191acc 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c @@ -35,7 +35,6 @@ #undef DEBUG -#include #include #include #include @@ -48,17 +47,18 @@ #include #include #include -#include #include #include #include #include +#include + #include #include #include -#include #include #include +#include #undef OSS_DOCUMENTED_MIXER_SEMANTICS @@ -78,7 +78,7 @@ * 0 = no VRA, 1 = use VRA if codec supports it */ static int vra = 1; -MODULE_PARM(vra, "i"); +module_param(vra, bool, 0); MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it"); static struct au1550_state { @@ -91,9 +91,9 @@ static struct au1550_state { int no_vra; /* do not use VRA */ spinlock_t lock; - struct semaphore open_sem; - struct semaphore sem; - mode_t open_mode; + struct mutex open_mutex; + struct mutex sem; + fmode_t open_mode; wait_queue_head_t open_wait; struct dmabuf { @@ -212,7 +212,8 @@ rdcodec(struct ac97_codec *codec, u8 addr) } if (i == POLL_COUNT) { err("rdcodec: read poll expired!"); - return 0; + data = 0; + goto out; } /* wait for command done? @@ -225,7 +226,8 @@ rdcodec(struct ac97_codec *codec, u8 addr) } if (i == POLL_COUNT) { err("rdcodec: read cmdwait expired!"); - return 0; + data = 0; + goto out; } data = au_readl(PSC_AC97CDC) & 0xffff; @@ -236,6 +238,7 @@ rdcodec(struct ac97_codec *codec, u8 addr) au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT); au_sync(); + out: spin_unlock_irqrestore(&s->lock, flags); return data; @@ -463,7 +466,7 @@ stop_dac(struct au1550_state *s) /* Wait for Transmit Busy to show disabled. */ do { - stat = readl((void *)PSC_AC97STAT); + stat = au_readl(PSC_AC97STAT); au_sync(); } while ((stat & PSC_AC97STAT_TB) != 0); @@ -492,7 +495,7 @@ stop_adc(struct au1550_state *s) /* Wait for Receive Busy to show disabled. */ do { - stat = readl((void *)PSC_AC97STAT); + stat = au_readl(PSC_AC97STAT); au_sync(); } while ((stat & PSC_AC97STAT_RB) != 0); @@ -542,7 +545,7 @@ set_xmit_slots(int num_channels) /* Wait for Device ready. */ do { - stat = readl((void *)PSC_AC97STAT); + stat = au_readl(PSC_AC97STAT); au_sync(); } while ((stat & PSC_AC97STAT_DR) == 0); } @@ -574,22 +577,20 @@ set_recv_slots(int num_channels) /* Wait for Device ready. */ do { - stat = readl((void *)PSC_AC97STAT); + stat = au_readl(PSC_AC97STAT); au_sync(); } while ((stat & PSC_AC97STAT_DR) == 0); } +/* Hold spinlock for both start_dac() and start_adc() calls */ static void start_dac(struct au1550_state *s) { struct dmabuf *db = &s->dma_dac; - unsigned long flags; if (!db->stopped) return; - spin_lock_irqsave(&s->lock, flags); - set_xmit_slots(db->num_channels); au_writel(PSC_AC97PCR_TC, PSC_AC97PCR); au_sync(); @@ -599,8 +600,6 @@ start_dac(struct au1550_state *s) au1xxx_dbdma_start(db->dmanr); db->stopped = 0; - - spin_unlock_irqrestore(&s->lock, flags); } static void @@ -719,14 +718,14 @@ prog_dmabuf_dac(struct au1550_state *s) } -/* hold spinlock for the following */ -static void -dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void dac_dma_interrupt(int irq, void *dev_id) { struct au1550_state *s = (struct au1550_state *) dev_id; struct dmabuf *db = &s->dma_dac; u32 ac97c_stat; + spin_lock(&s->lock); + ac97c_stat = au_readl(PSC_AC97STAT); if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE)) pr_debug("AC97C status = 0x%08x\n", ac97c_stat); @@ -748,17 +747,20 @@ dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) /* wake up anybody listening */ if (waitqueue_active(&db->wait)) wake_up(&db->wait); + + spin_unlock(&s->lock); } -static void -adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void adc_dma_interrupt(int irq, void *dev_id) { struct au1550_state *s = (struct au1550_state *)dev_id; struct dmabuf *dp = &s->dma_adc; u32 obytes; char *obuf; + spin_lock(&s->lock); + /* Pull the buffer from the dma queue. */ au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes); @@ -766,6 +768,7 @@ adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) if ((dp->count + obytes) > dp->dmasize) { /* Overrun. Stop ADC and log the error */ + spin_unlock(&s->lock); stop_adc(s); dp->error++; err("adc overrun"); @@ -788,6 +791,7 @@ adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (waitqueue_active(&dp->wait)) wake_up(&dp->wait); + spin_unlock(&s->lock); } static loff_t @@ -1042,16 +1046,16 @@ au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) count *= db->cnt_factor; - down(&s->sem); + mutex_lock(&s->sem); add_wait_queue(&db->wait, &wait); while (count > 0) { /* wait for samples in ADC dma buffer */ do { + spin_lock_irqsave(&s->lock, flags); if (db->stopped) start_adc(s); - spin_lock_irqsave(&s->lock, flags); avail = db->count; if (avail <= 0) __set_current_state(TASK_INTERRUPTIBLE); @@ -1062,14 +1066,14 @@ au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) ret = -EAGAIN; goto out; } - up(&s->sem); + mutex_unlock(&s->sem); schedule(); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; goto out2; } - down(&s->sem); + mutex_lock(&s->sem); } } while (avail <= 0); @@ -1097,7 +1101,7 @@ au1550_read(struct file *file, char *buffer, size_t count, loff_t *ppos) } /* while (count > 0) */ out: - up(&s->sem); + mutex_unlock(&s->sem); out2: remove_wait_queue(&db->wait, &wait); set_current_state(TASK_RUNNING); @@ -1123,7 +1127,7 @@ au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) count *= db->cnt_factor; - down(&s->sem); + mutex_lock(&s->sem); add_wait_queue(&db->wait, &wait); while (count > 0) { @@ -1141,14 +1145,14 @@ au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) ret = -EAGAIN; goto out; } - up(&s->sem); + mutex_unlock(&s->sem); schedule(); if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; goto out2; } - down(&s->sem); + mutex_lock(&s->sem); } } while (avail <= 0); @@ -1194,7 +1198,7 @@ au1550_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) } /* while (count > 0) */ out: - up(&s->sem); + mutex_unlock(&s->sem); out2: remove_wait_queue(&db->wait, &wait); set_current_state(TASK_RUNNING); @@ -1251,7 +1255,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma) int ret = 0; lock_kernel(); - down(&s->sem); + mutex_lock(&s->sem); if (vma->vm_flags & VM_WRITE) db = &s->dma_dac; else if (vma->vm_flags & VM_READ) @@ -1277,7 +1281,7 @@ au1550_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_flags &= ~VM_IO; db->mapped = 1; out: - up(&s->sem); + mutex_unlock(&s->sem); unlock_kernel(); return ret; } @@ -1349,11 +1353,11 @@ au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ((file->f_mode & FMODE_READ) && s->dma_adc.mapped); #ifdef DEBUG - for (count=0; countf_mode & FMODE_READ) { - if (val & PCM_ENABLE_INPUT) + if (val & PCM_ENABLE_INPUT) { + spin_lock_irqsave(&s->lock, flags); start_adc(s); - else + spin_unlock_irqrestore(&s->lock, flags); + } else stop_adc(s); } if (file->f_mode & FMODE_WRITE) { - if (val & PCM_ENABLE_OUTPUT) + if (val & PCM_ENABLE_OUTPUT) { + spin_lock_irqsave(&s->lock, flags); start_dac(s); - else + spin_unlock_irqrestore(&s->lock, flags); + } else stop_dac(s); } return 0; @@ -1619,7 +1627,9 @@ au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd, sizeof(abinfo)) ? -EFAULT : 0; case SNDCTL_DSP_NONBLOCK: + spin_lock(&file->f_lock); file->f_flags |= O_NONBLOCK; + spin_unlock(&file->f_lock); return 0; case SNDCTL_DSP_GETODELAY: @@ -1784,21 +1794,21 @@ au1550_open(struct inode *inode, struct file *file) file->private_data = s; /* wait for device to become free */ - down(&s->open_sem); + mutex_lock(&s->open_mutex); while (s->open_mode & file->f_mode) { if (file->f_flags & O_NONBLOCK) { - up(&s->open_sem); + mutex_unlock(&s->open_mutex); return -EBUSY; } add_wait_queue(&s->open_wait, &wait); __set_current_state(TASK_INTERRUPTIBLE); - up(&s->open_sem); + mutex_unlock(&s->open_mutex); schedule(); remove_wait_queue(&s->open_wait, &wait); set_current_state(TASK_RUNNING); if (signal_pending(current)) return -ERESTARTSYS; - down(&s->open_sem); + mutex_lock(&s->open_mutex); } stop_dac(s); @@ -1834,8 +1844,8 @@ au1550_open(struct inode *inode, struct file *file) } s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - up(&s->open_sem); - init_MUTEX(&s->sem); + mutex_unlock(&s->open_mutex); + mutex_init(&s->sem); return 0; } @@ -1852,7 +1862,7 @@ au1550_release(struct inode *inode, struct file *file) lock_kernel(); } - down(&s->open_sem); + mutex_lock(&s->open_mutex); if (file->f_mode & FMODE_WRITE) { stop_dac(s); kfree(s->dma_dac.rawbuf); @@ -1864,7 +1874,7 @@ au1550_release(struct inode *inode, struct file *file) s->dma_adc.rawbuf = NULL; } s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE)); - up(&s->open_sem); + mutex_unlock(&s->open_mutex); wake_up(&s->open_wait); unlock_kernel(); return 0; @@ -1884,6 +1894,8 @@ static /*const */ struct file_operations au1550_audio_fops = { MODULE_AUTHOR("Advanced Micro Devices (AMD), dan@embeddededge.com"); MODULE_DESCRIPTION("Au1550 AC97 Audio Driver"); +MODULE_LICENSE("GPL"); + static int __devinit au1550_probe(void) @@ -1896,7 +1908,7 @@ au1550_probe(void) init_waitqueue_head(&s->dma_adc.wait); init_waitqueue_head(&s->dma_dac.wait); init_waitqueue_head(&s->open_wait); - init_MUTEX(&s->open_sem); + mutex_init(&s->open_mutex); spin_lock_init(&s->lock); s->codec = ac97_alloc_codec(); @@ -1989,7 +2001,7 @@ au1550_probe(void) /* Wait for PSC ready. */ do { - val = readl((void *)PSC_AC97STAT); + val = au_readl(PSC_AC97STAT); au_sync(); } while ((val & PSC_AC97STAT_SR) == 0); @@ -2012,7 +2024,7 @@ au1550_probe(void) /* Wait for Device ready. */ do { - val = readl((void *)PSC_AC97STAT); + val = au_readl(PSC_AC97STAT); au_sync(); } while ((val & PSC_AC97STAT_DR) == 0);