Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
27a5e6d3 HV |
2 | /* |
3 | * Video capture interface for Linux version 2 | |
4 | * | |
5 | * A generic video device interface for the LINUX operating system | |
6 | * using a set of device structures/vectors for low level operations. | |
7 | * | |
d9b01449 | 8 | * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1) |
32590819 | 9 | * Mauro Carvalho Chehab <mchehab@kernel.org> (version 2) |
27a5e6d3 HV |
10 | * |
11 | * Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com> | |
12 | * - Added procfs support | |
13 | */ | |
14 | ||
baa057e2 MCC |
15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
16 | ||
517fd2b6 | 17 | #include <linux/debugfs.h> |
27a5e6d3 HV |
18 | #include <linux/module.h> |
19 | #include <linux/types.h> | |
20 | #include <linux/kernel.h> | |
21 | #include <linux/mm.h> | |
22 | #include <linux/string.h> | |
23 | #include <linux/errno.h> | |
24 | #include <linux/init.h> | |
25 | #include <linux/kmod.h> | |
26 | #include <linux/slab.h> | |
7c0f6ba6 | 27 | #include <linux/uaccess.h> |
27a5e6d3 HV |
28 | |
29 | #include <media/v4l2-common.h> | |
9bea3514 | 30 | #include <media/v4l2-device.h> |
bec43661 | 31 | #include <media/v4l2-ioctl.h> |
28955a61 | 32 | #include <media/v4l2-event.h> |
27a5e6d3 HV |
33 | |
34 | #define VIDEO_NUM_DEVICES 256 | |
35 | #define VIDEO_NAME "video4linux" | |
36 | ||
baa057e2 MCC |
37 | #define dprintk(fmt, arg...) do { \ |
38 | printk(KERN_DEBUG pr_fmt("%s: " fmt), \ | |
39 | __func__, ##arg); \ | |
40 | } while (0) | |
41 | ||
27a5e6d3 HV |
42 | /* |
43 | * sysfs stuff | |
44 | */ | |
45 | ||
13e2237f GKH |
46 | static ssize_t index_show(struct device *cd, |
47 | struct device_attribute *attr, char *buf) | |
27a5e6d3 | 48 | { |
dc93a70c | 49 | struct video_device *vdev = to_video_device(cd); |
bfa8a273 | 50 | |
dc93a70c | 51 | return sprintf(buf, "%i\n", vdev->index); |
27a5e6d3 | 52 | } |
13e2237f | 53 | static DEVICE_ATTR_RO(index); |
27a5e6d3 | 54 | |
17028cdb | 55 | static ssize_t dev_debug_show(struct device *cd, |
13e2237f | 56 | struct device_attribute *attr, char *buf) |
80131fe0 HV |
57 | { |
58 | struct video_device *vdev = to_video_device(cd); | |
59 | ||
17028cdb | 60 | return sprintf(buf, "%i\n", vdev->dev_debug); |
80131fe0 HV |
61 | } |
62 | ||
17028cdb | 63 | static ssize_t dev_debug_store(struct device *cd, struct device_attribute *attr, |
13e2237f | 64 | const char *buf, size_t len) |
80131fe0 HV |
65 | { |
66 | struct video_device *vdev = to_video_device(cd); | |
67 | int res = 0; | |
68 | u16 value; | |
69 | ||
70 | res = kstrtou16(buf, 0, &value); | |
71 | if (res) | |
72 | return res; | |
73 | ||
17028cdb | 74 | vdev->dev_debug = value; |
80131fe0 HV |
75 | return len; |
76 | } | |
17028cdb | 77 | static DEVICE_ATTR_RW(dev_debug); |
80131fe0 | 78 | |
13e2237f | 79 | static ssize_t name_show(struct device *cd, |
27a5e6d3 HV |
80 | struct device_attribute *attr, char *buf) |
81 | { | |
dc93a70c | 82 | struct video_device *vdev = to_video_device(cd); |
bfa8a273 | 83 | |
dc93a70c | 84 | return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name); |
27a5e6d3 | 85 | } |
13e2237f | 86 | static DEVICE_ATTR_RO(name); |
27a5e6d3 | 87 | |
13e2237f GKH |
88 | static struct attribute *video_device_attrs[] = { |
89 | &dev_attr_name.attr, | |
17028cdb | 90 | &dev_attr_dev_debug.attr, |
13e2237f GKH |
91 | &dev_attr_index.attr, |
92 | NULL, | |
27a5e6d3 | 93 | }; |
13e2237f | 94 | ATTRIBUTE_GROUPS(video_device); |
27a5e6d3 | 95 | |
ccb32f23 HV |
96 | static struct dentry *v4l2_debugfs_root_dir; |
97 | ||
7f8ecfab HV |
98 | /* |
99 | * Active devices | |
100 | */ | |
ee758243 | 101 | static struct video_device *video_devices[VIDEO_NUM_DEVICES]; |
7f8ecfab | 102 | static DEFINE_MUTEX(videodev_lock); |
22e22125 | 103 | static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES); |
7f8ecfab | 104 | |
5062cb70 HV |
105 | /* Device node utility functions */ |
106 | ||
107 | /* Note: these utility functions all assume that vfl_type is in the range | |
108 | [0, VFL_TYPE_MAX-1]. */ | |
109 | ||
110 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES | |
111 | /* Return the bitmap corresponding to vfl_type. */ | |
4839c58f | 112 | static inline unsigned long *devnode_bits(enum vfl_devnode_type vfl_type) |
5062cb70 HV |
113 | { |
114 | /* Any types not assigned to fixed minor ranges must be mapped to | |
115 | one single bitmap for the purposes of finding a free node number | |
116 | since all those unassigned types use the same minor range. */ | |
226c0eea | 117 | int idx = (vfl_type > VFL_TYPE_RADIO) ? VFL_TYPE_MAX - 1 : vfl_type; |
5062cb70 HV |
118 | |
119 | return devnode_nums[idx]; | |
120 | } | |
121 | #else | |
122 | /* Return the bitmap corresponding to vfl_type. */ | |
4839c58f | 123 | static inline unsigned long *devnode_bits(enum vfl_devnode_type vfl_type) |
5062cb70 HV |
124 | { |
125 | return devnode_nums[vfl_type]; | |
126 | } | |
127 | #endif | |
128 | ||
129 | /* Mark device node number vdev->num as used */ | |
130 | static inline void devnode_set(struct video_device *vdev) | |
131 | { | |
132 | set_bit(vdev->num, devnode_bits(vdev->vfl_type)); | |
133 | } | |
134 | ||
135 | /* Mark device node number vdev->num as unused */ | |
136 | static inline void devnode_clear(struct video_device *vdev) | |
137 | { | |
138 | clear_bit(vdev->num, devnode_bits(vdev->vfl_type)); | |
139 | } | |
140 | ||
141 | /* Try to find a free device node number in the range [from, to> */ | |
142 | static inline int devnode_find(struct video_device *vdev, int from, int to) | |
143 | { | |
144 | return find_next_zero_bit(devnode_bits(vdev->vfl_type), to, from); | |
145 | } | |
146 | ||
27a5e6d3 HV |
147 | struct video_device *video_device_alloc(void) |
148 | { | |
bfa8a273 | 149 | return kzalloc(sizeof(struct video_device), GFP_KERNEL); |
27a5e6d3 HV |
150 | } |
151 | EXPORT_SYMBOL(video_device_alloc); | |
152 | ||
dc93a70c | 153 | void video_device_release(struct video_device *vdev) |
27a5e6d3 | 154 | { |
dc93a70c | 155 | kfree(vdev); |
27a5e6d3 HV |
156 | } |
157 | EXPORT_SYMBOL(video_device_release); | |
158 | ||
dc93a70c | 159 | void video_device_release_empty(struct video_device *vdev) |
f9e86b5e HV |
160 | { |
161 | /* Do nothing */ | |
162 | /* Only valid when the video_device struct is a static. */ | |
163 | } | |
164 | EXPORT_SYMBOL(video_device_release_empty); | |
165 | ||
dc93a70c | 166 | static inline void video_get(struct video_device *vdev) |
7f8ecfab | 167 | { |
dc93a70c HV |
168 | get_device(&vdev->dev); |
169 | } | |
170 | ||
171 | static inline void video_put(struct video_device *vdev) | |
172 | { | |
173 | put_device(&vdev->dev); | |
174 | } | |
175 | ||
176 | /* Called when the last user of the video device exits. */ | |
177 | static void v4l2_device_release(struct device *cd) | |
178 | { | |
179 | struct video_device *vdev = to_video_device(cd); | |
bedf8bcf | 180 | struct v4l2_device *v4l2_dev = vdev->v4l2_dev; |
7f8ecfab HV |
181 | |
182 | mutex_lock(&videodev_lock); | |
ee758243 | 183 | if (WARN_ON(video_devices[vdev->minor] != vdev)) { |
dc93a70c | 184 | /* should not happen */ |
1fc2b5f7 | 185 | mutex_unlock(&videodev_lock); |
6ea9a182 HV |
186 | return; |
187 | } | |
7f8ecfab HV |
188 | |
189 | /* Free up this device for reuse */ | |
ee758243 | 190 | video_devices[vdev->minor] = NULL; |
7f8ecfab | 191 | |
dc93a70c HV |
192 | /* Delete the cdev on this minor as well */ |
193 | cdev_del(vdev->cdev); | |
194 | /* Just in case some driver tries to access this from | |
195 | the release() callback. */ | |
196 | vdev->cdev = NULL; | |
7f8ecfab | 197 | |
22e22125 | 198 | /* Mark device node number as free */ |
5062cb70 | 199 | devnode_clear(vdev); |
7f8ecfab | 200 | |
dc93a70c | 201 | mutex_unlock(&videodev_lock); |
27a5e6d3 | 202 | |
c064b8ea | 203 | #if defined(CONFIG_MEDIA_CONTROLLER) |
be2fff65 | 204 | if (v4l2_dev->mdev && vdev->vfl_dir != VFL_DIR_M2M) { |
d9c21e3e MCC |
205 | /* Remove interfaces and interface links */ |
206 | media_devnode_remove(vdev->intf_devnode); | |
4ca72efa | 207 | if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) |
d9c21e3e MCC |
208 | media_device_unregister_entity(&vdev->entity); |
209 | } | |
c064b8ea LP |
210 | #endif |
211 | ||
8280b662 HV |
212 | /* Do not call v4l2_device_put if there is no release callback set. |
213 | * Drivers that have no v4l2_device release callback might free the | |
214 | * v4l2_dev instance in the video_device release callback below, so we | |
215 | * must perform this check here. | |
216 | * | |
217 | * TODO: In the long run all drivers that use v4l2_device should use the | |
218 | * v4l2_device release callback. This check will then be unnecessary. | |
219 | */ | |
d9bfbcc0 | 220 | if (v4l2_dev->release == NULL) |
8280b662 HV |
221 | v4l2_dev = NULL; |
222 | ||
dc93a70c HV |
223 | /* Release video_device and perform other |
224 | cleanups as needed. */ | |
225 | vdev->release(vdev); | |
bedf8bcf HV |
226 | |
227 | /* Decrease v4l2_device refcount */ | |
228 | if (v4l2_dev) | |
229 | v4l2_device_put(v4l2_dev); | |
27a5e6d3 HV |
230 | } |
231 | ||
2b744cb1 | 232 | static const struct class video_class = { |
27a5e6d3 | 233 | .name = VIDEO_NAME, |
13e2237f | 234 | .dev_groups = video_device_groups, |
27a5e6d3 HV |
235 | }; |
236 | ||
27a5e6d3 HV |
237 | struct video_device *video_devdata(struct file *file) |
238 | { | |
ee758243 | 239 | return video_devices[iminor(file_inode(file))]; |
27a5e6d3 HV |
240 | } |
241 | EXPORT_SYMBOL(video_devdata); | |
242 | ||
02265493 HV |
243 | |
244 | /* Priority handling */ | |
245 | ||
246 | static inline bool prio_is_valid(enum v4l2_priority prio) | |
247 | { | |
248 | return prio == V4L2_PRIORITY_BACKGROUND || | |
249 | prio == V4L2_PRIORITY_INTERACTIVE || | |
250 | prio == V4L2_PRIORITY_RECORD; | |
251 | } | |
252 | ||
253 | void v4l2_prio_init(struct v4l2_prio_state *global) | |
254 | { | |
255 | memset(global, 0, sizeof(*global)); | |
256 | } | |
257 | EXPORT_SYMBOL(v4l2_prio_init); | |
258 | ||
259 | int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, | |
260 | enum v4l2_priority new) | |
261 | { | |
262 | if (!prio_is_valid(new)) | |
263 | return -EINVAL; | |
264 | if (*local == new) | |
265 | return 0; | |
266 | ||
267 | atomic_inc(&global->prios[new]); | |
268 | if (prio_is_valid(*local)) | |
269 | atomic_dec(&global->prios[*local]); | |
270 | *local = new; | |
271 | return 0; | |
272 | } | |
273 | EXPORT_SYMBOL(v4l2_prio_change); | |
274 | ||
275 | void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local) | |
276 | { | |
277 | v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT); | |
278 | } | |
279 | EXPORT_SYMBOL(v4l2_prio_open); | |
280 | ||
281 | void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local) | |
282 | { | |
283 | if (prio_is_valid(local)) | |
284 | atomic_dec(&global->prios[local]); | |
285 | } | |
286 | EXPORT_SYMBOL(v4l2_prio_close); | |
287 | ||
288 | enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global) | |
289 | { | |
290 | if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0) | |
291 | return V4L2_PRIORITY_RECORD; | |
292 | if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0) | |
293 | return V4L2_PRIORITY_INTERACTIVE; | |
294 | if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0) | |
295 | return V4L2_PRIORITY_BACKGROUND; | |
296 | return V4L2_PRIORITY_UNSET; | |
297 | } | |
298 | EXPORT_SYMBOL(v4l2_prio_max); | |
299 | ||
300 | int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local) | |
301 | { | |
302 | return (local < v4l2_prio_max(global)) ? -EBUSY : 0; | |
303 | } | |
304 | EXPORT_SYMBOL(v4l2_prio_check); | |
305 | ||
306 | ||
dc93a70c HV |
307 | static ssize_t v4l2_read(struct file *filp, char __user *buf, |
308 | size_t sz, loff_t *off) | |
309 | { | |
310 | struct video_device *vdev = video_devdata(filp); | |
2877842d | 311 | int ret = -ENODEV; |
dc93a70c HV |
312 | |
313 | if (!vdev->fops->read) | |
314 | return -EINVAL; | |
ee6869af HV |
315 | if (video_is_registered(vdev)) |
316 | ret = vdev->fops->read(filp, buf, sz, off); | |
17028cdb HV |
317 | if ((vdev->dev_debug & V4L2_DEV_DEBUG_FOP) && |
318 | (vdev->dev_debug & V4L2_DEV_DEBUG_STREAMING)) | |
baa057e2 | 319 | dprintk("%s: read: %zd (%d)\n", |
cc4b7e7f | 320 | video_device_node_name(vdev), sz, ret); |
ee6869af | 321 | return ret; |
dc93a70c HV |
322 | } |
323 | ||
324 | static ssize_t v4l2_write(struct file *filp, const char __user *buf, | |
325 | size_t sz, loff_t *off) | |
326 | { | |
327 | struct video_device *vdev = video_devdata(filp); | |
2877842d | 328 | int ret = -ENODEV; |
dc93a70c HV |
329 | |
330 | if (!vdev->fops->write) | |
331 | return -EINVAL; | |
ee6869af HV |
332 | if (video_is_registered(vdev)) |
333 | ret = vdev->fops->write(filp, buf, sz, off); | |
17028cdb HV |
334 | if ((vdev->dev_debug & V4L2_DEV_DEBUG_FOP) && |
335 | (vdev->dev_debug & V4L2_DEV_DEBUG_STREAMING)) | |
baa057e2 | 336 | dprintk("%s: write: %zd (%d)\n", |
cc4b7e7f | 337 | video_device_node_name(vdev), sz, ret); |
ee6869af | 338 | return ret; |
dc93a70c HV |
339 | } |
340 | ||
c23e0cb8 | 341 | static __poll_t v4l2_poll(struct file *filp, struct poll_table_struct *poll) |
dc93a70c HV |
342 | { |
343 | struct video_device *vdev = video_devdata(filp); | |
5cb0a64e | 344 | __poll_t res = EPOLLERR | EPOLLHUP | EPOLLPRI; |
ee6869af | 345 | |
5cb0a64e HV |
346 | if (video_is_registered(vdev)) { |
347 | if (!vdev->fops->poll) | |
348 | res = DEFAULT_POLLMASK; | |
349 | else | |
350 | res = vdev->fops->poll(filp, poll); | |
351 | } | |
17028cdb | 352 | if (vdev->dev_debug & V4L2_DEV_DEBUG_POLL) |
bea7515d HV |
353 | dprintk("%s: poll: %08x %08x\n", |
354 | video_device_node_name(vdev), res, | |
355 | poll_requested_events(poll)); | |
cf533735 | 356 | return res; |
dc93a70c HV |
357 | } |
358 | ||
86a5ef7d | 359 | static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
dc93a70c HV |
360 | { |
361 | struct video_device *vdev = video_devdata(filp); | |
72420630 | 362 | int ret = -ENODEV; |
dc93a70c | 363 | |
86a5ef7d | 364 | if (vdev->fops->unlocked_ioctl) { |
72420630 MCC |
365 | if (video_is_registered(vdev)) |
366 | ret = vdev->fops->unlocked_ioctl(filp, cmd, arg); | |
86a5ef7d AB |
367 | } else |
368 | ret = -ENOTTY; | |
dc93a70c | 369 | |
86a5ef7d | 370 | return ret; |
dc93a70c HV |
371 | } |
372 | ||
ecc6517d BL |
373 | #ifdef CONFIG_MMU |
374 | #define v4l2_get_unmapped_area NULL | |
375 | #else | |
376 | static unsigned long v4l2_get_unmapped_area(struct file *filp, | |
377 | unsigned long addr, unsigned long len, unsigned long pgoff, | |
378 | unsigned long flags) | |
379 | { | |
380 | struct video_device *vdev = video_devdata(filp); | |
cc4b7e7f | 381 | int ret; |
ecc6517d BL |
382 | |
383 | if (!vdev->fops->get_unmapped_area) | |
384 | return -ENOSYS; | |
385 | if (!video_is_registered(vdev)) | |
386 | return -ENODEV; | |
cc4b7e7f | 387 | ret = vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags); |
17028cdb | 388 | if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) |
baa057e2 | 389 | dprintk("%s: get_unmapped_area (%d)\n", |
cc4b7e7f HV |
390 | video_device_node_name(vdev), ret); |
391 | return ret; | |
ecc6517d BL |
392 | } |
393 | #endif | |
394 | ||
dc93a70c HV |
395 | static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) |
396 | { | |
397 | struct video_device *vdev = video_devdata(filp); | |
ee6869af HV |
398 | int ret = -ENODEV; |
399 | ||
400 | if (!vdev->fops->mmap) | |
cf533735 | 401 | return -ENODEV; |
ee6869af HV |
402 | if (video_is_registered(vdev)) |
403 | ret = vdev->fops->mmap(filp, vm); | |
17028cdb | 404 | if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) |
baa057e2 | 405 | dprintk("%s: mmap (%d)\n", |
cc4b7e7f | 406 | video_device_node_name(vdev), ret); |
ee6869af | 407 | return ret; |
dc93a70c HV |
408 | } |
409 | ||
410 | /* Override for the open function */ | |
411 | static int v4l2_open(struct inode *inode, struct file *filp) | |
412 | { | |
413 | struct video_device *vdev; | |
65d9ff9c | 414 | int ret = 0; |
dc93a70c HV |
415 | |
416 | /* Check if the video device is available */ | |
417 | mutex_lock(&videodev_lock); | |
418 | vdev = video_devdata(filp); | |
ee6869af | 419 | /* return ENODEV if the video device has already been removed. */ |
ca9afe6f | 420 | if (vdev == NULL || !video_is_registered(vdev)) { |
dc93a70c HV |
421 | mutex_unlock(&videodev_lock); |
422 | return -ENODEV; | |
423 | } | |
424 | /* and increase the device refcount */ | |
425 | video_get(vdev); | |
426 | mutex_unlock(&videodev_lock); | |
ee6869af | 427 | if (vdev->fops->open) { |
ee6869af HV |
428 | if (video_is_registered(vdev)) |
429 | ret = vdev->fops->open(filp); | |
430 | else | |
431 | ret = -ENODEV; | |
ee6869af | 432 | } |
65d9ff9c | 433 | |
17028cdb | 434 | if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) |
baa057e2 | 435 | dprintk("%s: open (%d)\n", |
cc4b7e7f | 436 | video_device_node_name(vdev), ret); |
8f695d3f EG |
437 | /* decrease the refcount in case of an error */ |
438 | if (ret) | |
439 | video_put(vdev); | |
dc93a70c HV |
440 | return ret; |
441 | } | |
442 | ||
443 | /* Override for the release function */ | |
444 | static int v4l2_release(struct inode *inode, struct file *filp) | |
445 | { | |
446 | struct video_device *vdev = video_devdata(filp); | |
65d9ff9c HV |
447 | int ret = 0; |
448 | ||
cc6eddcd HV |
449 | /* |
450 | * We need to serialize the release() with queueing new requests. | |
451 | * The release() may trigger the cancellation of a streaming | |
452 | * operation, and that should not be mixed with queueing a new | |
453 | * request at the same time. | |
454 | */ | |
455 | if (vdev->fops->release) { | |
456 | if (v4l2_device_supports_requests(vdev->v4l2_dev)) { | |
457 | mutex_lock(&vdev->v4l2_dev->mdev->req_queue_mutex); | |
458 | ret = vdev->fops->release(filp); | |
459 | mutex_unlock(&vdev->v4l2_dev->mdev->req_queue_mutex); | |
460 | } else { | |
461 | ret = vdev->fops->release(filp); | |
462 | } | |
463 | } | |
464 | ||
17028cdb | 465 | if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP) |
baa057e2 | 466 | dprintk("%s: release\n", |
cc4b7e7f | 467 | video_device_node_name(vdev)); |
cf533735 | 468 | |
8f695d3f EG |
469 | /* decrease the refcount unconditionally since the release() |
470 | return value is ignored. */ | |
471 | video_put(vdev); | |
dc93a70c HV |
472 | return ret; |
473 | } | |
474 | ||
dc93a70c HV |
475 | static const struct file_operations v4l2_fops = { |
476 | .owner = THIS_MODULE, | |
477 | .read = v4l2_read, | |
478 | .write = v4l2_write, | |
479 | .open = v4l2_open, | |
ecc6517d | 480 | .get_unmapped_area = v4l2_get_unmapped_area, |
dc93a70c | 481 | .mmap = v4l2_mmap, |
86a5ef7d | 482 | .unlocked_ioctl = v4l2_ioctl, |
dc93a70c | 483 | #ifdef CONFIG_COMPAT |
9bb7cde7 | 484 | .compat_ioctl = v4l2_compat_ioctl32, |
dc93a70c HV |
485 | #endif |
486 | .release = v4l2_release, | |
487 | .poll = v4l2_poll, | |
dc93a70c HV |
488 | }; |
489 | ||
27a5e6d3 | 490 | /** |
1c1d86a1 HV |
491 | * get_index - assign stream index number based on v4l2_dev |
492 | * @vdev: video_device to assign index number to, vdev->v4l2_dev should be assigned | |
27a5e6d3 | 493 | * |
dc93a70c | 494 | * Note that when this is called the new device has not yet been registered |
7ae0cd9b | 495 | * in the video_device array, but it was able to obtain a minor number. |
27a5e6d3 | 496 | * |
7ae0cd9b HV |
497 | * This means that we can always obtain a free stream index number since |
498 | * the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in | |
499 | * use of the video_device array. | |
500 | * | |
501 | * Returns a free index number. | |
27a5e6d3 | 502 | */ |
7ae0cd9b | 503 | static int get_index(struct video_device *vdev) |
27a5e6d3 | 504 | { |
775a05dd HV |
505 | /* This can be static since this function is called with the global |
506 | videodev_lock held. */ | |
507 | static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES); | |
27a5e6d3 HV |
508 | int i; |
509 | ||
775a05dd | 510 | bitmap_zero(used, VIDEO_NUM_DEVICES); |
806e5b7c | 511 | |
27a5e6d3 | 512 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) { |
ee758243 SQ |
513 | if (video_devices[i] != NULL && |
514 | video_devices[i]->v4l2_dev == vdev->v4l2_dev) { | |
0533d173 | 515 | __set_bit(video_devices[i]->index, used); |
27a5e6d3 HV |
516 | } |
517 | } | |
518 | ||
7ae0cd9b | 519 | return find_first_zero_bit(used, VIDEO_NUM_DEVICES); |
27a5e6d3 HV |
520 | } |
521 | ||
35037eab | 522 | #define SET_VALID_IOCTL(ops, cmd, op) \ |
0533d173 | 523 | do { if ((ops)->op) __set_bit(_IOC_NR(cmd), valid_ioctls); } while (0) |
48ea0be0 HV |
524 | |
525 | /* This determines which ioctls are actually implemented in the driver. | |
526 | It's a one-time thing which simplifies video_ioctl2 as it can just do | |
527 | a bit test. | |
528 | ||
529 | Note that drivers can override this by setting bits to 1 in | |
530 | vdev->valid_ioctls. If an ioctl is marked as 1 when this function is | |
531 | called, then that ioctl will actually be marked as unimplemented. | |
532 | ||
533 | It does that by first setting up the local valid_ioctls bitmap, and | |
534 | at the end do a: | |
535 | ||
536 | vdev->valid_ioctls = valid_ioctls & ~(vdev->valid_ioctls) | |
537 | */ | |
538 | static void determine_valid_ioctls(struct video_device *vdev) | |
539 | { | |
96f49c1a VB |
540 | const u32 vid_caps = V4L2_CAP_VIDEO_CAPTURE | |
541 | V4L2_CAP_VIDEO_CAPTURE_MPLANE | | |
542 | V4L2_CAP_VIDEO_OUTPUT | | |
543 | V4L2_CAP_VIDEO_OUTPUT_MPLANE | | |
544 | V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE; | |
545 | const u32 meta_caps = V4L2_CAP_META_CAPTURE | | |
546 | V4L2_CAP_META_OUTPUT; | |
48ea0be0 HV |
547 | DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE); |
548 | const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops; | |
238e4a5b | 549 | bool is_vid = vdev->vfl_type == VFL_TYPE_VIDEO && |
96f49c1a | 550 | (vdev->device_caps & vid_caps); |
4b20259f | 551 | bool is_vbi = vdev->vfl_type == VFL_TYPE_VBI; |
bfffd743 | 552 | bool is_radio = vdev->vfl_type == VFL_TYPE_RADIO; |
582c52cb | 553 | bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR; |
b2fe22d0 | 554 | bool is_tch = vdev->vfl_type == VFL_TYPE_TOUCH; |
238e4a5b | 555 | bool is_meta = vdev->vfl_type == VFL_TYPE_VIDEO && |
96f49c1a | 556 | (vdev->device_caps & meta_caps); |
4b20259f HV |
557 | bool is_rx = vdev->vfl_dir != VFL_DIR_TX; |
558 | bool is_tx = vdev->vfl_dir != VFL_DIR_RX; | |
f645e625 | 559 | bool is_io_mc = vdev->device_caps & V4L2_CAP_IO_MC; |
5f225889 | 560 | bool has_streaming = vdev->device_caps & V4L2_CAP_STREAMING; |
c9edd2e4 | 561 | bool is_edid = vdev->device_caps & V4L2_CAP_EDID; |
48ea0be0 HV |
562 | |
563 | bitmap_zero(valid_ioctls, BASE_VIDIOC_PRIVATE); | |
564 | ||
90d0fc49 HV |
565 | /* vfl_type and vfl_dir independent ioctls */ |
566 | ||
48ea0be0 | 567 | SET_VALID_IOCTL(ops, VIDIOC_QUERYCAP, vidioc_querycap); |
0533d173 CJ |
568 | __set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls); |
569 | __set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls); | |
2438e78a | 570 | |
90d0fc49 HV |
571 | /* Note: the control handler can also be passed through the filehandle, |
572 | and that can't be tested here. If the bit for these control ioctls | |
573 | is set, then the ioctl is valid. But if it is 0, then it can still | |
574 | be valid if the filehandle passed the control handler. */ | |
0f6b05e0 | 575 | if (vdev->ctrl_handler || ops->vidioc_query_ext_ctrl) |
0533d173 | 576 | __set_bit(_IOC_NR(VIDIOC_QUERYCTRL), valid_ioctls); |
e6bee368 | 577 | if (vdev->ctrl_handler || ops->vidioc_query_ext_ctrl) |
0533d173 | 578 | __set_bit(_IOC_NR(VIDIOC_QUERY_EXT_CTRL), valid_ioctls); |
70307f28 | 579 | if (vdev->ctrl_handler || ops->vidioc_g_ext_ctrls) |
0533d173 | 580 | __set_bit(_IOC_NR(VIDIOC_G_CTRL), valid_ioctls); |
0d751293 | 581 | if (vdev->ctrl_handler || ops->vidioc_s_ext_ctrls) |
0533d173 | 582 | __set_bit(_IOC_NR(VIDIOC_S_CTRL), valid_ioctls); |
90d0fc49 | 583 | if (vdev->ctrl_handler || ops->vidioc_g_ext_ctrls) |
0533d173 | 584 | __set_bit(_IOC_NR(VIDIOC_G_EXT_CTRLS), valid_ioctls); |
90d0fc49 | 585 | if (vdev->ctrl_handler || ops->vidioc_s_ext_ctrls) |
0533d173 | 586 | __set_bit(_IOC_NR(VIDIOC_S_EXT_CTRLS), valid_ioctls); |
90d0fc49 | 587 | if (vdev->ctrl_handler || ops->vidioc_try_ext_ctrls) |
0533d173 | 588 | __set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls); |
90d0fc49 | 589 | if (vdev->ctrl_handler || ops->vidioc_querymenu) |
0533d173 | 590 | __set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls); |
8669d847 HV |
591 | if (!is_tch) { |
592 | SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency); | |
593 | SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency); | |
594 | } | |
90d0fc49 HV |
595 | SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status); |
596 | #ifdef CONFIG_VIDEO_ADV_DEBUG | |
0533d173 CJ |
597 | __set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_INFO), valid_ioctls); |
598 | __set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls); | |
599 | __set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls); | |
90d0fc49 | 600 | #endif |
90d0fc49 HV |
601 | /* yes, really vidioc_subscribe_event */ |
602 | SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event); | |
603 | SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event); | |
604 | SET_VALID_IOCTL(ops, VIDIOC_UNSUBSCRIBE_EVENT, vidioc_unsubscribe_event); | |
90d0fc49 | 605 | if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator) |
0533d173 | 606 | __set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls); |
90d0fc49 | 607 | |
4fbd54bb HV |
608 | if (is_vid) { |
609 | /* video specific ioctls */ | |
4b20259f | 610 | if ((is_rx && (ops->vidioc_enum_fmt_vid_cap || |
96f49c1a VB |
611 | ops->vidioc_enum_fmt_vid_overlay)) || |
612 | (is_tx && ops->vidioc_enum_fmt_vid_out)) | |
0533d173 | 613 | __set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); |
4b20259f HV |
614 | if ((is_rx && (ops->vidioc_g_fmt_vid_cap || |
615 | ops->vidioc_g_fmt_vid_cap_mplane || | |
96f49c1a | 616 | ops->vidioc_g_fmt_vid_overlay)) || |
4b20259f HV |
617 | (is_tx && (ops->vidioc_g_fmt_vid_out || |
618 | ops->vidioc_g_fmt_vid_out_mplane || | |
96f49c1a | 619 | ops->vidioc_g_fmt_vid_out_overlay))) |
0533d173 | 620 | __set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); |
4b20259f HV |
621 | if ((is_rx && (ops->vidioc_s_fmt_vid_cap || |
622 | ops->vidioc_s_fmt_vid_cap_mplane || | |
96f49c1a | 623 | ops->vidioc_s_fmt_vid_overlay)) || |
4b20259f HV |
624 | (is_tx && (ops->vidioc_s_fmt_vid_out || |
625 | ops->vidioc_s_fmt_vid_out_mplane || | |
96f49c1a | 626 | ops->vidioc_s_fmt_vid_out_overlay))) |
0533d173 | 627 | __set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); |
4b20259f HV |
628 | if ((is_rx && (ops->vidioc_try_fmt_vid_cap || |
629 | ops->vidioc_try_fmt_vid_cap_mplane || | |
96f49c1a | 630 | ops->vidioc_try_fmt_vid_overlay)) || |
4b20259f HV |
631 | (is_tx && (ops->vidioc_try_fmt_vid_out || |
632 | ops->vidioc_try_fmt_vid_out_mplane || | |
96f49c1a | 633 | ops->vidioc_try_fmt_vid_out_overlay))) |
0533d173 | 634 | __set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); |
90d0fc49 HV |
635 | SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay); |
636 | SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf); | |
637 | SET_VALID_IOCTL(ops, VIDIOC_S_FBUF, vidioc_s_fbuf); | |
638 | SET_VALID_IOCTL(ops, VIDIOC_G_JPEGCOMP, vidioc_g_jpegcomp); | |
639 | SET_VALID_IOCTL(ops, VIDIOC_S_JPEGCOMP, vidioc_s_jpegcomp); | |
640 | SET_VALID_IOCTL(ops, VIDIOC_G_ENC_INDEX, vidioc_g_enc_index); | |
641 | SET_VALID_IOCTL(ops, VIDIOC_ENCODER_CMD, vidioc_encoder_cmd); | |
642 | SET_VALID_IOCTL(ops, VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd); | |
643 | SET_VALID_IOCTL(ops, VIDIOC_DECODER_CMD, vidioc_decoder_cmd); | |
644 | SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd); | |
645 | SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes); | |
646 | SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals); | |
dd4229fa PK |
647 | if (ops->vidioc_g_selection && |
648 | !test_bit(_IOC_NR(VIDIOC_G_SELECTION), vdev->valid_ioctls)) { | |
0533d173 CJ |
649 | __set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls); |
650 | __set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls); | |
5200ab6a | 651 | } |
dd4229fa PK |
652 | if (ops->vidioc_s_selection && |
653 | !test_bit(_IOC_NR(VIDIOC_S_SELECTION), vdev->valid_ioctls)) | |
0533d173 | 654 | __set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls); |
2c9fc463 HV |
655 | SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection); |
656 | SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection); | |
96f49c1a VB |
657 | } |
658 | if (is_meta && is_rx) { | |
659 | /* metadata capture specific ioctls */ | |
660 | SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_meta_cap); | |
661 | SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_meta_cap); | |
662 | SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_meta_cap); | |
663 | SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_meta_cap); | |
664 | } else if (is_meta && is_tx) { | |
665 | /* metadata output specific ioctls */ | |
666 | SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_meta_out); | |
667 | SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_meta_out); | |
668 | SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_meta_out); | |
669 | SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_meta_out); | |
670 | } | |
671 | if (is_vbi) { | |
90d0fc49 | 672 | /* vbi specific ioctls */ |
4b20259f HV |
673 | if ((is_rx && (ops->vidioc_g_fmt_vbi_cap || |
674 | ops->vidioc_g_fmt_sliced_vbi_cap)) || | |
675 | (is_tx && (ops->vidioc_g_fmt_vbi_out || | |
676 | ops->vidioc_g_fmt_sliced_vbi_out))) | |
0533d173 | 677 | __set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls); |
4b20259f HV |
678 | if ((is_rx && (ops->vidioc_s_fmt_vbi_cap || |
679 | ops->vidioc_s_fmt_sliced_vbi_cap)) || | |
680 | (is_tx && (ops->vidioc_s_fmt_vbi_out || | |
681 | ops->vidioc_s_fmt_sliced_vbi_out))) | |
0533d173 | 682 | __set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls); |
4b20259f HV |
683 | if ((is_rx && (ops->vidioc_try_fmt_vbi_cap || |
684 | ops->vidioc_try_fmt_sliced_vbi_cap)) || | |
685 | (is_tx && (ops->vidioc_try_fmt_vbi_out || | |
686 | ops->vidioc_try_fmt_sliced_vbi_out))) | |
0533d173 | 687 | __set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls); |
90d0fc49 | 688 | SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap); |
4fbd54bb HV |
689 | } else if (is_tch) { |
690 | /* touch specific ioctls */ | |
691 | SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_vid_cap); | |
692 | SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_vid_cap); | |
693 | SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_vid_cap); | |
694 | SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_vid_cap); | |
695 | SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes); | |
696 | SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals); | |
697 | SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input); | |
698 | SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input); | |
699 | SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input); | |
700 | SET_VALID_IOCTL(ops, VIDIOC_G_PARM, vidioc_g_parm); | |
701 | SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm); | |
9effc72f AP |
702 | } else if (is_sdr && is_rx) { |
703 | /* SDR receiver specific ioctls */ | |
8e72244b HV |
704 | SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_sdr_cap); |
705 | SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_sdr_cap); | |
706 | SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_sdr_cap); | |
707 | SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_sdr_cap); | |
9effc72f AP |
708 | } else if (is_sdr && is_tx) { |
709 | /* SDR transmitter specific ioctls */ | |
8e72244b HV |
710 | SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_sdr_out); |
711 | SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_sdr_out); | |
712 | SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_sdr_out); | |
713 | SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_sdr_out); | |
4b20259f | 714 | } |
582c52cb | 715 | |
5f225889 HV |
716 | if (has_streaming) { |
717 | /* ioctls valid for streaming I/O */ | |
5815d0c4 FS |
718 | SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs); |
719 | SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf); | |
720 | SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf); | |
721 | SET_VALID_IOCTL(ops, VIDIOC_EXPBUF, vidioc_expbuf); | |
722 | SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf); | |
723 | SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs); | |
724 | SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf); | |
72be89c8 HV |
725 | SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon); |
726 | SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff); | |
a3293a85 BG |
727 | /* VIDIOC_CREATE_BUFS support is mandatory to enable VIDIOC_REMOVE_BUFS */ |
728 | if (ops->vidioc_create_bufs) | |
729 | SET_VALID_IOCTL(ops, VIDIOC_REMOVE_BUFS, vidioc_remove_bufs); | |
582c52cb AP |
730 | } |
731 | ||
4fbd54bb HV |
732 | if (is_vid || is_vbi || is_meta) { |
733 | /* ioctls valid for video, vbi and metadata */ | |
4b20259f | 734 | if (ops->vidioc_s_std) |
0533d173 | 735 | __set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls); |
4b20259f | 736 | SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std); |
ca371575 | 737 | SET_VALID_IOCTL(ops, VIDIOC_G_STD, vidioc_g_std); |
4b20259f | 738 | if (is_rx) { |
90d0fc49 | 739 | SET_VALID_IOCTL(ops, VIDIOC_QUERYSTD, vidioc_querystd); |
f645e625 | 740 | if (is_io_mc) { |
0533d173 CJ |
741 | __set_bit(_IOC_NR(VIDIOC_ENUMINPUT), valid_ioctls); |
742 | __set_bit(_IOC_NR(VIDIOC_G_INPUT), valid_ioctls); | |
743 | __set_bit(_IOC_NR(VIDIOC_S_INPUT), valid_ioctls); | |
f645e625 NS |
744 | } else { |
745 | SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input); | |
746 | SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input); | |
747 | SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input); | |
748 | } | |
4b20259f HV |
749 | SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDIO, vidioc_enumaudio); |
750 | SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio); | |
751 | SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio); | |
90d0fc49 | 752 | SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings); |
dd519bb3 | 753 | SET_VALID_IOCTL(ops, VIDIOC_S_EDID, vidioc_s_edid); |
4b20259f HV |
754 | } |
755 | if (is_tx) { | |
f645e625 | 756 | if (is_io_mc) { |
0533d173 CJ |
757 | __set_bit(_IOC_NR(VIDIOC_ENUMOUTPUT), valid_ioctls); |
758 | __set_bit(_IOC_NR(VIDIOC_G_OUTPUT), valid_ioctls); | |
759 | __set_bit(_IOC_NR(VIDIOC_S_OUTPUT), valid_ioctls); | |
f645e625 NS |
760 | } else { |
761 | SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output); | |
762 | SET_VALID_IOCTL(ops, VIDIOC_G_OUTPUT, vidioc_g_output); | |
763 | SET_VALID_IOCTL(ops, VIDIOC_S_OUTPUT, vidioc_s_output); | |
764 | } | |
4b20259f HV |
765 | SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDOUT, vidioc_enumaudout); |
766 | SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout); | |
767 | SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout); | |
768 | } | |
4fbd54bb | 769 | if (ops->vidioc_g_parm || ops->vidioc_g_std) |
0533d173 | 770 | __set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls); |
4b20259f | 771 | SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm); |
4b20259f HV |
772 | SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings); |
773 | SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings); | |
774 | SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings); | |
4b20259f | 775 | SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap); |
dd519bb3 | 776 | SET_VALID_IOCTL(ops, VIDIOC_G_EDID, vidioc_g_edid); |
4b20259f | 777 | } |
bfffd743 HV |
778 | if (is_tx && (is_radio || is_sdr)) { |
779 | /* radio transmitter only ioctls */ | |
90d0fc49 HV |
780 | SET_VALID_IOCTL(ops, VIDIOC_G_MODULATOR, vidioc_g_modulator); |
781 | SET_VALID_IOCTL(ops, VIDIOC_S_MODULATOR, vidioc_s_modulator); | |
782 | } | |
8669d847 | 783 | if (is_rx && !is_tch) { |
90d0fc49 HV |
784 | /* receiver only ioctls */ |
785 | SET_VALID_IOCTL(ops, VIDIOC_G_TUNER, vidioc_g_tuner); | |
786 | SET_VALID_IOCTL(ops, VIDIOC_S_TUNER, vidioc_s_tuner); | |
787 | SET_VALID_IOCTL(ops, VIDIOC_S_HW_FREQ_SEEK, vidioc_s_hw_freq_seek); | |
788 | } | |
c9edd2e4 EL |
789 | if (is_edid) { |
790 | SET_VALID_IOCTL(ops, VIDIOC_G_EDID, vidioc_g_edid); | |
791 | if (is_tx) { | |
792 | SET_VALID_IOCTL(ops, VIDIOC_G_OUTPUT, vidioc_g_output); | |
793 | SET_VALID_IOCTL(ops, VIDIOC_S_OUTPUT, vidioc_s_output); | |
794 | SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output); | |
795 | } | |
796 | if (is_rx) { | |
797 | SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input); | |
798 | SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input); | |
799 | SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input); | |
800 | SET_VALID_IOCTL(ops, VIDIOC_S_EDID, vidioc_s_edid); | |
801 | } | |
802 | } | |
90d0fc49 | 803 | |
48ea0be0 HV |
804 | bitmap_andnot(vdev->valid_ioctls, valid_ioctls, vdev->valid_ioctls, |
805 | BASE_VIDIOC_PRIVATE); | |
806 | } | |
807 | ||
be2fff65 | 808 | static int video_register_media_controller(struct video_device *vdev) |
d9c21e3e MCC |
809 | { |
810 | #if defined(CONFIG_MEDIA_CONTROLLER) | |
811 | u32 intf_type; | |
812 | int ret; | |
813 | ||
be2fff65 EG |
814 | /* Memory-to-memory devices are more complex and use |
815 | * their own function to register its mc entities. | |
816 | */ | |
817 | if (!vdev->v4l2_dev->mdev || vdev->vfl_dir == VFL_DIR_M2M) | |
d9c21e3e MCC |
818 | return 0; |
819 | ||
b76a2a8c | 820 | vdev->entity.obj_type = MEDIA_ENTITY_TYPE_VIDEO_DEVICE; |
4ca72efa | 821 | vdev->entity.function = MEDIA_ENT_F_UNKNOWN; |
d9c21e3e | 822 | |
be2fff65 | 823 | switch (vdev->vfl_type) { |
238e4a5b | 824 | case VFL_TYPE_VIDEO: |
d9c21e3e | 825 | intf_type = MEDIA_INTF_T_V4L_VIDEO; |
4ca72efa | 826 | vdev->entity.function = MEDIA_ENT_F_IO_V4L; |
d9c21e3e MCC |
827 | break; |
828 | case VFL_TYPE_VBI: | |
829 | intf_type = MEDIA_INTF_T_V4L_VBI; | |
4ca72efa | 830 | vdev->entity.function = MEDIA_ENT_F_IO_VBI; |
d9c21e3e MCC |
831 | break; |
832 | case VFL_TYPE_SDR: | |
833 | intf_type = MEDIA_INTF_T_V4L_SWRADIO; | |
4ca72efa | 834 | vdev->entity.function = MEDIA_ENT_F_IO_SWRADIO; |
d9c21e3e | 835 | break; |
b2fe22d0 ND |
836 | case VFL_TYPE_TOUCH: |
837 | intf_type = MEDIA_INTF_T_V4L_TOUCH; | |
838 | vdev->entity.function = MEDIA_ENT_F_IO_V4L; | |
839 | break; | |
d9c21e3e MCC |
840 | case VFL_TYPE_RADIO: |
841 | intf_type = MEDIA_INTF_T_V4L_RADIO; | |
842 | /* | |
843 | * Radio doesn't have an entity at the V4L2 side to represent | |
844 | * radio input or output. Instead, the audio input/output goes | |
845 | * via either physical wires or ALSA. | |
846 | */ | |
847 | break; | |
848 | case VFL_TYPE_SUBDEV: | |
849 | intf_type = MEDIA_INTF_T_V4L_SUBDEV; | |
850 | /* Entity will be created via v4l2_device_register_subdev() */ | |
851 | break; | |
852 | default: | |
853 | return 0; | |
854 | } | |
855 | ||
4ca72efa | 856 | if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) { |
d9c21e3e MCC |
857 | vdev->entity.name = vdev->name; |
858 | ||
859 | /* Needed just for backward compatibility with legacy MC API */ | |
860 | vdev->entity.info.dev.major = VIDEO_MAJOR; | |
861 | vdev->entity.info.dev.minor = vdev->minor; | |
862 | ||
863 | ret = media_device_register_entity(vdev->v4l2_dev->mdev, | |
864 | &vdev->entity); | |
865 | if (ret < 0) { | |
baa057e2 | 866 | pr_warn("%s: media_device_register_entity failed\n", |
d9c21e3e MCC |
867 | __func__); |
868 | return ret; | |
869 | } | |
870 | } | |
871 | ||
872 | vdev->intf_devnode = media_devnode_create(vdev->v4l2_dev->mdev, | |
873 | intf_type, | |
874 | 0, VIDEO_MAJOR, | |
0b3b72df | 875 | vdev->minor); |
d9c21e3e MCC |
876 | if (!vdev->intf_devnode) { |
877 | media_device_unregister_entity(&vdev->entity); | |
878 | return -ENOMEM; | |
879 | } | |
880 | ||
4ca72efa | 881 | if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) { |
d9c21e3e MCC |
882 | struct media_link *link; |
883 | ||
884 | link = media_create_intf_link(&vdev->entity, | |
13f6e888 | 885 | &vdev->intf_devnode->intf, |
4d1e4545 HV |
886 | MEDIA_LNK_FL_ENABLED | |
887 | MEDIA_LNK_FL_IMMUTABLE); | |
d9c21e3e MCC |
888 | if (!link) { |
889 | media_devnode_remove(vdev->intf_devnode); | |
890 | media_device_unregister_entity(&vdev->entity); | |
891 | return -ENOMEM; | |
892 | } | |
893 | } | |
894 | ||
895 | /* FIXME: how to create the other interface links? */ | |
896 | ||
897 | #endif | |
898 | return 0; | |
899 | } | |
900 | ||
4839c58f MCC |
901 | int __video_register_device(struct video_device *vdev, |
902 | enum vfl_devnode_type type, | |
903 | int nr, int warn_if_nr_in_use, | |
904 | struct module *owner) | |
27a5e6d3 HV |
905 | { |
906 | int i = 0; | |
27a5e6d3 | 907 | int ret; |
dd89601d HV |
908 | int minor_offset = 0; |
909 | int minor_cnt = VIDEO_NUM_DEVICES; | |
910 | const char *name_base; | |
27a5e6d3 | 911 | |
dc93a70c HV |
912 | /* A minor value of -1 marks this video device as never |
913 | having been registered */ | |
428c8d19 | 914 | vdev->minor = -1; |
ee7aa9f8 | 915 | |
dc93a70c | 916 | /* the release callback MUST be present */ |
1fc2b5f7 | 917 | if (WARN_ON(!vdev->release)) |
f3b9f50e | 918 | return -EINVAL; |
1c1d86a1 HV |
919 | /* the v4l2_dev pointer MUST be present */ |
920 | if (WARN_ON(!vdev->v4l2_dev)) | |
921 | return -EINVAL; | |
049e684f HV |
922 | /* the device_caps field MUST be set for all but subdevs */ |
923 | if (WARN_ON(type != VFL_TYPE_SUBDEV && !vdev->device_caps)) | |
3c135050 | 924 | return -EINVAL; |
f3b9f50e | 925 | |
1babcb46 SA |
926 | /* v4l2_fh support */ |
927 | spin_lock_init(&vdev->fh_lock); | |
928 | INIT_LIST_HEAD(&vdev->fh_list); | |
929 | ||
dc93a70c | 930 | /* Part 1: check device type */ |
27a5e6d3 | 931 | switch (type) { |
238e4a5b | 932 | case VFL_TYPE_VIDEO: |
27a5e6d3 HV |
933 | name_base = "video"; |
934 | break; | |
27a5e6d3 | 935 | case VFL_TYPE_VBI: |
27a5e6d3 HV |
936 | name_base = "vbi"; |
937 | break; | |
938 | case VFL_TYPE_RADIO: | |
27a5e6d3 HV |
939 | name_base = "radio"; |
940 | break; | |
2096a5dc LP |
941 | case VFL_TYPE_SUBDEV: |
942 | name_base = "v4l-subdev"; | |
943 | break; | |
d42626bd AP |
944 | case VFL_TYPE_SDR: |
945 | /* Use device name 'swradio' because 'sdr' was already taken. */ | |
946 | name_base = "swradio"; | |
947 | break; | |
b2fe22d0 ND |
948 | case VFL_TYPE_TOUCH: |
949 | name_base = "v4l-touch"; | |
950 | break; | |
27a5e6d3 | 951 | default: |
baa057e2 | 952 | pr_err("%s called with unknown type: %d\n", |
27a5e6d3 | 953 | __func__, type); |
46f2c21c | 954 | return -EINVAL; |
27a5e6d3 HV |
955 | } |
956 | ||
dc93a70c HV |
957 | vdev->vfl_type = type; |
958 | vdev->cdev = NULL; | |
1c1d86a1 HV |
959 | if (vdev->dev_parent == NULL) |
960 | vdev->dev_parent = vdev->v4l2_dev->dev; | |
961 | if (vdev->ctrl_handler == NULL) | |
962 | vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler; | |
963 | /* If the prio state pointer is NULL, then use the v4l2_device | |
964 | prio state. */ | |
965 | if (vdev->prio == NULL) | |
966 | vdev->prio = &vdev->v4l2_dev->prio; | |
dd89601d | 967 | |
22e22125 | 968 | /* Part 2: find a free minor, device node number and device index. */ |
dd89601d HV |
969 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES |
970 | /* Keep the ranges for the first four types for historical | |
971 | * reasons. | |
972 | * Newer devices (not yet in place) should use the range | |
973 | * of 128-191 and just pick the first free minor there | |
974 | * (new style). */ | |
975 | switch (type) { | |
238e4a5b | 976 | case VFL_TYPE_VIDEO: |
dd89601d HV |
977 | minor_offset = 0; |
978 | minor_cnt = 64; | |
979 | break; | |
980 | case VFL_TYPE_RADIO: | |
981 | minor_offset = 64; | |
982 | minor_cnt = 64; | |
983 | break; | |
dd89601d HV |
984 | case VFL_TYPE_VBI: |
985 | minor_offset = 224; | |
986 | minor_cnt = 32; | |
987 | break; | |
988 | default: | |
989 | minor_offset = 128; | |
990 | minor_cnt = 64; | |
991 | break; | |
992 | } | |
993 | #endif | |
994 | ||
22e22125 | 995 | /* Pick a device node number */ |
27a5e6d3 | 996 | mutex_lock(&videodev_lock); |
5062cb70 | 997 | nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt); |
dd89601d | 998 | if (nr == minor_cnt) |
5062cb70 | 999 | nr = devnode_find(vdev, 0, minor_cnt); |
dd89601d | 1000 | if (nr == minor_cnt) { |
baa057e2 | 1001 | pr_err("could not get a free device node number\n"); |
dd89601d HV |
1002 | mutex_unlock(&videodev_lock); |
1003 | return -ENFILE; | |
27a5e6d3 | 1004 | } |
dd89601d | 1005 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES |
22e22125 | 1006 | /* 1-on-1 mapping of device node number to minor number */ |
dd89601d HV |
1007 | i = nr; |
1008 | #else | |
22e22125 HV |
1009 | /* The device node number and minor numbers are independent, so |
1010 | we just find the first free minor number. */ | |
dd89601d | 1011 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) |
ee758243 | 1012 | if (video_devices[i] == NULL) |
dd89601d HV |
1013 | break; |
1014 | if (i == VIDEO_NUM_DEVICES) { | |
1015 | mutex_unlock(&videodev_lock); | |
baa057e2 | 1016 | pr_err("could not get a free minor\n"); |
dd89601d HV |
1017 | return -ENFILE; |
1018 | } | |
1019 | #endif | |
dc93a70c HV |
1020 | vdev->minor = i + minor_offset; |
1021 | vdev->num = nr; | |
5062cb70 | 1022 | |
dc93a70c | 1023 | /* Should not happen since we thought this minor was free */ |
ee758243 | 1024 | if (WARN_ON(video_devices[vdev->minor])) { |
a95845ba | 1025 | mutex_unlock(&videodev_lock); |
baa057e2 | 1026 | pr_err("video_device not empty!\n"); |
a95845ba MCC |
1027 | return -ENFILE; |
1028 | } | |
1029 | devnode_set(vdev); | |
7ae0cd9b | 1030 | vdev->index = get_index(vdev); |
ee758243 | 1031 | video_devices[vdev->minor] = vdev; |
27a5e6d3 HV |
1032 | mutex_unlock(&videodev_lock); |
1033 | ||
48ea0be0 HV |
1034 | if (vdev->ioctl_ops) |
1035 | determine_valid_ioctls(vdev); | |
1036 | ||
dc93a70c HV |
1037 | /* Part 3: Initialize the character device */ |
1038 | vdev->cdev = cdev_alloc(); | |
1039 | if (vdev->cdev == NULL) { | |
1040 | ret = -ENOMEM; | |
1041 | goto cleanup; | |
1042 | } | |
86a5ef7d | 1043 | vdev->cdev->ops = &v4l2_fops; |
2096a5dc | 1044 | vdev->cdev->owner = owner; |
dc93a70c | 1045 | ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1); |
7f8ecfab | 1046 | if (ret < 0) { |
baa057e2 | 1047 | pr_err("%s: cdev_add failed\n", __func__); |
dc93a70c HV |
1048 | kfree(vdev->cdev); |
1049 | vdev->cdev = NULL; | |
1050 | goto cleanup; | |
7f8ecfab | 1051 | } |
dc93a70c HV |
1052 | |
1053 | /* Part 4: register the device with sysfs */ | |
dc93a70c HV |
1054 | vdev->dev.class = &video_class; |
1055 | vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor); | |
1c1d86a1 | 1056 | vdev->dev.parent = vdev->dev_parent; |
2a934fdb | 1057 | vdev->dev.release = v4l2_device_release; |
22e22125 | 1058 | dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num); |
2a934fdb MK |
1059 | |
1060 | /* Increase v4l2_device refcount */ | |
1061 | v4l2_device_get(vdev->v4l2_dev); | |
1062 | ||
1ed4477f | 1063 | mutex_lock(&videodev_lock); |
dc93a70c | 1064 | ret = device_register(&vdev->dev); |
27a5e6d3 | 1065 | if (ret < 0) { |
1ed4477f | 1066 | mutex_unlock(&videodev_lock); |
baa057e2 | 1067 | pr_err("%s: device_register failed\n", __func__); |
2a934fdb MK |
1068 | put_device(&vdev->dev); |
1069 | return ret; | |
27a5e6d3 | 1070 | } |
27a5e6d3 | 1071 | |
6b5270d2 | 1072 | if (nr != -1 && nr != vdev->num && warn_if_nr_in_use) |
baa057e2 | 1073 | pr_warn("%s: requested %s%d, got %s\n", __func__, |
eac8ea53 | 1074 | name_base, nr, video_device_node_name(vdev)); |
bedf8bcf | 1075 | |
2c0ab67b | 1076 | /* Part 5: Register the entity. */ |
be2fff65 | 1077 | ret = video_register_media_controller(vdev); |
d9c21e3e | 1078 | |
2c0ab67b | 1079 | /* Part 6: Activate this minor. The char device can now be used. */ |
957b4aa9 | 1080 | set_bit(V4L2_FL_REGISTERED, &vdev->flags); |
1ed4477f | 1081 | mutex_unlock(&videodev_lock); |
2c0ab67b | 1082 | |
dc93a70c | 1083 | return 0; |
7f8ecfab | 1084 | |
dc93a70c | 1085 | cleanup: |
27a5e6d3 | 1086 | mutex_lock(&videodev_lock); |
dc93a70c HV |
1087 | if (vdev->cdev) |
1088 | cdev_del(vdev->cdev); | |
ee758243 | 1089 | video_devices[vdev->minor] = NULL; |
5062cb70 | 1090 | devnode_clear(vdev); |
27a5e6d3 | 1091 | mutex_unlock(&videodev_lock); |
dc93a70c HV |
1092 | /* Mark this video device as never having been registered. */ |
1093 | vdev->minor = -1; | |
27a5e6d3 HV |
1094 | return ret; |
1095 | } | |
2096a5dc | 1096 | EXPORT_SYMBOL(__video_register_device); |
6b5270d2 | 1097 | |
27a5e6d3 HV |
1098 | /** |
1099 | * video_unregister_device - unregister a video4linux device | |
dc93a70c | 1100 | * @vdev: the device to unregister |
27a5e6d3 | 1101 | * |
dc93a70c HV |
1102 | * This unregisters the passed device. Future open calls will |
1103 | * be met with errors. | |
27a5e6d3 | 1104 | */ |
dc93a70c | 1105 | void video_unregister_device(struct video_device *vdev) |
27a5e6d3 | 1106 | { |
dc93a70c | 1107 | /* Check if vdev was ever registered at all */ |
957b4aa9 | 1108 | if (!vdev || !video_is_registered(vdev)) |
dc93a70c HV |
1109 | return; |
1110 | ||
ca9afe6f HV |
1111 | mutex_lock(&videodev_lock); |
1112 | /* This must be in a critical section to prevent a race with v4l2_open. | |
1113 | * Once this bit has been cleared video_get may never be called again. | |
1114 | */ | |
957b4aa9 | 1115 | clear_bit(V4L2_FL_REGISTERED, &vdev->flags); |
ca9afe6f | 1116 | mutex_unlock(&videodev_lock); |
28955a61 HV |
1117 | if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags)) |
1118 | v4l2_event_wake_all(vdev); | |
dc93a70c | 1119 | device_unregister(&vdev->dev); |
27a5e6d3 HV |
1120 | } |
1121 | EXPORT_SYMBOL(video_unregister_device); | |
1122 | ||
ccb32f23 HV |
1123 | #ifdef CONFIG_DEBUG_FS |
1124 | struct dentry *v4l2_debugfs_root(void) | |
1125 | { | |
1126 | if (!v4l2_debugfs_root_dir) | |
1127 | v4l2_debugfs_root_dir = debugfs_create_dir("v4l2", NULL); | |
1128 | return v4l2_debugfs_root_dir; | |
1129 | } | |
1130 | EXPORT_SYMBOL_GPL(v4l2_debugfs_root); | |
1131 | #endif | |
1132 | ||
340eba47 TV |
1133 | #if defined(CONFIG_MEDIA_CONTROLLER) |
1134 | ||
1135 | __must_check int video_device_pipeline_start(struct video_device *vdev, | |
1136 | struct media_pipeline *pipe) | |
1137 | { | |
1138 | struct media_entity *entity = &vdev->entity; | |
1139 | ||
1140 | if (entity->num_pads != 1) | |
1141 | return -ENODEV; | |
1142 | ||
9e3576a1 | 1143 | return media_pipeline_start(&entity->pads[0], pipe); |
340eba47 TV |
1144 | } |
1145 | EXPORT_SYMBOL_GPL(video_device_pipeline_start); | |
1146 | ||
1147 | __must_check int __video_device_pipeline_start(struct video_device *vdev, | |
1148 | struct media_pipeline *pipe) | |
1149 | { | |
1150 | struct media_entity *entity = &vdev->entity; | |
1151 | ||
1152 | if (entity->num_pads != 1) | |
1153 | return -ENODEV; | |
1154 | ||
9e3576a1 | 1155 | return __media_pipeline_start(&entity->pads[0], pipe); |
340eba47 TV |
1156 | } |
1157 | EXPORT_SYMBOL_GPL(__video_device_pipeline_start); | |
1158 | ||
1159 | void video_device_pipeline_stop(struct video_device *vdev) | |
1160 | { | |
1161 | struct media_entity *entity = &vdev->entity; | |
1162 | ||
1163 | if (WARN_ON(entity->num_pads != 1)) | |
1164 | return; | |
1165 | ||
9e3576a1 | 1166 | return media_pipeline_stop(&entity->pads[0]); |
340eba47 TV |
1167 | } |
1168 | EXPORT_SYMBOL_GPL(video_device_pipeline_stop); | |
1169 | ||
1170 | void __video_device_pipeline_stop(struct video_device *vdev) | |
1171 | { | |
1172 | struct media_entity *entity = &vdev->entity; | |
1173 | ||
1174 | if (WARN_ON(entity->num_pads != 1)) | |
1175 | return; | |
1176 | ||
9e3576a1 | 1177 | return __media_pipeline_stop(&entity->pads[0]); |
340eba47 TV |
1178 | } |
1179 | EXPORT_SYMBOL_GPL(__video_device_pipeline_stop); | |
1180 | ||
d9f44345 TV |
1181 | __must_check int video_device_pipeline_alloc_start(struct video_device *vdev) |
1182 | { | |
1183 | struct media_entity *entity = &vdev->entity; | |
1184 | ||
1185 | if (entity->num_pads != 1) | |
1186 | return -ENODEV; | |
1187 | ||
9e3576a1 | 1188 | return media_pipeline_alloc_start(&entity->pads[0]); |
d9f44345 TV |
1189 | } |
1190 | EXPORT_SYMBOL_GPL(video_device_pipeline_alloc_start); | |
1191 | ||
340eba47 TV |
1192 | struct media_pipeline *video_device_pipeline(struct video_device *vdev) |
1193 | { | |
1194 | struct media_entity *entity = &vdev->entity; | |
1195 | ||
1196 | if (WARN_ON(entity->num_pads != 1)) | |
1197 | return NULL; | |
1198 | ||
9e3576a1 | 1199 | return media_pad_pipeline(&entity->pads[0]); |
340eba47 TV |
1200 | } |
1201 | EXPORT_SYMBOL_GPL(video_device_pipeline); | |
1202 | ||
1203 | #endif /* CONFIG_MEDIA_CONTROLLER */ | |
1204 | ||
27a5e6d3 HV |
1205 | /* |
1206 | * Initialise video for linux | |
1207 | */ | |
27a5e6d3 HV |
1208 | static int __init videodev_init(void) |
1209 | { | |
7f8ecfab | 1210 | dev_t dev = MKDEV(VIDEO_MAJOR, 0); |
27a5e6d3 HV |
1211 | int ret; |
1212 | ||
baa057e2 | 1213 | pr_info("Linux video capture interface: v2.00\n"); |
7f8ecfab HV |
1214 | ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME); |
1215 | if (ret < 0) { | |
baa057e2 | 1216 | pr_warn("videodev: unable to get major %d\n", |
7f8ecfab HV |
1217 | VIDEO_MAJOR); |
1218 | return ret; | |
27a5e6d3 HV |
1219 | } |
1220 | ||
1221 | ret = class_register(&video_class); | |
1222 | if (ret < 0) { | |
7f8ecfab | 1223 | unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); |
baa057e2 | 1224 | pr_warn("video_dev: class_register failed\n"); |
27a5e6d3 HV |
1225 | return -EIO; |
1226 | } | |
1227 | ||
1228 | return 0; | |
1229 | } | |
1230 | ||
1231 | static void __exit videodev_exit(void) | |
1232 | { | |
7f8ecfab HV |
1233 | dev_t dev = MKDEV(VIDEO_MAJOR, 0); |
1234 | ||
27a5e6d3 | 1235 | class_unregister(&video_class); |
7f8ecfab | 1236 | unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); |
ccb32f23 HV |
1237 | debugfs_remove_recursive(v4l2_debugfs_root_dir); |
1238 | v4l2_debugfs_root_dir = NULL; | |
27a5e6d3 HV |
1239 | } |
1240 | ||
ee981c6f | 1241 | subsys_initcall(videodev_init); |
27a5e6d3 HV |
1242 | module_exit(videodev_exit) |
1243 | ||
ff35213f EG |
1244 | MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@kernel.org>, Bill Dirks, Justin Schoeman, Gerd Knorr"); |
1245 | MODULE_DESCRIPTION("Video4Linux2 core driver"); | |
27a5e6d3 | 1246 | MODULE_LICENSE("GPL"); |
cbb72b0f | 1247 | MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR); |