diff options
Diffstat (limited to 'drivers/media/video/v4l2-dev.c')
-rw-r--r-- | drivers/media/video/v4l2-dev.c | 300 |
1 files changed, 150 insertions, 150 deletions
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c index 155fdec9ac7d..ccd6566a515e 100644 --- a/drivers/media/video/v4l2-dev.c +++ b/drivers/media/video/v4l2-dev.c | |||
@@ -42,6 +42,7 @@ static ssize_t show_index(struct device *cd, | |||
42 | struct device_attribute *attr, char *buf) | 42 | struct device_attribute *attr, char *buf) |
43 | { | 43 | { |
44 | struct video_device *vfd = container_of(cd, struct video_device, dev); | 44 | struct video_device *vfd = container_of(cd, struct video_device, dev); |
45 | |||
45 | return sprintf(buf, "%i\n", vfd->index); | 46 | return sprintf(buf, "%i\n", vfd->index); |
46 | } | 47 | } |
47 | 48 | ||
@@ -49,6 +50,7 @@ static ssize_t show_name(struct device *cd, | |||
49 | struct device_attribute *attr, char *buf) | 50 | struct device_attribute *attr, char *buf) |
50 | { | 51 | { |
51 | struct video_device *vfd = container_of(cd, struct video_device, dev); | 52 | struct video_device *vfd = container_of(cd, struct video_device, dev); |
53 | |||
52 | return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); | 54 | return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); |
53 | } | 55 | } |
54 | 56 | ||
@@ -58,12 +60,16 @@ static struct device_attribute video_device_attrs[] = { | |||
58 | __ATTR_NULL | 60 | __ATTR_NULL |
59 | }; | 61 | }; |
60 | 62 | ||
63 | /* | ||
64 | * Active devices | ||
65 | */ | ||
66 | static struct video_device *video_device[VIDEO_NUM_DEVICES]; | ||
67 | static DEFINE_MUTEX(videodev_lock); | ||
68 | static DECLARE_BITMAP(video_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES); | ||
69 | |||
61 | struct video_device *video_device_alloc(void) | 70 | struct video_device *video_device_alloc(void) |
62 | { | 71 | { |
63 | struct video_device *vfd; | 72 | return kzalloc(sizeof(struct video_device), GFP_KERNEL); |
64 | |||
65 | vfd = kzalloc(sizeof(*vfd), GFP_KERNEL); | ||
66 | return vfd; | ||
67 | } | 73 | } |
68 | EXPORT_SYMBOL(video_device_alloc); | 74 | EXPORT_SYMBOL(video_device_alloc); |
69 | 75 | ||
@@ -73,16 +79,52 @@ void video_device_release(struct video_device *vfd) | |||
73 | } | 79 | } |
74 | EXPORT_SYMBOL(video_device_release); | 80 | EXPORT_SYMBOL(video_device_release); |
75 | 81 | ||
82 | void video_device_release_empty(struct video_device *vfd) | ||
83 | { | ||
84 | /* Do nothing */ | ||
85 | /* Only valid when the video_device struct is a static. */ | ||
86 | } | ||
87 | EXPORT_SYMBOL(video_device_release_empty); | ||
88 | |||
89 | /* Called when the last user of the character device is gone. */ | ||
90 | static void v4l2_chardev_release(struct kobject *kobj) | ||
91 | { | ||
92 | struct video_device *vfd = container_of(kobj, struct video_device, cdev.kobj); | ||
93 | |||
94 | mutex_lock(&videodev_lock); | ||
95 | if (video_device[vfd->minor] != vfd) { | ||
96 | mutex_unlock(&videodev_lock); | ||
97 | BUG(); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | /* Free up this device for reuse */ | ||
102 | video_device[vfd->minor] = NULL; | ||
103 | clear_bit(vfd->num, video_nums[vfd->vfl_type]); | ||
104 | mutex_unlock(&videodev_lock); | ||
105 | |||
106 | /* Release the character device */ | ||
107 | vfd->cdev_release(kobj); | ||
108 | /* Release video_device and perform other | ||
109 | cleanups as needed. */ | ||
110 | if (vfd->release) | ||
111 | vfd->release(vfd); | ||
112 | } | ||
113 | |||
114 | /* The new kobj_type for the character device */ | ||
115 | static struct kobj_type v4l2_ktype_cdev_default = { | ||
116 | .release = v4l2_chardev_release, | ||
117 | }; | ||
118 | |||
76 | static void video_release(struct device *cd) | 119 | static void video_release(struct device *cd) |
77 | { | 120 | { |
78 | struct video_device *vfd = container_of(cd, struct video_device, dev); | 121 | struct video_device *vfd = container_of(cd, struct video_device, dev); |
79 | 122 | ||
80 | #if 1 | 123 | /* It's now safe to delete the char device. |
81 | /* needed until all drivers are fixed */ | 124 | This will either trigger the v4l2_chardev_release immediately (if |
82 | if (!vfd->release) | 125 | the refcount goes to 0) or later when the last user of the |
83 | return; | 126 | character device closes it. */ |
84 | #endif | 127 | cdev_del(&vfd->cdev); |
85 | vfd->release(vfd); | ||
86 | } | 128 | } |
87 | 129 | ||
88 | static struct class video_class = { | 130 | static struct class video_class = { |
@@ -91,87 +133,12 @@ static struct class video_class = { | |||
91 | .dev_release = video_release, | 133 | .dev_release = video_release, |
92 | }; | 134 | }; |
93 | 135 | ||
94 | /* | ||
95 | * Active devices | ||
96 | */ | ||
97 | |||
98 | static struct video_device *video_device[VIDEO_NUM_DEVICES]; | ||
99 | static DEFINE_MUTEX(videodev_lock); | ||
100 | |||
101 | struct video_device *video_devdata(struct file *file) | 136 | struct video_device *video_devdata(struct file *file) |
102 | { | 137 | { |
103 | return video_device[iminor(file->f_path.dentry->d_inode)]; | 138 | return video_device[iminor(file->f_path.dentry->d_inode)]; |
104 | } | 139 | } |
105 | EXPORT_SYMBOL(video_devdata); | 140 | EXPORT_SYMBOL(video_devdata); |
106 | 141 | ||
107 | /* | ||
108 | * Open a video device - FIXME: Obsoleted | ||
109 | */ | ||
110 | static int video_open(struct inode *inode, struct file *file) | ||
111 | { | ||
112 | unsigned int minor = iminor(inode); | ||
113 | int err = 0; | ||
114 | struct video_device *vfl; | ||
115 | const struct file_operations *old_fops; | ||
116 | |||
117 | if (minor >= VIDEO_NUM_DEVICES) | ||
118 | return -ENODEV; | ||
119 | lock_kernel(); | ||
120 | mutex_lock(&videodev_lock); | ||
121 | vfl = video_device[minor]; | ||
122 | if (vfl == NULL) { | ||
123 | mutex_unlock(&videodev_lock); | ||
124 | request_module("char-major-%d-%d", VIDEO_MAJOR, minor); | ||
125 | mutex_lock(&videodev_lock); | ||
126 | vfl = video_device[minor]; | ||
127 | if (vfl == NULL) { | ||
128 | mutex_unlock(&videodev_lock); | ||
129 | unlock_kernel(); | ||
130 | return -ENODEV; | ||
131 | } | ||
132 | } | ||
133 | old_fops = file->f_op; | ||
134 | file->f_op = fops_get(vfl->fops); | ||
135 | if (file->f_op->open) | ||
136 | err = file->f_op->open(inode, file); | ||
137 | if (err) { | ||
138 | fops_put(file->f_op); | ||
139 | file->f_op = fops_get(old_fops); | ||
140 | } | ||
141 | fops_put(old_fops); | ||
142 | mutex_unlock(&videodev_lock); | ||
143 | unlock_kernel(); | ||
144 | return err; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * open/release helper functions -- handle exclusive opens | ||
149 | * Should be removed soon | ||
150 | */ | ||
151 | int video_exclusive_open(struct inode *inode, struct file *file) | ||
152 | { | ||
153 | struct video_device *vfl = video_devdata(file); | ||
154 | int retval = 0; | ||
155 | |||
156 | mutex_lock(&vfl->lock); | ||
157 | if (vfl->users) | ||
158 | retval = -EBUSY; | ||
159 | else | ||
160 | vfl->users++; | ||
161 | mutex_unlock(&vfl->lock); | ||
162 | return retval; | ||
163 | } | ||
164 | EXPORT_SYMBOL(video_exclusive_open); | ||
165 | |||
166 | int video_exclusive_release(struct inode *inode, struct file *file) | ||
167 | { | ||
168 | struct video_device *vfl = video_devdata(file); | ||
169 | |||
170 | vfl->users--; | ||
171 | return 0; | ||
172 | } | ||
173 | EXPORT_SYMBOL(video_exclusive_release); | ||
174 | |||
175 | /** | 142 | /** |
176 | * get_index - assign stream number based on parent device | 143 | * get_index - assign stream number based on parent device |
177 | * @vdev: video_device to assign index number to, vdev->dev should be assigned | 144 | * @vdev: video_device to assign index number to, vdev->dev should be assigned |
@@ -252,33 +219,29 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, | |||
252 | int index) | 219 | int index) |
253 | { | 220 | { |
254 | int i = 0; | 221 | int i = 0; |
255 | int base; | ||
256 | int end; | ||
257 | int ret; | 222 | int ret; |
258 | char *name_base; | 223 | int minor_offset = 0; |
224 | int minor_cnt = VIDEO_NUM_DEVICES; | ||
225 | const char *name_base; | ||
226 | void *priv = video_get_drvdata(vfd); | ||
227 | |||
228 | /* the release callback MUST be present */ | ||
229 | BUG_ON(!vfd->release); | ||
259 | 230 | ||
260 | if (vfd == NULL) | 231 | if (vfd == NULL) |
261 | return -EINVAL; | 232 | return -EINVAL; |
262 | 233 | ||
263 | switch (type) { | 234 | switch (type) { |
264 | case VFL_TYPE_GRABBER: | 235 | case VFL_TYPE_GRABBER: |
265 | base = MINOR_VFL_TYPE_GRABBER_MIN; | ||
266 | end = MINOR_VFL_TYPE_GRABBER_MAX+1; | ||
267 | name_base = "video"; | 236 | name_base = "video"; |
268 | break; | 237 | break; |
269 | case VFL_TYPE_VTX: | 238 | case VFL_TYPE_VTX: |
270 | base = MINOR_VFL_TYPE_VTX_MIN; | ||
271 | end = MINOR_VFL_TYPE_VTX_MAX+1; | ||
272 | name_base = "vtx"; | 239 | name_base = "vtx"; |
273 | break; | 240 | break; |
274 | case VFL_TYPE_VBI: | 241 | case VFL_TYPE_VBI: |
275 | base = MINOR_VFL_TYPE_VBI_MIN; | ||
276 | end = MINOR_VFL_TYPE_VBI_MAX+1; | ||
277 | name_base = "vbi"; | 242 | name_base = "vbi"; |
278 | break; | 243 | break; |
279 | case VFL_TYPE_RADIO: | 244 | case VFL_TYPE_RADIO: |
280 | base = MINOR_VFL_TYPE_RADIO_MIN; | ||
281 | end = MINOR_VFL_TYPE_RADIO_MAX+1; | ||
282 | name_base = "radio"; | 245 | name_base = "radio"; |
283 | break; | 246 | break; |
284 | default: | 247 | default: |
@@ -287,28 +250,70 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, | |||
287 | return -EINVAL; | 250 | return -EINVAL; |
288 | } | 251 | } |
289 | 252 | ||
253 | vfd->vfl_type = type; | ||
254 | |||
255 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES | ||
256 | /* Keep the ranges for the first four types for historical | ||
257 | * reasons. | ||
258 | * Newer devices (not yet in place) should use the range | ||
259 | * of 128-191 and just pick the first free minor there | ||
260 | * (new style). */ | ||
261 | switch (type) { | ||
262 | case VFL_TYPE_GRABBER: | ||
263 | minor_offset = 0; | ||
264 | minor_cnt = 64; | ||
265 | break; | ||
266 | case VFL_TYPE_RADIO: | ||
267 | minor_offset = 64; | ||
268 | minor_cnt = 64; | ||
269 | break; | ||
270 | case VFL_TYPE_VTX: | ||
271 | minor_offset = 192; | ||
272 | minor_cnt = 32; | ||
273 | break; | ||
274 | case VFL_TYPE_VBI: | ||
275 | minor_offset = 224; | ||
276 | minor_cnt = 32; | ||
277 | break; | ||
278 | default: | ||
279 | minor_offset = 128; | ||
280 | minor_cnt = 64; | ||
281 | break; | ||
282 | } | ||
283 | #endif | ||
284 | |||
285 | /* Initialize the character device */ | ||
286 | cdev_init(&vfd->cdev, vfd->fops); | ||
287 | vfd->cdev.owner = vfd->fops->owner; | ||
290 | /* pick a minor number */ | 288 | /* pick a minor number */ |
291 | mutex_lock(&videodev_lock); | 289 | mutex_lock(&videodev_lock); |
292 | if (nr >= 0 && nr < end-base) { | 290 | nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr); |
293 | /* use the one the driver asked for */ | 291 | if (nr == minor_cnt) |
294 | i = base + nr; | 292 | nr = find_first_zero_bit(video_nums[type], minor_cnt); |
295 | if (NULL != video_device[i]) { | 293 | if (nr == minor_cnt) { |
296 | mutex_unlock(&videodev_lock); | 294 | printk(KERN_ERR "could not get a free kernel number\n"); |
297 | return -ENFILE; | 295 | mutex_unlock(&videodev_lock); |
298 | } | 296 | return -ENFILE; |
299 | } else { | ||
300 | /* use first free */ | ||
301 | for (i = base; i < end; i++) | ||
302 | if (NULL == video_device[i]) | ||
303 | break; | ||
304 | if (i == end) { | ||
305 | mutex_unlock(&videodev_lock); | ||
306 | return -ENFILE; | ||
307 | } | ||
308 | } | 297 | } |
309 | video_device[i] = vfd; | 298 | #ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES |
310 | vfd->vfl_type = type; | 299 | /* 1-on-1 mapping of kernel number to minor number */ |
311 | vfd->minor = i; | 300 | i = nr; |
301 | #else | ||
302 | /* The kernel number and minor numbers are independent */ | ||
303 | for (i = 0; i < VIDEO_NUM_DEVICES; i++) | ||
304 | if (video_device[i] == NULL) | ||
305 | break; | ||
306 | if (i == VIDEO_NUM_DEVICES) { | ||
307 | mutex_unlock(&videodev_lock); | ||
308 | printk(KERN_ERR "could not get a free minor\n"); | ||
309 | return -ENFILE; | ||
310 | } | ||
311 | #endif | ||
312 | vfd->minor = i + minor_offset; | ||
313 | vfd->num = nr; | ||
314 | set_bit(nr, video_nums[type]); | ||
315 | BUG_ON(video_device[vfd->minor]); | ||
316 | video_device[vfd->minor] = vfd; | ||
312 | 317 | ||
313 | ret = get_index(vfd, index); | 318 | ret = get_index(vfd, index); |
314 | vfd->index = ret; | 319 | vfd->index = ret; |
@@ -320,35 +325,41 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, | |||
320 | goto fail_minor; | 325 | goto fail_minor; |
321 | } | 326 | } |
322 | 327 | ||
323 | mutex_init(&vfd->lock); | 328 | ret = cdev_add(&vfd->cdev, MKDEV(VIDEO_MAJOR, vfd->minor), 1); |
324 | 329 | if (ret < 0) { | |
330 | printk(KERN_ERR "%s: cdev_add failed\n", __func__); | ||
331 | goto fail_minor; | ||
332 | } | ||
325 | /* sysfs class */ | 333 | /* sysfs class */ |
326 | memset(&vfd->dev, 0x00, sizeof(vfd->dev)); | 334 | memset(&vfd->dev, 0, sizeof(vfd->dev)); |
335 | /* The memset above cleared the device's drvdata, so | ||
336 | put back the copy we made earlier. */ | ||
337 | video_set_drvdata(vfd, priv); | ||
327 | vfd->dev.class = &video_class; | 338 | vfd->dev.class = &video_class; |
328 | vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); | 339 | vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); |
329 | if (vfd->parent) | 340 | if (vfd->parent) |
330 | vfd->dev.parent = vfd->parent; | 341 | vfd->dev.parent = vfd->parent; |
331 | sprintf(vfd->dev.bus_id, "%s%d", name_base, i - base); | 342 | sprintf(vfd->dev.bus_id, "%s%d", name_base, nr); |
332 | ret = device_register(&vfd->dev); | 343 | ret = device_register(&vfd->dev); |
333 | if (ret < 0) { | 344 | if (ret < 0) { |
334 | printk(KERN_ERR "%s: device_register failed\n", __func__); | 345 | printk(KERN_ERR "%s: device_register failed\n", __func__); |
335 | goto fail_minor; | 346 | goto del_cdev; |
336 | } | 347 | } |
337 | 348 | /* Remember the cdev's release function */ | |
338 | #if 1 | 349 | vfd->cdev_release = vfd->cdev.kobj.ktype->release; |
339 | /* needed until all drivers are fixed */ | 350 | /* Install our own */ |
340 | if (!vfd->release) | 351 | vfd->cdev.kobj.ktype = &v4l2_ktype_cdev_default; |
341 | printk(KERN_WARNING "videodev: \"%s\" has no release callback. " | ||
342 | "Please fix your driver for proper sysfs support, see " | ||
343 | "http://lwn.net/Articles/36850/\n", vfd->name); | ||
344 | #endif | ||
345 | return 0; | 352 | return 0; |
346 | 353 | ||
354 | del_cdev: | ||
355 | cdev_del(&vfd->cdev); | ||
356 | |||
347 | fail_minor: | 357 | fail_minor: |
348 | mutex_lock(&videodev_lock); | 358 | mutex_lock(&videodev_lock); |
349 | video_device[vfd->minor] = NULL; | 359 | video_device[vfd->minor] = NULL; |
350 | vfd->minor = -1; | 360 | clear_bit(vfd->num, video_nums[type]); |
351 | mutex_unlock(&videodev_lock); | 361 | mutex_unlock(&videodev_lock); |
362 | vfd->minor = -1; | ||
352 | return ret; | 363 | return ret; |
353 | } | 364 | } |
354 | EXPORT_SYMBOL(video_register_device_index); | 365 | EXPORT_SYMBOL(video_register_device_index); |
@@ -363,42 +374,29 @@ EXPORT_SYMBOL(video_register_device_index); | |||
363 | 374 | ||
364 | void video_unregister_device(struct video_device *vfd) | 375 | void video_unregister_device(struct video_device *vfd) |
365 | { | 376 | { |
366 | mutex_lock(&videodev_lock); | ||
367 | if (video_device[vfd->minor] != vfd) | ||
368 | panic("videodev: bad unregister"); | ||
369 | |||
370 | video_device[vfd->minor] = NULL; | ||
371 | device_unregister(&vfd->dev); | 377 | device_unregister(&vfd->dev); |
372 | mutex_unlock(&videodev_lock); | ||
373 | } | 378 | } |
374 | EXPORT_SYMBOL(video_unregister_device); | 379 | EXPORT_SYMBOL(video_unregister_device); |
375 | 380 | ||
376 | /* | 381 | /* |
377 | * Video fs operations | ||
378 | */ | ||
379 | static const struct file_operations video_fops = { | ||
380 | .owner = THIS_MODULE, | ||
381 | .llseek = no_llseek, | ||
382 | .open = video_open, | ||
383 | }; | ||
384 | |||
385 | /* | ||
386 | * Initialise video for linux | 382 | * Initialise video for linux |
387 | */ | 383 | */ |
388 | |||
389 | static int __init videodev_init(void) | 384 | static int __init videodev_init(void) |
390 | { | 385 | { |
386 | dev_t dev = MKDEV(VIDEO_MAJOR, 0); | ||
391 | int ret; | 387 | int ret; |
392 | 388 | ||
393 | printk(KERN_INFO "Linux video capture interface: v2.00\n"); | 389 | printk(KERN_INFO "Linux video capture interface: v2.00\n"); |
394 | if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { | 390 | ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME); |
395 | printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); | 391 | if (ret < 0) { |
396 | return -EIO; | 392 | printk(KERN_WARNING "videodev: unable to get major %d\n", |
393 | VIDEO_MAJOR); | ||
394 | return ret; | ||
397 | } | 395 | } |
398 | 396 | ||
399 | ret = class_register(&video_class); | 397 | ret = class_register(&video_class); |
400 | if (ret < 0) { | 398 | if (ret < 0) { |
401 | unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); | 399 | unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); |
402 | printk(KERN_WARNING "video_dev: class_register failed\n"); | 400 | printk(KERN_WARNING "video_dev: class_register failed\n"); |
403 | return -EIO; | 401 | return -EIO; |
404 | } | 402 | } |
@@ -408,8 +406,10 @@ static int __init videodev_init(void) | |||
408 | 406 | ||
409 | static void __exit videodev_exit(void) | 407 | static void __exit videodev_exit(void) |
410 | { | 408 | { |
409 | dev_t dev = MKDEV(VIDEO_MAJOR, 0); | ||
410 | |||
411 | class_unregister(&video_class); | 411 | class_unregister(&video_class); |
412 | unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); | 412 | unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); |
413 | } | 413 | } |
414 | 414 | ||
415 | module_init(videodev_init) | 415 | module_init(videodev_init) |