linux/drivers/media/usb/uvc/uvc_status.c
<<
>>
Prefs
   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
  21static 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
  47error:
  48        input_free_device(input);
  49        return ret;
  50}
  51
  52static void uvc_input_unregister(struct uvc_device *dev)
  53{
  54        if (dev->input)
  55                input_unregister_device(dev->input);
  56}
  57
  58static 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 */
  76struct uvc_streaming_status {
  77        u8      bStatusType;
  78        u8      bOriginator;
  79        u8      bEvent;
  80        u8      bValue[];
  81} __packed;
  82
  83struct uvc_control_status {
  84        u8      bStatusType;
  85        u8      bOriginator;
  86        u8      bEvent;
  87        u8      bSelector;
  88        u8      bAttribute;
  89        u8      bValue[];
  90} __packed;
  91
  92static void uvc_event_streaming(struct uvc_device *dev,
  93                                struct uvc_streaming_status *status, int len)
  94{
  95        if (len < 3) {
  96                uvc_dbg(dev, STATUS,
  97                        "Invalid streaming status event received\n");
  98                return;
  99        }
 100
 101        if (status->bEvent == 0) {
 102                if (len < 4)
 103                        return;
 104                uvc_dbg(dev, 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_dbg(dev, STATUS, "Stream %u error event %02x len %d\n",
 110                        status->bOriginator, status->bEvent, len);
 111        }
 112}
 113
 114#define UVC_CTRL_VALUE_CHANGE   0
 115#define UVC_CTRL_INFO_CHANGE    1
 116#define UVC_CTRL_FAILURE_CHANGE 2
 117#define UVC_CTRL_MIN_CHANGE     3
 118#define UVC_CTRL_MAX_CHANGE     4
 119
 120static struct uvc_control *uvc_event_entity_find_ctrl(struct uvc_entity *entity,
 121                                                      u8 selector)
 122{
 123        struct uvc_control *ctrl;
 124        unsigned int i;
 125
 126        for (i = 0, ctrl = entity->controls; i < entity->ncontrols; i++, ctrl++)
 127                if (ctrl->info.selector == selector)
 128                        return ctrl;
 129
 130        return NULL;
 131}
 132
 133static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev,
 134                                        const struct uvc_control_status *status,
 135                                        struct uvc_video_chain **chain)
 136{
 137        list_for_each_entry((*chain), &dev->chains, list) {
 138                struct uvc_entity *entity;
 139                struct uvc_control *ctrl;
 140
 141                list_for_each_entry(entity, &(*chain)->entities, chain) {
 142                        if (entity->id != status->bOriginator)
 143                                continue;
 144
 145                        ctrl = uvc_event_entity_find_ctrl(entity,
 146                                                          status->bSelector);
 147                        if (ctrl)
 148                                return ctrl;
 149                }
 150        }
 151
 152        return NULL;
 153}
 154
 155static bool uvc_event_control(struct urb *urb,
 156                              const struct uvc_control_status *status, int len)
 157{
 158        static const char *attrs[] = { "value", "info", "failure", "min", "max" };
 159        struct uvc_device *dev = urb->context;
 160        struct uvc_video_chain *chain;
 161        struct uvc_control *ctrl;
 162
 163        if (len < 6 || status->bEvent != 0 ||
 164            status->bAttribute >= ARRAY_SIZE(attrs)) {
 165                uvc_dbg(dev, STATUS, "Invalid control status event received\n");
 166                return false;
 167        }
 168
 169        uvc_dbg(dev, STATUS, "Control %u/%u %s change len %d\n",
 170                status->bOriginator, status->bSelector,
 171                attrs[status->bAttribute], len);
 172
 173        /* Find the control. */
 174        ctrl = uvc_event_find_ctrl(dev, status, &chain);
 175        if (!ctrl)
 176                return false;
 177
 178        switch (status->bAttribute) {
 179        case UVC_CTRL_VALUE_CHANGE:
 180                return uvc_ctrl_status_event_async(urb, chain, ctrl,
 181                                                   status->bValue);
 182
 183        case UVC_CTRL_INFO_CHANGE:
 184        case UVC_CTRL_FAILURE_CHANGE:
 185        case UVC_CTRL_MIN_CHANGE:
 186        case UVC_CTRL_MAX_CHANGE:
 187                break;
 188        }
 189
 190        return false;
 191}
 192
 193static void uvc_status_complete(struct urb *urb)
 194{
 195        struct uvc_device *dev = urb->context;
 196        int len, ret;
 197
 198        switch (urb->status) {
 199        case 0:
 200                break;
 201
 202        case -ENOENT:           /* usb_kill_urb() called. */
 203        case -ECONNRESET:       /* usb_unlink_urb() called. */
 204        case -ESHUTDOWN:        /* The endpoint is being disabled. */
 205        case -EPROTO:           /* Device is disconnected (reported by some
 206                                 * host controller). */
 207                return;
 208
 209        default:
 210                dev_warn(&dev->udev->dev,
 211                         "Non-zero status (%d) in status completion handler.\n",
 212                         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_dbg(dev, STATUS, "Unknown status event type %u\n",
 239                                dev->status[0]);
 240                        break;
 241                }
 242        }
 243
 244        /* Resubmit the URB. */
 245        urb->interval = dev->int_ep->desc.bInterval;
 246        ret = usb_submit_urb(urb, GFP_ATOMIC);
 247        if (ret < 0)
 248                dev_err(&dev->udev->dev,
 249                        "Failed to resubmit status URB (%d).\n", ret);
 250}
 251
 252int 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
 290void uvc_status_unregister(struct uvc_device *dev)
 291{
 292        usb_kill_urb(dev->int_urb);
 293        uvc_input_unregister(dev);
 294}
 295
 296void uvc_status_cleanup(struct uvc_device *dev)
 297{
 298        usb_free_urb(dev->int_urb);
 299        kfree(dev->status);
 300}
 301
 302int 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
 310void uvc_status_stop(struct uvc_device *dev)
 311{
 312        usb_kill_urb(dev->int_urb);
 313}
 314