/* * The device has button events if both bTriggerSupport and * bTriggerUsage are one. Otherwise the camera button does not * exist or is handled automatically by the camera without host * driver or client application intervention.
*/
list_for_each_entry(stream, &dev->streams, list) { if (stream->header.bTriggerSupport == 1 &&
stream->header.bTriggerUsage == 1) returntrue;
}
returnfalse;
}
staticint uvc_input_init(struct uvc_device *dev)
{ struct input_dev *input; int ret;
if (!uvc_input_has_button(dev)) return 0;
input = input_allocate_device(); if (input == NULL) return -ENOMEM;
case -ENOENT: /* usb_kill_urb() called. */ case -ECONNRESET: /* usb_unlink_urb() called. */ case -ESHUTDOWN: /* The endpoint is being disabled. */ case -EPROTO: /* Device is disconnected (reported by some host controllers). */ return;
default:
dev_warn(&dev->udev->dev, "Non-zero status (%d) in status completion handler.\n",
urb->status); return;
}
len = urb->actual_length; if (len > 0) { switch (dev->status->bStatusType & 0x0f) { case UVC_STATUS_TYPE_CONTROL: { if (uvc_event_control(urb, dev->status, len)) /* The URB will be resubmitted in work context. */ return; break;
}
case UVC_STATUS_TYPE_STREAMING: {
uvc_event_streaming(dev, dev->status, len); break;
}
default:
uvc_dbg(dev, STATUS, "Unknown status event type %u\n",
dev->status->bStatusType); break;
}
}
/* Resubmit the URB. */
urb->interval = dev->int_ep->desc.bInterval;
ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0)
dev_err(&dev->udev->dev, "Failed to resubmit status URB (%d).\n", ret);
}
int uvc_status_init(struct uvc_device *dev)
{ struct usb_host_endpoint *ep = dev->int_ep; unsignedint pipe; int interval;
mutex_init(&dev->status_lock);
if (ep == NULL) return 0;
dev->status = kzalloc(sizeof(*dev->status), GFP_KERNEL); if (!dev->status) return -ENOMEM;
/* * For high-speed interrupt endpoints, the bInterval value is used as * an exponent of two. Some developers forgot about it.
*/
interval = ep->desc.bInterval; if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH &&
(dev->quirks & UVC_QUIRK_STATUS_INTERVAL))
interval = fls(interval) - 1;
/* * Prevent the asynchronous control handler from requeing the URB. The * barrier is needed so the flush_status change is visible to other * CPUs running the asynchronous handler before usb_kill_urb() is * called below.
*/
smp_store_release(&dev->flush_status, true);
/* * Cancel any pending asynchronous work. If any status event was queued, * process it synchronously.
*/ if (cancel_work_sync(&w->work))
uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
/* Kill the urb. */
usb_kill_urb(dev->int_urb);
/* * The URB completion handler may have queued asynchronous work. This * won't resubmit the URB as flush_status is set, but it needs to be * cancelled before returning or it could then race with a future * uvc_status_start() call.
*/ if (cancel_work_sync(&w->work))
uvc_ctrl_status_event(w->chain, w->ctrl, w->data);
/* * From this point, there are no events on the queue and the status URB * is dead. No events will be queued until uvc_status_start() is called. * The barrier is needed to make sure that flush_status is visible to * uvc_ctrl_status_event_work() when uvc_status_start() will be called * again.
*/
smp_store_release(&dev->flush_status, false);
}
int uvc_status_resume(struct uvc_device *dev)
{
guard(mutex)(&dev->status_lock);
if (dev->status_users) return uvc_status_start(dev, GFP_NOIO);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.