1*0c0d06caSMauro Carvalho Chehab /* 2*0c0d06caSMauro Carvalho Chehab * uvc_status.c -- USB Video Class driver - Status endpoint 3*0c0d06caSMauro Carvalho Chehab * 4*0c0d06caSMauro Carvalho Chehab * Copyright (C) 2005-2009 5*0c0d06caSMauro Carvalho Chehab * Laurent Pinchart (laurent.pinchart@ideasonboard.com) 6*0c0d06caSMauro Carvalho Chehab * 7*0c0d06caSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 8*0c0d06caSMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 9*0c0d06caSMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 10*0c0d06caSMauro Carvalho Chehab * (at your option) any later version. 11*0c0d06caSMauro Carvalho Chehab * 12*0c0d06caSMauro Carvalho Chehab */ 13*0c0d06caSMauro Carvalho Chehab 14*0c0d06caSMauro Carvalho Chehab #include <linux/kernel.h> 15*0c0d06caSMauro Carvalho Chehab #include <linux/input.h> 16*0c0d06caSMauro Carvalho Chehab #include <linux/slab.h> 17*0c0d06caSMauro Carvalho Chehab #include <linux/usb.h> 18*0c0d06caSMauro Carvalho Chehab #include <linux/usb/input.h> 19*0c0d06caSMauro Carvalho Chehab 20*0c0d06caSMauro Carvalho Chehab #include "uvcvideo.h" 21*0c0d06caSMauro Carvalho Chehab 22*0c0d06caSMauro Carvalho Chehab /* -------------------------------------------------------------------------- 23*0c0d06caSMauro Carvalho Chehab * Input device 24*0c0d06caSMauro Carvalho Chehab */ 25*0c0d06caSMauro Carvalho Chehab #ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV 26*0c0d06caSMauro Carvalho Chehab static int uvc_input_init(struct uvc_device *dev) 27*0c0d06caSMauro Carvalho Chehab { 28*0c0d06caSMauro Carvalho Chehab struct input_dev *input; 29*0c0d06caSMauro Carvalho Chehab int ret; 30*0c0d06caSMauro Carvalho Chehab 31*0c0d06caSMauro Carvalho Chehab input = input_allocate_device(); 32*0c0d06caSMauro Carvalho Chehab if (input == NULL) 33*0c0d06caSMauro Carvalho Chehab return -ENOMEM; 34*0c0d06caSMauro Carvalho Chehab 35*0c0d06caSMauro Carvalho Chehab usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys)); 36*0c0d06caSMauro Carvalho Chehab strlcat(dev->input_phys, "/button", sizeof(dev->input_phys)); 37*0c0d06caSMauro Carvalho Chehab 38*0c0d06caSMauro Carvalho Chehab input->name = dev->name; 39*0c0d06caSMauro Carvalho Chehab input->phys = dev->input_phys; 40*0c0d06caSMauro Carvalho Chehab usb_to_input_id(dev->udev, &input->id); 41*0c0d06caSMauro Carvalho Chehab input->dev.parent = &dev->intf->dev; 42*0c0d06caSMauro Carvalho Chehab 43*0c0d06caSMauro Carvalho Chehab __set_bit(EV_KEY, input->evbit); 44*0c0d06caSMauro Carvalho Chehab __set_bit(KEY_CAMERA, input->keybit); 45*0c0d06caSMauro Carvalho Chehab 46*0c0d06caSMauro Carvalho Chehab if ((ret = input_register_device(input)) < 0) 47*0c0d06caSMauro Carvalho Chehab goto error; 48*0c0d06caSMauro Carvalho Chehab 49*0c0d06caSMauro Carvalho Chehab dev->input = input; 50*0c0d06caSMauro Carvalho Chehab return 0; 51*0c0d06caSMauro Carvalho Chehab 52*0c0d06caSMauro Carvalho Chehab error: 53*0c0d06caSMauro Carvalho Chehab input_free_device(input); 54*0c0d06caSMauro Carvalho Chehab return ret; 55*0c0d06caSMauro Carvalho Chehab } 56*0c0d06caSMauro Carvalho Chehab 57*0c0d06caSMauro Carvalho Chehab static void uvc_input_cleanup(struct uvc_device *dev) 58*0c0d06caSMauro Carvalho Chehab { 59*0c0d06caSMauro Carvalho Chehab if (dev->input) 60*0c0d06caSMauro Carvalho Chehab input_unregister_device(dev->input); 61*0c0d06caSMauro Carvalho Chehab } 62*0c0d06caSMauro Carvalho Chehab 63*0c0d06caSMauro Carvalho Chehab static void uvc_input_report_key(struct uvc_device *dev, unsigned int code, 64*0c0d06caSMauro Carvalho Chehab int value) 65*0c0d06caSMauro Carvalho Chehab { 66*0c0d06caSMauro Carvalho Chehab if (dev->input) { 67*0c0d06caSMauro Carvalho Chehab input_report_key(dev->input, code, value); 68*0c0d06caSMauro Carvalho Chehab input_sync(dev->input); 69*0c0d06caSMauro Carvalho Chehab } 70*0c0d06caSMauro Carvalho Chehab } 71*0c0d06caSMauro Carvalho Chehab 72*0c0d06caSMauro Carvalho Chehab #else 73*0c0d06caSMauro Carvalho Chehab #define uvc_input_init(dev) 74*0c0d06caSMauro Carvalho Chehab #define uvc_input_cleanup(dev) 75*0c0d06caSMauro Carvalho Chehab #define uvc_input_report_key(dev, code, value) 76*0c0d06caSMauro Carvalho Chehab #endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */ 77*0c0d06caSMauro Carvalho Chehab 78*0c0d06caSMauro Carvalho Chehab /* -------------------------------------------------------------------------- 79*0c0d06caSMauro Carvalho Chehab * Status interrupt endpoint 80*0c0d06caSMauro Carvalho Chehab */ 81*0c0d06caSMauro Carvalho Chehab static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len) 82*0c0d06caSMauro Carvalho Chehab { 83*0c0d06caSMauro Carvalho Chehab if (len < 3) { 84*0c0d06caSMauro Carvalho Chehab uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event " 85*0c0d06caSMauro Carvalho Chehab "received.\n"); 86*0c0d06caSMauro Carvalho Chehab return; 87*0c0d06caSMauro Carvalho Chehab } 88*0c0d06caSMauro Carvalho Chehab 89*0c0d06caSMauro Carvalho Chehab if (data[2] == 0) { 90*0c0d06caSMauro Carvalho Chehab if (len < 4) 91*0c0d06caSMauro Carvalho Chehab return; 92*0c0d06caSMauro Carvalho Chehab uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n", 93*0c0d06caSMauro Carvalho Chehab data[1], data[3] ? "pressed" : "released", len); 94*0c0d06caSMauro Carvalho Chehab uvc_input_report_key(dev, KEY_CAMERA, data[3]); 95*0c0d06caSMauro Carvalho Chehab } else { 96*0c0d06caSMauro Carvalho Chehab uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x " 97*0c0d06caSMauro Carvalho Chehab "len %d.\n", data[1], data[2], data[3], len); 98*0c0d06caSMauro Carvalho Chehab } 99*0c0d06caSMauro Carvalho Chehab } 100*0c0d06caSMauro Carvalho Chehab 101*0c0d06caSMauro Carvalho Chehab static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len) 102*0c0d06caSMauro Carvalho Chehab { 103*0c0d06caSMauro Carvalho Chehab char *attrs[3] = { "value", "info", "failure" }; 104*0c0d06caSMauro Carvalho Chehab 105*0c0d06caSMauro Carvalho Chehab if (len < 6 || data[2] != 0 || data[4] > 2) { 106*0c0d06caSMauro Carvalho Chehab uvc_trace(UVC_TRACE_STATUS, "Invalid control status event " 107*0c0d06caSMauro Carvalho Chehab "received.\n"); 108*0c0d06caSMauro Carvalho Chehab return; 109*0c0d06caSMauro Carvalho Chehab } 110*0c0d06caSMauro Carvalho Chehab 111*0c0d06caSMauro Carvalho Chehab uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n", 112*0c0d06caSMauro Carvalho Chehab data[1], data[3], attrs[data[4]], len); 113*0c0d06caSMauro Carvalho Chehab } 114*0c0d06caSMauro Carvalho Chehab 115*0c0d06caSMauro Carvalho Chehab static void uvc_status_complete(struct urb *urb) 116*0c0d06caSMauro Carvalho Chehab { 117*0c0d06caSMauro Carvalho Chehab struct uvc_device *dev = urb->context; 118*0c0d06caSMauro Carvalho Chehab int len, ret; 119*0c0d06caSMauro Carvalho Chehab 120*0c0d06caSMauro Carvalho Chehab switch (urb->status) { 121*0c0d06caSMauro Carvalho Chehab case 0: 122*0c0d06caSMauro Carvalho Chehab break; 123*0c0d06caSMauro Carvalho Chehab 124*0c0d06caSMauro Carvalho Chehab case -ENOENT: /* usb_kill_urb() called. */ 125*0c0d06caSMauro Carvalho Chehab case -ECONNRESET: /* usb_unlink_urb() called. */ 126*0c0d06caSMauro Carvalho Chehab case -ESHUTDOWN: /* The endpoint is being disabled. */ 127*0c0d06caSMauro Carvalho Chehab case -EPROTO: /* Device is disconnected (reported by some 128*0c0d06caSMauro Carvalho Chehab * host controller). */ 129*0c0d06caSMauro Carvalho Chehab return; 130*0c0d06caSMauro Carvalho Chehab 131*0c0d06caSMauro Carvalho Chehab default: 132*0c0d06caSMauro Carvalho Chehab uvc_printk(KERN_WARNING, "Non-zero status (%d) in status " 133*0c0d06caSMauro Carvalho Chehab "completion handler.\n", urb->status); 134*0c0d06caSMauro Carvalho Chehab return; 135*0c0d06caSMauro Carvalho Chehab } 136*0c0d06caSMauro Carvalho Chehab 137*0c0d06caSMauro Carvalho Chehab len = urb->actual_length; 138*0c0d06caSMauro Carvalho Chehab if (len > 0) { 139*0c0d06caSMauro Carvalho Chehab switch (dev->status[0] & 0x0f) { 140*0c0d06caSMauro Carvalho Chehab case UVC_STATUS_TYPE_CONTROL: 141*0c0d06caSMauro Carvalho Chehab uvc_event_control(dev, dev->status, len); 142*0c0d06caSMauro Carvalho Chehab break; 143*0c0d06caSMauro Carvalho Chehab 144*0c0d06caSMauro Carvalho Chehab case UVC_STATUS_TYPE_STREAMING: 145*0c0d06caSMauro Carvalho Chehab uvc_event_streaming(dev, dev->status, len); 146*0c0d06caSMauro Carvalho Chehab break; 147*0c0d06caSMauro Carvalho Chehab 148*0c0d06caSMauro Carvalho Chehab default: 149*0c0d06caSMauro Carvalho Chehab uvc_trace(UVC_TRACE_STATUS, "Unknown status event " 150*0c0d06caSMauro Carvalho Chehab "type %u.\n", dev->status[0]); 151*0c0d06caSMauro Carvalho Chehab break; 152*0c0d06caSMauro Carvalho Chehab } 153*0c0d06caSMauro Carvalho Chehab } 154*0c0d06caSMauro Carvalho Chehab 155*0c0d06caSMauro Carvalho Chehab /* Resubmit the URB. */ 156*0c0d06caSMauro Carvalho Chehab urb->interval = dev->int_ep->desc.bInterval; 157*0c0d06caSMauro Carvalho Chehab if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { 158*0c0d06caSMauro Carvalho Chehab uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n", 159*0c0d06caSMauro Carvalho Chehab ret); 160*0c0d06caSMauro Carvalho Chehab } 161*0c0d06caSMauro Carvalho Chehab } 162*0c0d06caSMauro Carvalho Chehab 163*0c0d06caSMauro Carvalho Chehab int uvc_status_init(struct uvc_device *dev) 164*0c0d06caSMauro Carvalho Chehab { 165*0c0d06caSMauro Carvalho Chehab struct usb_host_endpoint *ep = dev->int_ep; 166*0c0d06caSMauro Carvalho Chehab unsigned int pipe; 167*0c0d06caSMauro Carvalho Chehab int interval; 168*0c0d06caSMauro Carvalho Chehab 169*0c0d06caSMauro Carvalho Chehab if (ep == NULL) 170*0c0d06caSMauro Carvalho Chehab return 0; 171*0c0d06caSMauro Carvalho Chehab 172*0c0d06caSMauro Carvalho Chehab uvc_input_init(dev); 173*0c0d06caSMauro Carvalho Chehab 174*0c0d06caSMauro Carvalho Chehab dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL); 175*0c0d06caSMauro Carvalho Chehab if (dev->status == NULL) 176*0c0d06caSMauro Carvalho Chehab return -ENOMEM; 177*0c0d06caSMauro Carvalho Chehab 178*0c0d06caSMauro Carvalho Chehab dev->int_urb = usb_alloc_urb(0, GFP_KERNEL); 179*0c0d06caSMauro Carvalho Chehab if (dev->int_urb == NULL) { 180*0c0d06caSMauro Carvalho Chehab kfree(dev->status); 181*0c0d06caSMauro Carvalho Chehab return -ENOMEM; 182*0c0d06caSMauro Carvalho Chehab } 183*0c0d06caSMauro Carvalho Chehab 184*0c0d06caSMauro Carvalho Chehab pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress); 185*0c0d06caSMauro Carvalho Chehab 186*0c0d06caSMauro Carvalho Chehab /* For high-speed interrupt endpoints, the bInterval value is used as 187*0c0d06caSMauro Carvalho Chehab * an exponent of two. Some developers forgot about it. 188*0c0d06caSMauro Carvalho Chehab */ 189*0c0d06caSMauro Carvalho Chehab interval = ep->desc.bInterval; 190*0c0d06caSMauro Carvalho Chehab if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH && 191*0c0d06caSMauro Carvalho Chehab (dev->quirks & UVC_QUIRK_STATUS_INTERVAL)) 192*0c0d06caSMauro Carvalho Chehab interval = fls(interval) - 1; 193*0c0d06caSMauro Carvalho Chehab 194*0c0d06caSMauro Carvalho Chehab usb_fill_int_urb(dev->int_urb, dev->udev, pipe, 195*0c0d06caSMauro Carvalho Chehab dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete, 196*0c0d06caSMauro Carvalho Chehab dev, interval); 197*0c0d06caSMauro Carvalho Chehab 198*0c0d06caSMauro Carvalho Chehab return 0; 199*0c0d06caSMauro Carvalho Chehab } 200*0c0d06caSMauro Carvalho Chehab 201*0c0d06caSMauro Carvalho Chehab void uvc_status_cleanup(struct uvc_device *dev) 202*0c0d06caSMauro Carvalho Chehab { 203*0c0d06caSMauro Carvalho Chehab usb_kill_urb(dev->int_urb); 204*0c0d06caSMauro Carvalho Chehab usb_free_urb(dev->int_urb); 205*0c0d06caSMauro Carvalho Chehab kfree(dev->status); 206*0c0d06caSMauro Carvalho Chehab uvc_input_cleanup(dev); 207*0c0d06caSMauro Carvalho Chehab } 208*0c0d06caSMauro Carvalho Chehab 209*0c0d06caSMauro Carvalho Chehab int uvc_status_start(struct uvc_device *dev) 210*0c0d06caSMauro Carvalho Chehab { 211*0c0d06caSMauro Carvalho Chehab if (dev->int_urb == NULL) 212*0c0d06caSMauro Carvalho Chehab return 0; 213*0c0d06caSMauro Carvalho Chehab 214*0c0d06caSMauro Carvalho Chehab return usb_submit_urb(dev->int_urb, GFP_KERNEL); 215*0c0d06caSMauro Carvalho Chehab } 216*0c0d06caSMauro Carvalho Chehab 217*0c0d06caSMauro Carvalho Chehab void uvc_status_stop(struct uvc_device *dev) 218*0c0d06caSMauro Carvalho Chehab { 219*0c0d06caSMauro Carvalho Chehab usb_kill_urb(dev->int_urb); 220*0c0d06caSMauro Carvalho Chehab } 221*0c0d06caSMauro Carvalho Chehab 222*0c0d06caSMauro Carvalho Chehab int uvc_status_suspend(struct uvc_device *dev) 223*0c0d06caSMauro Carvalho Chehab { 224*0c0d06caSMauro Carvalho Chehab if (atomic_read(&dev->users)) 225*0c0d06caSMauro Carvalho Chehab usb_kill_urb(dev->int_urb); 226*0c0d06caSMauro Carvalho Chehab 227*0c0d06caSMauro Carvalho Chehab return 0; 228*0c0d06caSMauro Carvalho Chehab } 229*0c0d06caSMauro Carvalho Chehab 230*0c0d06caSMauro Carvalho Chehab int uvc_status_resume(struct uvc_device *dev) 231*0c0d06caSMauro Carvalho Chehab { 232*0c0d06caSMauro Carvalho Chehab if (dev->int_urb == NULL || atomic_read(&dev->users) == 0) 233*0c0d06caSMauro Carvalho Chehab return 0; 234*0c0d06caSMauro Carvalho Chehab 235*0c0d06caSMauro Carvalho Chehab return usb_submit_urb(dev->int_urb, GFP_NOIO); 236*0c0d06caSMauro Carvalho Chehab } 237*0c0d06caSMauro Carvalho Chehab 238