Skip to contentSkip to conversation

USB: add Sensoray 2255 v4l driver

PATCH In review Greg KH 6 participants 20 messages May 14, 2008 – May 16, 2008 Media (V4L/DVB)

lore
Share & tools
lore

Greg KH

author
#0 lore raw

PATCH 1/1 USB: add Sensoray 2255 v4l driver

From: Dean Anderson <[email protected]>

This driver adds support for the Sensoray 2255 devices.

It was primarily developed by Dean Anderson with only a little bit of guidance and cleanup by Greg.

From: Dean Anderson <[email protected]>

---
 drivers/media/video/Kconfig    |    9 
 drivers/media/video/Makefile   |    1 
 drivers/media/video/s2255drv.c | 2719 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 2729 insertions(+)
drivers/media/video/Kconfig +9 -0
@@ -893,6 +893,15 @@ config USB_STKWEBCAM
 	  To compile this driver as a module, choose M here: the
 	  module will be called stkwebcam.
 
+config USB_S2255
+	tristate "USB Sensoray 2255 video capture device"
+	depends on VIDEO_V4L2
+	select VIDEOBUF_VMALLOC
+	default n
+	help
+	  Say Y here if you want support for the Sensoray 2255 USB device.
+	  This driver can be compiled as a module, called s2255drv.
+
 endif # V4L_USB_DRIVERS
 
 config SOC_CAMERA
drivers/media/video/Makefile +1 -0
@@ -122,6 +122,7 @@ obj-$(CONFIG_USB_IBMCAM)        += usbvi
 obj-$(CONFIG_USB_KONICAWC)      += usbvideo/
 obj-$(CONFIG_USB_VICAM)         += usbvideo/
 obj-$(CONFIG_USB_QUICKCAM_MESSENGER)	+= usbvideo/
+obj-$(CONFIG_USB_S2255)		+= s2255drv.o
 
 obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_CX18) += cx18/
drivers/media/video/s2255drv.c new file +2719 -0

2,719 lines not on this page · raw message

#1 lore raw

Hi Dean, Greg,

Quoted 198 lines · Greg KH

From: Dean Anderson <[email protected]>

drivers/media/video/s2255drv.c new file +123 -0
+static int norm_maxw(struct video_device *vdev)
+{
+	return (vdev->current_norm != V4L2_STD_PAL_B) ?
+	    LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
+}
+
+static int norm_maxh(struct video_device *vdev)
+{
+	return (vdev->current_norm != V4L2_STD_PAL_B) ?
+	    (NUM_LINES_1CIFS_NTSC * 2) : (NUM_LINES_1CIFS_PAL * 2);
+}
+
+static int norm_minw(struct video_device *vdev)
+{
+	return (vdev->current_norm != V4L2_STD_PAL_B) ?
+	    LINE_SZ_1CIFS_NTSC : LINE_SZ_1CIFS_PAL;
+}
+
+static int norm_minh(struct video_device *vdev)
+{
+	return (vdev->current_norm != V4L2_STD_PAL_B) ?
+	    (NUM_LINES_1CIFS_NTSC) : (NUM_LINES_1CIFS_PAL);
+}
+
+/*
+ * convert from YUV(YCrCb) to RGB
+ * 65536 R = 76533(Y-16) + 104936 * (Cr-128)
+ * 65536 G = 76533(Y-16) - 53451(Cr-128) - 25703(Cb -128)
+ * 65536 B = 76533(Y-16) + 132677(Cb-128)
+ */
+static void YCrCb2RGB(int Y, int Cr, int Cb, unsigned char *pR,
+		      unsigned char *pG, unsigned char *pB)
+{
+	int R, G, B;
+
+	Y = Y - 16;
+	Cr = Cr - 128;
+	Cb = Cb - 128;
+
+	R = (76533 * Y + 104936 * Cr) >> 16;
+	G = ((76533 * Y) - (53451 * Cr) - (25703 * Cb)) >> 16;
+	B = ((76533 * Y) + (132677 * Cb)) >> 16;
+	/* even with proper conversion, some values still need clipping. */
+	if (R > 255)
+		R = 255;
+	if (G > 255)
+		G = 255;
+	if (B > 255)
+		B = 255;
+	if (R < 0)
+		R = 0;
+	if (G < 0)
+		G = 0;
+	if (B < 0)
+		B = 0;
+	*pR = R;
+	*pG = G;
+	*pB = B;
+	return;
+}
+
+/* converts 2255 planar format to yuyv */
+static void planar422p_to_yuy2(const unsigned char *in, unsigned char *out,
+			       int width, int height)
+{
+	unsigned char *pY;
+	unsigned char *pCb;
+	unsigned char *pCr;
+	unsigned long size = height * width;
+	unsigned int i;
+	pY = (unsigned char *)in;
+	pCr = (unsigned char *)in + height * width;
+	pCb = (unsigned char *)in + height * width + (height * width / 2);
+	for (i = 0; i < size * 2; i += 4) {
+		out[i] = *pY++;
+		out[i + 1] = *pCr++;
+		out[i + 2] = *pY++;
+		out[i + 3] = *pCb++;
+	}
+	return;
+}
+
+/*
+ * basic 422 planar to RGB24 or BGR24 software conversion.
+ * This is best done with MMX. Update to kernel function
+ * when image conversion functions added to kernel.
+ */
+static void planar422p_to_rgb24(const unsigned char *in,
+				unsigned char *out, int width,
+				int height, int rev_order)
+{
+	unsigned char *pY;
+	unsigned char *pYEND;
+	unsigned char *pCb;
+	unsigned char *pCr;
+	unsigned char Cr, Cb, Y, r, g, b;
+	unsigned long k = 0;
+	pY = (unsigned char *)in;
+	pCb = (unsigned char *)in + (height * width);
+	pCr = (unsigned char *)in + (height * width) + (height * width / 2);
+	pYEND = pCb;
+	while (pY < pYEND) {
+		Y = *pY++;
+		Cr = *pCr;
+		Cb = *pCb;
+		YCrCb2RGB(Y, Cr, Cb, &r, &g, &b);
+		out[k++] = !rev_order ? b : r;
+		out[k++] = g;
+		out[k++] = !rev_order ? r : b;
+		if (pY >= pYEND)
+			break;
+		Y = *pY++;
+		Cr = *pCr++;
+		Cb = *pCb++;
+		YCrCb2RGB(Y, Cr, Cb, &r, &g, &b);
+		out[k++] = !rev_order ? b : r;
+		out[k++] = g;
+		out[k++] = !rev_order ? r : b;
+	}
+	return;
+}
+
+static void planar422p_to_rgb32(const unsigned char *in, unsigned char

*out,

drivers/media/video/s2255drv.c new file +37 -0
+				int width, int height, int rev_order)
+{
+	unsigned char *pY;
+	unsigned char *pYEND;
+	unsigned char *pCb;
+	unsigned char *pCr;
+	unsigned char Cr, Cb, Y, r, g, b;
+	unsigned long k = 0;
+	pY = (unsigned char *)in;
+	pCb = (unsigned char *)in + (height * width);
+	pCr = (unsigned char *)in + (height * width) + (height * width / 2);
+	pYEND = pCb;
+	while (pY < pYEND) {
+		Y = *pY++;
+		Cr = *pCr;
+		Cb = *pCb;
+		YCrCb2RGB(Y, Cr, Cb, &r, &g, &b);
+		out[k++] = rev_order ? b : r;
+		out[k++] = g;
+		out[k++] = rev_order ? r : b;
+		out[k++] = 0;
+		if (pY >= pYEND)
+			break;
+		Y = *pY++;
+		Cr = *pCr++;
+		Cb = *pCb++;
+		YCrCb2RGB(Y, Cr, Cb, &r, &g, &b);
+		out[k++] = rev_order ? b : r;
+		out[k++] = g;
+		out[k++] = rev_order ? r : b;
+		out[k++] = 0;
+	}
+
+	return;
+}
+
+static void planar422p_to_rgb565(unsigned char const *in, unsigned char

*out,

drivers/media/video/s2255drv.c new file +34 -0
+				 int width, int height, int rev_order)
+{
+	unsigned char *pY;
+	unsigned char *pYEND;
+	unsigned char *pCb;
+	unsigned char *pCr;
+	unsigned char Cr, Cb, Y, r, g, b;
+	unsigned long k = 0;
+	unsigned short rgbbytes;
+	pY = (unsigned char *)in;
+	pCb = (unsigned char *)in + (height * width);
+	pCr = (unsigned char *)in + (height * width) + (height * width / 2);
+	pYEND = pCb;
+	while (pY < pYEND) {
+		Y = *pY++;
+		Cr = *pCr;
+		Cb = *pCb;
+		YCrCb2RGB(Y, Cr, Cb, &r, &g, &b);
+		r = r >> 3;
+		g = g >> 2;
+		b = b >> 3;
+		if (rev_order)
+			rgbbytes = b + (g << 5) + (r << (5 + 6));
+		else
+			rgbbytes = r + (g << 5) + (b << (5 + 6));
+		out[k++] = rgbbytes & 0xff;
+		out[k++] = (rgbbytes >> 8) & 0xff;
+		Y = *pY++;
+		Cr = *pCr++;
+		Cb = *pCb++;
+		YCrCb2RGB(Y, Cr, Cb, &r, &g, &b);
+		r = r >> 3;
+		g = g >> 2;
+		b = b >> 3;

drivers/media/video/s2255drv.c line 652

Quoted 10 lines
drivers/media/video/s2255drv.c new file +10 -0
+		if (rev_order)
+			rgbbytes = b + (g << 5) + (r << (5 + 6));
+		else
+			rgbbytes = r + (g << 5) + (b << (5 + 6));
+		out[k++] = rgbbytes & 0xff;
+		out[k++] = (rgbbytes >> 8) & 0xff;
+	}
+	return;
+}
+

Why do you do those conversions in kernelspace? ffmpeg/libswscale has optimized code for colourspace conversions. I know a few drivers do that in kernelspace but it's way more flexible in userspace and depending on the optimization requires less CPU power.

Markus

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

author
#2 lore raw
Quoted 1 line · Markus Rechberger

Hi Dean, Greg,

Adding dean to the cc: line... :)

Quoted 4 lines · Greg KH
Quoted 2 lines

From: Dean Anderson <[email protected]>

<big patch snipped>

Quoted 5 lines

Why do you do those conversions in kernelspace? ffmpeg/libswscale has optimized code for colourspace conversions. I know a few drivers do that in kernelspace but it's way more flexible in userspace and depending on the optimization requires less CPU power.

I thought they were there as needed by some V4L1 applications, but that code was recently removed by Dean I think. If they don't need to be there, and userspace apps can properly handle the different colorspace, then I'll be glad to remove them.

thanks,

greg k-h

#3 lore raw
Quoted 17 lines · Greg KH
Quoted 1 line · Markus Rechberger

Hi Dean, Greg,

Adding dean to the cc: line... :)

Quoted 4 lines · Greg KH
Quoted 2 lines

From: Dean Anderson <[email protected]>

<big patch snipped>

Quoted 5 lines

Why do you do those conversions in kernelspace? ffmpeg/libswscale has optimized code for colourspace conversions. I know a few drivers do that in kernelspace but it's way more flexible in userspace and depending on the optimization requires less CPU power.

Quoted 4 lines

I thought they were there as needed by some V4L1 applications, but that code was recently removed by Dean I think. If they don't need to be there, and userspace apps can properly handle the different colorspace, then I'll be glad to remove them.

Virtually all apps (V4L1 & 2) can handle YUV and RGB colorspaces. Certainly all the major ones do and all the major libraries as well.

The problem is when the device only supports some vendor specific or otherwise very uncommon format. In that case not doing the conversion in the kernel means the device won't work with any existing software without patches. In this case, while it's not "the right way", drivers often end up including an in kernel conversion for pragmatic reasons.

This was a problem with the bayer format, but now userspace support for that format is more common.

#4 lore raw
Quoted 31 lines · Trent Piepho
Quoted 20 lines · Greg KH
Quoted 2 lines · Markus Rechberger

Hi Dean, Greg,

Adding dean to the cc: line... :)

Quoted 5 lines · Greg KH
Quoted 4 lines

From: Dean Anderson <[email protected]>

<big patch snipped>

Quoted 6 lines

Why do you do those conversions in kernelspace? ffmpeg/libswscale has optimized code for colourspace conversions. I know a few drivers do that in kernelspace but it's way more flexible in userspace and depending on the optimization requires less CPU power.

Quoted 5 lines

I thought they were there as needed by some V4L1 applications, but that code was recently removed by Dean I think. If they don't need to be there, and userspace apps can properly handle the different colorspace, then I'll be glad to remove them.

Virtually all apps (V4L1 & 2) can handle YUV and RGB colorspaces. Certainly all the major ones do and all the major libraries as well.

Quoted 9 lines

The problem is when the device only supports some vendor specific or otherwise very uncommon format. In that case not doing the conversion in the kernel means the device won't work with any existing software without patches. In this case, while it's not "the right way", drivers often end up including an in kernel conversion for pragmatic reasons.

This was a problem with the bayer format, but now userspace support for that format is more common.

I agree the conversions don't belong in a driver. For the record, the following are done in the 2255 hardware: V4L2_PIX_FMT_GREY and V4L2_PIX_FMT_YUV422P.

Since planar YUV formats such as V4L2_PIX_FMT_YUV422P are still not that well supported, is it possible to keep at least one packed YUV format(V4L2_PIX_FMT_YUYV) in the driver? If not, let me know. I will strongly suggest that the hardware Engineers add YUY2 or YUYV on board in the DSP firmware. Thanks, Dean

#5 lore raw
Quoted 18 lines · Dean Anderson
Quoted 4 lines

Virtually all apps (V4L1 & 2) can handle YUV and RGB colorspaces. Certainly all the major ones do and all the major libraries as well.

Quoted 9 lines

The problem is when the device only supports some vendor specific or otherwise very uncommon format. In that case not doing the conversion in the kernel means the device won't work with any existing software without patches. In this case, while it's not "the right way", drivers often end up including an in kernel conversion for pragmatic reasons.

This was a problem with the bayer format, but now userspace support for that format is more common.

I agree the conversions don't belong in a driver. For the record, the following are done in the 2255 hardware: V4L2_PIX_FMT_GREY and V4L2_PIX_FMT_YUV422P.

Quoted 6 lines

Since planar YUV formats such as V4L2_PIX_FMT_YUV422P are still not that well supported, is it possible to keep at least one packed YUV format(V4L2_PIX_FMT_YUYV) in the driver? If not, let me know. I will strongly suggest that the hardware Engineers add YUY2 or YUYV on board in the DSP firmware. Thanks, Dean

Maybe it's better to fix up the corresponding application? If someone wants to get those devices work he already either has to upgrade his system or compile it manually at the moment.
With libswscale it's just a few lines of code to convert the formats with a decent performance.
Seems like the demand of conversions is also growing for the future.

Markus

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

#6 lore raw
In reply to Dean Anderson
Quoted 6 lines

Since planar YUV formats such as V4L2_PIX_FMT_YUV422P are still not that well supported, is it possible to keep at least one packed YUV format(V4L2_PIX_FMT_YUYV) in the driver? If not, let me know. I will strongly suggest that the hardware Engineers add YUY2 or YUYV on board in the DSP firmware. Thanks, Dean

The better is to have YUY2 and YUYV formats at the firmware and/or hardware. Those are the more common formats, and userspace apps generally try one of those first. Also, as it is common on several devices, the userspace handlers are more tested.

Cheers,
Mauro

#7 lore raw
In reply to Greg KH

Hi,

1. how about a *.h file?

2. You can inline these.

+static int norm_maxw(struct video_device *vdev)
+{
+ return (vdev->current_norm != V4L2_STD_PAL_B) ?
+ LINE_SZ_4CIFS_NTSC : LINE_SZ_4CIFS_PAL;
+}

3. The firmware stuff. That's an interesting solution. However:

a - if you don't need that delay, use a work queue

b - that's mean, use interruptible sleep

+ /* give 1 second for firmware to load in case
+ driver loaded and then device immediately opened */
+ msleep(1000);

particularly you'd stall khubd processing an early unplug

c - obviously loading the firmware might have failed after waiting

+ if (dev->fw_data->fw_state == FWSTATE_NOTLOADED) {

+                       err("2255 firmware loading stalled\n");
+                       mutex_unlock(&usb_s2255_open_mutex);
+                       return -EAGAIN;

+ }
+ }

you need a check for failure in an else branch

d - so you'll never release firmware in the error case unless you unplug

+ /* if first open after firmware loaded, release the firmware */
+ if (dev->fw_data->fw) {
+ release_firmware(dev->fw_data->fw);
+ dev->fw_data->fw = NULL;
+ }

e - you need to report errors

+static void s2255_timer(unsigned long user_data)
+{

+       struct complete_data *data = (struct complete_data *)user_data;
+       dprintk(100, "s2255 timer\n");
+       if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) {

+ printk(KERN_ERR "s2255: can't submit urb\n");
+ if (data->fw) {
+ release_firmware(data->fw);
+ data->fw = NULL;
+ }
+ return;
+ }
+}

f - also here

+static void s2255_fwchunk_complete(struct urb *urb) +{

+       struct complete_data *data = urb->context;
+       struct usb_device *udev = urb->dev;
+       int len;
+       dprintk(100, "udev %p urb %p", udev, urb);

+
+ if (urb->status) {
+ dev_err(&udev->dev, "URB failed with status %d", urb->status);
+ return;
+ }

4. as a rule, init all locks before you start a timer

+ mod_timer(&dev->timer, jiffies + HZ);
+ spin_lock_init(&dev->slock);

5. Unnecessary init

+static void s2255_disconnect(struct usb_interface *interface) +{
+ struct s2255_dev *dev = NULL;

6. The initial firmware timer may still be ticking

+ if (dev->fw_data->fw_urb) {

+               dprintk(2, "kill URB\n");
+               usb_kill_urb(dev->fw_data->fw_urb);
+               usb_free_urb(dev->fw_data->fw_urb);

You need to delete that timer and kill the firmware urb after that.

7. That's not an error you want to return in that case. It may livelock

+ if (dev->users[cur_channel] > 1) {

+               dev->users[cur_channel]--;
+               dev_err(&dev->udev->dev, "one user at a time\n");
+               mutex_unlock(&usb_s2255_open_mutex);
+               return -EAGAIN;

+ }

8. Bogus check

+ if (data->fw_urb == NULL) {
+ dev_err(&udev->dev, "early disconncect\n");
+ return;
+ }

9. This can be computed directly

+ while (*size * *count > vid_limit * 1024 * 1024)
+ (*count)--;

10. This is fishy.

+static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh) +{
+ return (dev->resources[fh->channel]);
+}
+
+static void res_free(struct s2255_dev *dev, struct s2255_fh *fh) +{
+ dev->resources[fh->channel] = 0;
+ dprintk(1, "res: put\n");
+}

In theory out of order memory access might return false positives. Better use memory barriers or take the mutex.

11. Coding style

+ return (0);

12. This is close to obfuscated code

+ is_ntsc =
+ (dev->vdev[fh->channel]->current_norm != V4L2_STD_PAL_B) ? 1 : 0;

13. Coding style

+ if (ret < 0)
+ return (ret);

14. GFP_KERNEL in interrupt context

+
+ if (pipe_info->state != 0) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {

15. Error handling in s2255_probe() is a gigantic resource leak

+ if (!dev->fw_data->fw_urb) {
+ dev_err(&interface->dev, "out of memory!\n");
+ goto error;
+ }

You must free what you allocate

Regards
Oliver

#8 lore raw

Am Donnerstag 15 Mai 2008 13:38:37 schrieb Oliver Neukum:

Quoted 1 line

3. The firmware stuff. That's an interesting solution. However:

Actually, on second thought, I take that back. It's a bad solution. If you don't want to do it in probe(), the only other sensible place is in open(). That way you can avoid the whole trouble if nobody opens the device. And you need to handle the case of unloaded firmware anyway, so you can trigger firmware load there.

Regards
Oliver

author
#9 lore raw
Quoted 8 lines · Oliver Neukum

Am Donnerstag 15 Mai 2008 13:38:37 schrieb Oliver Neukum:

Quoted 1 line

3. The firmware stuff. That's an interesting solution. However:

Actually, on second thought, I take that back. It's a bad solution. If you don't want to do it in probe(), the only other sensible place is in open(). That way you can avoid the whole trouble if nobody opens the device. And you need to handle the case of unloaded firmware anyway, so you can trigger firmware load there.

No, we want to do firmware load on probe, I'll change it to be async so that probe can continue on. Need to see if I can disconnect the driver from device after probe succeeds in case the firmware fails.

thanks for the review, I appreciate it and will fix them up later today or tomorrow.

greg k-h

#10 lore raw

Am Donnerstag 15 Mai 2008 20:44:24 schrieb Greg KH:

Quoted 11 lines · Oliver Neukum
Quoted 8 lines

Am Donnerstag 15 Mai 2008 13:38:37 schrieb Oliver Neukum:

Quoted 1 line

3. The firmware stuff. That's an interesting solution. However:

Actually, on second thought, I take that back. It's a bad solution. If you don't want to do it in probe(), the only other sensible place is in open(). That way you can avoid the whole trouble if nobody opens the device. And you need to handle the case of unloaded firmware anyway, so you can trigger firmware load there.

No, we want to do firmware load on probe, I'll change it to be async so

Could you state your reasons for that preference?

Regards
Oliver

author
#11 lore raw
Quoted 11 lines · Oliver Neukum

Am Donnerstag 15 Mai 2008 20:44:24 schrieb Greg KH:

Quoted 10 lines · Oliver Neukum
Quoted 8 lines

Am Donnerstag 15 Mai 2008 13:38:37 schrieb Oliver Neukum:

Quoted 1 line

3. The firmware stuff. That's an interesting solution. However:

Actually, on second thought, I take that back. It's a bad solution. If you don't want to do it in probe(), the only other sensible place is in open(). That way you can avoid the whole trouble if nobody opens the device. And you need to handle the case of unloaded firmware anyway, so you can trigger firmware load there.

Quoted 3 lines
Quoted 1 line

No, we want to do firmware load on probe, I'll change it to be async so

Could you state your reasons for that preference?

I don't want to create the device nodes, and have userspace think the device really is working, only to have everything fall down and die if open() is called and the firmware isn't present. I'd rather not create the video devices if we know this isn't going to work at all.

Just trying to be nicer to users who would get very confused, "but wait, the device nodes are there, and the application finds the device, why is it not working properly?"

thanks,

greg k-h

#12 lore raw

Am Donnerstag 15 Mai 2008 22:10:49 schrieb Greg KH:

Quoted 12 lines · Oliver Neukum
Quoted 11 lines

Am Donnerstag 15 Mai 2008 20:44:24 schrieb Greg KH:

Quoted 10 lines · Oliver Neukum
Quoted 8 lines

Am Donnerstag 15 Mai 2008 13:38:37 schrieb Oliver Neukum:

Quoted 1 line

3. The firmware stuff. That's an interesting solution. However:

Actually, on second thought, I take that back. It's a bad solution. If you don't want to do it in probe(), the only other sensible place is in open(). That way you can avoid the whole trouble if nobody opens the device. And you need to handle the case of unloaded firmware anyway, so you can trigger firmware load there.

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

No, we want to do firmware load on probe, I'll change it to be async so

Could you state your reasons for that preference?

I don't want to create the device nodes, and have userspace think the device really is working, only to have everything fall down and die if open() is called and the firmware isn't present. I'd rather not create the video devices if we know this isn't going to work at all.

Yes, that makes sense. However, then you might want to look into spawning a thread per bus rather than a delayed failure mechanism.

Regards
Oliver

#13 lore raw
In reply to Greg KH

Hi Greg and Dean,

In general, the driver seems sane and almost ready for their kernel inclusion. However, there were several videobuf changes affecting mostly the users of videobuf-vmalloc during the last kernel development cycle, to fix lock issues. The code should be reviewed at the light of the latest version, and tested. The good news is that the videobuf handler will be simpler, but a lock is now required.

I have other comments to help improving the driver quality.

Btw, I noticed the lack of Dean's SOB. Is this intentional?

Cheers,
Mauro.

drivers/media/video/s2255drv.c line 59

Quoted 9 lines · On Wed, 14 May 2008 13:59:27 -0700 Greg KH <[email protected]> wrote:

From: Dean Anderson <[email protected]>

This driver adds support for the Sensoray 2255 devices.

It was primarily developed by Dean Anderson with only a little bit of guidance and cleanup by Greg.

drivers/media/video/s2255drv.c new file +2 -0
+#define DIR_IN			0
+#define DIR_OUT			1

It seems a little dangerous to use just DIR_IN/DIR_OUT, since a future change on a kernel header could cause namespace conflict. IMO, the better is to rename those macros to something more specific, like S2255_DIR_IN.

The same comment is also true to struct and other namespace definitions, like "framei", "bufferi", etc.

drivers/media/video/s2255drv.c line 266

Quoted 8 lines
drivers/media/video/s2255drv.c new file +8 -0
+
+/* buffer for one video frame */
+struct s2255_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+	const struct s2255_fmt *fmt;
+	/* future use */
+	int reserved[32];

Why to reserve 32 integers here? While this may have some sense at userspace API, I can't see any reason to use this internally.

Quoted 1 line

+#define S2255_NORMS (V4L2_STD_PAL_B | V4L2_STD_NTSC_M)

Just those two norms? Are you sure it doesn't support the other european PAL variants (PAL/G, PAL/D, PAL/K)?

Quoted 1 line

+static DEFINE_MUTEX(usb_s2255_open_mutex);

Hmmm... what happens if the user plugs two or more of such devices?

drivers/media/video/s2255drv.c line 363

Quoted 13 lines
drivers/media/video/s2255drv.c new file +13 -0
+/* supported controls */
+static struct v4l2_queryctrl s2255_qctrl[] = {
+	{
+	.id = V4L2_CID_BRIGHTNESS,
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.name = "Brightness",
+	.minimum = -127,
+	.maximum = 128,
+	.step = 1,
+	.default_value = 0,
+	.flags = 0,
+	},
+	{

This seems to be violating CodingStyle. It should be something like:

	{
		.id = foo,
<snip/>
	}, {

The same applies also to other structs. The better is to check the patch with checkpatch.pl, since other violations might be present.

drivers/media/video/s2255drv.c line 478

Quoted 7 lines
drivers/media/video/s2255drv.c new file +7 -0
+
+/*
+ * convert from YUV(YCrCb) to RGB
+ * 65536 R = 76533(Y-16) + 104936 * (Cr-128)
+ * 65536 G = 76533(Y-16) - 53451(Cr-128) - 25703(Cb -128)
+ * 65536 B = 76533(Y-16) + 132677(Cb-128)
+ */

As already discussed, the driver should support only the video standards supported by the hardware. colorspace conversion can happen at userspace apps.

drivers/media/video/s2255drv.c line 674

Quoted 6 lines
drivers/media/video/s2255drv.c new file +6 -0
+/* this loads the firmware asynchronously.
+   Originally this was done synchroously in probe.
+   But it is better to load it asynchronously here than block
+   inside the probe function. Blocking inside probe affects boot time.
+   FW loading is triggered by the timer in the probe function
+*/

I saw another discussion about this.

I like the idea of loading firmware asynchronously, provided that you block at open() or at ioctl(), if the user requested to open before having the firmware loaded.

Quoted 1 line

+static int restart_video_queue(struct s2255_dmaqueue *dma_q)

This is probably obsolete. We've cleaned up those code. The better is to take a look at videobuf implementation at em28xx-video, where some lock bugs were fixed and the code were simplified. I don't have your hardware to test, but I suspect that the driver suffers some bugs at videobuf implementation that we've removed recently.

drivers/media/video/s2255drv.c line 1088

Quoted 12 lines
drivers/media/video/s2255drv.c new file +12 -0
+/* ------------------------------------------------------------------
+   IOCTL vidioc handling
+   ------------------------------------------------------------------*/
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *cap)
+{
+	strcpy(cap->driver, "s2255");
+	strcpy(cap->card, "s2255");
+	cap->version = S2255_VERSION;
+	cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+	return 0;
+}

Better to use "strlcpy" instead of just "strcpy", to avoid the risk of buffer overflow. Ok, currently, there's no risk, but, if tomorrow someone changes something here, the bug will emerge.

Also, please fill bus info, with something like:

	strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info));

This is required for some udev implementations to properly work.

drivers/media/video/s2255drv.c line 1229

Quoted 3 lines
drivers/media/video/s2255drv.c new file +3 -0
+/* FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+			    struct v4l2_format *f)

The implementation you did is not generic enough for videodev2. I agree that we may improve the implementation of try_fmt/s_fmt at videobuf2. Feel free to propose such improvements.

drivers/media/video/s2255drv.c line 1324

Quoted 2 lines
drivers/media/video/s2255drv.c new file +2 -0
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)

There are now a videobuf method to implement vidiocgmbuf. The better is to use it, instead of duplicating the code.

Quoted 1 line

+#define EP_NUM_CONFIG 2

This define here sounds strange. I would move it to the beginning at the driver. Better to write a short comment about this magic number.

drivers/media/video/s2255drv.c line 1574

Quoted 4 lines
drivers/media/video/s2255drv.c new file +4 -0
+	s2255_stop_acquire(dev, fh->channel);
+	/* give time for last frame to be received/flush in the usb
+	   receive pipe*/
+	msleep(50);

The sleep above seems a hack to my eyes. The better is to protect with a spinlock. The current code, at vivi and em28xx already prevents such issues (at least, it went fine at the tests we did).

drivers/media/video/s2255drv.c line 1578

Quoted 4 lines
drivers/media/video/s2255drv.c new file +4 -0
+	res = videobuf_streamoff(&fh->vb_vidq);
+	res_free(dev, fh);
+	/* expire the queue timer now in case still active */
+	mod_timer(&dmaq->timeout, jiffies + HZ);

Also, the timeout is obsolete

drivers/media/video/s2255drv.c line 1595

Quoted 5 lines
drivers/media/video/s2255drv.c new file +5 -0
+	return res;
+}
+	if (*i == V4L2_STD_NTSC_M) {
+		dprintk(4, "vidioc_s_std NTSC\n");
+		mode->format = FORMAT_NTSC;

No. NTSC/M is just one variant of NTSC, used on US/Canada. There are other variants at Asia, in Korea and Japan. The difference is at the audio carrier.

drivers/media/video/s2255drv.c line 1597

Quoted 2 lines
drivers/media/video/s2255drv.c new file +2 -0
+	} else if (*i == V4L2_STD_PAL_B) {
+		dprintk(4, "vidioc_s_std PAL\n");

Also, PAL/B is just one variant.

A proper code would be to do this:

	if (*i & V4L2_STD_PAL)

(notice that the equal operator were replaced by the logical operation _AND_. This covers all european PAL. However, this mask doesn't cover PAL/N, PAL/Nc and PAL/M.

If all you need is to check if the video mode is 50Hz/60Hz, the proper code would be, instead:

	if (*i & V4L2_STD_525_60)
		/* some logic for NTSC/M, PAL/M and PAL/60 */
	else
		/* some logic for the other PAL variations and SECAM */

drivers/media/video/s2255drv.c line 1611

Quoted 7 lines
drivers/media/video/s2255drv.c new file +7 -0
+/* Sensoray 2255 is a multiple channel capture device.
+   It does not have a "crossbar" of inputs.
+   We use one V4L device per channel. The user must
+   be aware that certain combinations are not allowed.
+   For instance, you cannot do full FPS on more than 2 channels(2 videodevs)
+   at once in color(you can do full fps on 4 channels with greyscale.
+*/

The invalid combinations should be tested, to avoid OOPSes and other bad behaviours.

drivers/media/video/s2255drv.c line 1691

Quoted 9 lines
drivers/media/video/s2255drv.c new file +9 -0
+			/* update the mode to the corresponding value */
+			if (ctrl->id == V4L2_CID_BRIGHTNESS)
+				mode->bright = ctrl->value;
+			else if (ctrl->id == V4L2_CID_CONTRAST)
+				mode->contrast = ctrl->value;
+			else if (ctrl->id == V4L2_CID_HUE)
+				mode->hue = ctrl->value;
+			else if (ctrl->id == V4L2_CID_SATURATION)
+				mode->saturation = ctrl->value;

You have just a few controls. However, the better would be to use a switch(), since the compiler can reorder the operations to improve the code speed and size.

drivers/media/video/s2255drv.c line 1740

Quoted 5 lines
drivers/media/video/s2255drv.c new file +5 -0
+	if (dev->fw_data->fw_state == FWSTATE_FAILED) {
+		err("2255 firmware wasn't loaded\n");
+		mutex_unlock(&usb_s2255_open_mutex);
+		return -ENODEV;
+	}

It seems too hard to return ENODEV. Couldn't the driver try again to load the firmware here?

drivers/media/video/s2255drv.c line 1745

Quoted 4 lines
drivers/media/video/s2255drv.c new file +4 -0
+	if (dev->fw_data->fw_state == FWSTATE_NOTLOADED) {
+		/* give 1 second for firmware to load in case
+		   driver loaded and then device immediately opened */
+		msleep(1000);

Argh. I would use a wait_event_timeout() instead, and use a higher timeout value.

Also, it seems that fw_state needs to be atomic.

drivers/media/video/s2255drv.c line 1749

Quoted 4 lines
drivers/media/video/s2255drv.c new file +4 -0
+		if (dev->fw_data->fw_state == FWSTATE_NOTLOADED) {
+			err("2255 firmware loading stalled\n");
+			mutex_unlock(&usb_s2255_open_mutex);
+			return -EAGAIN;

Hmm... I'm in doubt if we should return, instead, -EBUSY.

drivers/media/video/s2255drv.c line 1756

Quoted 5 lines
drivers/media/video/s2255drv.c new file +5 -0
+	/* if first open after firmware loaded, release the firmware */
+	if (dev->fw_data->fw) {
+		release_firmware(dev->fw_data->fw);
+		dev->fw_data->fw = NULL;
+	}

This seems weird. Why to release the firmware?

drivers/media/video/s2255drv.c line 1764

Quoted 8 lines
drivers/media/video/s2255drv.c new file +8 -0
+
+	dev->users[cur_channel]++;
+
+	if (dev->users[cur_channel] > 1) {
+		dev->users[cur_channel]--;
+		dev_err(&dev->udev->dev, "one user at a time\n");
+		mutex_unlock(&usb_s2255_open_mutex);
+		return -EAGAIN;

In this case, it should return -EBUSY.

drivers/media/video/s2255drv.c line 1776

Quoted 12 lines
drivers/media/video/s2255drv.c new file +12 -0
+	}
+
+	dprintk(1, "open minor=%d type=%s users=%d\n",
+		minor, v4l2_type_names[type], dev->users[cur_channel]);
+
+	/* allocate + initialize per filehandle data */
+	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+	if (NULL == fh) {
+		dev->users[cur_channel]--;
+		mutex_unlock(&usb_s2255_open_mutex);
+		return -ENOMEM;
+	}

Instead of incrementing the usage, printing the open message just to discover that you don't have enough memory, I would move the users increment and the dprintk to happen after the allocation of fh.

drivers/media/video/s2255drv.c line 1805

Quoted 5 lines
drivers/media/video/s2255drv.c new file +5 -0
+	videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
+				    NULL, NULL,
+				    fh->type,
+				    V4L2_FIELD_INTERLACED,
+				    sizeof(struct s2255_buffer), fh);

You'll need to define a spinlock for videoqueue, otherwise the kernel will now complain. Please test your code against the latest development version (or the latest code at mainstream).

--
video4linux-list mailing list
Unsubscribe mailto:[email protected]?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list

#14 lore raw

Am Freitag 16 Mai 2008 04:51:02 schrieb Mauro Carvalho Chehab:

Quoted 3 lines
Quoted 1 line

+static DEFINE_MUTEX(usb_s2255_open_mutex);

Hmmm... what happens if the user plugs two or more of such devices?

Concurrent calls to open() will be delayed. Not a problem, if the firmware issue is fixed as it needs to be.

Regards
Oliver

#15 lore raw

Hi Oliver,

Just to be clear. You mean fixing the loading issues(ugly msleep, etc...) that Mauro mentioned, not the YUV formats(which seem unrelated)?

Would it be ok to have just 422P and greyscale in the driver for now if we can't get a firmware update in a reasonable timeframe? It's certainly not ideal, but we could direct our customers to the libraries, at least until we get a proper HW fix.

Best regards,

Dean

Quoted 15 lines · Oliver Neukum

Am Freitag 16 Mai 2008 04:51:02 schrieb Mauro Carvalho Chehab:

Quoted 4 lines
Quoted 2 lines

+static DEFINE_MUTEX(usb_s2255_open_mutex);

Hmmm... what happens if the user plugs two or more of such devices?

Concurrent calls to open() will be delayed. Not a problem, if the firmware issue is fixed as it needs to be.

Regards
Oliver

#16 lore raw

Am Freitag 16 Mai 2008 17:57:15 schrieb dean:

Quoted 3 lines

Hi Oliver,

Just to be clear. You mean fixing the loading issues(ugly msleep,

Yes.

Quoted 6 lines

etc...) that Mauro mentioned, not the YUV formats(which seem unrelated)?

Would it be ok to have just 422P and greyscale in the driver for now if we can't get a firmware update in a reasonable timeframe? It's certainly not ideal, but we could direct our customers to the libraries, at least until we get a proper HW fix.

I am incompetent to answer that.

Regards
Oliver

#17 lore raw
In reply to dean

Dean,

Quoted 9 lines · On Fri, 16 May 2008 08:57:15 -0700 dean <[email protected]> wrote:

Hi Oliver,

Just to be clear. You mean fixing the loading issues(ugly msleep, etc...) that Mauro mentioned, not the YUV formats(which seem unrelated)?

Would it be ok to have just 422P and greyscale in the driver for now if we can't get a firmware update in a reasonable timeframe? It's certainly not ideal, but we could direct our customers to the libraries, at least until we get a proper HW fix.

Feature regression is something that shouldn't happen. If we add the driver with a color conversion inside, we should somehow keep this feature available on newer versions. That's said, I don't see any issue if the later versions do this implementation inside hardware/firmware, since the end result is that the driver will keep supporting those standards.

Quoted 1 line

From my side, I'm ok on having this color conversion for a short timeframe (one

or two kernel releases), if you are sure that those features will be present on the next firmwares.

The better is to mark the driver as EXPERIMENTAL, at Kconfig.

Cheers,
Mauro

#18 lore raw
In reply to Mauro Carvalho Chehab
Quoted 1 line

Btw, I noticed the lack of Dean's SOB. Is this intentional?

It's not intentional, I can sign off on it. The suggestions look good.

I have a few other questions. First, is Video for Linux version 1 going to be obsoleted soon? Do the V4L1 compatibility routines still work in the latest driver? I had problems running the VIVI (virtual video driver) driver with VideoLan/VLC 0.8.6a-f, but it worked with VLC 9.0 with the new V4L2 interface.

"videodev: "s2255v" has no release callback. Please fix your driver for proper sysfs support, see http://lwn.net/Articles/36850/"

Should we get rid of the warning message above? It's also been present in VIVI for quite a few kernel releases.

#19 lore raw
Quoted 2 lines · On Fri, 16 May 2008 07:53:46 -0700 dean <[email protected]> wrote:
Quoted 1 line

Btw, I noticed the lack of Dean's SOB. Is this intentional?

It's not intentional, I can sign off on it.

Thanks. Please send your SOB at the next version.

Quoted 2 lines

I have a few other questions. First, is Video for Linux version 1 going to be obsoleted soon?

We intend to, but people are currently lacking time to port old drivers to V4L2.

Quoted 2 lines

Do the V4L1 compatibility routines still work in
the latest driver?

V4L1 compat will still be kept for some time after the end of V4L1 drivers.

Quoted 3 lines

I had problems running the VIVI (virtual video
driver) driver with VideoLan/VLC 0.8.6a-f, but it worked with VLC 9.0 with the new V4L2 interface.

VLC V4L1 implementation were broken. It first starts DMA and streaming, then, it calls some ioctls that changes the buffer size. The compat handler doesn't accept this behaviour, since it would cause buffer overflow. AFAIK, only bttv driver used to support this behaviour. On V4L1 mode, bttv were allocating enough memory for the maximum resolution. So, subsequent buffer changes works properly.

It would be valuable if you could work on a safe way to implement backward compat for this broken behaviour. In this case, you would need to change the compat implementation at videobuf, and let v4l1-compat module to be aware that it is safe to allow buffer size changes.

Yet, this seems to much work for something that should be already removed from kernel (V4L1).

Quoted 5 lines

"videodev: "s2255v" has no release callback. Please fix your driver for proper sysfs support, see http://lwn.net/Articles/36850/"

Should we get rid of the warning message above? It's also been present in VIVI for quite a few kernel releases.

The message doesn't cause any harm, but the better is to fix this also. This were already corrected at the latest vivi versions.

Cheers,
Mauro