diff options
Diffstat (limited to 'drivers/media/video/v4l2-dev.c')
-rw-r--r-- | drivers/media/video/v4l2-dev.c | 96 |
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 | */ |
66 | static struct video_device *video_device[VIDEO_NUM_DEVICES]; | 66 | static struct video_device *video_device[VIDEO_NUM_DEVICES]; |
67 | static DEFINE_MUTEX(videodev_lock); | 67 | static DEFINE_MUTEX(videodev_lock); |
68 | static DECLARE_BITMAP(video_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES); | ||
68 | 69 | ||
69 | struct video_device *video_device_alloc(void) | 70 | struct 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: | |||
324 | fail_minor: | 357 | fail_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; |