gspca_amscope: AmScope MT1000 camera driver
Subsystems (2)
PATCH 1/1 gspca_amscope: AmScope MT1000 camera driver
Hello, I'm working on adding a new GSPCA driver for the AmScope MT1000 series microscope camera and I'm having a bit of trouble. The patch below is my work-in-progress. I can succesfully get a video stream from the device at 1280x1024 (the default) and can set the exposure value, but I seem to be having trouble with data corruption while retrieving the image data. I'm sure I'll figure it out eventually but any suggestions would be appreciated.
I retrieve the frames as the camera sends them out through a bulk DMA transfer into the URB's transfer buffer. The data should come out as (1280 * 1024) each time but it's always a few kilobytes shy of that number. The missing data appears to be at random points in the image and occurs at roughly 32kb intervals. The resulting image looks like it's been cut into horizontal ribbons with about 1/10 of the image missing at the bottom.
Here's what the image should look like (from windows):
http://imgur.com/fFXyB9c
Here's how it currently looks with my WIP driver:
http://imgur.com/sLDMKbx
I'm assuming this is because I'm losing some of the packets at the USB layer, but I don't really know where to look to fix it. I've tried tweaking the URB buffer to all different sizes and I find that anything less than 32Kb makes the ribbon effect worse, so I'm keeping it large. Has anyone seen this behavior before, and if so, is it a problem with my gspca config, the device, or something further down in the USB layer?
This is the lsusb -vv output:
Bus 001 Device 004: ID 0547:92a0 Anchor Chips, Inc. Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0547 Anchor Chips, Inc. idProduct 0x92a0 bcdDevice 0.00 iManufacturer 1 DO3THINK iProduct 2 10M USBCam iSerial 0 bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 32
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0004 1x 4 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
--- drivers/media/usb/gspca/Kconfig | 9 ++ drivers/media/usb/gspca/Makefile | 2 + drivers/media/usb/gspca/amscope.c | 317 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 328 insertions(+)
drivers/media/usb/gspca/Kconfig +9 -0
@@ -21,6 +21,15 @@ source "drivers/media/usb/gspca/m5602/Kconfig" source "drivers/media/usb/gspca/stv06xx/Kconfig" source "drivers/media/usb/gspca/gl860/Kconfig" +config USB_GSPCA_AMSCOPE + tristate "AmScope USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for AmScope series cameras + + To compile this driver as a module, choose M here: the + module will be called gspca_amscope. + config USB_GSPCA_BENQ tristate "Benq USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA
drivers/media/usb/gspca/Makefile +2 -0
@@ -1,4 +1,5 @@ obj-$(CONFIG_USB_GSPCA) += gspca_main.o +obj-$(CONFIG_USB_GSPCA_AMSCOPE) += gspca_amscope.o obj-$(CONFIG_USB_GSPCA_BENQ) += gspca_benq.o obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o
@@ -45,6 +46,7 @@ obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o gspca_main-objs := gspca.o autogain_functions.o +gspca_amscope-objs := amscope.o gspca_benq-objs := benq.o gspca_conex-objs := conex.o gspca_cpia1-objs := cpia1.o
drivers/media/usb/gspca/amscope.c new file +317 -0
317 lines not on this page · raw message
Hi,
Quoted 21 lines · Todd Brandt
Hello, I'm working on adding a new GSPCA driver for the AmScope MT1000 series microscope camera and I'm having a bit of trouble. The patch below is my work-in-progress. I can succesfully get a video stream from the device at 1280x1024 (the default) and can set the exposure value, but I seem to be having trouble with data corruption while retrieving the image data. I'm sure I'll figure it out eventually but any suggestions would be appreciated.
I retrieve the frames as the camera sends them out through a bulk DMA transfer into the URB's transfer buffer. The data should come out as (1280 * 1024) each time but it's always a few kilobytes shy of that number. The missing data appears to be at random points in the image and occurs at roughly 32kb intervals. The resulting image looks like it's been cut into horizontal ribbons with about 1/10 of the image missing at the bottom.
Here's what the image should look like (from windows):
http://imgur.com/fFXyB9cHere's how it currently looks with my WIP driver:
http://imgur.com/sLDMKbx
Quoted 6 lines
I'm assuming this is because I'm losing some of the packets at the USB layer, but I don't really know where to look to fix it. I've tried tweaking the URB buffer to all different sizes and I find that anything less than 32Kb makes the ribbon effect worse, so I'm keeping it large. Has anyone seen this behavior before, and if so, is it a problem with my gspca config, the device, or something further down in the USB layer?
You could try submitting multiple urbs at once. IOW change bulk_nurbs to something larger then you've now. As for the packet size, if you've windows traces those should show you what size of transfers windows is using, try mimicking those.
Once size which comes to mind to use is 5120 bytes, as that is the lowest multiple of the sensor width, which also is a multiple of the bulk endpoint maxpacketsize.
Last, you could check to see that you've all the sensor / bridge registers set up as windows does. This could be the bridge and sensor chip loosing sync, or some bridge fifo settings which are off.
Regards,
Hans
Quoted 434 lines
This is the lsusb -vv output:
Bus 001 Device 004: ID 0547:92a0 Anchor Chips, Inc. Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x0547 Anchor Chips, Inc. idProduct 0x92a0 bcdDevice 0.00 iManufacturer 1 DO3THINK iProduct 2 10M USBCam iSerial 0 bNumConfigurations 1Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 32
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes0x80
(Bus Powered)
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress0x81EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize0x00041x 4 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress0x82EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize0x02001x 512 bytes
bInterval 0Signed-off-by Todd Brandt <[email protected]>--- drivers/media/usb/gspca/Kconfig | 9 ++ drivers/media/usb/gspca/Makefile | 2 + drivers/media/usb/gspca/amscope.c | 317 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 328 insertions(+)drivers/media/usb/gspca/Kconfig +9
-0@@ -21,6 +21,15 @@ source "drivers/media/usb/gspca/m5602/Kconfig" source "drivers/media/usb/gspca/stv06xx/Kconfig" source "drivers/media/usb/gspca/gl860/Kconfig" +config USB_GSPCA_AMSCOPE + tristate "AmScope USB Camera Driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for AmScope series cameras + + To compile this driver as a module, choose M here: the + module will be called gspca_amscope. + config USB_GSPCA_BENQ tristate "Benq USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCAdrivers/media/usb/gspca/Makefile +2
-0@@ -1,4 +1,5 @@ obj-$(CONFIG_USB_GSPCA) += gspca_main.o +obj-$(CONFIG_USB_GSPCA_AMSCOPE) += gspca_amscope.o obj-$(CONFIG_USB_GSPCA_BENQ) += gspca_benq.o obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o@@ -45,6 +46,7 @@ obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o gspca_main-objs := gspca.o autogain_functions.o +gspca_amscope-objs := amscope.o gspca_benq-objs := benq.o gspca_conex-objs := conex.o gspca_cpia1-objs := cpia1.odrivers/media/usb/gspca/amscope.c new file +317
-1@@ -0,0 +1,317 @@ +/* +* AmScope series microscope camera driver +* +* Todd Brandt <[email protected]> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +*/ +#define MODULE_NAME "amscope" +#define DEBUG 1 + +#include "gspca.h" + +MODULE_AUTHOR ("Todd Brandt <[email protected]>" ); +MODULE_DESCRIPTION ("AmScope USB Camera Driver" ); +MODULE_LICENSE ("GPL" ); + +#define BULK_SIZE (20 * 16384) + +/* specific webcam descriptor */ +struct sd { +struct gspca_dev gspca_dev;/* !! must be the first item */ +unsigned int count; +}; + +static const struct v4l2_pix_format vga_mode[] = { +/* +{640, 480, +V4L2_PIX_FMT_SGRBG8, +V4L2_FIELD_NONE, +.bytesperline = 640, +.sizeimage = 640 * 480, +.colorspace = V4L2_COLORSPACE_SRGB}, +*/ + {1280 ,1024 , +V4L2_PIX_FMT_SGRBG8 , +V4L2_FIELD_NONE , + .bytesperline =1280 , + .sizeimage =1280 *1024 , + .colorspace =V4L2_COLORSPACE_SRGB }, +/* +{3856, 2764, +V4L2_PIX_FMT_GREY, +V4L2_FIELD_NONE, +.bytesperline = 3856, +.sizeimage = 3856 * 2764, +.colorspace = V4L2_COLORSPACE_SRGB}, +*/ +}; + +static int usb_dev_write (struct gspca_dev *gspca_dev, +u8 request,u16 value,u16 index,u16 length) +{ +int rc; + + rc =usb_control_msg (gspca_dev->dev, +usb_sndctrlpipe (gspca_dev->dev,0 ), request, +USB_DIR_OUT |USB_TYPE_VENDOR |USB_RECIP_DEVICE , + value, index, gspca_dev->usb_buf, length,500 ); + +return rc; +} + +static int usb_dev_read (struct gspca_dev *gspca_dev, +u8 request,u16 value,u16 index,u16 length) +{ +int rc; + +memset (gspca_dev->usb_buf,0 , length); + rc =usb_control_msg (gspca_dev->dev, +usb_rcvctrlpipe (gspca_dev->dev,0 ), request, +USB_DIR_IN |USB_TYPE_VENDOR |USB_RECIP_DEVICE , + value, index, gspca_dev->usb_buf, length,500 ); + +return rc; +} + +/* called at probe time (after sd_probe) */ +static int sd_config (struct gspca_dev *gspca_dev, +const struct usb_device_id *id) +{ +struct cam *cam = &gspca_dev->cam; + +pr_devel ("sd_config, Vendor=%04x, Product=%04x" , + id->idVendor, id->idProduct); + + cam->cam_mode = vga_mode; + cam->nmodes =ARRAY_SIZE (vga_mode); + cam->no_urb_create =0 ; + cam->bulk_nurbs =1 ; + cam->bulk_size =BULK_SIZE ; + cam->bulk =1 ; + +return 0 ; +} + +/* called at probe (after sd_config), and resume time */ +static int sd_init (struct gspca_dev *gspca_dev) +{ +return 0 ; +} + +static void setexposure (struct gspca_dev *gspca_dev,s32 val) +{ +if (val <0 ) + val =0 ; +else if (val >0xf0 ) + val =0xf0 ; + +/* exposure (0x1800 - 0x18f0) */ +usb_dev_write (gspca_dev,0x9 ,0x1800 +val,1 ,0 ); +} + +/* -- start the camera -- */ +static int sd_start (struct gspca_dev *gspca_dev) +{ +struct sd *sd = (struct sd *) gspca_dev; +#if 0 +__u8 *b = gspca_dev->usb_buf; +__u8 data[160 ], data2[136 ]; +u16 idx; +#endif +pr_devel ("sd_start" ); + sd->count =0 ; + +usb_dev_write (gspca_dev,0x2 ,0x1 ,0xf ,0 ); +#if 0 +for (idx =0 ; idx <0xa0 ; idx +=2 ) { +usb_dev_read (gspca_dev,0x11 ,0 , idx,3 ); + data[idx] = b[0 ]; + data[idx +1 ] = b[1 ]; + } +usb_dev_read (gspca_dev,0xa ,0x17a0 ,0x16a0 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x16a0 ,0x16a3 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x16a0 ,0x16a4 ,1 ); +#endif +usb_dev_write (gspca_dev,0x9 ,0 ,0 ,0 ); +usb_dev_read (gspca_dev,0xa ,0x16a0 ,0x16a4 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x1580 ,0x14e4 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x1bbd ,0x14e8 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x1630 ,0x14e6 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x1ead ,0x14ea ,1 ); +usb_dev_read (gspca_dev,0xa ,0x1563 ,0x27e0 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17a0 ,0x13a0 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17b0 ,0x13a4 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x12a0 ,0x14ec ,1 ); +usb_dev_read (gspca_dev,0xa ,0x1460 ,0x14ee ,1 ); +usb_dev_read (gspca_dev,0xa ,0x13f1 ,0x14e0 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x1cf4 ,0x14e2 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17a0 ,0x16a4 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17a1 ,0x16a4 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17a0 ,0x16a0 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17a2 ,0x14a4 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x1788 ,0x14a6 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17a5 ,0x14a0 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17a1 ,0x14a2 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17aa ,0x14a8 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17a2 ,0x14aa ,1 ); +usb_dev_read (gspca_dev,0xa ,0x8778 ,0x27ba ,1 ); +usb_dev_read (gspca_dev,0xa ,0x17a0 ,0x16a4 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x16a0 ,0x16a0 ,1 ); +usb_dev_read (gspca_dev,0xa ,0x18c0 ,0x27b2 ,1 ); +#if 0 +usb_dev_read (gspca_dev,0x11 ,0 ,0x24c0 ,3 ); +usb_dev_read (gspca_dev,0x11 ,0 ,0x24cc ,3 ); +usb_dev_read (gspca_dev,0x11 ,0 ,0x24ce ,3 ); +for (idx =0 ; idx <0x88 ; idx +=2 ) { +usb_dev_read (gspca_dev,0x11 ,0 , idx +0x2820 ,3 ); + data2[idx] = b[0 ]; + data2[idx +1 ] = b[1 ]; + } +#endif +usb_dev_write (gspca_dev,0x3 ,0x1 ,0xe ,0 ); +return 0 ; +} + +static void sd_stopN (struct gspca_dev *gspca_dev) +{ +pr_devel ("sd_stop" ); +usb_dev_write (gspca_dev,0x2 ,0x0 ,0xf ,0 ); +usb_dev_write (gspca_dev,0x3 ,0x0 ,0xe ,0 ); +} + +static void sd_pkt_scan (struct gspca_dev *gspca_dev, +u8 *data,/* bulk URB data */ +int len)/* bulk URB data length */ +{ +struct sd *sd = (struct sd *) gspca_dev; +#if 0 +size_t sizeimage = vga_mode[gspca_dev->curr_mode].sizeimage; +int packet_type; + +pr_devel ("packet: %d" , len); +if (sd->count <=0 ) { + packet_type =FIRST_PACKET ; + sd->count += len; + }else if (sd->count + len >= sizeimage) { + len = sizeimage - sd->count; + packet_type =LAST_PACKET ; + sd->count =0 ; + }else { + packet_type =INTER_PACKET ; + sd->count += len; + } +#else +int packet_type =INTER_PACKET ; + +if (len ==BULK_SIZE ) { +if (sd->count <=0 ) + packet_type =FIRST_PACKET ; + sd->count++; + }else { +pr_devel ("frame: %d, %d" , sd->count, len); + sd->count =0 ; + packet_type =LAST_PACKET ; + } +#endif +gspca_frame_add (gspca_dev, packet_type, data, len); +} + +static int sd_s_ctrl (struct v4l2_ctrl *ctrl) +{ +struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + +pr_devel ("sd_s_ctrl" ); + gspca_dev->usb_err =0 ; + +if (!gspca_dev->streaming) +return 0 ; + +switch (ctrl->id) { +case V4L2_CID_EXPOSURE : +pr_devel ("set exposure %x" , ctrl->val); +setexposure (gspca_dev, ctrl->val); +break ; + } + +return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +/* called at probe (after sd_init) */ +static int sd_init_controls (struct gspca_dev *gspca_dev) +{ +struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; +pr_devel ("sd_init_controls" ); + + gspca_dev->vdev.ctrl_handler = hdl; +v4l2_ctrl_handler_init (hdl,2 ); + +v4l2_ctrl_new_std (hdl, &sd_ctrl_ops, +V4L2_CID_EXPOSURE ,0 ,0xf0 ,1 ,0x5a ); + +if (hdl->error) { +pr_err ("Could not initialize controls\n" ); +return hdl->error; + } +return 0 ; +} + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name =MODULE_NAME , + .config = sd_config, + .init = sd_init, + .init_controls = sd_init_controls, + .start = sd_start, + .stopN = sd_stopN, + .pkt_scan = sd_pkt_scan, +}; + +/* supported device list */ +static const struct usb_device_id device_table[] = { + {USB_DEVICE (0x0547 ,0x92a0 )},/* AmScope MT1000 */ + {} +}; + +MODULE_DEVICE_TABLE (usb, device_table); + +/* -- device connect -- */ +static int sd_probe (struct usb_interface *intf, +const struct usb_device_id *id) +{ +pr_devel ("sd_probe, alt=%d, vendor=%04x, product=%04x" , + intf->num_altsetting, id->idVendor, id->idProduct); +return gspca_dev_probe (intf, id, &sd_desc, +sizeof (struct sd ),THIS_MODULE ); +} + +static struct usb_driver sd_driver = { + .name =MODULE_NAME , + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +module_usb_driver (sd_driver); --To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html