2019-05-27 06:55:01 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2008-06-30 18:04:50 +00:00
|
|
|
/*
|
|
|
|
* uvc_status.c -- USB Video Class driver - Status endpoint
|
|
|
|
*
|
2010-09-20 09:10:10 +00:00
|
|
|
* Copyright (C) 2005-2009
|
|
|
|
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
2008-06-30 18:04:50 +00:00
|
|
|
*/
|
|
|
|
|
2023-01-05 14:31:29 +00:00
|
|
|
#include <asm/barrier.h>
|
2008-06-30 18:04:50 +00:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/input.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 08:04:11 +00:00
|
|
|
#include <linux/slab.h>
|
2008-06-30 18:04:50 +00:00
|
|
|
#include <linux/usb.h>
|
|
|
|
#include <linux/usb/input.h>
|
|
|
|
|
|
|
|
#include "uvcvideo.h"
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------
|
|
|
|
* Input device
|
|
|
|
*/
|
2008-07-08 02:04:29 +00:00
|
|
|
#ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
|
2022-09-20 14:09:50 +00:00
|
|
|
|
|
|
|
static bool uvc_input_has_button(struct uvc_device *dev)
|
|
|
|
{
|
|
|
|
struct uvc_streaming *stream;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-06-30 18:04:50 +00:00
|
|
|
static int uvc_input_init(struct uvc_device *dev)
|
|
|
|
{
|
|
|
|
struct input_dev *input;
|
|
|
|
int ret;
|
|
|
|
|
2022-09-20 14:09:50 +00:00
|
|
|
if (!uvc_input_has_button(dev))
|
|
|
|
return 0;
|
|
|
|
|
2008-06-30 18:04:50 +00:00
|
|
|
input = input_allocate_device();
|
|
|
|
if (input == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2009-01-22 15:45:10 +00:00
|
|
|
usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys));
|
|
|
|
strlcat(dev->input_phys, "/button", sizeof(dev->input_phys));
|
2008-06-30 18:04:50 +00:00
|
|
|
|
|
|
|
input->name = dev->name;
|
2009-01-22 15:45:10 +00:00
|
|
|
input->phys = dev->input_phys;
|
|
|
|
usb_to_input_id(dev->udev, &input->id);
|
2008-06-30 18:04:50 +00:00
|
|
|
input->dev.parent = &dev->intf->dev;
|
|
|
|
|
2009-01-11 07:44:22 +00:00
|
|
|
__set_bit(EV_KEY, input->evbit);
|
|
|
|
__set_bit(KEY_CAMERA, input->keybit);
|
2008-06-30 18:04:50 +00:00
|
|
|
|
|
|
|
if ((ret = input_register_device(input)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
dev->input = input;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
input_free_device(input);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
media: uvcvideo: Refactor teardown of uvc on USB disconnect
Currently, disconnecting a USB webcam while it is in use prints out a
number of warnings, such as:
WARNING: CPU: 2 PID: 3118 at /build/linux-ezBi1T/linux-4.8.0/fs/sysfs/group.c:237 sysfs_remove_group+0x8b/0x90
sysfs group ffffffffa7cd0780 not found for kobject 'event13'
This has been noticed before. [0]
This is because of the order in which things are torn down.
If there are no streams active during a USB disconnect:
- uvc_disconnect() is invoked via device_del() through the bus
notifier mechanism.
- this calls uvc_unregister_video().
- uvc_unregister_video() unregisters the video device for each
stream,
- because there are no streams open, it calls uvc_delete()
- uvc_delete() calls uvc_status_cleanup(), which cleans up the status
input device.
- uvc_delete() calls media_device_unregister(), which cleans up the
media device
- uvc_delete(), uvc_unregister_video() and uvc_disconnect() all
return, and we end up back in device_del().
- device_del() then cleans up the sysfs folder for the camera with
dpm_sysfs_remove(). Because uvc_status_cleanup() and
media_device_unregister() have already been called, this all works
nicely.
If, on the other hand, there *are* streams active during a USB disconnect:
- uvc_disconnect() is invoked
- this calls uvc_unregister_video()
- uvc_unregister_video() unregisters the video device for each
stream,
- uvc_unregister_video() and uvc_disconnect() return, and we end up
back in device_del().
- device_del() then cleans up the sysfs folder for the camera with
dpm_sysfs_remove(). Because the status input device and the media
device are children of the USB device, this also deletes their
sysfs folders.
- Sometime later, the final stream is closed, invoking uvc_release().
- uvc_release() calls uvc_delete()
- uvc_delete() calls uvc_status_cleanup(), which cleans up the status
input device. Because the sysfs directory has already been removed,
this causes a WARNing.
- uvc_delete() calls media_device_unregister(), which cleans up the
media device. Because the sysfs directory has already been removed,
this causes another WARNing.
To fix this, we need to make sure the devices are always unregistered
before the end of uvc_disconnect(). To this, move the unregistration
into the disconnect path:
- split uvc_status_cleanup() into two parts, one on disconnect that
unregisters and one on delete that frees.
- move v4l2_device_unregister() and media_device_unregister() into
the disconnect path.
[0]: https://lkml.org/lkml/2016/12/8/657
[Renamed uvc_input_cleanup() to uvc_input_unregister()]
Signed-off-by: Daniel Axtens <dja@axtens.net>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2017-04-23 04:53:49 +00:00
|
|
|
static void uvc_input_unregister(struct uvc_device *dev)
|
2008-06-30 18:04:50 +00:00
|
|
|
{
|
|
|
|
if (dev->input)
|
|
|
|
input_unregister_device(dev->input);
|
|
|
|
}
|
|
|
|
|
2008-07-08 02:04:29 +00:00
|
|
|
static void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
|
|
|
|
int value)
|
|
|
|
{
|
2009-01-11 07:44:22 +00:00
|
|
|
if (dev->input) {
|
2008-07-08 02:04:29 +00:00
|
|
|
input_report_key(dev->input, code, value);
|
2009-01-11 07:44:22 +00:00
|
|
|
input_sync(dev->input);
|
|
|
|
}
|
2008-07-08 02:04:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
#define uvc_input_init(dev)
|
media: uvcvideo: Refactor teardown of uvc on USB disconnect
Currently, disconnecting a USB webcam while it is in use prints out a
number of warnings, such as:
WARNING: CPU: 2 PID: 3118 at /build/linux-ezBi1T/linux-4.8.0/fs/sysfs/group.c:237 sysfs_remove_group+0x8b/0x90
sysfs group ffffffffa7cd0780 not found for kobject 'event13'
This has been noticed before. [0]
This is because of the order in which things are torn down.
If there are no streams active during a USB disconnect:
- uvc_disconnect() is invoked via device_del() through the bus
notifier mechanism.
- this calls uvc_unregister_video().
- uvc_unregister_video() unregisters the video device for each
stream,
- because there are no streams open, it calls uvc_delete()
- uvc_delete() calls uvc_status_cleanup(), which cleans up the status
input device.
- uvc_delete() calls media_device_unregister(), which cleans up the
media device
- uvc_delete(), uvc_unregister_video() and uvc_disconnect() all
return, and we end up back in device_del().
- device_del() then cleans up the sysfs folder for the camera with
dpm_sysfs_remove(). Because uvc_status_cleanup() and
media_device_unregister() have already been called, this all works
nicely.
If, on the other hand, there *are* streams active during a USB disconnect:
- uvc_disconnect() is invoked
- this calls uvc_unregister_video()
- uvc_unregister_video() unregisters the video device for each
stream,
- uvc_unregister_video() and uvc_disconnect() return, and we end up
back in device_del().
- device_del() then cleans up the sysfs folder for the camera with
dpm_sysfs_remove(). Because the status input device and the media
device are children of the USB device, this also deletes their
sysfs folders.
- Sometime later, the final stream is closed, invoking uvc_release().
- uvc_release() calls uvc_delete()
- uvc_delete() calls uvc_status_cleanup(), which cleans up the status
input device. Because the sysfs directory has already been removed,
this causes a WARNing.
- uvc_delete() calls media_device_unregister(), which cleans up the
media device. Because the sysfs directory has already been removed,
this causes another WARNing.
To fix this, we need to make sure the devices are always unregistered
before the end of uvc_disconnect(). To this, move the unregistration
into the disconnect path:
- split uvc_status_cleanup() into two parts, one on disconnect that
unregisters and one on delete that frees.
- move v4l2_device_unregister() and media_device_unregister() into
the disconnect path.
[0]: https://lkml.org/lkml/2016/12/8/657
[Renamed uvc_input_cleanup() to uvc_input_unregister()]
Signed-off-by: Daniel Axtens <dja@axtens.net>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2017-04-23 04:53:49 +00:00
|
|
|
#define uvc_input_unregister(dev)
|
2008-07-08 02:04:29 +00:00
|
|
|
#define uvc_input_report_key(dev, code, value)
|
|
|
|
#endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */
|
|
|
|
|
2008-06-30 18:04:50 +00:00
|
|
|
/* --------------------------------------------------------------------------
|
|
|
|
* Status interrupt endpoint
|
|
|
|
*/
|
2018-07-26 08:17:53 +00:00
|
|
|
static void uvc_event_streaming(struct uvc_device *dev,
|
2022-12-20 22:56:44 +00:00
|
|
|
struct uvc_status *status, int len)
|
2008-06-30 18:04:50 +00:00
|
|
|
{
|
2022-12-20 22:56:44 +00:00
|
|
|
if (len <= offsetof(struct uvc_status, bEvent)) {
|
2020-12-23 13:35:27 +00:00
|
|
|
uvc_dbg(dev, STATUS,
|
|
|
|
"Invalid streaming status event received\n");
|
2008-06-30 18:04:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-26 08:17:53 +00:00
|
|
|
if (status->bEvent == 0) {
|
2022-12-20 22:56:44 +00:00
|
|
|
if (len <= offsetof(struct uvc_status, streaming))
|
2008-06-30 18:04:50 +00:00
|
|
|
return;
|
2022-12-20 22:56:44 +00:00
|
|
|
|
2020-12-23 13:35:27 +00:00
|
|
|
uvc_dbg(dev, STATUS, "Button (intf %u) %s len %d\n",
|
|
|
|
status->bOriginator,
|
2022-12-20 22:56:44 +00:00
|
|
|
status->streaming.button ? "pressed" : "released", len);
|
|
|
|
uvc_input_report_key(dev, KEY_CAMERA, status->streaming.button);
|
2008-06-30 18:04:50 +00:00
|
|
|
} else {
|
2020-12-23 13:35:27 +00:00
|
|
|
uvc_dbg(dev, STATUS, "Stream %u error event %02x len %d\n",
|
|
|
|
status->bOriginator, status->bEvent, len);
|
2018-07-26 08:17:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define UVC_CTRL_VALUE_CHANGE 0
|
|
|
|
#define UVC_CTRL_INFO_CHANGE 1
|
|
|
|
#define UVC_CTRL_FAILURE_CHANGE 2
|
|
|
|
#define UVC_CTRL_MIN_CHANGE 3
|
|
|
|
#define UVC_CTRL_MAX_CHANGE 4
|
|
|
|
|
|
|
|
static struct uvc_control *uvc_event_entity_find_ctrl(struct uvc_entity *entity,
|
|
|
|
u8 selector)
|
|
|
|
{
|
|
|
|
struct uvc_control *ctrl;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0, ctrl = entity->controls; i < entity->ncontrols; i++, ctrl++)
|
|
|
|
if (ctrl->info.selector == selector)
|
|
|
|
return ctrl;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct uvc_control *uvc_event_find_ctrl(struct uvc_device *dev,
|
2022-12-20 22:56:44 +00:00
|
|
|
const struct uvc_status *status,
|
2018-07-26 08:17:53 +00:00
|
|
|
struct uvc_video_chain **chain)
|
|
|
|
{
|
|
|
|
list_for_each_entry((*chain), &dev->chains, list) {
|
|
|
|
struct uvc_entity *entity;
|
|
|
|
struct uvc_control *ctrl;
|
|
|
|
|
|
|
|
list_for_each_entry(entity, &(*chain)->entities, chain) {
|
|
|
|
if (entity->id != status->bOriginator)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ctrl = uvc_event_entity_find_ctrl(entity,
|
2022-12-20 22:56:44 +00:00
|
|
|
status->control.bSelector);
|
2018-07-26 08:17:53 +00:00
|
|
|
if (ctrl)
|
|
|
|
return ctrl;
|
|
|
|
}
|
2008-06-30 18:04:50 +00:00
|
|
|
}
|
2018-07-26 08:17:53 +00:00
|
|
|
|
|
|
|
return NULL;
|
2008-06-30 18:04:50 +00:00
|
|
|
}
|
|
|
|
|
2018-07-26 08:17:53 +00:00
|
|
|
static bool uvc_event_control(struct urb *urb,
|
2022-12-20 22:56:44 +00:00
|
|
|
const struct uvc_status *status, int len)
|
2008-06-30 18:04:50 +00:00
|
|
|
{
|
2018-07-26 08:17:53 +00:00
|
|
|
static const char *attrs[] = { "value", "info", "failure", "min", "max" };
|
|
|
|
struct uvc_device *dev = urb->context;
|
|
|
|
struct uvc_video_chain *chain;
|
|
|
|
struct uvc_control *ctrl;
|
2008-06-30 18:04:50 +00:00
|
|
|
|
2018-07-26 08:17:53 +00:00
|
|
|
if (len < 6 || status->bEvent != 0 ||
|
2022-12-20 22:56:44 +00:00
|
|
|
status->control.bAttribute >= ARRAY_SIZE(attrs)) {
|
2020-12-23 13:35:27 +00:00
|
|
|
uvc_dbg(dev, STATUS, "Invalid control status event received\n");
|
2018-07-26 08:17:53 +00:00
|
|
|
return false;
|
2008-06-30 18:04:50 +00:00
|
|
|
}
|
|
|
|
|
2020-12-23 13:35:27 +00:00
|
|
|
uvc_dbg(dev, STATUS, "Control %u/%u %s change len %d\n",
|
2022-12-20 22:56:44 +00:00
|
|
|
status->bOriginator, status->control.bSelector,
|
|
|
|
attrs[status->control.bAttribute], len);
|
2018-07-26 08:17:53 +00:00
|
|
|
|
|
|
|
/* Find the control. */
|
|
|
|
ctrl = uvc_event_find_ctrl(dev, status, &chain);
|
|
|
|
if (!ctrl)
|
|
|
|
return false;
|
|
|
|
|
2022-12-20 22:56:44 +00:00
|
|
|
switch (status->control.bAttribute) {
|
2018-07-26 08:17:53 +00:00
|
|
|
case UVC_CTRL_VALUE_CHANGE:
|
2020-12-23 13:35:20 +00:00
|
|
|
return uvc_ctrl_status_event_async(urb, chain, ctrl,
|
2022-12-20 22:56:44 +00:00
|
|
|
status->control.bValue);
|
2018-07-26 08:17:53 +00:00
|
|
|
|
|
|
|
case UVC_CTRL_INFO_CHANGE:
|
|
|
|
case UVC_CTRL_FAILURE_CHANGE:
|
|
|
|
case UVC_CTRL_MIN_CHANGE:
|
|
|
|
case UVC_CTRL_MAX_CHANGE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2008-06-30 18:04:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void uvc_status_complete(struct urb *urb)
|
|
|
|
{
|
|
|
|
struct uvc_device *dev = urb->context;
|
|
|
|
int len, ret;
|
|
|
|
|
|
|
|
switch (urb->status) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case -ENOENT: /* usb_kill_urb() called. */
|
|
|
|
case -ECONNRESET: /* usb_unlink_urb() called. */
|
|
|
|
case -ESHUTDOWN: /* The endpoint is being disabled. */
|
2022-06-08 17:38:52 +00:00
|
|
|
case -EPROTO: /* Device is disconnected (reported by some host controllers). */
|
2008-06-30 18:04:50 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
default:
|
2020-12-23 13:35:24 +00:00
|
|
|
dev_warn(&dev->udev->dev,
|
|
|
|
"Non-zero status (%d) in status completion handler.\n",
|
|
|
|
urb->status);
|
2008-06-30 18:04:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
len = urb->actual_length;
|
|
|
|
if (len > 0) {
|
2022-12-20 22:56:44 +00:00
|
|
|
switch (dev->status->bStatusType & 0x0f) {
|
2018-07-26 08:17:53 +00:00
|
|
|
case UVC_STATUS_TYPE_CONTROL: {
|
2022-12-20 22:56:44 +00:00
|
|
|
if (uvc_event_control(urb, dev->status, len))
|
2018-07-26 08:17:53 +00:00
|
|
|
/* The URB will be resubmitted in work context. */
|
|
|
|
return;
|
2008-06-30 18:04:50 +00:00
|
|
|
break;
|
2018-07-26 08:17:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case UVC_STATUS_TYPE_STREAMING: {
|
2022-12-20 22:56:44 +00:00
|
|
|
uvc_event_streaming(dev, dev->status, len);
|
2008-06-30 18:04:50 +00:00
|
|
|
break;
|
2018-07-26 08:17:53 +00:00
|
|
|
}
|
2008-06-30 18:04:50 +00:00
|
|
|
|
|
|
|
default:
|
2020-12-23 13:35:27 +00:00
|
|
|
uvc_dbg(dev, STATUS, "Unknown status event type %u\n",
|
2022-12-20 22:56:44 +00:00
|
|
|
dev->status->bStatusType);
|
2008-06-30 18:04:50 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Resubmit the URB. */
|
|
|
|
urb->interval = dev->int_ep->desc.bInterval;
|
2020-12-23 13:35:24 +00:00
|
|
|
ret = usb_submit_urb(urb, GFP_ATOMIC);
|
|
|
|
if (ret < 0)
|
|
|
|
dev_err(&dev->udev->dev,
|
|
|
|
"Failed to resubmit status URB (%d).\n", ret);
|
2008-06-30 18:04:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int uvc_status_init(struct uvc_device *dev)
|
|
|
|
{
|
|
|
|
struct usb_host_endpoint *ep = dev->int_ep;
|
|
|
|
unsigned int pipe;
|
|
|
|
int interval;
|
|
|
|
|
|
|
|
if (ep == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uvc_input_init(dev);
|
|
|
|
|
2022-12-20 22:56:44 +00:00
|
|
|
dev->status = kzalloc(sizeof(*dev->status), GFP_KERNEL);
|
|
|
|
if (!dev->status)
|
2008-09-16 06:32:20 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2008-06-30 18:04:50 +00:00
|
|
|
dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
|
2022-12-20 22:56:44 +00:00
|
|
|
if (!dev->int_urb) {
|
2008-09-16 06:32:20 +00:00
|
|
|
kfree(dev->status);
|
2008-06-30 18:04:50 +00:00
|
|
|
return -ENOMEM;
|
2008-09-16 06:32:20 +00:00
|
|
|
}
|
2008-06-30 18:04:50 +00:00
|
|
|
|
|
|
|
pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
|
|
|
|
|
2022-06-08 17:38:52 +00:00
|
|
|
/*
|
|
|
|
* For high-speed interrupt endpoints, the bInterval value is used as
|
2008-06-30 18:04:50 +00:00
|
|
|
* 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;
|
|
|
|
|
|
|
|
usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
|
2022-12-20 22:56:44 +00:00
|
|
|
dev->status, sizeof(*dev->status), uvc_status_complete,
|
2008-06-30 18:04:50 +00:00
|
|
|
dev, interval);
|
|
|
|
|
2009-05-19 13:08:03 +00:00
|
|
|
return 0;
|
2008-06-30 18:04:50 +00:00
|
|
|
}
|
|
|
|
|
media: uvcvideo: Refactor teardown of uvc on USB disconnect
Currently, disconnecting a USB webcam while it is in use prints out a
number of warnings, such as:
WARNING: CPU: 2 PID: 3118 at /build/linux-ezBi1T/linux-4.8.0/fs/sysfs/group.c:237 sysfs_remove_group+0x8b/0x90
sysfs group ffffffffa7cd0780 not found for kobject 'event13'
This has been noticed before. [0]
This is because of the order in which things are torn down.
If there are no streams active during a USB disconnect:
- uvc_disconnect() is invoked via device_del() through the bus
notifier mechanism.
- this calls uvc_unregister_video().
- uvc_unregister_video() unregisters the video device for each
stream,
- because there are no streams open, it calls uvc_delete()
- uvc_delete() calls uvc_status_cleanup(), which cleans up the status
input device.
- uvc_delete() calls media_device_unregister(), which cleans up the
media device
- uvc_delete(), uvc_unregister_video() and uvc_disconnect() all
return, and we end up back in device_del().
- device_del() then cleans up the sysfs folder for the camera with
dpm_sysfs_remove(). Because uvc_status_cleanup() and
media_device_unregister() have already been called, this all works
nicely.
If, on the other hand, there *are* streams active during a USB disconnect:
- uvc_disconnect() is invoked
- this calls uvc_unregister_video()
- uvc_unregister_video() unregisters the video device for each
stream,
- uvc_unregister_video() and uvc_disconnect() return, and we end up
back in device_del().
- device_del() then cleans up the sysfs folder for the camera with
dpm_sysfs_remove(). Because the status input device and the media
device are children of the USB device, this also deletes their
sysfs folders.
- Sometime later, the final stream is closed, invoking uvc_release().
- uvc_release() calls uvc_delete()
- uvc_delete() calls uvc_status_cleanup(), which cleans up the status
input device. Because the sysfs directory has already been removed,
this causes a WARNing.
- uvc_delete() calls media_device_unregister(), which cleans up the
media device. Because the sysfs directory has already been removed,
this causes another WARNing.
To fix this, we need to make sure the devices are always unregistered
before the end of uvc_disconnect(). To this, move the unregistration
into the disconnect path:
- split uvc_status_cleanup() into two parts, one on disconnect that
unregisters and one on delete that frees.
- move v4l2_device_unregister() and media_device_unregister() into
the disconnect path.
[0]: https://lkml.org/lkml/2016/12/8/657
[Renamed uvc_input_cleanup() to uvc_input_unregister()]
Signed-off-by: Daniel Axtens <dja@axtens.net>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2017-04-23 04:53:49 +00:00
|
|
|
void uvc_status_unregister(struct uvc_device *dev)
|
2008-06-30 18:04:50 +00:00
|
|
|
{
|
|
|
|
usb_kill_urb(dev->int_urb);
|
media: uvcvideo: Refactor teardown of uvc on USB disconnect
Currently, disconnecting a USB webcam while it is in use prints out a
number of warnings, such as:
WARNING: CPU: 2 PID: 3118 at /build/linux-ezBi1T/linux-4.8.0/fs/sysfs/group.c:237 sysfs_remove_group+0x8b/0x90
sysfs group ffffffffa7cd0780 not found for kobject 'event13'
This has been noticed before. [0]
This is because of the order in which things are torn down.
If there are no streams active during a USB disconnect:
- uvc_disconnect() is invoked via device_del() through the bus
notifier mechanism.
- this calls uvc_unregister_video().
- uvc_unregister_video() unregisters the video device for each
stream,
- because there are no streams open, it calls uvc_delete()
- uvc_delete() calls uvc_status_cleanup(), which cleans up the status
input device.
- uvc_delete() calls media_device_unregister(), which cleans up the
media device
- uvc_delete(), uvc_unregister_video() and uvc_disconnect() all
return, and we end up back in device_del().
- device_del() then cleans up the sysfs folder for the camera with
dpm_sysfs_remove(). Because uvc_status_cleanup() and
media_device_unregister() have already been called, this all works
nicely.
If, on the other hand, there *are* streams active during a USB disconnect:
- uvc_disconnect() is invoked
- this calls uvc_unregister_video()
- uvc_unregister_video() unregisters the video device for each
stream,
- uvc_unregister_video() and uvc_disconnect() return, and we end up
back in device_del().
- device_del() then cleans up the sysfs folder for the camera with
dpm_sysfs_remove(). Because the status input device and the media
device are children of the USB device, this also deletes their
sysfs folders.
- Sometime later, the final stream is closed, invoking uvc_release().
- uvc_release() calls uvc_delete()
- uvc_delete() calls uvc_status_cleanup(), which cleans up the status
input device. Because the sysfs directory has already been removed,
this causes a WARNing.
- uvc_delete() calls media_device_unregister(), which cleans up the
media device. Because the sysfs directory has already been removed,
this causes another WARNing.
To fix this, we need to make sure the devices are always unregistered
before the end of uvc_disconnect(). To this, move the unregistration
into the disconnect path:
- split uvc_status_cleanup() into two parts, one on disconnect that
unregisters and one on delete that frees.
- move v4l2_device_unregister() and media_device_unregister() into
the disconnect path.
[0]: https://lkml.org/lkml/2016/12/8/657
[Renamed uvc_input_cleanup() to uvc_input_unregister()]
Signed-off-by: Daniel Axtens <dja@axtens.net>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2017-04-23 04:53:49 +00:00
|
|
|
uvc_input_unregister(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
void uvc_status_cleanup(struct uvc_device *dev)
|
|
|
|
{
|
2008-06-30 18:04:50 +00:00
|
|
|
usb_free_urb(dev->int_urb);
|
2008-09-16 06:32:20 +00:00
|
|
|
kfree(dev->status);
|
2008-06-30 18:04:50 +00:00
|
|
|
}
|
|
|
|
|
2013-04-26 01:28:51 +00:00
|
|
|
int uvc_status_start(struct uvc_device *dev, gfp_t flags)
|
2009-05-19 13:08:03 +00:00
|
|
|
{
|
|
|
|
if (dev->int_urb == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2013-04-26 01:28:51 +00:00
|
|
|
return usb_submit_urb(dev->int_urb, flags);
|
2009-05-19 13:08:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void uvc_status_stop(struct uvc_device *dev)
|
2008-06-30 18:04:50 +00:00
|
|
|
{
|
2023-01-05 14:31:29 +00:00
|
|
|
struct uvc_ctrl_work *w = &dev->async_ctrl;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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. */
|
2008-06-30 18:04:50 +00:00
|
|
|
usb_kill_urb(dev->int_urb);
|
2023-01-05 14:31:29 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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);
|
2009-05-19 13:08:03 +00:00
|
|
|
}
|