Commit e29b3d48 authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[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().
parent ac1aff99
...@@ -139,13 +139,10 @@ void msnd_fifo_make_empty(msnd_fifo *f) ...@@ -139,13 +139,10 @@ void msnd_fifo_make_empty(msnd_fifo *f)
f->len = f->tail = f->head = 0; 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; int count = 0;
if (f->len == f->n)
return 0;
while ((count < len) && (f->len != f->n)) { while ((count < len) && (f->len != f->n)) {
int nwritten; int nwritten;
...@@ -161,10 +158,6 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user) ...@@ -161,10 +158,6 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user)
nwritten = len - count; 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; count += nwritten;
...@@ -177,13 +170,10 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user) ...@@ -177,13 +170,10 @@ int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len, int user)
return count; 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; int count = 0;
if (f->len == 0)
return f->len;
while ((count < len) && (f->len > 0)) { while ((count < len) && (f->len > 0)) {
int nread; int nread;
...@@ -199,10 +189,6 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user) ...@@ -199,10 +189,6 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user)
nread = len - count; 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; count += nread;
......
...@@ -266,8 +266,8 @@ void msnd_fifo_init(msnd_fifo *f); ...@@ -266,8 +266,8 @@ void msnd_fifo_init(msnd_fifo *f);
void msnd_fifo_free(msnd_fifo *f); void msnd_fifo_free(msnd_fifo *f);
int msnd_fifo_alloc(msnd_fifo *f, size_t n); int msnd_fifo_alloc(msnd_fifo *f, size_t n);
void msnd_fifo_make_empty(msnd_fifo *f); 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_write(msnd_fifo *f, const char *buf, size_t len);
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 msnd_wait_TXDE(multisound_dev_t *dev); int msnd_wait_TXDE(multisound_dev_t *dev);
int msnd_wait_HC0(multisound_dev_t *dev); int msnd_wait_HC0(multisound_dev_t *dev);
......
...@@ -809,7 +809,7 @@ static int dev_release(struct inode *inode, struct file *file) ...@@ -809,7 +809,7 @@ static int dev_release(struct inode *inode, struct file *file)
static __inline__ int pack_DARQ_to_DARF(register int bank) static __inline__ int pack_DARQ_to_DARF(register int bank)
{ {
register int size, n, timeout = 3; register int size, timeout = 3;
register WORD wTmp; register WORD wTmp;
LPDAQD DAQD; LPDAQD DAQD;
...@@ -830,13 +830,10 @@ static __inline__ int pack_DARQ_to_DARF(register int bank) ...@@ -830,13 +830,10 @@ static __inline__ int pack_DARQ_to_DARF(register int bank)
/* Read data from the head (unprotected bank 1 access okay /* Read data from the head (unprotected bank 1 access okay
since this is only called inside an interrupt) */ since this is only called inside an interrupt) */
outb(HPBLKSEL_1, dev.io + HP_BLKS); outb(HPBLKSEL_1, dev.io + HP_BLKS);
if ((n = msnd_fifo_write( msnd_fifo_write(
&dev.DARF, &dev.DARF,
(char *)(dev.base + bank * DAR_BUFF_SIZE), (char *)(dev.base + bank * DAR_BUFF_SIZE),
size, 0)) <= 0) { size);
outb(HPBLKSEL_0, dev.io + HP_BLKS);
return n;
}
outb(HPBLKSEL_0, dev.io + HP_BLKS); outb(HPBLKSEL_0, dev.io + HP_BLKS);
return 1; return 1;
...@@ -858,21 +855,16 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start) ...@@ -858,21 +855,16 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start)
if (protect) { if (protect) {
/* Critical section: protect fifo in non-interrupt */ /* Critical section: protect fifo in non-interrupt */
spin_lock_irqsave(&dev.lock, flags); spin_lock_irqsave(&dev.lock, flags);
if ((n = msnd_fifo_read( n = msnd_fifo_read(
&dev.DAPF, &dev.DAPF,
(char *)(dev.base + bank_num * DAP_BUFF_SIZE), (char *)(dev.base + bank_num * DAP_BUFF_SIZE),
DAP_BUFF_SIZE, 0)) < 0) { DAP_BUFF_SIZE);
spin_unlock_irqrestore(&dev.lock, flags);
return n;
}
spin_unlock_irqrestore(&dev.lock, flags); spin_unlock_irqrestore(&dev.lock, flags);
} else { } else {
if ((n = msnd_fifo_read( n = msnd_fifo_read(
&dev.DAPF, &dev.DAPF,
(char *)(dev.base + bank_num * DAP_BUFF_SIZE), (char *)(dev.base + bank_num * DAP_BUFF_SIZE),
DAP_BUFF_SIZE, 0)) < 0) { DAP_BUFF_SIZE);
return n;
}
} }
if (!n) if (!n)
break; break;
...@@ -899,30 +891,43 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start) ...@@ -899,30 +891,43 @@ static __inline__ int pack_DAPF_to_DAPQ(register int start)
static int dsp_read(char *buf, size_t len) static int dsp_read(char *buf, size_t len)
{ {
int count = len; int count = len;
char *page = (char *)__get_free_page(PAGE_SIZE);
if (!page)
return -ENOMEM;
while (count > 0) { while (count > 0) {
int n; int n, k;
unsigned long flags; unsigned long flags;
k = PAGE_SIZE;
if (k > count)
k = count;
/* Critical section: protect fifo in non-interrupt */ /* Critical section: protect fifo in non-interrupt */
spin_lock_irqsave(&dev.lock, flags); spin_lock_irqsave(&dev.lock, flags);
if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) { n = msnd_fifo_read(&dev.DARF, page, k);
printk(KERN_WARNING LOGNAME ": FIFO read error\n");
spin_unlock_irqrestore(&dev.lock, flags); spin_unlock_irqrestore(&dev.lock, flags);
return n; if (copy_to_user(buf, page, n)) {
free_page((unsigned long)page);
return -EFAULT;
} }
spin_unlock_irqrestore(&dev.lock, flags);
buf += n; buf += n;
count -= n; count -= n;
if (n == k && count)
continue;
if (!test_bit(F_READING, &dev.flags) && dev.mode & FMODE_READ) { if (!test_bit(F_READING, &dev.flags) && dev.mode & FMODE_READ) {
dev.last_recbank = -1; dev.last_recbank = -1;
if (chk_send_dsp_cmd(&dev, HDEX_RECORD_START) == 0) if (chk_send_dsp_cmd(&dev, HDEX_RECORD_START) == 0)
set_bit(F_READING, &dev.flags); 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; return count == len ? -EAGAIN : len - count;
}
if (count > 0) { if (count > 0) {
set_bit(F_READBLOCK, &dev.flags); set_bit(F_READBLOCK, &dev.flags);
...@@ -931,41 +936,57 @@ static int dsp_read(char *buf, size_t len) ...@@ -931,41 +936,57 @@ static int dsp_read(char *buf, size_t len)
get_rec_delay_jiffies(DAR_BUFF_SIZE))) get_rec_delay_jiffies(DAR_BUFF_SIZE)))
clear_bit(F_READING, &dev.flags); clear_bit(F_READING, &dev.flags);
clear_bit(F_READBLOCK, &dev.flags); clear_bit(F_READBLOCK, &dev.flags);
if (signal_pending(current)) if (signal_pending(current)) {
free_page((unsigned long)page);
return -EINTR; return -EINTR;
} }
} }
}
free_page((unsigned long)page);
return len - count; return len - count;
} }
static int dsp_write(const char *buf, size_t len) static int dsp_write(const char *buf, size_t len)
{ {
int count = len; int count = len;
char *page = (char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
while (count > 0) { while (count > 0) {
int n; int n, k;
unsigned long flags; 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 */ /* Critical section: protect fifo in non-interrupt */
spin_lock_irqsave(&dev.lock, flags); spin_lock_irqsave(&dev.lock, flags);
if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) { n = msnd_fifo_write(&dev.DAPF, page, k);
printk(KERN_WARNING LOGNAME ": FIFO write error\n");
spin_unlock_irqrestore(&dev.lock, flags);
return n;
}
spin_unlock_irqrestore(&dev.lock, flags); spin_unlock_irqrestore(&dev.lock, flags);
buf += n; buf += n;
count -= n; count -= n;
if (count && n == k)
continue;
if (!test_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) { if (!test_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
dev.last_playbank = -1; dev.last_playbank = -1;
if (pack_DAPF_to_DAPQ(1) > 0) if (pack_DAPF_to_DAPQ(1) > 0)
set_bit(F_WRITING, &dev.flags); 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; return count == len ? -EAGAIN : len - count;
}
if (count > 0) { if (count > 0) {
set_bit(F_WRITEBLOCK, &dev.flags); set_bit(F_WRITEBLOCK, &dev.flags);
...@@ -973,11 +994,14 @@ static int dsp_write(const char *buf, size_t len) ...@@ -973,11 +994,14 @@ static int dsp_write(const char *buf, size_t len)
&dev.writeblock, &dev.writeblock,
get_play_delay_jiffies(DAP_BUFF_SIZE)); get_play_delay_jiffies(DAP_BUFF_SIZE));
clear_bit(F_WRITEBLOCK, &dev.flags); clear_bit(F_WRITEBLOCK, &dev.flags);
if (signal_pending(current)) if (signal_pending(current)) {
free_page((unsigned long)page);
return -EINTR; return -EINTR;
} }
} }
}
free_page((unsigned long)page);
return len - count; return len - count;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment