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