Skip to content

Commit 10acb91

Browse files
ribaldahverkuil
authored andcommitted
media: uvcvideo: Increase/decrease the PM counter per IOCTL
Now we call uvc_pm_get/put from the device open/close. This low level of granularity might leave the camera powered on in situations where it is not needed. Increase the granularity by increasing and decreasing the Power Management counter per ioctl. There are two special cases where the power management outlives the ioctl: async controls and streamon. Handle those cases as well. In a future patch, we will remove the uvc_pm_get/put from open/close. Reviewed-by: Hans de Goede <[email protected]> Signed-off-by: Ricardo Ribalda <[email protected]> Message-ID: <[email protected]> Signed-off-by: Hans de Goede <[email protected]> Signed-off-by: Hans Verkuil <[email protected]>
1 parent 2f10157 commit 10acb91

File tree

2 files changed

+64
-13
lines changed

2 files changed

+64
-13
lines changed

drivers/media/usb/uvc/uvc_ctrl.c

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1812,38 +1812,49 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain,
18121812
uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
18131813
}
18141814

1815-
static void uvc_ctrl_set_handle(struct uvc_fh *handle, struct uvc_control *ctrl,
1816-
struct uvc_fh *new_handle)
1815+
static int uvc_ctrl_set_handle(struct uvc_fh *handle, struct uvc_control *ctrl,
1816+
struct uvc_fh *new_handle)
18171817
{
18181818
lockdep_assert_held(&handle->chain->ctrl_mutex);
18191819

18201820
if (new_handle) {
1821+
int ret;
1822+
18211823
if (ctrl->handle)
18221824
dev_warn_ratelimited(&handle->stream->dev->udev->dev,
18231825
"UVC non compliance: Setting an async control with a pending operation.");
18241826

18251827
if (new_handle == ctrl->handle)
1826-
return;
1828+
return 0;
18271829

18281830
if (ctrl->handle) {
18291831
WARN_ON(!ctrl->handle->pending_async_ctrls);
18301832
if (ctrl->handle->pending_async_ctrls)
18311833
ctrl->handle->pending_async_ctrls--;
1834+
ctrl->handle = new_handle;
1835+
handle->pending_async_ctrls++;
1836+
return 0;
18321837
}
18331838

1839+
ret = uvc_pm_get(handle->chain->dev);
1840+
if (ret)
1841+
return ret;
1842+
18341843
ctrl->handle = new_handle;
18351844
handle->pending_async_ctrls++;
1836-
return;
1845+
return 0;
18371846
}
18381847

18391848
/* Cannot clear the handle for a control not owned by us.*/
18401849
if (WARN_ON(ctrl->handle != handle))
1841-
return;
1850+
return -EINVAL;
18421851

18431852
ctrl->handle = NULL;
18441853
if (WARN_ON(!handle->pending_async_ctrls))
1845-
return;
1854+
return -EINVAL;
18461855
handle->pending_async_ctrls--;
1856+
uvc_pm_put(handle->chain->dev);
1857+
return 0;
18471858
}
18481859

18491860
void uvc_ctrl_status_event(struct uvc_video_chain *chain,
@@ -2137,15 +2148,15 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
21372148

21382149
ctrl->dirty = 0;
21392150

2151+
if (!rollback && handle && !ret &&
2152+
ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
2153+
ret = uvc_ctrl_set_handle(handle, ctrl, handle);
2154+
21402155
if (ret < 0) {
21412156
if (err_ctrl)
21422157
*err_ctrl = ctrl;
21432158
return ret;
21442159
}
2145-
2146-
if (!rollback && handle &&
2147-
ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
2148-
uvc_ctrl_set_handle(handle, ctrl, handle);
21492160
}
21502161

21512162
return 0;
@@ -3222,6 +3233,7 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
32223233
void uvc_ctrl_cleanup_fh(struct uvc_fh *handle)
32233234
{
32243235
struct uvc_entity *entity;
3236+
int i;
32253237

32263238
guard(mutex)(&handle->chain->ctrl_mutex);
32273239

@@ -3236,7 +3248,11 @@ void uvc_ctrl_cleanup_fh(struct uvc_fh *handle)
32363248
}
32373249
}
32383250

3239-
WARN_ON(handle->pending_async_ctrls);
3251+
if (!WARN_ON(handle->pending_async_ctrls))
3252+
return;
3253+
3254+
for (i = 0; i < handle->pending_async_ctrls; i++)
3255+
uvc_pm_put(handle->stream->dev);
32403256
}
32413257

32423258
/*

drivers/media/usb/uvc/uvc_v4l2.c

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,9 @@ static int uvc_v4l2_release(struct file *file)
697697
if (uvc_has_privileges(handle))
698698
uvc_queue_release(&stream->queue);
699699

700+
if (handle->is_streaming)
701+
uvc_pm_put(stream->dev);
702+
700703
/* Release the file handle. */
701704
uvc_dismiss_privileges(handle);
702705
v4l2_fh_del(&handle->vfh);
@@ -862,6 +865,11 @@ static int uvc_ioctl_streamon(struct file *file, void *fh,
862865
if (ret)
863866
return ret;
864867

868+
ret = uvc_pm_get(stream->dev);
869+
if (ret) {
870+
uvc_queue_streamoff(&stream->queue, type);
871+
return ret;
872+
}
865873
handle->is_streaming = true;
866874

867875
return 0;
@@ -879,7 +887,10 @@ static int uvc_ioctl_streamoff(struct file *file, void *fh,
879887
guard(mutex)(&stream->mutex);
880888

881889
uvc_queue_streamoff(&stream->queue, type);
882-
handle->is_streaming = false;
890+
if (handle->is_streaming) {
891+
handle->is_streaming = false;
892+
uvc_pm_put(stream->dev);
893+
}
883894

884895
return 0;
885896
}
@@ -1378,9 +1389,11 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp,
13781389
#define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32)
13791390
#define UVCIOC_CTRL_QUERY32 _IOWR('u', 0x21, struct uvc_xu_control_query32)
13801391

1392+
DEFINE_FREE(uvc_pm_put, struct uvc_device *, if (_T) uvc_pm_put(_T))
13811393
static long uvc_v4l2_compat_ioctl32(struct file *file,
13821394
unsigned int cmd, unsigned long arg)
13831395
{
1396+
struct uvc_device *uvc_device __free(uvc_pm_put) = NULL;
13841397
struct uvc_fh *handle = file->private_data;
13851398
union {
13861399
struct uvc_xu_control_mapping xmap;
@@ -1389,6 +1402,12 @@ static long uvc_v4l2_compat_ioctl32(struct file *file,
13891402
void __user *up = compat_ptr(arg);
13901403
long ret;
13911404

1405+
ret = uvc_pm_get(handle->stream->dev);
1406+
if (ret)
1407+
return ret;
1408+
1409+
uvc_device = handle->stream->dev;
1410+
13921411
switch (cmd) {
13931412
case UVCIOC_CTRL_MAP32:
13941413
ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up);
@@ -1423,6 +1442,22 @@ static long uvc_v4l2_compat_ioctl32(struct file *file,
14231442
}
14241443
#endif
14251444

1445+
static long uvc_v4l2_unlocked_ioctl(struct file *file,
1446+
unsigned int cmd, unsigned long arg)
1447+
{
1448+
struct uvc_fh *handle = file->private_data;
1449+
int ret;
1450+
1451+
ret = uvc_pm_get(handle->stream->dev);
1452+
if (ret)
1453+
return ret;
1454+
1455+
ret = video_ioctl2(file, cmd, arg);
1456+
1457+
uvc_pm_put(handle->stream->dev);
1458+
return ret;
1459+
}
1460+
14261461
static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
14271462
size_t count, loff_t *ppos)
14281463
{
@@ -1507,7 +1542,7 @@ const struct v4l2_file_operations uvc_fops = {
15071542
.owner = THIS_MODULE,
15081543
.open = uvc_v4l2_open,
15091544
.release = uvc_v4l2_release,
1510-
.unlocked_ioctl = video_ioctl2,
1545+
.unlocked_ioctl = uvc_v4l2_unlocked_ioctl,
15111546
#ifdef CONFIG_COMPAT
15121547
.compat_ioctl32 = uvc_v4l2_compat_ioctl32,
15131548
#endif

0 commit comments

Comments
 (0)