diff options
author | Dean Anderson <dean@sensoray.com> | 2008-07-22 13:43:27 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-26 12:18:14 -0400 |
commit | f78d92c9ffcda7451b5943ab491c087f1ec7e08d (patch) | |
tree | c9cf013cc73d875fd45160af11b2256ae87741fc | |
parent | 655b8408557d586212d0797d423babdc464c587f (diff) |
V4L/DVB (8490): s2255drv Sensoray 2255 driver fixes
This patch fixes timer issues in driver disconnect.
It also removes the restriction of one user per channel at a time.
Thanks to Oliver Neukum and Mauro Chehab for finding these issues.
Locking of video stream partly based on saa7134 driver.
Signed-off-by: Dean Anderson <dean@sensoray.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | drivers/media/video/s2255drv.c | 111 |
1 files changed, 65 insertions, 46 deletions
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 2428d441fe15..9ff5403483e5 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c | |||
@@ -185,6 +185,7 @@ struct s2255_dmaqueue { | |||
185 | #define S2255_FW_LOADED_DSPWAIT 1 | 185 | #define S2255_FW_LOADED_DSPWAIT 1 |
186 | #define S2255_FW_SUCCESS 2 | 186 | #define S2255_FW_SUCCESS 2 |
187 | #define S2255_FW_FAILED 3 | 187 | #define S2255_FW_FAILED 3 |
188 | #define S2255_FW_DISCONNECTING 4 | ||
188 | 189 | ||
189 | struct s2255_fw { | 190 | struct s2255_fw { |
190 | int fw_loaded; | 191 | int fw_loaded; |
@@ -264,7 +265,6 @@ struct s2255_buffer { | |||
264 | 265 | ||
265 | struct s2255_fh { | 266 | struct s2255_fh { |
266 | struct s2255_dev *dev; | 267 | struct s2255_dev *dev; |
267 | unsigned int resources; | ||
268 | const struct s2255_fmt *fmt; | 268 | const struct s2255_fmt *fmt; |
269 | unsigned int width; | 269 | unsigned int width; |
270 | unsigned int height; | 270 | unsigned int height; |
@@ -274,14 +274,9 @@ struct s2255_fh { | |||
274 | /* mode below is the desired mode. | 274 | /* mode below is the desired mode. |
275 | mode in s2255_dev is the current mode that was last set */ | 275 | mode in s2255_dev is the current mode that was last set */ |
276 | struct s2255_mode mode; | 276 | struct s2255_mode mode; |
277 | int resources[MAX_CHANNELS]; | ||
277 | }; | 278 | }; |
278 | 279 | ||
279 | /* | ||
280 | * TODO: fixme S2255_MAX_USERS. Do not limit open driver handles. | ||
281 | * Limit V4L to one stream at a time. | ||
282 | */ | ||
283 | #define S2255_MAX_USERS 1 | ||
284 | |||
285 | #define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */ | 280 | #define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */ |
286 | #define S2255_MAJOR_VERSION 1 | 281 | #define S2255_MAJOR_VERSION 1 |
287 | #define S2255_MINOR_VERSION 13 | 282 | #define S2255_MINOR_VERSION 13 |
@@ -477,10 +472,9 @@ static void s2255_timer(unsigned long user_data) | |||
477 | dprintk(100, "s2255 timer\n"); | 472 | dprintk(100, "s2255 timer\n"); |
478 | if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { | 473 | if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { |
479 | printk(KERN_ERR "s2255: can't submit urb\n"); | 474 | printk(KERN_ERR "s2255: can't submit urb\n"); |
480 | if (data->fw) { | 475 | atomic_set(&data->fw_state, S2255_FW_FAILED); |
481 | release_firmware(data->fw); | 476 | /* wake up anything waiting for the firmware */ |
482 | data->fw = NULL; | 477 | wake_up(&data->wait_fw); |
483 | } | ||
484 | return; | 478 | return; |
485 | } | 479 | } |
486 | } | 480 | } |
@@ -510,13 +504,18 @@ static void s2255_fwchunk_complete(struct urb *urb) | |||
510 | struct usb_device *udev = urb->dev; | 504 | struct usb_device *udev = urb->dev; |
511 | int len; | 505 | int len; |
512 | dprintk(100, "udev %p urb %p", udev, urb); | 506 | dprintk(100, "udev %p urb %p", udev, urb); |
513 | /* TODO: fixme. reflect change in status */ | ||
514 | if (urb->status) { | 507 | if (urb->status) { |
515 | dev_err(&udev->dev, "URB failed with status %d", urb->status); | 508 | dev_err(&udev->dev, "URB failed with status %d", urb->status); |
509 | atomic_set(&data->fw_state, S2255_FW_FAILED); | ||
510 | /* wake up anything waiting for the firmware */ | ||
511 | wake_up(&data->wait_fw); | ||
516 | return; | 512 | return; |
517 | } | 513 | } |
518 | if (data->fw_urb == NULL) { | 514 | if (data->fw_urb == NULL) { |
519 | dev_err(&udev->dev, "early disconncect\n"); | 515 | dev_err(&udev->dev, "s2255 disconnected\n"); |
516 | atomic_set(&data->fw_state, S2255_FW_FAILED); | ||
517 | /* wake up anything waiting for the firmware */ | ||
518 | wake_up(&data->wait_fw); | ||
520 | return; | 519 | return; |
521 | } | 520 | } |
522 | #define CHUNK_SIZE 512 | 521 | #define CHUNK_SIZE 512 |
@@ -790,7 +789,8 @@ static int res_get(struct s2255_dev *dev, struct s2255_fh *fh) | |||
790 | } | 789 | } |
791 | /* it's free, grab it */ | 790 | /* it's free, grab it */ |
792 | dev->resources[fh->channel] = 1; | 791 | dev->resources[fh->channel] = 1; |
793 | dprintk(1, "res: get\n"); | 792 | fh->resources[fh->channel] = 1; |
793 | dprintk(1, "s2255: res: get\n"); | ||
794 | mutex_unlock(&dev->lock); | 794 | mutex_unlock(&dev->lock); |
795 | return 1; | 795 | return 1; |
796 | } | 796 | } |
@@ -800,9 +800,18 @@ static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh) | |||
800 | return dev->resources[fh->channel]; | 800 | return dev->resources[fh->channel]; |
801 | } | 801 | } |
802 | 802 | ||
803 | static int res_check(struct s2255_fh *fh) | ||
804 | { | ||
805 | return fh->resources[fh->channel]; | ||
806 | } | ||
807 | |||
808 | |||
803 | static void res_free(struct s2255_dev *dev, struct s2255_fh *fh) | 809 | static void res_free(struct s2255_dev *dev, struct s2255_fh *fh) |
804 | { | 810 | { |
811 | mutex_lock(&dev->lock); | ||
805 | dev->resources[fh->channel] = 0; | 812 | dev->resources[fh->channel] = 0; |
813 | fh->resources[fh->channel] = 0; | ||
814 | mutex_unlock(&dev->lock); | ||
806 | dprintk(1, "res: put\n"); | 815 | dprintk(1, "res: put\n"); |
807 | } | 816 | } |
808 | 817 | ||
@@ -1233,7 +1242,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | |||
1233 | } | 1242 | } |
1234 | 1243 | ||
1235 | if (!res_get(dev, fh)) { | 1244 | if (!res_get(dev, fh)) { |
1236 | dev_err(&dev->udev->dev, "res get busy\n"); | 1245 | dev_err(&dev->udev->dev, "s2255: stream busy\n"); |
1237 | return -EBUSY; | 1246 | return -EBUSY; |
1238 | } | 1247 | } |
1239 | 1248 | ||
@@ -1289,8 +1298,10 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | |||
1289 | } | 1298 | } |
1290 | s2255_stop_acquire(dev, fh->channel); | 1299 | s2255_stop_acquire(dev, fh->channel); |
1291 | res = videobuf_streamoff(&fh->vb_vidq); | 1300 | res = videobuf_streamoff(&fh->vb_vidq); |
1301 | if (res < 0) | ||
1302 | return res; | ||
1292 | res_free(dev, fh); | 1303 | res_free(dev, fh); |
1293 | return res; | 1304 | return 0; |
1294 | } | 1305 | } |
1295 | 1306 | ||
1296 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) | 1307 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) |
@@ -1463,12 +1474,7 @@ static int s2255_open(struct inode *inode, struct file *file) | |||
1463 | mutex_lock(&dev->open_lock); | 1474 | mutex_lock(&dev->open_lock); |
1464 | 1475 | ||
1465 | dev->users[cur_channel]++; | 1476 | dev->users[cur_channel]++; |
1466 | if (dev->users[cur_channel] > S2255_MAX_USERS) { | 1477 | dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]); |
1467 | dev->users[cur_channel]--; | ||
1468 | mutex_unlock(&dev->open_lock); | ||
1469 | printk(KERN_INFO "s2255drv: too many open handles!\n"); | ||
1470 | return -EBUSY; | ||
1471 | } | ||
1472 | 1478 | ||
1473 | if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) { | 1479 | if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) { |
1474 | err("2255 firmware load failed. retrying.\n"); | 1480 | err("2255 firmware load failed. retrying.\n"); |
@@ -1479,7 +1485,8 @@ static int s2255_open(struct inode *inode, struct file *file) | |||
1479 | msecs_to_jiffies(S2255_LOAD_TIMEOUT)); | 1485 | msecs_to_jiffies(S2255_LOAD_TIMEOUT)); |
1480 | if (atomic_read(&dev->fw_data->fw_state) | 1486 | if (atomic_read(&dev->fw_data->fw_state) |
1481 | != S2255_FW_SUCCESS) { | 1487 | != S2255_FW_SUCCESS) { |
1482 | printk(KERN_INFO "2255 FW load failed after 2 tries\n"); | 1488 | printk(KERN_INFO "2255 FW load failed.\n"); |
1489 | dev->users[cur_channel]--; | ||
1483 | mutex_unlock(&dev->open_lock); | 1490 | mutex_unlock(&dev->open_lock); |
1484 | return -EFAULT; | 1491 | return -EFAULT; |
1485 | } | 1492 | } |
@@ -1495,6 +1502,7 @@ static int s2255_open(struct inode *inode, struct file *file) | |||
1495 | != S2255_FW_SUCCESS) { | 1502 | != S2255_FW_SUCCESS) { |
1496 | printk(KERN_INFO "2255 firmware not loaded" | 1503 | printk(KERN_INFO "2255 firmware not loaded" |
1497 | "try again\n"); | 1504 | "try again\n"); |
1505 | dev->users[cur_channel]--; | ||
1498 | mutex_unlock(&dev->open_lock); | 1506 | mutex_unlock(&dev->open_lock); |
1499 | return -EBUSY; | 1507 | return -EBUSY; |
1500 | } | 1508 | } |
@@ -1503,6 +1511,7 @@ static int s2255_open(struct inode *inode, struct file *file) | |||
1503 | /* allocate + initialize per filehandle data */ | 1511 | /* allocate + initialize per filehandle data */ |
1504 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 1512 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
1505 | if (NULL == fh) { | 1513 | if (NULL == fh) { |
1514 | dev->users[cur_channel]--; | ||
1506 | mutex_unlock(&dev->open_lock); | 1515 | mutex_unlock(&dev->open_lock); |
1507 | return -ENOMEM; | 1516 | return -ENOMEM; |
1508 | } | 1517 | } |
@@ -1562,44 +1571,48 @@ static void s2255_destroy(struct kref *kref) | |||
1562 | printk(KERN_ERR "s2255drv: kref problem\n"); | 1571 | printk(KERN_ERR "s2255drv: kref problem\n"); |
1563 | return; | 1572 | return; |
1564 | } | 1573 | } |
1574 | |||
1575 | /* | ||
1576 | * Wake up any firmware load waiting (only done in .open, | ||
1577 | * which holds the open_lock mutex) | ||
1578 | */ | ||
1579 | atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING); | ||
1580 | wake_up(&dev->fw_data->wait_fw); | ||
1581 | |||
1565 | /* prevent s2255_disconnect from racing s2255_open */ | 1582 | /* prevent s2255_disconnect from racing s2255_open */ |
1566 | mutex_lock(&dev->open_lock); | 1583 | mutex_lock(&dev->open_lock); |
1567 | s2255_exit_v4l(dev); | 1584 | s2255_exit_v4l(dev); |
1568 | /* device unregistered so no longer possible to open. open_mutex | 1585 | /* |
1569 | can be unlocked */ | 1586 | * device unregistered so no longer possible to open. open_mutex |
1587 | * can be unlocked and timers deleted afterwards. | ||
1588 | */ | ||
1570 | mutex_unlock(&dev->open_lock); | 1589 | mutex_unlock(&dev->open_lock); |
1571 | 1590 | ||
1572 | /* board shutdown stops the read pipe if it is running */ | 1591 | /* board shutdown stops the read pipe if it is running */ |
1573 | s2255_board_shutdown(dev); | 1592 | s2255_board_shutdown(dev); |
1574 | 1593 | ||
1575 | /* make sure firmware still not trying to load */ | 1594 | /* make sure firmware still not trying to load */ |
1595 | del_timer(&dev->timer); /* only started in .probe and .open */ | ||
1596 | |||
1576 | if (dev->fw_data->fw_urb) { | 1597 | if (dev->fw_data->fw_urb) { |
1577 | dprintk(2, "kill fw_urb\n"); | 1598 | dprintk(2, "kill fw_urb\n"); |
1578 | usb_kill_urb(dev->fw_data->fw_urb); | 1599 | usb_kill_urb(dev->fw_data->fw_urb); |
1579 | usb_free_urb(dev->fw_data->fw_urb); | 1600 | usb_free_urb(dev->fw_data->fw_urb); |
1580 | dev->fw_data->fw_urb = NULL; | 1601 | dev->fw_data->fw_urb = NULL; |
1581 | } | 1602 | } |
1603 | |||
1582 | /* | 1604 | /* |
1583 | * TODO: fixme(above, below): potentially leaving timers alive. | 1605 | * delete the dsp_wait timer, which sets the firmware |
1584 | * do not ignore timeout below if | 1606 | * state on completion. This is done before fw_data |
1585 | * it occurs. | 1607 | * is freed below. |
1586 | */ | 1608 | */ |
1587 | 1609 | ||
1588 | /* make sure we aren't waiting for the DSP */ | 1610 | del_timer(&dev->fw_data->dsp_wait); /* only started in .open */ |
1589 | if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_LOADED_DSPWAIT) { | ||
1590 | /* if we are, wait for the wakeup for fw_success or timeout */ | ||
1591 | wait_event_timeout(dev->fw_data->wait_fw, | ||
1592 | (atomic_read(&dev->fw_data->fw_state) | ||
1593 | == S2255_FW_SUCCESS), | ||
1594 | msecs_to_jiffies(S2255_LOAD_TIMEOUT)); | ||
1595 | } | ||
1596 | 1611 | ||
1597 | if (dev->fw_data) { | 1612 | if (dev->fw_data->fw) |
1598 | if (dev->fw_data->fw) | 1613 | release_firmware(dev->fw_data->fw); |
1599 | release_firmware(dev->fw_data->fw); | 1614 | kfree(dev->fw_data->pfw_data); |
1600 | kfree(dev->fw_data->pfw_data); | 1615 | kfree(dev->fw_data); |
1601 | kfree(dev->fw_data); | ||
1602 | } | ||
1603 | 1616 | ||
1604 | usb_put_dev(dev->udev); | 1617 | usb_put_dev(dev->udev); |
1605 | dprintk(1, "%s", __func__); | 1618 | dprintk(1, "%s", __func__); |
@@ -1616,17 +1629,23 @@ static int s2255_close(struct inode *inode, struct file *file) | |||
1616 | 1629 | ||
1617 | mutex_lock(&dev->open_lock); | 1630 | mutex_lock(&dev->open_lock); |
1618 | 1631 | ||
1619 | if (dev->b_acquire[fh->channel]) | 1632 | /* turn off stream */ |
1620 | s2255_stop_acquire(dev, fh->channel); | 1633 | if (res_check(fh)) { |
1621 | res_free(dev, fh); | 1634 | if (dev->b_acquire[fh->channel]) |
1635 | s2255_stop_acquire(dev, fh->channel); | ||
1636 | videobuf_streamoff(&fh->vb_vidq); | ||
1637 | res_free(dev, fh); | ||
1638 | } | ||
1639 | |||
1622 | videobuf_mmap_free(&fh->vb_vidq); | 1640 | videobuf_mmap_free(&fh->vb_vidq); |
1623 | kfree(fh); | ||
1624 | dev->users[fh->channel]--; | 1641 | dev->users[fh->channel]--; |
1642 | |||
1625 | mutex_unlock(&dev->open_lock); | 1643 | mutex_unlock(&dev->open_lock); |
1626 | 1644 | ||
1627 | kref_put(&dev->kref, s2255_destroy); | 1645 | kref_put(&dev->kref, s2255_destroy); |
1628 | dprintk(1, "s2255: close called (minor=%d, users=%d)\n", | 1646 | dprintk(1, "s2255: close called (minor=%d, users=%d)\n", |
1629 | minor, dev->users[fh->channel]); | 1647 | minor, dev->users[fh->channel]); |
1648 | kfree(fh); | ||
1630 | return 0; | 1649 | return 0; |
1631 | } | 1650 | } |
1632 | 1651 | ||