162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *      uvc_status.c  --  USB Video Class driver - Status endpoint
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *      Copyright (C) 2005-2009
662306a36Sopenharmony_ci *          Laurent Pinchart (laurent.pinchart@ideasonboard.com)
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <asm/barrier.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/input.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/usb.h>
1462306a36Sopenharmony_ci#include <linux/usb/input.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "uvcvideo.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* --------------------------------------------------------------------------
1962306a36Sopenharmony_ci * Input device
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci#ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic bool uvc_input_has_button(struct uvc_device *dev)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct uvc_streaming *stream;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	/*
2862306a36Sopenharmony_ci	 * The device has button events if both bTriggerSupport and
2962306a36Sopenharmony_ci	 * bTriggerUsage are one. Otherwise the camera button does not
3062306a36Sopenharmony_ci	 * exist or is handled automatically by the camera without host
3162306a36Sopenharmony_ci	 * driver or client application intervention.
3262306a36Sopenharmony_ci	 */
3362306a36Sopenharmony_ci	list_for_each_entry(stream, &dev->streams, list) {
3462306a36Sopenharmony_ci		if (stream->header.bTriggerSupport == 1 &&
3562306a36Sopenharmony_ci		    stream->header.bTriggerUsage == 1)
3662306a36Sopenharmony_ci			return true;
3762306a36Sopenharmony_ci	}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	return false;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cistatic int uvc_input_init(struct uvc_device *dev)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct input_dev *input;
4562306a36Sopenharmony_ci	int ret;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (!uvc_input_has_button(dev))
4862306a36Sopenharmony_ci		return 0;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	input = input_allocate_device();
5162306a36Sopenharmony_ci	if (input == NULL)
5262306a36Sopenharmony_ci		return -ENOMEM;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys));
5562306a36Sopenharmony_ci	strlcat(dev->input_phys, "/button", sizeof(dev->input_phys));
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	input->name = dev->name;
5862306a36Sopenharmony_ci	input->phys = dev->input_phys;
5962306a36Sopenharmony_ci	usb_to_input_id(dev->udev, &input->id);
6062306a36Sopenharmony_ci	input->dev.parent = &dev->intf->dev;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	__set_bit(EV_KEY, input->evbit);
6362306a36Sopenharmony_ci	__set_bit(KEY_CAMERA, input->keybit);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if ((ret = input_register_device(input)) < 0)
6662306a36Sopenharmony_ci		goto error;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	dev->input = input;
6962306a36Sopenharmony_ci	return 0;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cierror:
7262306a36Sopenharmony_ci	input_free_device(input);
7362306a36Sopenharmony_ci	return ret;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic void uvc_input_unregister(struct uvc_device *dev)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	if (dev->input)
7962306a36Sopenharmony_ci		input_unregister_device(dev->input);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
8362306a36Sopenharmony_ci	int value)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	if (dev->input) {
8662306a36Sopenharmony_ci		input_report_key(dev->input, code, value);
8762306a36Sopenharmony_ci		input_sync(dev->input);
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#else
9262306a36Sopenharmony_ci#define uvc_input_init(dev)
9362306a36Sopenharmony_ci#define uvc_input_unregister(dev)
9462306a36Sopenharmony_ci#define uvc_input_report_key(dev, code, value)
9562306a36Sopenharmony_ci#endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/* --------------------------------------------------------------------------
9862306a36Sopenharmony_ci * Status interrupt endpoint
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_cistatic void uvc_event_streaming(struct uvc_device *dev,
10162306a36Sopenharmony_ci				struct uvc_status *status, int len)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	if (len <= offsetof(struct uvc_status, bEvent)) {
10462306a36Sopenharmony_ci		uvc_dbg(dev, STATUS,
10562306a36Sopenharmony_ci			"Invalid streaming status event received\n");
10662306a36Sopenharmony_ci		return;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (status->bEvent == 0) {
11062306a36Sopenharmony_ci		if (len <= offsetof(struct uvc_status, streaming))
11162306a36Sopenharmony_ci			return;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci		uvc_dbg(dev, STATUS, "Button (intf %u) %s len %d\n",
11462306a36Sopenharmony_ci			status->bOriginator,
11562306a36Sopenharmony_ci			status->streaming.button ? "pressed" : "released", len);
11662306a36Sopenharmony_ci		uvc_input_report_key(dev, KEY_CAMERA, status->streaming.button);
11762306a36Sopenharmony_ci	} else {
11862306a36Sopenharmony_ci		uvc_dbg(dev, STATUS, "Stream %u error event %02x len %d\n",
11962306a36Sopenharmony_ci			status->bOriginator, status->bEvent, len);
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#define UVC_CTRL_VALUE_CHANGE	0
12462306a36Sopenharmony_ci#define UVC_CTRL_INFO_CHANGE	1
12562306a36Sopenharmony_ci#define UVC_CTRL_FAILURE_CHANGE	2
12662306a36Sopenharmony_ci#define UVC_CTRL_MIN_CHANGE	3
12762306a36Sopenharmony_ci#define UVC_CTRL_MAX_CHANGE	4
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic struct uvc_control *uvc_event_entity_find_ctrl(struct uvc_entity *entity,
13062306a36Sopenharmony_ci						      u8 selector)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	struct uvc_control *ctrl;
13362306a36Sopenharmony_ci	unsigned int i;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	for (i = 0, ctrl = entity->controls; i < entity->ncontrols; i++, ctrl++)
13662306a36Sopenharmony_ci		if (ctrl->info.selector == selector)
13762306a36Sopenharmony_ci			return ctrl;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return NULL;
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev,
14362306a36Sopenharmony_ci					const struct uvc_status *status,
14462306a36Sopenharmony_ci					struct uvc_video_chain **chain)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	list_for_each_entry((*chain), &dev->chains, list) {
14762306a36Sopenharmony_ci		struct uvc_entity *entity;
14862306a36Sopenharmony_ci		struct uvc_control *ctrl;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci		list_for_each_entry(entity, &(*chain)->entities, chain) {
15162306a36Sopenharmony_ci			if (entity->id != status->bOriginator)
15262306a36Sopenharmony_ci				continue;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci			ctrl = uvc_event_entity_find_ctrl(entity,
15562306a36Sopenharmony_ci						     status->control.bSelector);
15662306a36Sopenharmony_ci			if (ctrl)
15762306a36Sopenharmony_ci				return ctrl;
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	return NULL;
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic bool uvc_event_control(struct urb *urb,
16562306a36Sopenharmony_ci			      const struct uvc_status *status, int len)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	static const char *attrs[] = { "value", "info", "failure", "min", "max" };
16862306a36Sopenharmony_ci	struct uvc_device *dev = urb->context;
16962306a36Sopenharmony_ci	struct uvc_video_chain *chain;
17062306a36Sopenharmony_ci	struct uvc_control *ctrl;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (len < 6 || status->bEvent != 0 ||
17362306a36Sopenharmony_ci	    status->control.bAttribute >= ARRAY_SIZE(attrs)) {
17462306a36Sopenharmony_ci		uvc_dbg(dev, STATUS, "Invalid control status event received\n");
17562306a36Sopenharmony_ci		return false;
17662306a36Sopenharmony_ci	}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	uvc_dbg(dev, STATUS, "Control %u/%u %s change len %d\n",
17962306a36Sopenharmony_ci		status->bOriginator, status->control.bSelector,
18062306a36Sopenharmony_ci		attrs[status->control.bAttribute], len);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* Find the control. */
18362306a36Sopenharmony_ci	ctrl = uvc_event_find_ctrl(dev, status, &chain);
18462306a36Sopenharmony_ci	if (!ctrl)
18562306a36Sopenharmony_ci		return false;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	switch (status->control.bAttribute) {
18862306a36Sopenharmony_ci	case UVC_CTRL_VALUE_CHANGE:
18962306a36Sopenharmony_ci		return uvc_ctrl_status_event_async(urb, chain, ctrl,
19062306a36Sopenharmony_ci						   status->control.bValue);
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	case UVC_CTRL_INFO_CHANGE:
19362306a36Sopenharmony_ci	case UVC_CTRL_FAILURE_CHANGE:
19462306a36Sopenharmony_ci	case UVC_CTRL_MIN_CHANGE:
19562306a36Sopenharmony_ci	case UVC_CTRL_MAX_CHANGE:
19662306a36Sopenharmony_ci		break;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	return false;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic void uvc_status_complete(struct urb *urb)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct uvc_device *dev = urb->context;
20562306a36Sopenharmony_ci	int len, ret;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	switch (urb->status) {
20862306a36Sopenharmony_ci	case 0:
20962306a36Sopenharmony_ci		break;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	case -ENOENT:		/* usb_kill_urb() called. */
21262306a36Sopenharmony_ci	case -ECONNRESET:	/* usb_unlink_urb() called. */
21362306a36Sopenharmony_ci	case -ESHUTDOWN:	/* The endpoint is being disabled. */
21462306a36Sopenharmony_ci	case -EPROTO:		/* Device is disconnected (reported by some host controllers). */
21562306a36Sopenharmony_ci		return;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	default:
21862306a36Sopenharmony_ci		dev_warn(&dev->udev->dev,
21962306a36Sopenharmony_ci			 "Non-zero status (%d) in status completion handler.\n",
22062306a36Sopenharmony_ci			 urb->status);
22162306a36Sopenharmony_ci		return;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	len = urb->actual_length;
22562306a36Sopenharmony_ci	if (len > 0) {
22662306a36Sopenharmony_ci		switch (dev->status->bStatusType & 0x0f) {
22762306a36Sopenharmony_ci		case UVC_STATUS_TYPE_CONTROL: {
22862306a36Sopenharmony_ci			if (uvc_event_control(urb, dev->status, len))
22962306a36Sopenharmony_ci				/* The URB will be resubmitted in work context. */
23062306a36Sopenharmony_ci				return;
23162306a36Sopenharmony_ci			break;
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		case UVC_STATUS_TYPE_STREAMING: {
23562306a36Sopenharmony_ci			uvc_event_streaming(dev, dev->status, len);
23662306a36Sopenharmony_ci			break;
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		default:
24062306a36Sopenharmony_ci			uvc_dbg(dev, STATUS, "Unknown status event type %u\n",
24162306a36Sopenharmony_ci				dev->status->bStatusType);
24262306a36Sopenharmony_ci			break;
24362306a36Sopenharmony_ci		}
24462306a36Sopenharmony_ci	}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	/* Resubmit the URB. */
24762306a36Sopenharmony_ci	urb->interval = dev->int_ep->desc.bInterval;
24862306a36Sopenharmony_ci	ret = usb_submit_urb(urb, GFP_ATOMIC);
24962306a36Sopenharmony_ci	if (ret < 0)
25062306a36Sopenharmony_ci		dev_err(&dev->udev->dev,
25162306a36Sopenharmony_ci			"Failed to resubmit status URB (%d).\n", ret);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ciint uvc_status_init(struct uvc_device *dev)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct usb_host_endpoint *ep = dev->int_ep;
25762306a36Sopenharmony_ci	unsigned int pipe;
25862306a36Sopenharmony_ci	int interval;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (ep == NULL)
26162306a36Sopenharmony_ci		return 0;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	uvc_input_init(dev);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	dev->status = kzalloc(sizeof(*dev->status), GFP_KERNEL);
26662306a36Sopenharmony_ci	if (!dev->status)
26762306a36Sopenharmony_ci		return -ENOMEM;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
27062306a36Sopenharmony_ci	if (!dev->int_urb) {
27162306a36Sopenharmony_ci		kfree(dev->status);
27262306a36Sopenharmony_ci		return -ENOMEM;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	/*
27862306a36Sopenharmony_ci	 * For high-speed interrupt endpoints, the bInterval value is used as
27962306a36Sopenharmony_ci	 * an exponent of two. Some developers forgot about it.
28062306a36Sopenharmony_ci	 */
28162306a36Sopenharmony_ci	interval = ep->desc.bInterval;
28262306a36Sopenharmony_ci	if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH &&
28362306a36Sopenharmony_ci	    (dev->quirks & UVC_QUIRK_STATUS_INTERVAL))
28462306a36Sopenharmony_ci		interval = fls(interval) - 1;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
28762306a36Sopenharmony_ci		dev->status, sizeof(*dev->status), uvc_status_complete,
28862306a36Sopenharmony_ci		dev, interval);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	return 0;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_civoid uvc_status_unregister(struct uvc_device *dev)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	usb_kill_urb(dev->int_urb);
29662306a36Sopenharmony_ci	uvc_input_unregister(dev);
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_civoid uvc_status_cleanup(struct uvc_device *dev)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	usb_free_urb(dev->int_urb);
30262306a36Sopenharmony_ci	kfree(dev->status);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ciint uvc_status_start(struct uvc_device *dev, gfp_t flags)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	if (dev->int_urb == NULL)
30862306a36Sopenharmony_ci		return 0;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	return usb_submit_urb(dev->int_urb, flags);
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_civoid uvc_status_stop(struct uvc_device *dev)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	struct uvc_ctrl_work *w = &dev->async_ctrl;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/*
31862306a36Sopenharmony_ci	 * Prevent the asynchronous control handler from requeing the URB. The
31962306a36Sopenharmony_ci	 * barrier is needed so the flush_status change is visible to other
32062306a36Sopenharmony_ci	 * CPUs running the asynchronous handler before usb_kill_urb() is
32162306a36Sopenharmony_ci	 * called below.
32262306a36Sopenharmony_ci	 */
32362306a36Sopenharmony_ci	smp_store_release(&dev->flush_status, true);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/*
32662306a36Sopenharmony_ci	 * Cancel any pending asynchronous work. If any status event was queued,
32762306a36Sopenharmony_ci	 * process it synchronously.
32862306a36Sopenharmony_ci	 */
32962306a36Sopenharmony_ci	if (cancel_work_sync(&w->work))
33062306a36Sopenharmony_ci		uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* Kill the urb. */
33362306a36Sopenharmony_ci	usb_kill_urb(dev->int_urb);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/*
33662306a36Sopenharmony_ci	 * The URB completion handler may have queued asynchronous work. This
33762306a36Sopenharmony_ci	 * won't resubmit the URB as flush_status is set, but it needs to be
33862306a36Sopenharmony_ci	 * cancelled before returning or it could then race with a future
33962306a36Sopenharmony_ci	 * uvc_status_start() call.
34062306a36Sopenharmony_ci	 */
34162306a36Sopenharmony_ci	if (cancel_work_sync(&w->work))
34262306a36Sopenharmony_ci		uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/*
34562306a36Sopenharmony_ci	 * From this point, there are no events on the queue and the status URB
34662306a36Sopenharmony_ci	 * is dead. No events will be queued until uvc_status_start() is called.
34762306a36Sopenharmony_ci	 * The barrier is needed to make sure that flush_status is visible to
34862306a36Sopenharmony_ci	 * uvc_ctrl_status_event_work() when uvc_status_start() will be called
34962306a36Sopenharmony_ci	 * again.
35062306a36Sopenharmony_ci	 */
35162306a36Sopenharmony_ci	smp_store_release(&dev->flush_status, false);
35262306a36Sopenharmony_ci}
353