root/drivers/media/usb/uvc/uvc_status.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. uvc_input_init
  2. uvc_input_unregister
  3. uvc_input_report_key
  4. uvc_event_streaming
  5. uvc_event_entity_find_ctrl
  6. uvc_event_find_ctrl
  7. uvc_event_control
  8. uvc_status_complete
  9. uvc_status_init
  10. uvc_status_unregister
  11. uvc_status_cleanup
  12. uvc_status_start
  13. uvc_status_stop

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *      uvc_status.c  --  USB Video Class driver - Status endpoint
   4  *
   5  *      Copyright (C) 2005-2009
   6  *          Laurent Pinchart (laurent.pinchart@ideasonboard.com)
   7  */
   8 
   9 #include <linux/kernel.h>
  10 #include <linux/input.h>
  11 #include <linux/slab.h>
  12 #include <linux/usb.h>
  13 #include <linux/usb/input.h>
  14 
  15 #include "uvcvideo.h"
  16 
  17 /* --------------------------------------------------------------------------
  18  * Input device
  19  */
  20 #ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
  21 static int uvc_input_init(struct uvc_device *dev)
  22 {
  23         struct input_dev *input;
  24         int ret;
  25 
  26         input = input_allocate_device();
  27         if (input == NULL)
  28                 return -ENOMEM;
  29 
  30         usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys));
  31         strlcat(dev->input_phys, "/button", sizeof(dev->input_phys));
  32 
  33         input->name = dev->name;
  34         input->phys = dev->input_phys;
  35         usb_to_input_id(dev->udev, &input->id);
  36         input->dev.parent = &dev->intf->dev;
  37 
  38         __set_bit(EV_KEY, input->evbit);
  39         __set_bit(KEY_CAMERA, input->keybit);
  40 
  41         if ((ret = input_register_device(input)) < 0)
  42                 goto error;
  43 
  44         dev->input = input;
  45         return 0;
  46 
  47 error:
  48         input_free_device(input);
  49         return ret;
  50 }
  51 
  52 static void uvc_input_unregister(struct uvc_device *dev)
  53 {
  54         if (dev->input)
  55                 input_unregister_device(dev->input);
  56 }
  57 
  58 static void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
  59         int value)
  60 {
  61         if (dev->input) {
  62                 input_report_key(dev->input, code, value);
  63                 input_sync(dev->input);
  64         }
  65 }
  66 
  67 #else
  68 #define uvc_input_init(dev)
  69 #define uvc_input_unregister(dev)
  70 #define uvc_input_report_key(dev, code, value)
  71 #endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */
  72 
  73 /* --------------------------------------------------------------------------
  74  * Status interrupt endpoint
  75  */
  76 struct uvc_streaming_status {
  77         u8      bStatusType;
  78         u8      bOriginator;
  79         u8      bEvent;
  80         u8      bValue[];
  81 } __packed;
  82 
  83 struct uvc_control_status {
  84         u8      bStatusType;
  85         u8      bOriginator;
  86         u8      bEvent;
  87         u8      bSelector;
  88         u8      bAttribute;
  89         u8      bValue[];
  90 } __packed;
  91 
  92 static void uvc_event_streaming(struct uvc_device *dev,
  93                                 struct uvc_streaming_status *status, int len)
  94 {
  95         if (len < 3) {
  96                 uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event "
  97                                 "received.\n");
  98                 return;
  99         }
 100 
 101         if (status->bEvent == 0) {
 102                 if (len < 4)
 103                         return;
 104                 uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n",
 105                           status->bOriginator,
 106                           status->bValue[0] ? "pressed" : "released", len);
 107                 uvc_input_report_key(dev, KEY_CAMERA, status->bValue[0]);
 108         } else {
 109                 uvc_trace(UVC_TRACE_STATUS,
 110                           "Stream %u error event %02x len %d.\n",
 111                           status->bOriginator, status->bEvent, len);
 112         }
 113 }
 114 
 115 #define UVC_CTRL_VALUE_CHANGE   0
 116 #define UVC_CTRL_INFO_CHANGE    1
 117 #define UVC_CTRL_FAILURE_CHANGE 2
 118 #define UVC_CTRL_MIN_CHANGE     3
 119 #define UVC_CTRL_MAX_CHANGE     4
 120 
 121 static struct uvc_control *uvc_event_entity_find_ctrl(struct uvc_entity *entity,
 122                                                       u8 selector)
 123 {
 124         struct uvc_control *ctrl;
 125         unsigned int i;
 126 
 127         for (i = 0, ctrl = entity->controls; i < entity->ncontrols; i++, ctrl++)
 128                 if (ctrl->info.selector == selector)
 129                         return ctrl;
 130 
 131         return NULL;
 132 }
 133 
 134 static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev,
 135                                         const struct uvc_control_status *status,
 136                                         struct uvc_video_chain **chain)
 137 {
 138         list_for_each_entry((*chain), &dev->chains, list) {
 139                 struct uvc_entity *entity;
 140                 struct uvc_control *ctrl;
 141 
 142                 list_for_each_entry(entity, &(*chain)->entities, chain) {
 143                         if (entity->id != status->bOriginator)
 144                                 continue;
 145 
 146                         ctrl = uvc_event_entity_find_ctrl(entity,
 147                                                           status->bSelector);
 148                         if (ctrl)
 149                                 return ctrl;
 150                 }
 151         }
 152 
 153         return NULL;
 154 }
 155 
 156 static bool uvc_event_control(struct urb *urb,
 157                               const struct uvc_control_status *status, int len)
 158 {
 159         static const char *attrs[] = { "value", "info", "failure", "min", "max" };
 160         struct uvc_device *dev = urb->context;
 161         struct uvc_video_chain *chain;
 162         struct uvc_control *ctrl;
 163 
 164         if (len < 6 || status->bEvent != 0 ||
 165             status->bAttribute >= ARRAY_SIZE(attrs)) {
 166                 uvc_trace(UVC_TRACE_STATUS, "Invalid control status event "
 167                                 "received.\n");
 168                 return false;
 169         }
 170 
 171         uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n",
 172                   status->bOriginator, status->bSelector,
 173                   attrs[status->bAttribute], len);
 174 
 175         /* Find the control. */
 176         ctrl = uvc_event_find_ctrl(dev, status, &chain);
 177         if (!ctrl)
 178                 return false;
 179 
 180         switch (status->bAttribute) {
 181         case UVC_CTRL_VALUE_CHANGE:
 182                 return uvc_ctrl_status_event(urb, chain, ctrl, status->bValue);
 183 
 184         case UVC_CTRL_INFO_CHANGE:
 185         case UVC_CTRL_FAILURE_CHANGE:
 186         case UVC_CTRL_MIN_CHANGE:
 187         case UVC_CTRL_MAX_CHANGE:
 188                 break;
 189         }
 190 
 191         return false;
 192 }
 193 
 194 static void uvc_status_complete(struct urb *urb)
 195 {
 196         struct uvc_device *dev = urb->context;
 197         int len, ret;
 198 
 199         switch (urb->status) {
 200         case 0:
 201                 break;
 202 
 203         case -ENOENT:           /* usb_kill_urb() called. */
 204         case -ECONNRESET:       /* usb_unlink_urb() called. */
 205         case -ESHUTDOWN:        /* The endpoint is being disabled. */
 206         case -EPROTO:           /* Device is disconnected (reported by some
 207                                  * host controller). */
 208                 return;
 209 
 210         default:
 211                 uvc_printk(KERN_WARNING, "Non-zero status (%d) in status "
 212                         "completion handler.\n", urb->status);
 213                 return;
 214         }
 215 
 216         len = urb->actual_length;
 217         if (len > 0) {
 218                 switch (dev->status[0] & 0x0f) {
 219                 case UVC_STATUS_TYPE_CONTROL: {
 220                         struct uvc_control_status *status =
 221                                 (struct uvc_control_status *)dev->status;
 222 
 223                         if (uvc_event_control(urb, status, len))
 224                                 /* The URB will be resubmitted in work context. */
 225                                 return;
 226                         break;
 227                 }
 228 
 229                 case UVC_STATUS_TYPE_STREAMING: {
 230                         struct uvc_streaming_status *status =
 231                                 (struct uvc_streaming_status *)dev->status;
 232 
 233                         uvc_event_streaming(dev, status, len);
 234                         break;
 235                 }
 236 
 237                 default:
 238                         uvc_trace(UVC_TRACE_STATUS, "Unknown status event "
 239                                 "type %u.\n", dev->status[0]);
 240                         break;
 241                 }
 242         }
 243 
 244         /* Resubmit the URB. */
 245         urb->interval = dev->int_ep->desc.bInterval;
 246         if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
 247                 uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
 248                         ret);
 249         }
 250 }
 251 
 252 int uvc_status_init(struct uvc_device *dev)
 253 {
 254         struct usb_host_endpoint *ep = dev->int_ep;
 255         unsigned int pipe;
 256         int interval;
 257 
 258         if (ep == NULL)
 259                 return 0;
 260 
 261         uvc_input_init(dev);
 262 
 263         dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL);
 264         if (dev->status == NULL)
 265                 return -ENOMEM;
 266 
 267         dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
 268         if (dev->int_urb == NULL) {
 269                 kfree(dev->status);
 270                 return -ENOMEM;
 271         }
 272 
 273         pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
 274 
 275         /* For high-speed interrupt endpoints, the bInterval value is used as
 276          * an exponent of two. Some developers forgot about it.
 277          */
 278         interval = ep->desc.bInterval;
 279         if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH &&
 280             (dev->quirks & UVC_QUIRK_STATUS_INTERVAL))
 281                 interval = fls(interval) - 1;
 282 
 283         usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
 284                 dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
 285                 dev, interval);
 286 
 287         return 0;
 288 }
 289 
 290 void uvc_status_unregister(struct uvc_device *dev)
 291 {
 292         usb_kill_urb(dev->int_urb);
 293         uvc_input_unregister(dev);
 294 }
 295 
 296 void uvc_status_cleanup(struct uvc_device *dev)
 297 {
 298         usb_free_urb(dev->int_urb);
 299         kfree(dev->status);
 300 }
 301 
 302 int uvc_status_start(struct uvc_device *dev, gfp_t flags)
 303 {
 304         if (dev->int_urb == NULL)
 305                 return 0;
 306 
 307         return usb_submit_urb(dev->int_urb, flags);
 308 }
 309 
 310 void uvc_status_stop(struct uvc_device *dev)
 311 {
 312         usb_kill_urb(dev->int_urb);
 313 }

/* [<][>][^][v][top][bottom][index][help] */