summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorRaymond Chen <Raymond.Chen@Sun.COM>2008-10-14 23:28:00 -0700
committerRaymond Chen <Raymond.Chen@Sun.COM>2008-10-14 23:28:00 -0700
commit09dd0d6c99966261df3f1fee78347f66cae3235a (patch)
tree0320f74857512607e735a2eef8afc099689d4086 /usr/src
parentaf95cb89d151671bd61d7c43bc88c7cb13f9271b (diff)
downloadillumos-joyent-09dd0d6c99966261df3f1fee78347f66cae3235a.tar.gz
6748123 The ekiga application when displaying images from your camera hangs upon resume
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/io/usb/clients/video/usbvc/usbvc.c112
-rw-r--r--usr/src/uts/common/io/usb/clients/video/usbvc/usbvc_v4l2.c2
-rw-r--r--usr/src/uts/common/sys/usb/clients/video/usbvc/usbvc_var.h8
3 files changed, 121 insertions, 1 deletions
diff --git a/usr/src/uts/common/io/usb/clients/video/usbvc/usbvc.c b/usr/src/uts/common/io/usb/clients/video/usbvc/usbvc.c
index b5d9aa5bea..8bfdff0f23 100644
--- a/usr/src/uts/common/io/usb/clients/video/usbvc/usbvc.c
+++ b/usr/src/uts/common/io/usb/clients/video/usbvc/usbvc.c
@@ -278,7 +278,7 @@ static struct dev_ops usbvc_ops = {
&usbvc_cb_ops, /* driver operations */
NULL, /* bus operations */
usbvc_power, /* power */
- ddi_quiesce_not_needed, /* quiesce */
+ ddi_quiesce_not_needed, /* quiesce */
};
static struct modldrv usbvc_modldrv = {
@@ -707,6 +707,8 @@ usbvc_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
mutex_enter(&usbvcp->usbvc_mutex);
strm_if->start_polling = 0;
}
+ strm_if->stream_on = 0;
+
usbvc_close_isoc_pipe(usbvcp, strm_if);
if_num = strm_if->if_descr->if_alt->altif_descr.bInterfaceNumber;
mutex_exit(&usbvcp->usbvc_mutex);
@@ -1490,6 +1492,91 @@ usbvc_cpr_suspend(dev_info_t *dip)
/*
+ * If the polling has been stopped due to some exceptional errors,
+ * we reconfigure the device and start polling again. Only for S/R
+ * resume or hotplug reconnect operations.
+ */
+static int
+usbvc_resume_operation(usbvc_state_t *usbvcp)
+{
+ usbvc_stream_if_t *strm_if;
+ int rv = USB_SUCCESS;
+
+ USB_DPRINTF_L4(PRINT_MASK_IOCTL, usbvcp->usbvc_log_handle,
+ "usbvc_resume_operation: enter");
+
+ mutex_enter(&usbvcp->usbvc_mutex);
+ strm_if = usbvcp->usbvc_curr_strm;
+ if (!strm_if) {
+ mutex_exit(&usbvcp->usbvc_mutex);
+ rv = USB_FAILURE;
+
+ return (rv);
+ }
+
+ /*
+ * 1) if application has not started STREAMON ioctl yet,
+ * just return
+ * 2) if application use READ mode, return immediately
+ */
+ if (strm_if->stream_on == 0) {
+ mutex_exit(&usbvcp->usbvc_mutex);
+
+ return (rv);
+ }
+
+ /* isoc pipe is expected to be opened already if (stream_on==1) */
+ if (!strm_if->datain_ph) {
+ mutex_exit(&usbvcp->usbvc_mutex);
+ rv = USB_FAILURE;
+
+ return (rv);
+ }
+
+ mutex_exit(&usbvcp->usbvc_mutex);
+
+ /* first commit the parameters negotiated and saved during S_FMT */
+ if ((rv = usbvc_vs_set_probe_commit(usbvcp, strm_if,
+ &strm_if->ctrl_pc, VS_COMMIT_CONTROL)) != USB_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_IOCTL,
+ usbvcp->usbvc_log_handle,
+ "usbvc_resume_operation: set probe failed, rv=%d", rv);
+
+ return (rv);
+ }
+
+ mutex_enter(&usbvcp->usbvc_mutex);
+
+ /* Set alt interfaces, must be after probe_commit according to spec */
+ if ((rv = usbvc_set_alt(usbvcp, strm_if)) != USB_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_IOCTL,
+ usbvcp->usbvc_log_handle,
+ "usbvc_resume_operation: set alt failed");
+ mutex_exit(&usbvcp->usbvc_mutex);
+
+ return (rv);
+ }
+
+ /*
+ * The isoc polling could be stopped by isoc_exc_cb
+ * during suspend or hotplug. Restart it.
+ */
+ if (usbvc_start_isoc_polling(usbvcp, strm_if, V4L2_MEMORY_MMAP)
+ != USB_SUCCESS) {
+ rv = USB_FAILURE;
+ mutex_exit(&usbvcp->usbvc_mutex);
+
+ return (rv);
+ }
+
+ strm_if->start_polling = 1;
+
+ mutex_exit(&usbvcp->usbvc_mutex);
+
+ return (rv);
+}
+
+/*
* usbvc_cpr_resume:
*
* usbvc_restore_device_state marks success by putting device back online
@@ -1564,6 +1651,14 @@ usbvc_restore_device_state(dev_info_t *dip, usbvc_state_t *usbvcp)
"Please verify reconnection");
}
}
+
+ if (usbvc_resume_operation(usbvcp) != USB_SUCCESS) {
+ USB_DPRINTF_L2(PRINT_MASK_PM, usbvcp->usbvc_log_handle,
+ "usbvc_restore_device_state: can't resume operation");
+
+ goto fail;
+ }
+
mutex_enter(&usbvcp->usbvc_mutex);
usbvc_pm_idle_component(usbvcp);
@@ -2931,6 +3026,8 @@ usbvc_open_isoc_pipe(usbvc_state_t *usbvcp, usbvc_stream_if_t *strm_if)
mutex_enter(&usbvcp->usbvc_mutex);
strm_if->start_polling = 0;
+ strm_if->stream_on = 0;
+
USB_DPRINTF_L4(PRINT_MASK_OPEN, usbvcp->usbvc_log_handle,
"usbvc_open_isoc_pipe: success, datain_ph=%p",
(void *)strm_if->datain_ph);
@@ -3370,7 +3467,20 @@ usbvc_decode_stream_header(usbvc_state_t *usbvcp, usbvc_buf_grp_t *bufgrp,
/* if no buf room left, then return with a err status */
if (buf_left == 0) {
+ /* buffer full, got an EOF packet(head only, no payload) */
+ if ((head_flag & USBVC_STREAM_EOF) &&
+ (actual_len == head_len)) {
+ buf_filling->status = USBVC_BUF_DONE;
+ USB_DPRINTF_L3(PRINT_MASK_CB, usbvcp->usbvc_log_handle,
+ "usbvc_decode_stream_header: got a EOF packet");
+
+ return (USB_SUCCESS);
+ }
+
+ /* Otherwise, mark the buf error and return failure */
buf_filling->status = USBVC_BUF_ERR;
+ USB_DPRINTF_L3(PRINT_MASK_CB, usbvcp->usbvc_log_handle,
+ "usbvc_decode_stream_header: frame buf full");
return (USB_FAILURE);
}
diff --git a/usr/src/uts/common/io/usb/clients/video/usbvc/usbvc_v4l2.c b/usr/src/uts/common/io/usb/clients/video/usbvc/usbvc_v4l2.c
index 9ec8b72dba..db327ba49e 100644
--- a/usr/src/uts/common/io/usb/clients/video/usbvc/usbvc_v4l2.c
+++ b/usr/src/uts/common/io/usb/clients/video/usbvc/usbvc_v4l2.c
@@ -487,6 +487,7 @@ usbvc_v4l2_ioctl(usbvc_state_t *usbvcp, int cmd, intptr_t arg, int mode)
break;
}
strm_if->start_polling = 1;
+ strm_if->stream_on = 1; /* the only place to set this value */
mutex_exit(&usbvcp->usbvc_mutex);
@@ -529,6 +530,7 @@ usbvc_v4l2_ioctl(usbvc_state_t *usbvcp, int cmd, intptr_t arg, int mode)
mutex_enter(&usbvcp->usbvc_mutex);
strm_if->start_polling = 0;
}
+ strm_if->stream_on = 0;
mutex_exit(&usbvcp->usbvc_mutex);
break;
diff --git a/usr/src/uts/common/sys/usb/clients/video/usbvc/usbvc_var.h b/usr/src/uts/common/sys/usb/clients/video/usbvc/usbvc_var.h
index f74e54b214..ed07742ad9 100644
--- a/usr/src/uts/common/sys/usb/clients/video/usbvc/usbvc_var.h
+++ b/usr/src/uts/common/sys/usb/clients/video/usbvc/usbvc_var.h
@@ -122,6 +122,14 @@ typedef struct usbvc_stream_if {
uint32_t max_isoc_payload;
uchar_t start_polling; /* indicate if isoc polling started */
+
+ /*
+ * To flag if VIDIOC_STREAMON is executed, only used by STREAM mode
+ * for suspend/resume. If it's non-zero, we'll have to resume the
+ * device's isoc polling operation after resume.
+ */
+ uint8_t stream_on;
+
uchar_t fid; /* the MJPEG FID bit */
usbvc_buf_grp_t buf_read; /* buf used for read I/O */
uint8_t buf_read_num; /* desired buf num for read I/O */