aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/v4l2-dev.c
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2008-10-04 07:36:54 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-10-12 07:37:16 -0400
commitdd89601d47e2eeab7c17b25f2549444751bcffe4 (patch)
treeda21e8b17e49d175f5b8cbd14a772bf00f7fb63a /drivers/media/video/v4l2-dev.c
parente86a93dc3c870c412592c1f298c1425d80c58c6e (diff)
V4L/DVB (9133): v4l: disconnect kernel number from minor
The v4l core creates four different video devices (video, vbi, radio, vtx) and each has its own range of minor numbers. However, modern devices keep increasing the number of devices that they need so a maximum of 64 video devices will not be enough in the future. In addition this scheme makes it very hard to add new device types. This patch disconnects the kernel number allocation (e.g. video0, video1, etc.) from the actual minor number (just pick the first free minor). This allows for much more flexibility in the future. However, it does require the use of udev. For those who cannot use udev a new CONFIG option was created that changes the allocation scheme back to the old behavior. Thanks to Greg KH for suggesting this approach during the 2008 LPC. In addition, several bugs were fixed in the ivtv and cx18 drivers: these drivers try to allocate specific kernel numbers but that scheme contained a bug which caused what should have been e.g. video17 to appear as e.g. video2. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/v4l2-dev.c')
-rw-r--r--drivers/media/video/v4l2-dev.c96
1 files changed, 65 insertions, 31 deletions
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 7addf2fd55de..ccd6566a515e 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -65,6 +65,7 @@ static struct device_attribute video_device_attrs[] = {
65 */ 65 */
66static struct video_device *video_device[VIDEO_NUM_DEVICES]; 66static struct video_device *video_device[VIDEO_NUM_DEVICES];
67static DEFINE_MUTEX(videodev_lock); 67static DEFINE_MUTEX(videodev_lock);
68static DECLARE_BITMAP(video_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
68 69
69struct video_device *video_device_alloc(void) 70struct video_device *video_device_alloc(void)
70{ 71{
@@ -99,6 +100,7 @@ static void v4l2_chardev_release(struct kobject *kobj)
99 100
100 /* Free up this device for reuse */ 101 /* Free up this device for reuse */
101 video_device[vfd->minor] = NULL; 102 video_device[vfd->minor] = NULL;
103 clear_bit(vfd->num, video_nums[vfd->vfl_type]);
102 mutex_unlock(&videodev_lock); 104 mutex_unlock(&videodev_lock);
103 105
104 /* Release the character device */ 106 /* Release the character device */
@@ -217,10 +219,10 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
217 int index) 219 int index)
218{ 220{
219 int i = 0; 221 int i = 0;
220 int base;
221 int end;
222 int ret; 222 int ret;
223 char *name_base; 223 int minor_offset = 0;
224 int minor_cnt = VIDEO_NUM_DEVICES;
225 const char *name_base;
224 void *priv = video_get_drvdata(vfd); 226 void *priv = video_get_drvdata(vfd);
225 227
226 /* the release callback MUST be present */ 228 /* the release callback MUST be present */
@@ -231,23 +233,15 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
231 233
232 switch (type) { 234 switch (type) {
233 case VFL_TYPE_GRABBER: 235 case VFL_TYPE_GRABBER:
234 base = MINOR_VFL_TYPE_GRABBER_MIN;
235 end = MINOR_VFL_TYPE_GRABBER_MAX+1;
236 name_base = "video"; 236 name_base = "video";
237 break; 237 break;
238 case VFL_TYPE_VTX: 238 case VFL_TYPE_VTX:
239 base = MINOR_VFL_TYPE_VTX_MIN;
240 end = MINOR_VFL_TYPE_VTX_MAX+1;
241 name_base = "vtx"; 239 name_base = "vtx";
242 break; 240 break;
243 case VFL_TYPE_VBI: 241 case VFL_TYPE_VBI:
244 base = MINOR_VFL_TYPE_VBI_MIN;
245 end = MINOR_VFL_TYPE_VBI_MAX+1;
246 name_base = "vbi"; 242 name_base = "vbi";
247 break; 243 break;
248 case VFL_TYPE_RADIO: 244 case VFL_TYPE_RADIO:
249 base = MINOR_VFL_TYPE_RADIO_MIN;
250 end = MINOR_VFL_TYPE_RADIO_MAX+1;
251 name_base = "radio"; 245 name_base = "radio";
252 break; 246 break;
253 default: 247 default:
@@ -256,31 +250,70 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
256 return -EINVAL; 250 return -EINVAL;
257 } 251 }
258 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
259 /* Initialize the character device */ 285 /* Initialize the character device */
260 cdev_init(&vfd->cdev, vfd->fops); 286 cdev_init(&vfd->cdev, vfd->fops);
261 vfd->cdev.owner = vfd->fops->owner; 287 vfd->cdev.owner = vfd->fops->owner;
262 /* pick a minor number */ 288 /* pick a minor number */
263 mutex_lock(&videodev_lock); 289 mutex_lock(&videodev_lock);
264 if (nr >= 0 && nr < end-base) { 290 nr = find_next_zero_bit(video_nums[type], minor_cnt, nr == -1 ? 0 : nr);
265 /* use the one the driver asked for */ 291 if (nr == minor_cnt)
266 i = base + nr; 292 nr = find_first_zero_bit(video_nums[type], minor_cnt);
267 if (NULL != video_device[i]) { 293 if (nr == minor_cnt) {
268 mutex_unlock(&videodev_lock); 294 printk(KERN_ERR "could not get a free kernel number\n");
269 return -ENFILE; 295 mutex_unlock(&videodev_lock);
270 } 296 return -ENFILE;
271 } else {
272 /* use first free */
273 for (i = base; i < end; i++)
274 if (NULL == video_device[i])
275 break;
276 if (i == end) {
277 mutex_unlock(&videodev_lock);
278 return -ENFILE;
279 }
280 } 297 }
281 video_device[i] = vfd; 298#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
282 vfd->vfl_type = type; 299 /* 1-on-1 mapping of kernel number to minor number */
283 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;
284 317
285 ret = get_index(vfd, index); 318 ret = get_index(vfd, index);
286 vfd->index = ret; 319 vfd->index = ret;
@@ -306,7 +339,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr,
306 vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); 339 vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
307 if (vfd->parent) 340 if (vfd->parent)
308 vfd->dev.parent = vfd->parent; 341 vfd->dev.parent = vfd->parent;
309 sprintf(vfd->dev.bus_id, "%s%d", name_base, i - base); 342 sprintf(vfd->dev.bus_id, "%s%d", name_base, nr);
310 ret = device_register(&vfd->dev); 343 ret = device_register(&vfd->dev);
311 if (ret < 0) { 344 if (ret < 0) {
312 printk(KERN_ERR "%s: device_register failed\n", __func__); 345 printk(KERN_ERR "%s: device_register failed\n", __func__);
@@ -324,6 +357,7 @@ del_cdev:
324fail_minor: 357fail_minor:
325 mutex_lock(&videodev_lock); 358 mutex_lock(&videodev_lock);
326 video_device[vfd->minor] = NULL; 359 video_device[vfd->minor] = NULL;
360 clear_bit(vfd->num, video_nums[type]);
327 mutex_unlock(&videodev_lock); 361 mutex_unlock(&videodev_lock);
328 vfd->minor = -1; 362 vfd->minor = -1;
329 return ret; 363 return ret;