Hello all, I have attached sound driver locking patches for: drivers/sound/cs4281/cs4281m.c drivers/sound/i810_audio.c The patches are against 2.4.5-ac13, and address the sound driver locking issue mentioned in the -ac series. Please review. Thanks. Regards, Frank
--- drivers/sound/cs4281/cs4281m.c.old Mon Jun 11 00:23:02 2001 +++ drivers/sound/cs4281/cs4281m.c Tue Jun 12 01:17:14 2001 @@ -293,6 +293,7 @@ struct cs4281_pm pm; struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES]; + struct semaphore sem; }; #include "cs4281pm-24.c" @@ -2876,7 +2877,7 @@ { struct cs4281_state *s = (struct cs4281_state *) file->private_data; - ssize_t ret; + ssize_t ret = 0; unsigned long flags; unsigned swptr; int cnt; @@ -2890,11 +2891,12 @@ return -ESPIPE; if (s->dma_adc.mapped) return -ENXIO; - if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) - return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; - ret = 0; + + down(&s->sem); + if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s))) + goto out; // // "count" is the amount of bytes to read (from app), is decremented each loop // by the amount of bytes that have been returned to the user buffer. @@ -2950,10 +2952,23 @@ // the loop when wake up occurs. start_adc(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; + { + if(!ret) ret = -EAGAIN; + goto out; + } + up(&s->sem); interruptible_sleep_on(&s->dma_adc.wait); if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + { + if(!ret) ret = -ERESTARTSYS; + goto out; + } + down(&s->sem); + if (s->dma_adc.mapped) + { + ret = -ENXIO; + goto out; + } continue; } // there are bytes in the buffer to read. @@ -2971,7 +2986,10 @@ if (cs_copy_to_user (s, buffer, s->dma_adc.rawbuf + swptr, cnt, &copied)) - return ret ? ret : -EFAULT; + { + if(!ret) ret = -EFAULT; + goto out; + } swptr = (swptr + cnt) % s->dma_adc.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_adc.swptr = swptr; @@ -2984,6 +3002,8 @@ } CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2, printk(KERN_INFO "cs4281: cs4281_read()- %d\n", ret)); +out: + up(&s->sem); return ret; } @@ -3007,10 +3027,12 @@ return -ESPIPE; if (s->dma_dac.mapped) return -ENXIO; - if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) - return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; + down(&s->sem); + if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s))) + goto out; + ret = 0; while (count > 0) { spin_lock_irqsave(&s->lock, flags); @@ -3035,14 +3057,30 @@ if (cnt <= 0) { start_dac(s); if (file->f_flags & O_NONBLOCK) - return ret ? ret : -EAGAIN; + { + if(!ret) ret = -EAGAIN; + goto out; + } + up(&s->sem); interruptible_sleep_on(&s->dma_dac.wait); if (signal_pending(current)) - return ret ? ret : -ERESTARTSYS; + { + if(!ret) ret = -ERESTARTSYS; + goto out; + } + down(&s->sem); + if (s->dma_dac.mapped) + { + ret = -ENXIO; + goto out; + } continue; } if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) - return ret ? ret : -EFAULT; + { + if(!ret) ret = -EFAULT; + goto out; + } swptr = (swptr + cnt) % s->dma_dac.dmasize; spin_lock_irqsave(&s->lock, flags); s->dma_dac.swptr = swptr; @@ -3056,6 +3094,8 @@ } CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2, printk(KERN_INFO "cs4281: cs4281_write()- %d\n", ret)); +out: + up(&s->sem); return ret; } @@ -3132,35 +3172,49 @@ printk(KERN_INFO "cs4281: cs4281_mmap()+\n")); VALIDATE_STATE(s); + down(&s->sem); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf_dac(s)) != 0) - return ret; + goto out; db = &s->dma_dac; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf_adc(s)) != 0) - return ret; + goto out; db = &s->dma_adc; - } else - return -EINVAL; + } else { + ret = -EINVAL; + goto out; + } // // only support PLAYBACK for now // db = &s->dma_dac; if (cs4x_pgoff(vma) != 0) - return -EINVAL; + { + ret = -EINVAL; + goto out; + } size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) - return -EINVAL; + { + ret = -EINVAL; + goto out; + } if (remap_page_range (vma->vm_start, virt_to_phys(db->rawbuf), size, - vma->vm_page_prot)) return -EAGAIN; + vma->vm_page_prot)) + { + ret = -EAGAIN; + goto out; + } db->mapped = 1; CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4, printk(KERN_INFO "cs4281: cs4281_mmap()- 0 size=%d\n", (unsigned) size)); - +out: + up(&s->sem); return 0; } @@ -4323,6 +4377,7 @@ init_waitqueue_head(&s->midi.iwait); init_waitqueue_head(&s->midi.owait); init_MUTEX(&s->open_sem); + init_MUTEX(&s->sem); init_MUTEX(&s->open_sem_adc); init_MUTEX(&s->open_sem_dac); spin_lock_init(&s->lock);
--- drivers/sound/i810_audio.c.old Mon Jun 11 00:23:05 2001 +++ drivers/sound/i810_audio.c Tue Jun 12 19:03:50 2001 @@ -298,6 +298,7 @@ unsigned ossmaxfrags; unsigned subdivision; } dmabuf; + struct semaphore sem; }; @@ -1066,7 +1067,7 @@ { struct i810_state *state = (struct i810_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; - ssize_t ret; + ssize_t ret = 0; unsigned long flags; unsigned int swptr; int cnt; @@ -1088,13 +1089,14 @@ return -EBUSY; } } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; dmabuf->trigger &= ~PCM_ENABLE_OUTPUT; - ret = 0; + down(&state->sem); + if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) + goto out; + while (count > 0) { spin_lock_irqsave(&state->card->lock, flags); swptr = dmabuf->swptr; @@ -1119,8 +1121,9 @@ } if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; - return ret; + goto out; } + up(&state->sem); /* This isnt strictly right for the 810 but it'll do */ tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 2); tmo >>= 1; @@ -1142,15 +1145,21 @@ while loop begin and we REALLY have space to record */ } if (signal_pending(current)) { - ret = ret ? ret : -ERESTARTSYS; - return ret; + if(!ret) ret = -ERESTARTSYS; + goto out; + } + down(&state->sem); + if (dmabuf->mapped) + { + ret = -ENXIO; + goto out; } continue; } if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { if (!ret) ret = -EFAULT; - return ret; + goto out; } swptr = (swptr + cnt) % dmabuf->dmasize; @@ -1164,6 +1173,8 @@ buffer += cnt; ret += cnt; } +out: + up(&state->sem); i810_update_lvi(state,1); start_adc(state); return ret; @@ -1196,11 +1207,12 @@ if(!dmabuf->write_channel) return -EBUSY; } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) - return ret; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; dmabuf->trigger &= ~PCM_ENABLE_INPUT; + down(&state->sem); + if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) + goto out; ret = 0; while (count > 0) { @@ -1228,8 +1240,9 @@ } if (file->f_flags & O_NONBLOCK) { if (!ret) ret = -EAGAIN; - return ret; + goto out; } + up(&state->sem); /* Not strictly correct but works */ tmo = (dmabuf->dmasize * HZ) / (dmabuf->rate * 4); /* There are two situations when sleep_on_timeout returns, one is when @@ -1252,13 +1265,19 @@ } if (signal_pending(current)) { if (!ret) ret = -ERESTARTSYS; - return ret; + goto out; } continue; } + down(&state->sem); + if (dmabuf->mapped) + { + ret = -ENXIO; + goto out; + } if (copy_from_user(dmabuf->rawbuf+swptr,buffer,cnt)) { if (!ret) ret = -EFAULT; - return ret; + goto out; } swptr = (swptr + cnt) % dmabuf->dmasize; @@ -1277,6 +1296,8 @@ if((x + dmabuf->count) < dmabuf->dmasize) memset(dmabuf->rawbuf + swptr, '\0', x); } +out: + up(&state->sem); i810_update_lvi(state,0); if (!dmabuf->enable && dmabuf->count >= dmabuf->userfragsize) start_dac(state); @@ -1323,6 +1344,7 @@ unsigned long size; lock_kernel(); + down(&state->sem); if (vma->vm_flags & VM_WRITE) { if (!dmabuf->write_channel && (dmabuf->write_channel = @@ -1362,6 +1384,7 @@ printk("i810_audio: mmap'ed %ld bytes of data space\n", size); #endif out: + up(&state->sem); unlock_kernel(); return ret; } @@ -1784,6 +1807,7 @@ state->magic = I810_STATE_MAGIC; init_waitqueue_head(&dmabuf->wait); init_MUTEX(&state->open_sem); + init_MUTEX(&state->sem); file->private_data = state; dmabuf->trigger = 0;