return -ENOENT;
}
/*****************************************************************************/
-static int easycap_ioctl_bkl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if ((defined(EASYCAP_IS_VIDEODEV_CLIENT)) || \
+ (defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)))
+long
+easycap_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) {
+ return (long)easycap_ioctl((struct inode *)NULL, file, cmd, arg);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT||EASYCAP_NEEDS_UNLOCKED_IOCTL*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*---------------------------------------------------------------------------*/
+int
+easycap_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct easycap *peasycap;
struct usb_device *p;
+int kd;
if (NULL == file) {
SAY("ERROR: file is NULL\n");
SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
+kd = isdongle(peasycap);
+if (0 <= kd && DONGLE_MANY > kd) {
+ if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
+ SAY("ERROR: cannot lock easycap_dongle[%i].mutex_video\n", kd);
+ return -ERESTARTSYS;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
+/*---------------------------------------------------------------------------*/
+/*
+ * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
+ * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
+ * IF NECESSARY, BAIL OUT.
+*/
+/*---------------------------------------------------------------------------*/
+ if (kd != isdongle(peasycap))
+ return -ERESTARTSYS;
+ if (NULL == file) {
+ SAY("ERROR: file is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+ peasycap = file->private_data;
+ if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+ p = peasycap->pusb_device;
+ if (NULL == peasycap->pusb_device) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+} else {
+/*---------------------------------------------------------------------------*/
+/*
+ * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
+ * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
+*/
+/*---------------------------------------------------------------------------*/
+ return -ERESTARTSYS;
+}
/*---------------------------------------------------------------------------*/
switch (cmd) {
case VIDIOC_QUERYCAP: {
JOM(8, "VIDIOC_QUERYCAP\n");
if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
- SAM("ERROR: bad driver version string\n"); return -EINVAL;
+ SAM("ERROR: bad driver version string\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -EINVAL;
}
strcpy(&version[0], EASYCAP_DRIVER_VERSION);
for (i = 0; i < 3; i++)
if (0 != rc) {
SAM("ERROR: %i=strict_strtol(%s,.,,)\n", \
rc, p1);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
k[i] = (int)lng;
&v4l2_capability.bus_info[0]);
}
if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \
- sizeof(struct v4l2_capability)))
+ sizeof(struct v4l2_capability))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
JOM(8, "VIDIOC_ENUMINPUT\n");
if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \
- sizeof(struct v4l2_input)))
+ sizeof(struct v4l2_input))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
index = v4l2_input.index;
memset(&v4l2_input, 0, sizeof(struct v4l2_input));
}
default: {
JOM(8, "%i=index: exhausts inputs\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_input, \
- sizeof(struct v4l2_input)))
+ sizeof(struct v4l2_input))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
JOM(8, "VIDIOC_G_INPUT\n");
index = (__u32)peasycap->input;
JOM(8, "user is told: %i\n", index);
- if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32)))
+ if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
JOM(8, "VIDIOC_S_INPUT\n");
- if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32)))
+ if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
JOM(8, "user requests input %i\n", index);
if ((0 > index) || (INPUT_MANY <= index)) {
JOM(8, "ERROR: bad requested input: %i\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
JOM(8, "newinput(.,%i) OK\n", (int)index);
} else {
SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
break;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_ENUMAUDIO: {
JOM(8, "VIDIOC_ENUMAUDIO\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
JOM(8, "VIDIOC_ENUMAUDOUT\n");
if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \
- sizeof(struct v4l2_audioout)))
+ sizeof(struct v4l2_audioout))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
- if (0 != v4l2_audioout.index)
+ if (0 != v4l2_audioout.index) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
v4l2_audioout.index = 0;
strcpy(&v4l2_audioout.name[0], "Soundtrack");
if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \
- sizeof(struct v4l2_audioout)))
+ sizeof(struct v4l2_audioout))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
JOM(8, "VIDIOC_QUERYCTRL\n");
if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \
- sizeof(struct v4l2_queryctrl)))
+ sizeof(struct v4l2_queryctrl))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
i1 = 0;
while (0xFFFFFFFF != easycap_control[i1].id) {
}
if (0xFFFFFFFF == easycap_control[i1].id) {
JOM(8, "%i=index: exhausts controls\n", i1);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \
- sizeof(struct v4l2_queryctrl)))
+ sizeof(struct v4l2_queryctrl))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYMENU: {
JOM(8, "VIDIOC_QUERYMENU unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
- break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_CTRL: {
pv4l2_control = kzalloc(sizeof(struct v4l2_control), GFP_KERNEL);
if (!pv4l2_control) {
SAM("ERROR: out of memory\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -ENOMEM;
}
if (0 != copy_from_user(pv4l2_control, (void __user *)arg, \
sizeof(struct v4l2_control))) {
kfree(pv4l2_control);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \
pv4l2_control->id);
kfree(pv4l2_control);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, pv4l2_control, \
sizeof(struct v4l2_control))) {
kfree(pv4l2_control);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
kfree(pv4l2_control);
JOM(8, "VIDIOC_S_CTRL\n");
if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
- sizeof(struct v4l2_control)))
+ sizeof(struct v4l2_control))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
switch (v4l2_control.id) {
case V4L2_CID_BRIGHTNESS: {
default: {
SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \
v4l2_control.id);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
- }
+ }
}
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_EXT_CTRLS: {
JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
JOM(8, "VIDIOC_ENUM_FMT\n");
if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \
- sizeof(struct v4l2_fmtdesc)))
+ sizeof(struct v4l2_fmtdesc))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
index = v4l2_fmtdesc.index;
memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc));
}
default: {
JOM(8, "%i=index: exhausts formats\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \
- sizeof(struct v4l2_fmtdesc)))
+ sizeof(struct v4l2_fmtdesc))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
JOM(8, "VIDIOC_ENUM_FRAMESIZES\n");
if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, \
- sizeof(struct v4l2_frmsizeenum)))
+ sizeof(struct v4l2_frmsizeenum))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
index = v4l2_frmsizeenum.index;
}
default: {
JOM(8, "%i=index: exhausts framesizes\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
}
}
default: {
JOM(8, "%i=index: exhausts framesizes\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_frmsizeenum, \
- sizeof(struct v4l2_frmsizeenum)))
+ sizeof(struct v4l2_frmsizeenum))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, \
sizeof(struct v4l2_frmivalenum))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
}
default: {
JOM(8, "%i=index: exhausts frameintervals\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
}
if (0 != copy_to_user((void __user *)arg, &v4l2_frmivalenum, \
- sizeof(struct v4l2_frmivalenum)))
+ sizeof(struct v4l2_frmivalenum))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL);
if (!pv4l2_format) {
SAM("ERROR: out of memory\n");
- return -ENOMEM;
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ENOMEM;
}
pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL);
if (!pv4l2_pix_format) {
SAM("ERROR: out of memory\n");
kfree(pv4l2_format);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -ENOMEM;
}
if (0 != copy_from_user(pv4l2_format, (void __user *)arg, \
sizeof(struct v4l2_format))) {
kfree(pv4l2_format);
kfree(pv4l2_pix_format);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
kfree(pv4l2_format);
kfree(pv4l2_pix_format);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
sizeof(struct v4l2_format))) {
kfree(pv4l2_format);
kfree(pv4l2_pix_format);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
kfree(pv4l2_format);
}
if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
- sizeof(struct v4l2_format)))
+ sizeof(struct v4l2_format))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
best_format = adjust_format(peasycap, \
v4l2_format.fmt.pix.width, \
v4l2_format.fmt.pix.field, \
try);
if (0 > best_format) {
- if (-EBUSY == best_format)
+ if (-EBUSY == best_format) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EBUSY;
+ }
JOM(8, "WARNING: adjust_format() returned %i\n", best_format);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -ENOENT;
}
/*...........................................................................*/
JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
- sizeof(struct v4l2_format)))
+ sizeof(struct v4l2_format))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
JOM(8, "VIDIOC_CROPCAP\n");
if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \
- sizeof(struct v4l2_cropcap)))
+ sizeof(struct v4l2_cropcap))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \
- sizeof(struct v4l2_cropcap)))
+ sizeof(struct v4l2_cropcap))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_CROP:
case VIDIOC_S_CROP: {
JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_QUERYSTD: {
JOM(8, "VIDIOC_QUERYSTD: " \
"EasyCAP is incapable of detecting standard\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
break;
}
JOM(8, "VIDIOC_ENUMSTD\n");
if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \
- sizeof(struct v4l2_standard)))
+ sizeof(struct v4l2_standard))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
index = v4l2_standard.index;
last3 = last2; last2 = last1; last1 = last0; last0 = index;
}
if (0xFFFF == peasycap_standard->mask) {
JOM(8, "%i=index: exhausts standards\n", index);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
JOM(8, "%i=index: %s\n", index, \
v4l2_standard.index = index;
if (0 != copy_to_user((void __user *)arg, &v4l2_standard, \
- sizeof(struct v4l2_standard)))
+ sizeof(struct v4l2_standard))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (0 > peasycap->standard_offset) {
JOM(8, "%i=peasycap->standard_offset\n", \
peasycap->standard_offset);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EBUSY;
}
if (0 != copy_from_user(&std_id, (void __user *)arg, \
- sizeof(v4l2_std_id)))
+ sizeof(v4l2_std_id))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
peasycap_standard = &easycap_standard[peasycap->standard_offset];
std_id = peasycap_standard->v4l2_standard.id;
&peasycap_standard->v4l2_standard.name[0]);
if (0 != copy_to_user((void __user *)arg, &std_id, \
- sizeof(v4l2_std_id)))
+ sizeof(v4l2_std_id))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
JOM(8, "VIDIOC_S_STD\n");
if (0 != copy_from_user(&std_id, (void __user *)arg, \
- sizeof(v4l2_std_id)))
+ sizeof(v4l2_std_id))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
JOM(8, "User requests standard: 0x%08X%08X\n", \
(int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32), \
rc = adjust_standard(peasycap, std_id);
if (0 > rc) {
JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -ENOENT;
}
break;
JOM(8, "VIDIOC_REQBUFS\n");
if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \
- sizeof(struct v4l2_requestbuffers)))
+ sizeof(struct v4l2_requestbuffers))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
- if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
- if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP)
+ }
+ if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
nbuffers = v4l2_requestbuffers.count;
JOM(8, " User requests %i buffers ...\n", nbuffers);
if (nbuffers < 2)
peasycap->frame_buffer_many = nbuffers;
if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \
- sizeof(struct v4l2_requestbuffers)))
+ sizeof(struct v4l2_requestbuffers))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (peasycap->video_eof) {
JOM(8, "returning -EIO because %i=video_eof\n", \
peasycap->video_eof);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EIO;
}
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
- sizeof(struct v4l2_buffer)))
+ sizeof(struct v4l2_buffer))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
- if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
index = v4l2_buffer.index;
if (index < 0 || index >= peasycap->frame_buffer_many)
return -EINVAL;
JOM(16, " %10i=length\n", v4l2_buffer.length);
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
- sizeof(struct v4l2_buffer)))
+ sizeof(struct v4l2_buffer))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
break;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
JOM(8, "VIDIOC_QBUF\n");
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
- sizeof(struct v4l2_buffer)))
+ sizeof(struct v4l2_buffer))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
- if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
- if (v4l2_buffer.memory != V4L2_MEMORY_MMAP)
+ }
+ if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
if (v4l2_buffer.index < 0 || \
- (v4l2_buffer.index >= peasycap->frame_buffer_many))
+ (v4l2_buffer.index >= peasycap->frame_buffer_many)) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
peasycap->done[v4l2_buffer.index] = 0;
peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED;
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
- sizeof(struct v4l2_buffer)))
+ sizeof(struct v4l2_buffer))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
JOM(8, "..... user queueing frame buffer %i\n", \
(int)v4l2_buffer.index);
JOM(8, "returning -EIO because " \
"%i=video_idle %i=video_eof\n", \
peasycap->video_idle, peasycap->video_eof);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EIO;
}
if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
- sizeof(struct v4l2_buffer)))
+ sizeof(struct v4l2_buffer))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
- if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
+ }
if (true == peasycap->offerfields) {
/*-----------------------------------------------------------*/
if (!peasycap->video_isoc_streaming) {
JOM(16, "returning -EIO because video urbs not streaming\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EIO;
}
/*---------------------------------------------------------------------------*/
if (-EIO == rcdq) {
JOM(8, "returning -EIO because " \
"dqbuf() returned -EIO\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EIO;
}
} while (0 != rcdq);
} else {
- if (peasycap->video_eof)
+ if (peasycap->video_eof) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EIO;
+ }
}
if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
SAM("ERROR: V4L2_BUF_FLAG_DONE != 0x%08X\n", \
JOM(16, " %10i=length\n", v4l2_buffer.length);
if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
- sizeof(struct v4l2_buffer)))
+ sizeof(struct v4l2_buffer))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
+ }
input = peasycap->frame_buffer[peasycap->frame_read][0].input;
if (0x08 & input) {
peasycap->merit[i] = 0;
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
submit_video_urbs(peasycap);
if ((struct usb_device *)NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
pv4l2_streamparm = kzalloc(sizeof(struct v4l2_streamparm), GFP_KERNEL);
if (!pv4l2_streamparm) {
SAM("ERROR: out of memory\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -ENOMEM;
}
if (0 != copy_from_user(pv4l2_streamparm, (void __user *)arg, \
sizeof(struct v4l2_streamparm))) {
kfree(pv4l2_streamparm);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
kfree(pv4l2_streamparm);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
pv4l2_streamparm->parm.capture.capability = 0;
if (0 != copy_to_user((void __user *)arg, pv4l2_streamparm, \
sizeof(struct v4l2_streamparm))) {
kfree(pv4l2_streamparm);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EFAULT;
}
kfree(pv4l2_streamparm);
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_PARM: {
JOM(8, "VIDIOC_S_PARM unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_AUDIO: {
JOM(8, "VIDIOC_G_AUDIO unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_AUDIO: {
JOM(8, "VIDIOC_S_AUDIO unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_TUNER: {
JOM(8, "VIDIOC_S_TUNER unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_S_FBUF:
case VIDIOC_OVERLAY: {
JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
case VIDIOC_G_TUNER: {
JOM(8, "VIDIOC_G_TUNER unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY: {
JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -EINVAL;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
default: {
JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
return -ENOIOCTLCMD;
}
}
+mutex_unlock(&easycap_dongle[kd].mutex_video);
+JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
return 0;
}
-
-long easycap_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct inode *inode = file->f_dentry->d_inode;
- long ret;
-
- lock_kernel();
- ret = easycap_ioctl_bkl(inode, file, cmd, arg);
- unlock_kernel();
-
- return ret;
-}
/*****************************************************************************/
-static int easysnd_ioctl_bkl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
+#if ((defined(EASYCAP_IS_VIDEODEV_CLIENT)) || \
+ (defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)))
+long
+easysnd_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) {
+ return (long)easysnd_ioctl((struct inode *)NULL, file, cmd, arg);
+}
+#endif /*EASYCAP_IS_VIDEODEV_CLIENT||EASYCAP_NEEDS_UNLOCKED_IOCTL*/
+/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
+/*---------------------------------------------------------------------------*/
+int
+easysnd_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
struct easycap *peasycap;
struct usb_device *p;
+int kd;
if (NULL == file) {
SAY("ERROR: file is NULL\n");
SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
}
+kd = isdongle(peasycap);
+if (0 <= kd && DONGLE_MANY > kd) {
+ if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_audio)) {
+ SAY("ERROR: cannot lock easycap_dongle[%i].mutex_audio\n", kd);
+ return -ERESTARTSYS;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
+/*---------------------------------------------------------------------------*/
+/*
+ * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
+ * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
+ * IF NECESSARY, BAIL OUT.
+*/
+/*---------------------------------------------------------------------------*/
+ if (kd != isdongle(peasycap))
+ return -ERESTARTSYS;
+ if (NULL == file) {
+ SAY("ERROR: file is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ERESTARTSYS;
+ }
+ peasycap = file->private_data;
+ if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ERESTARTSYS;
+ }
+ p = peasycap->pusb_device;
+ if (NULL == peasycap->pusb_device) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ return -ERESTARTSYS;
+ }
+} else {
+/*---------------------------------------------------------------------------*/
+/*
+ * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
+ * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
+*/
+/*---------------------------------------------------------------------------*/
+ return -ERESTARTSYS;
+}
/*---------------------------------------------------------------------------*/
switch (cmd) {
case SNDCTL_DSP_GETCAPS: {
caps = 0x04400000;
#endif /*UPSAMPLE*/
- if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_GETFMTS: {
incoming = AFMT_S16_LE;
#endif /*UPSAMPLE*/
- if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_SETFMT: {
int incoming, outgoing;
JOM(8, "SNDCTL_DSP_SETFMT\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
JOM(8, "........... %i=incoming\n", incoming);
#if defined(UPSAMPLE)
JOM(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE);
JOM(8, " cf. %i=AFMT_U8\n", AFMT_U8);
if (0 != copy_to_user((void __user *)arg, &outgoing, \
- sizeof(int)))
+ sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EINVAL ;
}
break;
case SNDCTL_DSP_STEREO: {
int incoming;
JOM(8, "SNDCTL_DSP_STEREO\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
JOM(8, "........... %i=incoming\n", incoming);
#if defined(UPSAMPLE)
incoming = 1;
#endif /*UPSAMPLE*/
- if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_SPEED: {
int incoming;
JOM(8, "SNDCTL_DSP_SPEED\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
JOM(8, "........... %i=incoming\n", incoming);
#if defined(UPSAMPLE)
incoming = 48000;
#endif /*UPSAMPLE*/
- if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_GETTRIGGER: {
int incoming;
JOM(8, "SNDCTL_DSP_GETTRIGGER\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
JOM(8, "........... %i=incoming\n", incoming);
incoming = PCM_ENABLE_INPUT;
- if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_SETTRIGGER: {
int incoming;
JOM(8, "SNDCTL_DSP_SETTRIGGER\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
JOM(8, "........... %i=incoming\n", incoming);
JOM(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \
"0x%x=PCM_ENABLE_OUTPUT\n", \
case SNDCTL_DSP_GETBLKSIZE: {
int incoming;
JOM(8, "SNDCTL_DSP_GETBLKSIZE\n");
- if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int)))
+ if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
JOM(8, "........... %i=incoming\n", incoming);
incoming = peasycap->audio_bytes_per_fragment;
- if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int)))
+ if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case SNDCTL_DSP_GETISPACE: {
audio_buf_info.fragstotal = 0;
if (0 != copy_to_user((void __user *)arg, &audio_buf_info, \
- sizeof(int)))
+ sizeof(int))) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -EFAULT;
+ }
break;
}
case 0x00005401:
case 0x00005405:
case 0x00005406: {
JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd);
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -ENOIOCTLCMD;
}
default: {
JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
return -ENOIOCTLCMD;
}
}
+mutex_unlock(&easycap_dongle[kd].mutex_audio);
return 0;
}
-
-long easysnd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct inode *inode = file->f_dentry->d_inode;
- long ret;
-
- lock_kernel();
- ret = easysnd_ioctl_bkl(inode, file, cmd, arg);
- unlock_kernel();
-
- return ret;
-}
/*****************************************************************************/
* IS CALLED SUCCESSIVELY FOR INTERFACES 0, 1, 2 AND THE POINTER peasycap
* ALLOCATED DURING THE PROBING OF INTERFACE 0 MUST BE REMEMBERED WHEN
* PROBING INTERFACES 1 AND 2.
+ *
+ * IOCTL LOCKING IS DONE AT MODULE LEVEL, NOT DEVICE LEVEL.
*/
/*---------------------------------------------------------------------------*/
-struct easycap *peasycap_dongle[DONGLE_MANY];
+struct easycap_dongle easycap_dongle[DONGLE_MANY];
static int dongle_this;
+static int dongle_done;
/*---------------------------------------------------------------------------*/
/*
.owner = THIS_MODULE,
.open = easycap_open,
.release = easycap_release,
- .unlocked_ioctl = easycap_ioctl,
+#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
+ .unlocked_ioctl = easycap_ioctl_noinode,
+#else
+ .ioctl = easycap_ioctl,
+#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
.poll = easycap_poll,
.mmap = easycap_mmap,
.llseek = no_llseek,
.owner = THIS_MODULE,
.open = easycap_open_noinode,
.release = easycap_release_noinode,
- .unlocked_ioctl = easycap_ioctl,
+#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
+ .unlocked_ioctl = easycap_ioctl_noinode,
+#else
+ .ioctl = easycap_ioctl,
+#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
.poll = easycap_poll,
.mmap = easycap_mmap,
};
.owner = THIS_MODULE,
.open = easysnd_open,
.release = easysnd_release,
- .unlocked_ioctl = easysnd_ioctl,
+#if defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)
+ .unlocked_ioctl = easysnd_ioctl_noinode,
+#else
+ .ioctl = easysnd_ioctl,
+#endif /*EASYCAP_NEEDS_UNLOCKED_IOCTL*/
.read = easysnd_read,
.llseek = no_llseek,
};
isdongle(struct easycap *peasycap)
{
int k;
-if ((struct easycap *)NULL == peasycap)
+if (NULL == peasycap)
return -2;
for (k = 0; k < DONGLE_MANY; k++) {
- if (peasycap_dongle[k] == peasycap) {
+ if (easycap_dongle[k].peasycap == peasycap) {
peasycap->isdongle = k;
return k;
}
peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-if ((struct easycap *)NULL == peasycap) {
+if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
-file->private_data = peasycap;
if (NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
return -EFAULT;
JOM(16, "0x%08lX=peasycap->pusb_device\n", \
(long int)peasycap->pusb_device);
}
+file->private_data = peasycap;
rc = wakeup_device(peasycap->pusb_device);
if (0 == rc)
JOM(8, "wakeup_device() OK\n");
int i, rc, input, rate;
bool ntsc, other;
-if ((struct easycap *)NULL == peasycap) {
+if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
/*---------------------------------------------------------------------------*/
/*
- * IF THE SAA7113H HAS ALREADY ACQUIRED LOCK, USE ITS HARDWARE-DETECTED
+ * IF THE SAA7113H HAS ALREADY ACQUIRED SYNC, USE ITS HARDWARE-DETECTED
* FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL. THIS IS ESSENTIAL FOR
* gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE
* A SWITCH BETWEEN PAL AND NTSC.
}
JOM(8, "%i=input sought\n", input);
-if ((0 > input) &&(INPUT_MANY <= input))
+if (0 > input && INPUT_MANY <= input)
return -ENOENT;
inputnow = peasycap->input;
if (input == inputnow)
return -ENOENT;
}
/*---------------------------------------------------------------------------*/
-if ((struct usb_device *)NULL == peasycap->pusb_device) {
+if (NULL == peasycap->pusb_device) {
SAM("ERROR: peasycap->pusb_device is NULL\n");
return -ENODEV;
}
int j, isbad, nospc, m, rc;
int isbuf;
-if ((struct easycap *)NULL == peasycap) {
+if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
-if ((struct list_head *)NULL == peasycap->purb_video_head) {
+if (NULL == peasycap->purb_video_head) {
SAY("ERROR: peasycap->urb_video_head uninitialized\n");
return -EFAULT;
}
-if ((struct usb_device *)NULL == peasycap->pusb_device) {
+if (NULL == peasycap->pusb_device) {
SAY("ERROR: peasycap->pusb_device is NULL\n");
return -ENODEV;
}
struct list_head *plist_head;
struct data_urb *pdata_urb;
-if ((struct easycap *)NULL == peasycap) {
+if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
list_for_each(plist_head, (peasycap->purb_video_head)) {
pdata_urb = list_entry(plist_head, struct data_urb, \
list_head);
- if ((struct data_urb *)NULL != pdata_urb) {
- if ((struct urb *)NULL != pdata_urb->purb) {
+ if (NULL != pdata_urb) {
+ if (NULL != pdata_urb->purb) {
usb_kill_urb(pdata_urb->purb);
m++;
}
/*****************************************************************************/
/*--------------------------------------------------------------------------*/
/*
- * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect().
- * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED.
- * peasycap->pusb_device IS NO LONGER VALID AND SHOULD HAVE BEEN SET TO NULL.
+ * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect() AND IS
+ * PROTECTED BY SEMAPHORES SET AND CLEARED BY easycap_usb_disconnect().
+ *
+ * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED, SO
+ * peasycap->pusb_device IS NO LONGER VALID.
*/
/*---------------------------------------------------------------------------*/
void
easycap_delete(struct kref *pkref)
{
-int k, m, gone;
+int k, m, gone, kd;
int allocation_video_urb, allocation_video_page, allocation_video_struct;
int allocation_audio_urb, allocation_audio_page, allocation_audio_struct;
int registered_video, registered_audio;
JOT(4, "\n");
peasycap = container_of(pkref, struct easycap, kref);
-if ((struct easycap *)NULL == peasycap) {
+if (NULL == peasycap) {
SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
return;
}
+kd = isdongle(peasycap);
/*---------------------------------------------------------------------------*/
/*
* FREE VIDEO.
JOM(4, "%i video data_urb structures freed\n", m);
JOM(4, "setting peasycap->purb_video_head=NULL\n");
peasycap->purb_video_head = (struct list_head *)NULL;
- } else {
-JOM(4, "peasycap->purb_video_head is NULL\n");
}
/*---------------------------------------------------------------------------*/
JOM(4, "freeing video isoc buffers.\n");
allocation_audio_page = peasycap->allocation_audio_page;
allocation_audio_struct = peasycap->allocation_audio_struct;
registered_audio = peasycap->registered_audio;
-m = 0;
-if ((struct easycap *)NULL != peasycap) {
- kfree(peasycap); peasycap = (struct easycap *)NULL;
+
+kfree(peasycap);
+if (0 <= kd && DONGLE_MANY > kd) {
+ easycap_dongle[kd].peasycap = (struct easycap *)NULL;
+ JOT(4, " null-->easycap_dongle[%i].peasycap\n", kd);
allocation_video_struct -= sizeof(struct easycap);
- m++;
+} else {
+ SAY("ERROR: cannot purge easycap_dongle[].peasycap");
}
-JOT(4, "%i easycap structure freed\n", m);
/*---------------------------------------------------------------------------*/
-
SAY("%8i= video urbs after all deletions\n", allocation_video_urb);
SAY("%8i= video pages after all deletions\n", allocation_video_page);
SAY("%8i= video structs after all deletions\n", allocation_video_struct);
unsigned int easycap_poll(struct file *file, poll_table *wait)
{
struct easycap *peasycap;
+int rc, kd;
JOT(8, "\n");
if (NULL == ((poll_table *)wait))
JOT(8, "WARNING: poll table pointer is NULL ... continuing\n");
-if (NULL == ((struct file *)file)) {
+if ((struct file *)NULL == file) {
SAY("ERROR: file pointer is NULL\n");
- return -EFAULT;
+ return -ERESTARTSYS;
}
peasycap = file->private_data;
if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
+if (NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
+/*---------------------------------------------------------------------------*/
+kd = isdongle(peasycap);
+if (0 <= kd && DONGLE_MANY > kd) {
+ if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
+ SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd);
+ return -ERESTARTSYS;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
+ /*-------------------------------------------------------------------*/
+ /*
+ * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER
+ * peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
+ * IF NECESSARY, BAIL OUT.
+ */
+ /*-------------------------------------------------------------------*/
+ if (kd != isdongle(peasycap))
+ return -ERESTARTSYS;
+ if (NULL == file) {
+ SAY("ERROR: file is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+ peasycap = file->private_data;
+ if (NULL == peasycap) {
+ SAY("ERROR: peasycap is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+ if (NULL == peasycap->pusb_device) {
+ SAM("ERROR: peasycap->pusb_device is NULL\n");
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ return -ERESTARTSYS;
+ }
+} else
+ /*-------------------------------------------------------------------*/
+ /*
+ * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap
+ * BEFORE THE ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL
+ * HAVE FAILED. BAIL OUT.
+ */
+ /*-------------------------------------------------------------------*/
+ return -ERESTARTSYS;
+/*---------------------------------------------------------------------------*/
+rc = easycap_dqbuf(peasycap, 0);
peasycap->polled = 1;
-
-if (0 == easycap_dqbuf(peasycap, 0))
+mutex_unlock(&easycap_dongle[kd].mutex_video);
+if (0 == rc)
return POLLIN | POLLRDNORM;
else
return POLLERR;
-
}
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
+if (NULL == peasycap->pusb_device) {
+ SAY("ERROR: peasycap->pusb_device is NULL\n");
+ return -EFAULT;
+}
ifield = 0;
JOM(8, "%i=ifield\n", ifield);
/*---------------------------------------------------------------------------*/
* CHECK FOR LOST INPUT SIGNAL.
*
* FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED.
- * IF INPUT 0 IS PRESENT AND LOCKED, UNPLUGGING INPUT 4 DOES NOT RESULT IN
- * SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE IS FLYWHEELING
- * ON INPUT 0. THE UPSHOT IS:
+ * IF INPUT 0 IS PRESENT AND SYNC ACQUIRED, UNPLUGGING INPUT 4 DOES NOT
+ * RESULT IN SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE
+ * IS FLYWHEELING ON INPUT 0. THE UPSHOT IS:
*
* INPUT 0 PLUGGED, INPUT 4 PLUGGED => SCREEN 0 OK, SCREEN 4 OK
* INPUT 0 PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK, SCREEN 4 BLACK
__u8 mask, margin;
bool odd, isuy, decimatepixel, offerfields, badinput;
-if ((struct easycap *)NULL == peasycap) {
+if (NULL == peasycap) {
SAY("ERROR: peasycap is NULL\n");
return -EFAULT;
}
much) / 2;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (1 < bytesperpixel) {
- if ((rad * \
- 2) < (much * \
- bytesperpixel)) {
+ if (rad * 2 < much * bytesperpixel) {
/*
** INJUDICIOUS ALTERATION OF THIS
- ** BLOCK WILL CAUSE BREAKAGE.
- ** BEWARE.
+ ** STATEMENT BLOCK WILL CAUSE
+ ** BREAKAGE. BEWARE.
**/
rad2 = rad + bytesperpixel - 1;
much = ((((2 * \
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (rump)
caches++;
-
if (true == badinput) {
JOM(8, "ERROR: 0x%02X=->field_buffer" \
"[%i][%i].input, " \
[kex][mex].input, kex, mex, \
(0x08|peasycap->input));
}
-
rc = redaub(peasycap, pad, pex, much, more, \
mask, margin, isuy);
if (0 > rc) {
much) / 4;
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
if (1 < bytesperpixel) {
- if ((rad * 4) < (much * \
- bytesperpixel)) {
+ if (rad * 4 < much * bytesperpixel) {
/*
** INJUDICIOUS ALTERATION OF THIS
- ** BLOCK WILL CAUSE BREAKAGE.
- ** BEWARE.
+ ** STATEMENT BLOCK WILL CAUSE
+ ** BREAKAGE. BEWARE.
**/
rad2 = rad + bytesperpixel - 1;
much = ((((2 * rad2)/bytesperpixel)/2)\
[kex][mex].input, kex, mex, \
(0x08|peasycap->input));
}
-
rc = redaub(peasycap, pad, pex, much, more, \
mask, margin, isuy);
if (0 > rc) {
* FIXME
*
*
- * THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE DEVICE IS
- * PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.
+ * THIS FUNCTION ASSUMES THAT, ON EACH AND EVERY OCCASION THAT THE EasyCAP
+ * IS PHYSICALLY PLUGGED IN, INTERFACE 0 IS PROBED FIRST.
* IF THIS IS NOT TRUE, THERE IS THE POSSIBILITY OF AN Oops.
*
* THIS HAS NEVER BEEN A PROBLEM IN PRACTICE, BUT SOMETHING SEEMS WRONG HERE.
struct easycap_format *peasycap_format;
JOT(4, "\n");
+
+if (!dongle_done) {
+ dongle_done = 1;
+ for (k = 0; k < DONGLE_MANY; k++) {
+ easycap_dongle[k].peasycap = (struct easycap *)NULL;
+ mutex_init(&easycap_dongle[k].mutex_video);
+ mutex_init(&easycap_dongle[k].mutex_audio);
+ }
+}
+
peasycap = (struct easycap *)NULL;
if ((struct usb_interface *)NULL == pusb_interface) {
init_waitqueue_head(&peasycap->wq_audio);
for (dongle_this = 0; dongle_this < DONGLE_MANY; dongle_this++) {
- if ((struct easycap *)NULL == peasycap_dongle[dongle_this]) {
- peasycap_dongle[dongle_this] = peasycap;
- JOM(8, "intf[%i]: peasycap-->easycap" \
+ if (NULL == easycap_dongle[dongle_this].peasycap) {
+ if (0 == mutex_is_locked(&easycap_dongle\
+ [dongle_this].mutex_video)) {
+ if (0 == mutex_is_locked(&easycap_dongle\
+ [dongle_this].mutex_audio)) {
+ easycap_dongle\
+ [dongle_this].peasycap = \
+ peasycap;
+ JOM(8, "intf[%i]: peasycap-->easycap" \
"_dongle[%i].peasycap\n", \
bInterfaceNumber, dongle_this);
- break;
+ break;
+ }
+ }
}
}
if (DONGLE_MANY <= dongle_this) {
* FOR INTERFACES 1 AND 2 THE POINTER peasycap IS OBTAINED BY ASSUMING
* THAT dongle_this HAS NOT CHANGED SINCE INTERFACE 0 WAS PROBED. IF
* THIS IS NOT THE CASE, FOR EXAMPLE WHEN TWO EASYCAPs ARE PLUGGED IN
- * SIMULTANEOUSLY, THERE WILL BE VERY SERIOUS TROUBLE.
+ * SIMULTANEOUSLY, THERE WILL BE SERIOUS TROUBLE.
*/
/*---------------------------------------------------------------------------*/
if ((0 > dongle_this) || (DONGLE_MANY <= dongle_this)) {
SAY("ERROR: bad dongle count\n");
return -EFAULT;
}
- peasycap = peasycap_dongle[dongle_this];
- JOT(8, "intf[%i]: peasycap_dongle[%i]-->peasycap\n", \
+ peasycap = easycap_dongle[dongle_this].peasycap;
+ JOT(8, "intf[%i]: easycap_dongle[%i].peasycap-->peasycap\n", \
bInterfaceNumber, dongle_this);
if ((struct easycap *)NULL == peasycap) {
*/
/*---------------------------------------------------------------------------*/
isokalt = 0;
+
for (i = 0; i < pusb_interface->num_altsetting; i++) {
pusb_host_interface = &(pusb_interface->altsetting[i]);
if ((struct usb_host_interface *)NULL == pusb_host_interface) {
}
/*---------------------------------------------------------------------------*/
/*
+ * FIXME
+ *
+ *
* THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
*/
/*---------------------------------------------------------------------------*/
/*****************************************************************************/
/*---------------------------------------------------------------------------*/
/*
- * WHEN THIS FUNCTION IS CALLED THE DEVICE HAS ALREADY BEEN PHYSICALLY
- * UNPLUGGED.
- * HENCE peasycap->pusb_device IS NO LONGER VALID AND MUST BE SET TO NULL.
+ * WHEN THIS FUNCTION IS CALLED THE EasyCAP HAS ALREADY BEEN PHYSICALLY
+ * UNPLUGGED. HENCE peasycap->pusb_device IS NO LONGER VALID.
*/
/*---------------------------------------------------------------------------*/
void
struct list_head *plist_head;
struct data_urb *pdata_urb;
-int minor, m;
+int minor, m, kd;
JOT(4, "\n");
/*--------------------------------------------------------------------------*/
/*
* DEREGISTER
+ *
+ * THIS PROCEDURE WILL BLOCK UNTIL easycap_poll(), VIDEO IOCTL AND AUDIO
+ * IOCTL ARE ALL UNLOCKED. IF THIS IS NOT DONE AN Oops CAN OCCUR WHEN
+ * AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING. BEWARE.
*/
/*--------------------------------------------------------------------------*/
+kd = isdongle(peasycap);
switch (bInterfaceNumber) {
case 0: {
+ if (0 <= kd && DONGLE_MANY > kd) {
+ wake_up_interruptible(&peasycap->wq_video);
+ JOM(4, "about to lock easycap_dongle[%i].mutex_video\n", kd);
+ if (mutex_lock_interruptible(&easycap_dongle[kd].\
+ mutex_video)) {
+ SAY("ERROR: cannot lock easycap_dongle[%i]." \
+ "mutex_video\n", kd);
+ return;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
+ } else
+ SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
+/*---------------------------------------------------------------------------*/
#if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
if ((struct easycap *)NULL == peasycap) {
SAM("ERROR: peasycap has become NULL\n");
} else {
- lock_kernel();
usb_deregister_dev(pusb_interface, &easycap_class);
(peasycap->registered_video)--;
-
JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
- unlock_kernel();
SAM("easycap detached from minor #%d\n", minor);
}
/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
#else
- if ((struct easycap *)NULL == peasycap)
- SAM("ERROR: peasycap has become NULL\n");
- else {
- lock_kernel();
- video_unregister_device(&peasycap->video_device);
- (peasycap->registered_video)--;
- unlock_kernel();
- JOM(4, "unregistered with videodev: %i=minor\n", \
+ video_unregister_device(&peasycap->video_device);
+ JOM(4, "unregistered with videodev: %i=minor\n", \
peasycap->video_device.minor);
- }
+ (peasycap->registered_video)--;
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
#endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
+ if (0 <= kd && DONGLE_MANY > kd) {
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
+ }
break;
}
case 2: {
- lock_kernel();
+ if (0 <= kd && DONGLE_MANY > kd) {
+ wake_up_interruptible(&peasycap->wq_audio);
+ JOM(4, "about to lock easycap_dongle[%i].mutex_audio\n", kd);
+ if (mutex_lock_interruptible(&easycap_dongle[kd].\
+ mutex_audio)) {
+ SAY("ERROR: cannot lock easycap_dongle[%i]." \
+ "mutex_audio\n", kd);
+ return;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
+ } else
+ SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
usb_deregister_dev(pusb_interface, &easysnd_class);
- if ((struct easycap *)NULL != peasycap)
- (peasycap->registered_audio)--;
+ (peasycap->registered_audio)--;
JOM(4, "intf[%i]: usb_deregister_dev()\n", bInterfaceNumber);
- unlock_kernel();
-
SAM("easysnd detached from minor #%d\n", minor);
+
+ if (0 <= kd && DONGLE_MANY > kd) {
+ mutex_unlock(&easycap_dongle[kd].mutex_audio);
+ JOM(4, "unlocked easycap_dongle[%i].mutex_audio\n", kd);
+ }
break;
}
default:
* CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
*/
/*---------------------------------------------------------------------------*/
-if ((struct easycap *)NULL == peasycap) {
- SAM("ERROR: peasycap has become NULL\n");
- SAM("cannot call kref_put()\n");
- SAM("ending unsuccessfully: may cause memory leak\n");
- return;
-}
if (!peasycap->kref.refcount.counter) {
- SAM("ERROR: peasycap->kref.refcount.counter is zero " \
+ SAM("ERROR: peasycap->kref.refcount.counter is zero "
"so cannot call kref_put()\n");
SAM("ending unsuccessfully: may cause memory leak\n");
return;
}
-JOM(4, "intf[%i]: kref_put() with %i=peasycap->kref.refcount.counter\n", \
+if (0 <= kd && DONGLE_MANY > kd) {
+ JOM(4, "about to lock easycap_dongle[%i].mutex_video\n", kd);
+ if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_video)) {
+ SAY("ERROR: cannot down easycap_dongle[%i].mutex_video\n", kd);
+ SAM("ending unsuccessfully: may cause memory leak\n");
+ return;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_video\n", kd);
+ JOM(4, "about to lock easycap_dongle[%i].mutex_audio\n", kd);
+ if (mutex_lock_interruptible(&easycap_dongle[kd].mutex_audio)) {
+ SAY("ERROR: cannot down easycap_dongle[%i].mutex_audio\n", kd);
+ mutex_unlock(&(easycap_dongle[kd].mutex_video));
+ JOM(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
+ SAM("ending unsuccessfully: may cause memory leak\n");
+ return;
+ }
+ JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
+}
+JOM(4, "intf[%i]: %i=peasycap->kref.refcount.counter\n", \
bInterfaceNumber, (int)peasycap->kref.refcount.counter);
kref_put(&peasycap->kref, easycap_delete);
-JOM(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
+JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
+if (0 <= kd && DONGLE_MANY > kd) {
+ mutex_unlock(&(easycap_dongle[kd].mutex_audio));
+ JOT(4, "unlocked easycap_dongle[%i].mutex_audio\n", kd);
+ mutex_unlock(&easycap_dongle[kd].mutex_video);
+ JOT(4, "unlocked easycap_dongle[%i].mutex_video\n", kd);
+}
/*---------------------------------------------------------------------------*/
-
JOM(4, "ends\n");
return;
}