cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

uvc_status.c (7213B)


      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}