diff options
author | Alexander Viro <viro@parcelfarce.linux.theplanet.co.uk> | 2004-06-03 02:47:28 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-06-03 02:47:28 -0700 |
commit | e29b3d48f5cbaa4fa6255569e3204444fe205661 (patch) | |
tree | 78f0de522c28fa07a7e0705339225eae55d63df1 /sound | |
parent | ac1aff9920bd6f8b12972fc376bc41b64fa2cf4e (diff) | |
download | history-e29b3d48f5cbaa4fa6255569e3204444fe205661.tar.gz |
[PATCH] sparse: msnd sound fix
msnd_pinnacle/msnd_classic do copy_{to,from}_user under a spinlock.
Taken out of spinlock (into a temp. buffer). Calls of msnd_fifo_{read,write}
always go from kernel buffer now, so we can drop the 'int user' argument in
them _and_ simplify error handling - all errors were from copy_..._user() and
now these are called directly by dsp_read()/dsp_write().
Diffstat (limited to 'sound')
-rw-r--r-- | sound/oss/msnd.c | 22 | ||||
-rw-r--r-- | sound/oss/msnd.h | 4 | ||||
-rw-r--r-- | sound/oss/msnd_pinnacle.c | 88 |
3 files changed, 62 insertions, 52 deletions
diff --git a/sound/oss/msnd.c b/sound/oss/msnd.c index 3fdbaf5f206385..6ccdd096f9183e 100644 --- a/sound/oss/msnd.c +++ b/sound/oss/msnd.c @@ -139,13 +139,10 @@ void msnd_fifo_make_empty(msnd_fifo *f) f->len = f->tail = f->head = 0; } -int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user) +int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len) { int count = 0; - if (f->len == f->n) - return 0; - while ((count < len) && (f->len != f->n)) { int nwritten; @@ -161,11 +158,7 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user) nwritten = len - count; } - if (user) { - if (copy_from_user(f->data + f->tail, buf, nwritten)) - return -EFAULT; - } else - isa_memcpy_fromio(f->data + f->tail, (unsigned long) buf, nwritten); + isa_memcpy_fromio(f->data + f->tail, (unsigned long) buf, nwritten); count += nwritten; buf += nwritten; @@ -177,13 +170,10 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user) return count; } -int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user) +int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len) { int count = 0; - if (f->len == 0) - return f->len; - while ((count < len) && (f->len > 0)) { int nread; @@ -199,11 +189,7 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user) nread = len - count; } - if (user) { - if (copy_to_user(buf, f->data + f->head, nread)) - return -EFAULT; - } else - isa_memcpy_toio((unsigned long) buf, f->data + f->head, nread); + isa_memcpy_toio((unsigned long) buf, f->data + f->head, nread); count += nread; buf += nread; diff --git a/sound/oss/msnd.h b/sound/oss/msnd.h index 7b361921e6d08f..73148d2eefe78d 100644 --- a/sound/oss/msnd.h +++ b/sound/oss/msnd.h @@ -266,8 +266,8 @@ void msnd_fifo_init(msnd_fifo *f); void msnd_fifo_free(msnd_fifo *f); int msnd_fifo_alloc(msnd_fifo *f, size_t n); void msnd_fifo_make_empty(msnd_fifo *f); -int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user); -int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user); +int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len); +int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len); int msnd_wait_TXDE(multisound_dev_t *dev); int msnd_wait_HC0(multisound_dev_t *dev); diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c index aea4a65f78fb1d..16a918fb442c9d 100644 --- a/sound/oss/msnd_pinnacle.c +++ b/sound/oss/msnd_pinnacle.c @@ -809,7 +809,7 @@ static int dev_release(struct inode *inode, struct file *file) static __inline__ int pack_DARQ_to_DARF(register int bank) { - register int size, n, timeout = 3; + register int size, timeout = 3; register WORD wTmp; LPDAQD DAQD; @@ -830,13 +830,10 @@ static __inline__ int pack_DARQ_to_DARF(register int bank) /* Read data from the head (unprotected bank 1 access okay since this is only called inside an interrupt) */ outb(HPBLKSEL_1, dev.io + HP_BLKS); - if ((n = msnd_fifo_write( + msnd_fifo_write( &dev.DARF, (char *)(dev.base + bank * DAR_BUFF_SIZE), - size, 0)) <= 0) { - outb(HPBLKSEL_0, dev.io + HP_BLKS); - return n; - } + size); outb(HPBLKSEL_0, dev.io + HP_BLKS); return 1; @@ -858,21 +855,16 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start) if (protect) { /* Critical section: protect fifo in non-interrupt */ spin_lock_irqsave(&dev.lock, flags); - if ((n = msnd_fifo_read( + n = msnd_fifo_read( &dev.DAPF, (char *)(dev.base + bank_num * DAP_BUFF_SIZE), - DAP_BUFF_SIZE, 0)) < 0) { - spin_unlock_irqrestore(&dev.lock, flags); - return n; - } + DAP_BUFF_SIZE); spin_unlock_irqrestore(&dev.lock, flags); } else { - if ((n = msnd_fifo_read( + n = msnd_fifo_read( &dev.DAPF, (char *)(dev.base + bank_num * DAP_BUFF_SIZE), - DAP_BUFF_SIZE, 0)) < 0) { - return n; - } + DAP_BUFF_SIZE); } if (!n) break; @@ -899,30 +891,43 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start) static int dsp_read(char *buf, size_t len) { int count = len; + char *page = (char *)__get_free_page(PAGE_SIZE); + + if (!page) + return -ENOMEM; while (count > 0) { - int n; + int n, k; unsigned long flags; + k = PAGE_SIZE; + if (k > count) + k = count; + /* Critical section: protect fifo in non-interrupt */ spin_lock_irqsave(&dev.lock, flags); - if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) { - printk(KERN_WARNING LOGNAME ": FIFO read error\n"); - spin_unlock_irqrestore(&dev.lock, flags); - return n; - } + n = msnd_fifo_read(&dev.DARF, page, k); spin_unlock_irqrestore(&dev.lock, flags); + if (copy_to_user(buf, page, n)) { + free_page((unsigned long)page); + return -EFAULT; + } buf += n; count -= n; + if (n == k && count) + continue; + if (!test_bit(F_READING, &dev.flags) && dev.mode & FMODE_READ) { dev.last_recbank = -1; if (chk_send_dsp_cmd(&dev, HDEX_RECORD_START) == 0) set_bit(F_READING, &dev.flags); } - if (dev.rec_ndelay) + if (dev.rec_ndelay) { + free_page((unsigned long)page); return count == len ? -EAGAIN : len - count; + } if (count > 0) { set_bit(F_READBLOCK, &dev.flags); @@ -931,41 +936,57 @@ static int dsp_read(char *buf, size_t len) get_rec_delay_jiffies(DAR_BUFF_SIZE))) clear_bit(F_READING, &dev.flags); clear_bit(F_READBLOCK, &dev.flags); - if (signal_pending(current)) + if (signal_pending(current)) { + free_page((unsigned long)page); return -EINTR; + } } } - + free_page((unsigned long)page); return len - count; } static int dsp_write(const char *buf, size_t len) { int count = len; + char *page = (char *)__get_free_page(GFP_KERNEL); + + if (!page) + return -ENOMEM; while (count > 0) { - int n; + int n, k; unsigned long flags; + k = PAGE_SIZE; + if (k > count) + k = count; + + if (copy_from_user(page, buf, k)) { + free_page((unsigned long)page); + return -EFAULT; + } + /* Critical section: protect fifo in non-interrupt */ spin_lock_irqsave(&dev.lock, flags); - if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) { - printk(KERN_WARNING LOGNAME ": FIFO write error\n"); - spin_unlock_irqrestore(&dev.lock, flags); - return n; - } + n = msnd_fifo_write(&dev.DAPF, page, k); spin_unlock_irqrestore(&dev.lock, flags); buf += n; count -= n; + if (count && n == k) + continue; + if (!test_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) { dev.last_playbank = -1; if (pack_DAPF_to_DAPQ(1) > 0) set_bit(F_WRITING, &dev.flags); } - if (dev.play_ndelay) + if (dev.play_ndelay) { + free_page((unsigned long)page); return count == len ? -EAGAIN : len - count; + } if (count > 0) { set_bit(F_WRITEBLOCK, &dev.flags); @@ -973,11 +994,14 @@ static int dsp_write(const char *buf, size_t len) &dev.writeblock, get_play_delay_jiffies(DAP_BUFF_SIZE)); clear_bit(F_WRITEBLOCK, &dev.flags); - if (signal_pending(current)) + if (signal_pending(current)) { + free_page((unsigned long)page); return -EINTR; + } } } + free_page((unsigned long)page); return len - count; } |