diff options
Diffstat (limited to 'drivers/media/video/s2255drv.c')
-rw-r--r-- | drivers/media/video/s2255drv.c | 130 |
1 files changed, 77 insertions, 53 deletions
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c index 04eb2c3fabd8..b1d09d8e2b85 100644 --- a/drivers/media/video/s2255drv.c +++ b/drivers/media/video/s2255drv.c | |||
@@ -47,8 +47,10 @@ | |||
47 | #include <linux/mutex.h> | 47 | #include <linux/mutex.h> |
48 | #include <linux/videodev2.h> | 48 | #include <linux/videodev2.h> |
49 | #include <linux/version.h> | 49 | #include <linux/version.h> |
50 | #include <linux/mm.h> | ||
50 | #include <media/videobuf-vmalloc.h> | 51 | #include <media/videobuf-vmalloc.h> |
51 | #include <media/v4l2-common.h> | 52 | #include <media/v4l2-common.h> |
53 | #include <media/v4l2-ioctl.h> | ||
52 | #include <linux/vmalloc.h> | 54 | #include <linux/vmalloc.h> |
53 | #include <linux/usb.h> | 55 | #include <linux/usb.h> |
54 | 56 | ||
@@ -184,6 +186,7 @@ struct s2255_dmaqueue { | |||
184 | #define S2255_FW_LOADED_DSPWAIT 1 | 186 | #define S2255_FW_LOADED_DSPWAIT 1 |
185 | #define S2255_FW_SUCCESS 2 | 187 | #define S2255_FW_SUCCESS 2 |
186 | #define S2255_FW_FAILED 3 | 188 | #define S2255_FW_FAILED 3 |
189 | #define S2255_FW_DISCONNECTING 4 | ||
187 | 190 | ||
188 | struct s2255_fw { | 191 | struct s2255_fw { |
189 | int fw_loaded; | 192 | int fw_loaded; |
@@ -263,7 +266,6 @@ struct s2255_buffer { | |||
263 | 266 | ||
264 | struct s2255_fh { | 267 | struct s2255_fh { |
265 | struct s2255_dev *dev; | 268 | struct s2255_dev *dev; |
266 | unsigned int resources; | ||
267 | const struct s2255_fmt *fmt; | 269 | const struct s2255_fmt *fmt; |
268 | unsigned int width; | 270 | unsigned int width; |
269 | unsigned int height; | 271 | unsigned int height; |
@@ -273,14 +275,9 @@ struct s2255_fh { | |||
273 | /* mode below is the desired mode. | 275 | /* mode below is the desired mode. |
274 | mode in s2255_dev is the current mode that was last set */ | 276 | mode in s2255_dev is the current mode that was last set */ |
275 | struct s2255_mode mode; | 277 | struct s2255_mode mode; |
278 | int resources[MAX_CHANNELS]; | ||
276 | }; | 279 | }; |
277 | 280 | ||
278 | /* | ||
279 | * TODO: fixme S2255_MAX_USERS. Do not limit open driver handles. | ||
280 | * Limit V4L to one stream at a time. | ||
281 | */ | ||
282 | #define S2255_MAX_USERS 1 | ||
283 | |||
284 | #define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */ | 281 | #define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */ |
285 | #define S2255_MAJOR_VERSION 1 | 282 | #define S2255_MAJOR_VERSION 1 |
286 | #define S2255_MINOR_VERSION 13 | 283 | #define S2255_MINOR_VERSION 13 |
@@ -476,10 +473,9 @@ static void s2255_timer(unsigned long user_data) | |||
476 | dprintk(100, "s2255 timer\n"); | 473 | dprintk(100, "s2255 timer\n"); |
477 | if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { | 474 | if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { |
478 | printk(KERN_ERR "s2255: can't submit urb\n"); | 475 | printk(KERN_ERR "s2255: can't submit urb\n"); |
479 | if (data->fw) { | 476 | atomic_set(&data->fw_state, S2255_FW_FAILED); |
480 | release_firmware(data->fw); | 477 | /* wake up anything waiting for the firmware */ |
481 | data->fw = NULL; | 478 | wake_up(&data->wait_fw); |
482 | } | ||
483 | return; | 479 | return; |
484 | } | 480 | } |
485 | } | 481 | } |
@@ -509,13 +505,18 @@ static void s2255_fwchunk_complete(struct urb *urb) | |||
509 | struct usb_device *udev = urb->dev; | 505 | struct usb_device *udev = urb->dev; |
510 | int len; | 506 | int len; |
511 | dprintk(100, "udev %p urb %p", udev, urb); | 507 | dprintk(100, "udev %p urb %p", udev, urb); |
512 | /* TODO: fixme. reflect change in status */ | ||
513 | if (urb->status) { | 508 | if (urb->status) { |
514 | dev_err(&udev->dev, "URB failed with status %d", urb->status); | 509 | dev_err(&udev->dev, "URB failed with status %d", urb->status); |
510 | atomic_set(&data->fw_state, S2255_FW_FAILED); | ||
511 | /* wake up anything waiting for the firmware */ | ||
512 | wake_up(&data->wait_fw); | ||
515 | return; | 513 | return; |
516 | } | 514 | } |
517 | if (data->fw_urb == NULL) { | 515 | if (data->fw_urb == NULL) { |
518 | dev_err(&udev->dev, "early disconncect\n"); | 516 | dev_err(&udev->dev, "s2255 disconnected\n"); |
517 | atomic_set(&data->fw_state, S2255_FW_FAILED); | ||
518 | /* wake up anything waiting for the firmware */ | ||
519 | wake_up(&data->wait_fw); | ||
519 | return; | 520 | return; |
520 | } | 521 | } |
521 | #define CHUNK_SIZE 512 | 522 | #define CHUNK_SIZE 512 |
@@ -789,7 +790,8 @@ static int res_get(struct s2255_dev *dev, struct s2255_fh *fh) | |||
789 | } | 790 | } |
790 | /* it's free, grab it */ | 791 | /* it's free, grab it */ |
791 | dev->resources[fh->channel] = 1; | 792 | dev->resources[fh->channel] = 1; |
792 | dprintk(1, "res: get\n"); | 793 | fh->resources[fh->channel] = 1; |
794 | dprintk(1, "s2255: res: get\n"); | ||
793 | mutex_unlock(&dev->lock); | 795 | mutex_unlock(&dev->lock); |
794 | return 1; | 796 | return 1; |
795 | } | 797 | } |
@@ -799,9 +801,18 @@ static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh) | |||
799 | return dev->resources[fh->channel]; | 801 | return dev->resources[fh->channel]; |
800 | } | 802 | } |
801 | 803 | ||
804 | static int res_check(struct s2255_fh *fh) | ||
805 | { | ||
806 | return fh->resources[fh->channel]; | ||
807 | } | ||
808 | |||
809 | |||
802 | static void res_free(struct s2255_dev *dev, struct s2255_fh *fh) | 810 | static void res_free(struct s2255_dev *dev, struct s2255_fh *fh) |
803 | { | 811 | { |
812 | mutex_lock(&dev->lock); | ||
804 | dev->resources[fh->channel] = 0; | 813 | dev->resources[fh->channel] = 0; |
814 | fh->resources[fh->channel] = 0; | ||
815 | mutex_unlock(&dev->lock); | ||
805 | dprintk(1, "res: put\n"); | 816 | dprintk(1, "res: put\n"); |
806 | } | 817 | } |
807 | 818 | ||
@@ -1232,7 +1243,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) | |||
1232 | } | 1243 | } |
1233 | 1244 | ||
1234 | if (!res_get(dev, fh)) { | 1245 | if (!res_get(dev, fh)) { |
1235 | dev_err(&dev->udev->dev, "res get busy\n"); | 1246 | dev_err(&dev->udev->dev, "s2255: stream busy\n"); |
1236 | return -EBUSY; | 1247 | return -EBUSY; |
1237 | } | 1248 | } |
1238 | 1249 | ||
@@ -1288,8 +1299,10 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) | |||
1288 | } | 1299 | } |
1289 | s2255_stop_acquire(dev, fh->channel); | 1300 | s2255_stop_acquire(dev, fh->channel); |
1290 | res = videobuf_streamoff(&fh->vb_vidq); | 1301 | res = videobuf_streamoff(&fh->vb_vidq); |
1302 | if (res < 0) | ||
1303 | return res; | ||
1291 | res_free(dev, fh); | 1304 | res_free(dev, fh); |
1292 | return res; | 1305 | return 0; |
1293 | } | 1306 | } |
1294 | 1307 | ||
1295 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) | 1308 | static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) |
@@ -1462,12 +1475,7 @@ static int s2255_open(struct inode *inode, struct file *file) | |||
1462 | mutex_lock(&dev->open_lock); | 1475 | mutex_lock(&dev->open_lock); |
1463 | 1476 | ||
1464 | dev->users[cur_channel]++; | 1477 | dev->users[cur_channel]++; |
1465 | if (dev->users[cur_channel] > S2255_MAX_USERS) { | 1478 | dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]); |
1466 | dev->users[cur_channel]--; | ||
1467 | mutex_unlock(&dev->open_lock); | ||
1468 | printk(KERN_INFO "s2255drv: too many open handles!\n"); | ||
1469 | return -EBUSY; | ||
1470 | } | ||
1471 | 1479 | ||
1472 | if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) { | 1480 | if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) { |
1473 | err("2255 firmware load failed. retrying.\n"); | 1481 | err("2255 firmware load failed. retrying.\n"); |
@@ -1478,7 +1486,8 @@ static int s2255_open(struct inode *inode, struct file *file) | |||
1478 | msecs_to_jiffies(S2255_LOAD_TIMEOUT)); | 1486 | msecs_to_jiffies(S2255_LOAD_TIMEOUT)); |
1479 | if (atomic_read(&dev->fw_data->fw_state) | 1487 | if (atomic_read(&dev->fw_data->fw_state) |
1480 | != S2255_FW_SUCCESS) { | 1488 | != S2255_FW_SUCCESS) { |
1481 | printk(KERN_INFO "2255 FW load failed after 2 tries\n"); | 1489 | printk(KERN_INFO "2255 FW load failed.\n"); |
1490 | dev->users[cur_channel]--; | ||
1482 | mutex_unlock(&dev->open_lock); | 1491 | mutex_unlock(&dev->open_lock); |
1483 | return -EFAULT; | 1492 | return -EFAULT; |
1484 | } | 1493 | } |
@@ -1494,6 +1503,7 @@ static int s2255_open(struct inode *inode, struct file *file) | |||
1494 | != S2255_FW_SUCCESS) { | 1503 | != S2255_FW_SUCCESS) { |
1495 | printk(KERN_INFO "2255 firmware not loaded" | 1504 | printk(KERN_INFO "2255 firmware not loaded" |
1496 | "try again\n"); | 1505 | "try again\n"); |
1506 | dev->users[cur_channel]--; | ||
1497 | mutex_unlock(&dev->open_lock); | 1507 | mutex_unlock(&dev->open_lock); |
1498 | return -EBUSY; | 1508 | return -EBUSY; |
1499 | } | 1509 | } |
@@ -1502,6 +1512,7 @@ static int s2255_open(struct inode *inode, struct file *file) | |||
1502 | /* allocate + initialize per filehandle data */ | 1512 | /* allocate + initialize per filehandle data */ |
1503 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); | 1513 | fh = kzalloc(sizeof(*fh), GFP_KERNEL); |
1504 | if (NULL == fh) { | 1514 | if (NULL == fh) { |
1515 | dev->users[cur_channel]--; | ||
1505 | mutex_unlock(&dev->open_lock); | 1516 | mutex_unlock(&dev->open_lock); |
1506 | return -ENOMEM; | 1517 | return -ENOMEM; |
1507 | } | 1518 | } |
@@ -1561,44 +1572,48 @@ static void s2255_destroy(struct kref *kref) | |||
1561 | printk(KERN_ERR "s2255drv: kref problem\n"); | 1572 | printk(KERN_ERR "s2255drv: kref problem\n"); |
1562 | return; | 1573 | return; |
1563 | } | 1574 | } |
1575 | |||
1576 | /* | ||
1577 | * Wake up any firmware load waiting (only done in .open, | ||
1578 | * which holds the open_lock mutex) | ||
1579 | */ | ||
1580 | atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING); | ||
1581 | wake_up(&dev->fw_data->wait_fw); | ||
1582 | |||
1564 | /* prevent s2255_disconnect from racing s2255_open */ | 1583 | /* prevent s2255_disconnect from racing s2255_open */ |
1565 | mutex_lock(&dev->open_lock); | 1584 | mutex_lock(&dev->open_lock); |
1566 | s2255_exit_v4l(dev); | 1585 | s2255_exit_v4l(dev); |
1567 | /* device unregistered so no longer possible to open. open_mutex | 1586 | /* |
1568 | can be unlocked */ | 1587 | * device unregistered so no longer possible to open. open_mutex |
1588 | * can be unlocked and timers deleted afterwards. | ||
1589 | */ | ||
1569 | mutex_unlock(&dev->open_lock); | 1590 | mutex_unlock(&dev->open_lock); |
1570 | 1591 | ||
1571 | /* board shutdown stops the read pipe if it is running */ | 1592 | /* board shutdown stops the read pipe if it is running */ |
1572 | s2255_board_shutdown(dev); | 1593 | s2255_board_shutdown(dev); |
1573 | 1594 | ||
1574 | /* make sure firmware still not trying to load */ | 1595 | /* make sure firmware still not trying to load */ |
1596 | del_timer(&dev->timer); /* only started in .probe and .open */ | ||
1597 | |||
1575 | if (dev->fw_data->fw_urb) { | 1598 | if (dev->fw_data->fw_urb) { |
1576 | dprintk(2, "kill fw_urb\n"); | 1599 | dprintk(2, "kill fw_urb\n"); |
1577 | usb_kill_urb(dev->fw_data->fw_urb); | 1600 | usb_kill_urb(dev->fw_data->fw_urb); |
1578 | usb_free_urb(dev->fw_data->fw_urb); | 1601 | usb_free_urb(dev->fw_data->fw_urb); |
1579 | dev->fw_data->fw_urb = NULL; | 1602 | dev->fw_data->fw_urb = NULL; |
1580 | } | 1603 | } |
1604 | |||
1581 | /* | 1605 | /* |
1582 | * TODO: fixme(above, below): potentially leaving timers alive. | 1606 | * delete the dsp_wait timer, which sets the firmware |
1583 | * do not ignore timeout below if | 1607 | * state on completion. This is done before fw_data |
1584 | * it occurs. | 1608 | * is freed below. |
1585 | */ | 1609 | */ |
1586 | 1610 | ||
1587 | /* make sure we aren't waiting for the DSP */ | 1611 | del_timer(&dev->fw_data->dsp_wait); /* only started in .open */ |
1588 | if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_LOADED_DSPWAIT) { | ||
1589 | /* if we are, wait for the wakeup for fw_success or timeout */ | ||
1590 | wait_event_timeout(dev->fw_data->wait_fw, | ||
1591 | (atomic_read(&dev->fw_data->fw_state) | ||
1592 | == S2255_FW_SUCCESS), | ||
1593 | msecs_to_jiffies(S2255_LOAD_TIMEOUT)); | ||
1594 | } | ||
1595 | 1612 | ||
1596 | if (dev->fw_data) { | 1613 | if (dev->fw_data->fw) |
1597 | if (dev->fw_data->fw) | 1614 | release_firmware(dev->fw_data->fw); |
1598 | release_firmware(dev->fw_data->fw); | 1615 | kfree(dev->fw_data->pfw_data); |
1599 | kfree(dev->fw_data->pfw_data); | 1616 | kfree(dev->fw_data); |
1600 | kfree(dev->fw_data); | ||
1601 | } | ||
1602 | 1617 | ||
1603 | usb_put_dev(dev->udev); | 1618 | usb_put_dev(dev->udev); |
1604 | dprintk(1, "%s", __func__); | 1619 | dprintk(1, "%s", __func__); |
@@ -1615,17 +1630,23 @@ static int s2255_close(struct inode *inode, struct file *file) | |||
1615 | 1630 | ||
1616 | mutex_lock(&dev->open_lock); | 1631 | mutex_lock(&dev->open_lock); |
1617 | 1632 | ||
1618 | if (dev->b_acquire[fh->channel]) | 1633 | /* turn off stream */ |
1619 | s2255_stop_acquire(dev, fh->channel); | 1634 | if (res_check(fh)) { |
1620 | res_free(dev, fh); | 1635 | if (dev->b_acquire[fh->channel]) |
1636 | s2255_stop_acquire(dev, fh->channel); | ||
1637 | videobuf_streamoff(&fh->vb_vidq); | ||
1638 | res_free(dev, fh); | ||
1639 | } | ||
1640 | |||
1621 | videobuf_mmap_free(&fh->vb_vidq); | 1641 | videobuf_mmap_free(&fh->vb_vidq); |
1622 | kfree(fh); | ||
1623 | dev->users[fh->channel]--; | 1642 | dev->users[fh->channel]--; |
1643 | |||
1624 | mutex_unlock(&dev->open_lock); | 1644 | mutex_unlock(&dev->open_lock); |
1625 | 1645 | ||
1626 | kref_put(&dev->kref, s2255_destroy); | 1646 | kref_put(&dev->kref, s2255_destroy); |
1627 | dprintk(1, "s2255: close called (minor=%d, users=%d)\n", | 1647 | dprintk(1, "s2255: close called (minor=%d, users=%d)\n", |
1628 | minor, dev->users[fh->channel]); | 1648 | minor, dev->users[fh->channel]); |
1649 | kfree(fh); | ||
1629 | return 0; | 1650 | return 0; |
1630 | } | 1651 | } |
1631 | 1652 | ||
@@ -1658,12 +1679,7 @@ static const struct file_operations s2255_fops_v4l = { | |||
1658 | .llseek = no_llseek, | 1679 | .llseek = no_llseek, |
1659 | }; | 1680 | }; |
1660 | 1681 | ||
1661 | static struct video_device template = { | 1682 | static const struct v4l2_ioctl_ops s2255_ioctl_ops = { |
1662 | .name = "s2255v", | ||
1663 | .type = VID_TYPE_CAPTURE, | ||
1664 | .fops = &s2255_fops_v4l, | ||
1665 | .minor = -1, | ||
1666 | .release = video_device_release, | ||
1667 | .vidioc_querycap = vidioc_querycap, | 1683 | .vidioc_querycap = vidioc_querycap, |
1668 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | 1684 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, |
1669 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, | 1685 | .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, |
@@ -1685,6 +1701,14 @@ static struct video_device template = { | |||
1685 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | 1701 | #ifdef CONFIG_VIDEO_V4L1_COMPAT |
1686 | .vidiocgmbuf = vidioc_cgmbuf, | 1702 | .vidiocgmbuf = vidioc_cgmbuf, |
1687 | #endif | 1703 | #endif |
1704 | }; | ||
1705 | |||
1706 | static struct video_device template = { | ||
1707 | .name = "s2255v", | ||
1708 | .fops = &s2255_fops_v4l, | ||
1709 | .ioctl_ops = &s2255_ioctl_ops, | ||
1710 | .minor = -1, | ||
1711 | .release = video_device_release, | ||
1688 | .tvnorms = S2255_NORMS, | 1712 | .tvnorms = S2255_NORMS, |
1689 | .current_norm = V4L2_STD_NTSC_M, | 1713 | .current_norm = V4L2_STD_NTSC_M, |
1690 | }; | 1714 | }; |
@@ -1706,7 +1730,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) | |||
1706 | /* register 4 video devices */ | 1730 | /* register 4 video devices */ |
1707 | dev->vdev[i] = video_device_alloc(); | 1731 | dev->vdev[i] = video_device_alloc(); |
1708 | memcpy(dev->vdev[i], &template, sizeof(struct video_device)); | 1732 | memcpy(dev->vdev[i], &template, sizeof(struct video_device)); |
1709 | dev->vdev[i]->dev = &dev->interface->dev; | 1733 | dev->vdev[i]->parent = &dev->interface->dev; |
1710 | if (video_nr == -1) | 1734 | if (video_nr == -1) |
1711 | ret = video_register_device(dev->vdev[i], | 1735 | ret = video_register_device(dev->vdev[i], |
1712 | VFL_TYPE_GRABBER, | 1736 | VFL_TYPE_GRABBER, |