Hi, Hans de Goede wrote: > Hi, > > Thanks for working on this! I think it would be great if we could > get support for camera buttons in general into gspca. > > I've not looked closely at your code yet, have you looked at > the camera button code in the gspca sn9c20x.c driver? Also I would really As you proposed I had a look on sn9c20x. It seems that sn9c20x uses register read via USB control message. The pac7302 uses interrupt endpoint. So it looks like quite different to me. Currently I see the common point in the connection to input subsystem only. > like to see as much of the button handling code as possible go into > the gspca core. AFAIK many many camera's use an usb interrupt ep for this, so > I would like to see the setting up and cleanup of this interrupt ep be in > the core (as said before see the sn9c20x driver for another driver which > does such things). Unfortunately I do not know how the USB descriptors of other webcams look like. I have access to two webcams which are handled by gspca: 1. Labtec Webcam 2200 (USB ID 093a:2626): Interface Number: 0 Name: (none) Alternate Number: 0 Class: ff(vend.) Sub Class: ff Protocol: ff Number of Endpoints: 6 [...] Endpoint Address: 83 Direction: in Attribute: 3 Type: Int. Max Packet Size: 2 Interval: 50ms This endpoint handles the capture button. 2. Trust 610 LCD PowerC@m Zoom (USB ID 06d6:0031) Interface Number: 1 Name: (none) Alternate Number: 0 Class: ff(vend.) Sub Class: 00 Protocol: 00 Number of Endpoints: 3 [...] Endpoint Address: 84 Direction: in Attribute: 3 Type: Int. Max Packet Size: 1 Interval: 1ms I don't know what this interrupt endpoint is useful for. Comparing these two endpoints shows the common and different points: Common: interface class, endpoint direction, endpoint type. Different: interface number, sub class, protocol, endpoint address, max packet size, interval. Maybe the second example is not a good one because I don't know whether the interrupt endpoint is used for buttons or not. Do you have access to webcams equipped with button? Could you please send the device descriptor (lsusb -v) about these devices in order the common points can be identified for interrupt endpoints? Regards, Márton Németh > On 11/15/2009 09:47 AM, Németh Márton wrote: >> From: Márton Németh<nm127@xxxxxxxxxxx> >> >> Add support for snapshot button found on Labtec Webcam 2200. >> >> Signed-off-by: Márton Németh<nm127@xxxxxxxxxxx> >> --- >> Hi, >> >> this is the first trial to add support for the snapshot button. This >> code is working only before the streaming is started. When the streaming >> is started the alternate number of the interface 0 is changed and the >> interrupt URB is no longer usable. I guess the interrupt URB is to >> be reconstructed every time when the alternate number is changed. >> >> When I disconnect the device I get the following error: >> >> uhci_hcd 0000:00:1d.1: dma_pool_free buffer-32, f58ba168/358ba168 (bad dma) >> >> I guess something is wrong in this patch with the cleanup routine. >> >> Regards, >> >> Márton Németh >> >> --- >> diff -r 09c1284de47d linux/drivers/media/video/gspca/gspca.h >> --- a/linux/drivers/media/video/gspca/gspca.h Sat Nov 14 08:58:12 2009 +0100 >> +++ b/linux/drivers/media/video/gspca/gspca.h Sun Nov 15 10:40:54 2009 +0100 >> @@ -138,6 +138,7 @@ >> struct module *module; /* subdriver handling the device */ >> struct usb_device *dev; >> struct file *capt_file; /* file doing video capture */ >> + struct input_dev *input_dev; >> >> struct cam cam; /* device information */ >> const struct sd_desc *sd_desc; /* subdriver description */ >> @@ -147,6 +148,7 @@ >> #define USB_BUF_SZ 64 >> __u8 *usb_buf; /* buffer for USB exchanges */ >> struct urb *urb[MAX_NURBS]; >> + struct urb *int_urb; >> >> __u8 *frbuf; /* buffer for nframes */ >> struct gspca_frame frame[GSPCA_MAX_FRAMES]; >> diff -r 09c1284de47d linux/drivers/media/video/gspca/pac7302.c >> --- a/linux/drivers/media/video/gspca/pac7302.c Sat Nov 14 08:58:12 2009 +0100 >> +++ b/linux/drivers/media/video/gspca/pac7302.c Sun Nov 15 10:40:54 2009 +0100 >> @@ -68,6 +68,7 @@ >> >> #define MODULE_NAME "pac7302" >> >> +#include<linux/input.h> >> #include<media/v4l2-chip-ident.h> >> #include "gspca.h" >> >> @@ -1220,6 +1221,50 @@ >> } >> #endif >> >> +#if LINUX_VERSION_CODE< KERNEL_VERSION(2, 6, 19) >> +static void int_irq(struct urb *urb, struct pt_regs *regs) >> +#else >> +static void int_irq(struct urb *urb) >> +#endif >> +{ >> + struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; >> + int ret; >> + int i; >> + __u8 data0, data1; >> + >> + printk(KERN_DEBUG "int_irq()\n"); >> + printk(KERN_DEBUG "urb->status: %i\n", urb->status); >> + if (urb->status == 0) { >> + printk(KERN_DEBUG "urb->actual_length: %u\n", urb->actual_length); >> + for (i = 0; i< urb->actual_length; i++) { >> + printk(KERN_DEBUG "urb->transfer_buffer[%i]=0x%x\n", >> + i, ((__u8*)urb->transfer_buffer)[i]); >> + } >> + if (urb->actual_length == 2) { >> + data0 = ((__u8*)urb->transfer_buffer)[0]; >> + data1 = ((__u8*)urb->transfer_buffer)[1]; >> + if ((data0 == 0x00&& data1 == 0x11) || >> + (data0 == 0x22&& data1 == 0x33) || >> + (data0 == 0x44&& data1 == 0x55) || >> + (data0 == 0x66&& data1 == 0x77) || >> + (data0 == 0x88&& data1 == 0x99) || >> + (data0 == 0xaa&& data1 == 0xbb) || >> + (data0 == 0xcc&& data1 == 0xdd) || >> + (data0 == 0xee&& data1 == 0xff)) { >> + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); >> + input_sync(gspca_dev->input_dev); >> + input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); >> + input_sync(gspca_dev->input_dev); >> + } else >> + printk(KERN_DEBUG "Unknown packet received\n"); >> + } >> + ret = usb_submit_urb(urb, GFP_ATOMIC); >> + printk(KERN_DEBUG "resubmit urb: %i\n", ret); >> + } >> + >> +} >> + >> + >> /* sub-driver description for pac7302 */ >> static struct sd_desc sd_desc = { >> .name = MODULE_NAME, >> @@ -1254,19 +1299,132 @@ >> }; >> MODULE_DEVICE_TABLE(usb, device_table); >> >> +static int init_camera_input(struct gspca_dev *gspca_dev, const struct usb_device_id *id) >> +{ >> + struct input_dev *input_dev; >> + int err; >> + >> + printk(KERN_DEBUG "allocating input device\n"); >> + input_dev = input_allocate_device(); >> + if (!input_dev) >> + return -ENOMEM; >> + >> + //input_dev->name = "Camera capture button"; >> + //input_dev->phys = "camera"; >> + input_dev->id.bustype = BUS_USB; >> + input_dev->id.vendor = id->idVendor; >> + input_dev->id.product = id->idProduct; >> + input_dev->id.version = id->bcdDevice_hi; >> + //input_dev->id.version = id->bcdDevice_lo; >> + >> + input_dev->evbit[0] = BIT_MASK(EV_KEY); >> + input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA); >> + //input_dev->dev.parent = ; >> + >> + printk(KERN_DEBUG "registering input device\n"); >> + err = input_register_device(input_dev); >> + if (err) { >> + input_dev->dev.parent = NULL; >> + input_free_device(input_dev); >> + } else { >> + gspca_dev->input_dev = input_dev; >> + } >> + >> + return err; >> +} >> + >> /* -- device connect -- */ >> static int sd_probe(struct usb_interface *intf, >> const struct usb_device_id *id) >> { >> - return gspca_dev_probe(intf, id,&sd_desc, sizeof(struct sd), >> + int ret; >> + struct usb_host_interface *intf_desc; >> + struct usb_endpoint_descriptor *ep; >> + int i; >> + >> + struct urb *urb; >> + void* buffer = NULL; >> + unsigned int buffer_len; >> + int interval; >> + struct gspca_dev *gspca_dev; >> + struct usb_device *dev; >> + >> + ret = gspca_dev_probe(intf, id,&sd_desc, sizeof(struct sd), >> THIS_MODULE); >> + if (0<= ret) { >> + intf_desc = intf->cur_altsetting; >> + for (i = 0; i< intf_desc->desc.bNumEndpoints; i++) { >> + ep =&intf_desc->endpoint[i].desc; >> + if ((ep->bEndpointAddress& USB_DIR_IN)&& >> + ((ep->bmAttributes& USB_ENDPOINT_XFERTYPE_MASK) >> + == USB_ENDPOINT_XFER_INT)) { >> + >> + buffer_len = ep->wMaxPacketSize; >> + interval = ep->bInterval; >> + printk(KERN_DEBUG "found int in endpoint: 0x%x\n", ep->bEndpointAddress); >> + printk(KERN_DEBUG " - buffer_len = %u\n", buffer_len); >> + printk(KERN_DEBUG " - interval = %u\n", interval); >> + >> + gspca_dev = usb_get_intfdata(intf); >> + dev = gspca_dev->dev; >> + gspca_dev->int_urb = NULL; >> + gspca_dev->input_dev = NULL; >> + >> + buffer = kmalloc(ep->wMaxPacketSize, GFP_KERNEL); >> + if (buffer) >> + urb = usb_alloc_urb(0, GFP_KERNEL); >> + else { >> + kfree(buffer); >> + urb = NULL; >> + } >> + if (buffer&& urb) { >> + usb_fill_int_urb(urb, dev, >> + usb_rcvintpipe(dev, ep->bEndpointAddress), >> + buffer, buffer_len, >> + int_irq, (void*)gspca_dev, interval); >> + ret = init_camera_input(gspca_dev, id); >> + if (0<= ret) { >> + gspca_dev->int_urb = urb; >> + ret = usb_submit_urb(urb, GFP_KERNEL); >> + printk(KERN_DEBUG "usb_submit_urb() returns %i\n", ret); >> + } >> + } >> + } >> + >> + } >> + } >> + return ret; >> +} >> + >> +static void sd_disconnect(struct usb_interface *intf) >> +{ >> + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); >> + struct urb *urb; >> + struct input_dev *input_dev; >> + >> + urb = gspca_dev->int_urb; >> + if (urb != NULL) { >> + gspca_dev->int_urb = NULL; >> + usb_kill_urb(urb); >> + usb_buffer_free(gspca_dev->dev, >> + urb->transfer_buffer_length, >> + urb->transfer_buffer, >> + urb->transfer_dma); >> + usb_free_urb(urb); >> + } >> + input_dev = gspca_dev->input_dev; >> + if (input_dev) { >> + gspca_dev->input_dev = NULL; >> + input_unregister_device(input_dev); >> + } >> + gspca_disconnect(intf); >> } >> >> static struct usb_driver sd_driver = { >> .name = MODULE_NAME, >> .id_table = device_table, >> .probe = sd_probe, >> - .disconnect = gspca_disconnect, >> + .disconnect = sd_disconnect, >> #ifdef CONFIG_PM >> .suspend = gspca_suspend, >> .resume = gspca_resume, -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html