X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sound%2Foss%2Fnec_vrc5477.c;h=da9728e17727a9a60d3d1d9cb1ca79f8725c6820;hb=refs%2Fheads%2Fvserver;hp=0242f9021079bd2907967a80efe7802ce4dcd702;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/sound/oss/nec_vrc5477.c b/sound/oss/nec_vrc5477.c index 0242f9021..da9728e17 100644 --- a/sound/oss/nec_vrc5477.c +++ b/sound/oss/nec_vrc5477.c @@ -78,7 +78,8 @@ #include #include #include -#include +#include + #include #include #include @@ -199,7 +200,7 @@ struct vrc5477_ac97_state { unsigned short extended_status; spinlock_t lock; - struct semaphore open_sem; + struct mutex open_mutex; mode_t open_mode; wait_queue_head_t open_wait; @@ -396,10 +397,47 @@ static void set_dac_rate(struct vrc5477_ac97_state *s, unsigned rate) } } +static int ac97_codec_not_present(struct ac97_codec *codec) +{ + struct vrc5477_ac97_state *s = + (struct vrc5477_ac97_state *)codec->private_data; + unsigned long flags; + unsigned short count = 0xffff; + + spin_lock_irqsave(&s->lock, flags); + + /* wait until we can access codec registers */ + do { + if (!(inl(s->io + VRC5477_CODEC_WR) & 0x80000000)) + break; + } while (--count); + + if (count == 0) { + spin_unlock_irqrestore(&s->lock, flags); + return -1; + } + + /* write 0 to reset */ + outl((AC97_RESET << 16) | 0, s->io + VRC5477_CODEC_WR); + + /* test whether we get a response from ac97 chip */ + count = 0xffff; + do { + if (!(inl(s->io + VRC5477_CODEC_WR) & 0x80000000)) + break; + } while (--count); + + if (count == 0) { + spin_unlock_irqrestore(&s->lock, flags); + return -1; + } + spin_unlock_irqrestore(&s->lock, flags); + return 0; +} /* --------------------------------------------------------------------- */ -static inline void +static inline void stop_dac(struct vrc5477_ac97_state *s) { struct dmabuf* db = &s->dma_dac; @@ -616,7 +654,7 @@ static void start_adc(struct vrc5477_ac97_state *s) #define DMABUF_DEFAULTORDER (16-PAGE_SHIFT) #define DMABUF_MINORDER 1 -static inline void dealloc_dmabuf(struct vrc5477_ac97_state *s, +static inline void dealloc_dmabuf(struct vrc5477_ac97_state *s, struct dmabuf *db) { if (db->lbuf) { @@ -810,7 +848,7 @@ static inline void vrc5477_ac97_dac_interrupt(struct vrc5477_ac97_state *s) wake_up_interruptible(&dac->wait); } -static irqreturn_t vrc5477_ac97_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t vrc5477_ac97_interrupt(int irq, void *dev_id) { struct vrc5477_ac97_state *s = (struct vrc5477_ac97_state *)dev_id; u32 irqStatus; @@ -1581,22 +1619,22 @@ static int vrc5477_ac97_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); } spin_lock_irqsave(&s->lock, flags); @@ -1623,7 +1661,7 @@ static int vrc5477_ac97_open(struct inode *inode, struct file *file) bailout: spin_unlock_irqrestore(&s->lock, flags); - up(&s->open_sem); + mutex_unlock(&s->open_mutex); return ret; } @@ -1635,7 +1673,7 @@ static int vrc5477_ac97_release(struct inode *inode, struct file *file) lock_kernel(); if (file->f_mode & FMODE_WRITE) drain_dac(s, file->f_flags & O_NONBLOCK); - down(&s->open_sem); + mutex_lock(&s->open_mutex); if (file->f_mode & FMODE_WRITE) { stop_dac(s); dealloc_dmabuf(s, &s->dma_dac); @@ -1645,7 +1683,7 @@ static int vrc5477_ac97_release(struct inode *inode, struct file *file) dealloc_dmabuf(s, &s->dma_adc); } 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; @@ -1831,7 +1869,7 @@ static int __devinit vrc5477_ac97_probe(struct pci_dev *pcidev, 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->dev = pcidev; @@ -1858,13 +1896,20 @@ static int __devinit vrc5477_ac97_probe(struct pci_dev *pcidev, } + /* test if get response from ac97, if not return */ + if (ac97_codec_not_present(&(s->codec))) { + printk(KERN_ERR PFX "no ac97 codec\n"); + goto err_region; + + } + if (!request_region(s->io, pci_resource_len(pcidev,0), VRC5477_AC97_MODULE_NAME)) { printk(KERN_ERR PFX "io ports %#lx->%#lx in use\n", s->io, s->io + pci_resource_len(pcidev,0)-1); goto err_region; } - if (request_irq(s->irq, vrc5477_ac97_interrupt, SA_INTERRUPT, + if (request_irq(s->irq, vrc5477_ac97_interrupt, IRQF_DISABLED, VRC5477_AC97_MODULE_NAME, s)) { printk(KERN_ERR PFX "irq %u in use\n", s->irq); goto err_irq; @@ -1973,7 +2018,7 @@ static void __devexit vrc5477_ac97_remove(struct pci_dev *dev) remove_proc_entry(VRC5477_AC97_MODULE_NAME, NULL); #endif /* VRC5477_AC97_DEBUG */ - synchronize_irq(s->irq); + synchronize_irq(); free_irq(s->irq, s); release_region(s->io, pci_resource_len(dev,0)); unregister_sound_dsp(s->dev_audio); @@ -1996,13 +2041,13 @@ static struct pci_driver vrc5477_ac97_driver = { .name = VRC5477_AC97_MODULE_NAME, .id_table = id_table, .probe = vrc5477_ac97_probe, - .remove = __devexit_p(vrc5477_ac97_remove), + .remove = __devexit_p(vrc5477_ac97_remove) }; static int __init init_vrc5477_ac97(void) { printk("Vrc5477 AC97 driver: version v0.2 time " __TIME__ " " __DATE__ " by Jun Sun\n"); - return pci_module_init(&vrc5477_ac97_driver); + return pci_register_driver(&vrc5477_ac97_driver); } static void __exit cleanup_vrc5477_ac97(void)