diff options
-rw-r--r-- | drivers/staging/comedi/comedi_fops.c | 25 |
1 files changed, 15 insertions, 10 deletions
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 6cdef9d5f8d0..f4a197b2d1fd 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c | |||
@@ -1413,22 +1413,19 @@ static int do_cmd_ioctl(struct comedi_device *dev, | |||
1413 | DPRINTK("subdevice busy\n"); | 1413 | DPRINTK("subdevice busy\n"); |
1414 | return -EBUSY; | 1414 | return -EBUSY; |
1415 | } | 1415 | } |
1416 | s->busy = file; | ||
1417 | 1416 | ||
1418 | /* make sure channel/gain list isn't too long */ | 1417 | /* make sure channel/gain list isn't too long */ |
1419 | if (cmd.chanlist_len > s->len_chanlist) { | 1418 | if (cmd.chanlist_len > s->len_chanlist) { |
1420 | DPRINTK("channel/gain list too long %u > %d\n", | 1419 | DPRINTK("channel/gain list too long %u > %d\n", |
1421 | cmd.chanlist_len, s->len_chanlist); | 1420 | cmd.chanlist_len, s->len_chanlist); |
1422 | ret = -EINVAL; | 1421 | return -EINVAL; |
1423 | goto cleanup; | ||
1424 | } | 1422 | } |
1425 | 1423 | ||
1426 | /* make sure channel/gain list isn't too short */ | 1424 | /* make sure channel/gain list isn't too short */ |
1427 | if (cmd.chanlist_len < 1) { | 1425 | if (cmd.chanlist_len < 1) { |
1428 | DPRINTK("channel/gain list too short %u < 1\n", | 1426 | DPRINTK("channel/gain list too short %u < 1\n", |
1429 | cmd.chanlist_len); | 1427 | cmd.chanlist_len); |
1430 | ret = -EINVAL; | 1428 | return -EINVAL; |
1431 | goto cleanup; | ||
1432 | } | 1429 | } |
1433 | 1430 | ||
1434 | async->cmd = cmd; | 1431 | async->cmd = cmd; |
@@ -1438,8 +1435,7 @@ static int do_cmd_ioctl(struct comedi_device *dev, | |||
1438 | kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL); | 1435 | kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL); |
1439 | if (!async->cmd.chanlist) { | 1436 | if (!async->cmd.chanlist) { |
1440 | DPRINTK("allocation failed\n"); | 1437 | DPRINTK("allocation failed\n"); |
1441 | ret = -ENOMEM; | 1438 | return -ENOMEM; |
1442 | goto cleanup; | ||
1443 | } | 1439 | } |
1444 | 1440 | ||
1445 | if (copy_from_user(async->cmd.chanlist, user_chanlist, | 1441 | if (copy_from_user(async->cmd.chanlist, user_chanlist, |
@@ -1491,6 +1487,9 @@ static int do_cmd_ioctl(struct comedi_device *dev, | |||
1491 | 1487 | ||
1492 | comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING); | 1488 | comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING); |
1493 | 1489 | ||
1490 | /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with | ||
1491 | * comedi_read() or comedi_write() */ | ||
1492 | s->busy = file; | ||
1494 | ret = s->do_cmd(dev, s); | 1493 | ret = s->do_cmd(dev, s); |
1495 | if (ret == 0) | 1494 | if (ret == 0) |
1496 | return 0; | 1495 | return 0; |
@@ -2058,11 +2057,13 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, | |||
2058 | 2057 | ||
2059 | if (!comedi_is_subdevice_running(s)) { | 2058 | if (!comedi_is_subdevice_running(s)) { |
2060 | if (count == 0) { | 2059 | if (count == 0) { |
2060 | mutex_lock(&dev->mutex); | ||
2061 | if (comedi_is_subdevice_in_error(s)) | 2061 | if (comedi_is_subdevice_in_error(s)) |
2062 | retval = -EPIPE; | 2062 | retval = -EPIPE; |
2063 | else | 2063 | else |
2064 | retval = 0; | 2064 | retval = 0; |
2065 | do_become_nonbusy(dev, s); | 2065 | do_become_nonbusy(dev, s); |
2066 | mutex_unlock(&dev->mutex); | ||
2066 | } | 2067 | } |
2067 | break; | 2068 | break; |
2068 | } | 2069 | } |
@@ -2161,11 +2162,13 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, | |||
2161 | 2162 | ||
2162 | if (n == 0) { | 2163 | if (n == 0) { |
2163 | if (!comedi_is_subdevice_running(s)) { | 2164 | if (!comedi_is_subdevice_running(s)) { |
2165 | mutex_lock(&dev->mutex); | ||
2164 | do_become_nonbusy(dev, s); | 2166 | do_become_nonbusy(dev, s); |
2165 | if (comedi_is_subdevice_in_error(s)) | 2167 | if (comedi_is_subdevice_in_error(s)) |
2166 | retval = -EPIPE; | 2168 | retval = -EPIPE; |
2167 | else | 2169 | else |
2168 | retval = 0; | 2170 | retval = 0; |
2171 | mutex_unlock(&dev->mutex); | ||
2169 | break; | 2172 | break; |
2170 | } | 2173 | } |
2171 | if (file->f_flags & O_NONBLOCK) { | 2174 | if (file->f_flags & O_NONBLOCK) { |
@@ -2203,9 +2206,11 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, | |||
2203 | buf += n; | 2206 | buf += n; |
2204 | break; /* makes device work like a pipe */ | 2207 | break; /* makes device work like a pipe */ |
2205 | } | 2208 | } |
2206 | if (comedi_is_subdevice_idle(s) && | 2209 | if (comedi_is_subdevice_idle(s)) { |
2207 | async->buf_read_count - async->buf_write_count == 0) { | 2210 | mutex_lock(&dev->mutex); |
2208 | do_become_nonbusy(dev, s); | 2211 | if (async->buf_read_count - async->buf_write_count == 0) |
2212 | do_become_nonbusy(dev, s); | ||
2213 | mutex_unlock(&dev->mutex); | ||
2209 | } | 2214 | } |
2210 | set_current_state(TASK_RUNNING); | 2215 | set_current_state(TASK_RUNNING); |
2211 | remove_wait_queue(&async->wait_head, &wait); | 2216 | remove_wait_queue(&async->wait_head, &wait); |