aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/media/video/Kconfig9
-rw-r--r--drivers/media/video/cx18/cx18-driver.c4
-rw-r--r--drivers/media/video/cx18/cx18-streams.c41
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c8
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c6
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c40
-rw-r--r--drivers/media/video/v4l2-dev.c96
-rw-r--r--include/media/v4l2-dev.h12
8 files changed, 128 insertions, 88 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index e28e292fe202..2dce16f863bb 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -72,6 +72,15 @@ config VIDEO_ADV_DEBUG
72 V4L devices. 72 V4L devices.
73 In doubt, say N. 73 In doubt, say N.
74 74
75config VIDEO_FIXED_MINOR_RANGES
76 bool "Enable old-style fixed minor ranges for video devices"
77 default n
78 ---help---
79 Say Y here to enable the old-style fixed-range minor assignments.
80 Only useful if you rely on the old behavior and use mknod instead of udev.
81
82 When in doubt, say N.
83
75config VIDEO_HELPER_CHIPS_AUTO 84config VIDEO_HELPER_CHIPS_AUTO
76 bool "Autoselect pertinent encoders/decoders and other helper chips" 85 bool "Autoselect pertinent encoders/decoders and other helper chips"
77 default y 86 default y
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 6bf9ac8c4e70..085121c2b47f 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -175,7 +175,7 @@ MODULE_PARM_DESC(enc_pcm_buffers,
175 "Encoder PCM buffers (in MB)\n" 175 "Encoder PCM buffers (in MB)\n"
176 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); 176 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
177 177
178MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card"); 178MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card");
179 179
180MODULE_AUTHOR("Hans Verkuil"); 180MODULE_AUTHOR("Hans Verkuil");
181MODULE_DESCRIPTION("CX23418 driver"); 181MODULE_DESCRIPTION("CX23418 driver");
@@ -959,7 +959,7 @@ static int module_start(void)
959 959
960 /* Validate parameters */ 960 /* Validate parameters */
961 if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) { 961 if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
962 printk(KERN_ERR "cx18: Exiting, ivtv_first_minor must be between 0 and %d\n", 962 printk(KERN_ERR "cx18: Exiting, cx18_first_minor must be between 0 and %d\n",
963 CX18_MAX_CARDS - 1); 963 CX18_MAX_CARDS - 1);
964 return -1; 964 return -1;
965 } 965 }
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index c752a6a4dbd3..0c8e7542cf60 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -57,7 +57,7 @@ static struct file_operations cx18_v4l2_enc_fops = {
57static struct { 57static struct {
58 const char *name; 58 const char *name;
59 int vfl_type; 59 int vfl_type;
60 int minor_offset; 60 int num_offset;
61 int dma; 61 int dma;
62 enum v4l2_buf_type buf_type; 62 enum v4l2_buf_type buf_type;
63 struct file_operations *fops; 63 struct file_operations *fops;
@@ -144,8 +144,8 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
144{ 144{
145 struct cx18_stream *s = &cx->streams[type]; 145 struct cx18_stream *s = &cx->streams[type];
146 u32 cap = cx->v4l2_cap; 146 u32 cap = cx->v4l2_cap;
147 int minor_offset = cx18_stream_info[type].minor_offset; 147 int num_offset = cx18_stream_info[type].num_offset;
148 int minor; 148 int num = cx->num + cx18_first_minor + num_offset;
149 149
150 /* These four fields are always initialized. If v4l2dev == NULL, then 150 /* These four fields are always initialized. If v4l2dev == NULL, then
151 this stream is not in use. In that case no other fields but these 151 this stream is not in use. In that case no other fields but these
@@ -164,9 +164,6 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
164 !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) 164 !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)))
165 return 0; 165 return 0;
166 166
167 /* card number + user defined offset + device offset */
168 minor = cx->num + cx18_first_minor + minor_offset;
169
170 /* User explicitly selected 0 buffers for these streams, so don't 167 /* User explicitly selected 0 buffers for these streams, so don't
171 create them. */ 168 create them. */
172 if (cx18_stream_info[type].dma != PCI_DMA_NONE && 169 if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
@@ -177,7 +174,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
177 174
178 cx18_stream_init(cx, type); 175 cx18_stream_init(cx, type);
179 176
180 if (minor_offset == -1) 177 if (num_offset == -1)
181 return 0; 178 return 0;
182 179
183 /* allocate and initialize the v4l2 video device structure */ 180 /* allocate and initialize the v4l2 video device structure */
@@ -191,7 +188,7 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
191 snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d", 188 snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d",
192 cx->num); 189 cx->num);
193 190
194 s->v4l2dev->minor = minor; 191 s->v4l2dev->num = num;
195 s->v4l2dev->parent = &cx->dev->dev; 192 s->v4l2dev->parent = &cx->dev->dev;
196 s->v4l2dev->fops = cx18_stream_info[type].fops; 193 s->v4l2dev->fops = cx18_stream_info[type].fops;
197 s->v4l2dev->release = video_device_release; 194 s->v4l2dev->release = video_device_release;
@@ -227,7 +224,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
227{ 224{
228 struct cx18_stream *s = &cx->streams[type]; 225 struct cx18_stream *s = &cx->streams[type];
229 int vfl_type = cx18_stream_info[type].vfl_type; 226 int vfl_type = cx18_stream_info[type].vfl_type;
230 int minor; 227 int num;
231 228
232 /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something? 229 /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
233 * We need a VFL_TYPE_TS defined. 230 * We need a VFL_TYPE_TS defined.
@@ -245,38 +242,44 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
245 if (s->v4l2dev == NULL) 242 if (s->v4l2dev == NULL)
246 return 0; 243 return 0;
247 244
248 minor = s->v4l2dev->minor; 245 num = s->v4l2dev->num;
246 /* card number + user defined offset + device offset */
247 if (type != CX18_ENC_STREAM_TYPE_MPG) {
248 struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
249
250 if (s_mpg->v4l2dev)
251 num = s_mpg->v4l2dev->num + cx18_stream_info[type].num_offset;
252 }
249 253
250 /* Register device. First try the desired minor, then any free one. */ 254 /* Register device. First try the desired minor, then any free one. */
251 if (video_register_device(s->v4l2dev, vfl_type, minor) && 255 if (video_register_device(s->v4l2dev, vfl_type, num)) {
252 video_register_device(s->v4l2dev, vfl_type, -1)) { 256 CX18_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
253 CX18_ERR("Couldn't register v4l2 device for %s minor %d\n", 257 s->name, num);
254 s->name, minor);
255 video_device_release(s->v4l2dev); 258 video_device_release(s->v4l2dev);
256 s->v4l2dev = NULL; 259 s->v4l2dev = NULL;
257 return -ENOMEM; 260 return -ENOMEM;
258 } 261 }
259 minor = s->v4l2dev->minor; 262 num = s->v4l2dev->num;
260 263
261 switch (vfl_type) { 264 switch (vfl_type) {
262 case VFL_TYPE_GRABBER: 265 case VFL_TYPE_GRABBER:
263 CX18_INFO("Registered device video%d for %s (%d MB)\n", 266 CX18_INFO("Registered device video%d for %s (%d MB)\n",
264 minor, s->name, cx->options.megabytes[type]); 267 num, s->name, cx->options.megabytes[type]);
265 break; 268 break;
266 269
267 case VFL_TYPE_RADIO: 270 case VFL_TYPE_RADIO:
268 CX18_INFO("Registered device radio%d for %s\n", 271 CX18_INFO("Registered device radio%d for %s\n",
269 minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); 272 num, s->name);
270 break; 273 break;
271 274
272 case VFL_TYPE_VBI: 275 case VFL_TYPE_VBI:
273 if (cx->options.megabytes[type]) 276 if (cx->options.megabytes[type])
274 CX18_INFO("Registered device vbi%d for %s (%d MB)\n", 277 CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
275 minor - MINOR_VFL_TYPE_VBI_MIN, 278 num,
276 s->name, cx->options.megabytes[type]); 279 s->name, cx->options.megabytes[type]);
277 else 280 else
278 CX18_INFO("Registered device vbi%d for %s\n", 281 CX18_INFO("Registered device vbi%d for %s\n",
279 minor - MINOR_VFL_TYPE_VBI_MIN, s->name); 282 num, s->name);
280 break; 283 break;
281 } 284 }
282 285
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 50d2c7a9b3c1..c53649e5315b 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1600,8 +1600,7 @@ static void em28xx_release_resources(struct em28xx *dev)
1600 /*FIXME: I2C IR should be disconnected */ 1600 /*FIXME: I2C IR should be disconnected */
1601 1601
1602 em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", 1602 em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n",
1603 dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, 1603 dev->vdev->num, dev->vbi_dev->num);
1604 dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
1605 list_del(&dev->devlist); 1604 list_del(&dev->devlist);
1606 if (dev->sbutton_input_dev) 1605 if (dev->sbutton_input_dev)
1607 em28xx_deregister_snapshot_button(dev); 1606 em28xx_deregister_snapshot_button(dev);
@@ -2073,8 +2072,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
2073 video_mux(dev, 0); 2072 video_mux(dev, 0);
2074 2073
2075 em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", 2074 em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n",
2076 dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, 2075 dev->vdev->num, dev->vbi_dev->num);
2077 dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN);
2078 2076
2079 mutex_lock(&em28xx_extension_devlist_lock); 2077 mutex_lock(&em28xx_extension_devlist_lock);
2080 if (!list_empty(&em28xx_extension_devlist)) { 2078 if (!list_empty(&em28xx_extension_devlist)) {
@@ -2274,7 +2272,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
2274 em28xx_warn 2272 em28xx_warn
2275 ("device /dev/video%d is open! Deregistration and memory " 2273 ("device /dev/video%d is open! Deregistration and memory "
2276 "deallocation are deferred on close.\n", 2274 "deallocation are deferred on close.\n",
2277 dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); 2275 dev->vdev->num);
2278 2276
2279 dev->state |= DEV_MISCONFIGURED; 2277 dev->state |= DEV_MISCONFIGURED;
2280 em28xx_uninit_isoc(dev); 2278 em28xx_uninit_isoc(dev);
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 6b04930d1278..7aa61b617496 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -61,14 +61,14 @@
61#include "tuner-xc2028.h" 61#include "tuner-xc2028.h"
62 62
63/* var to keep track of the number of array elements in use */ 63/* var to keep track of the number of array elements in use */
64int ivtv_cards_active = 0; 64int ivtv_cards_active;
65 65
66/* If you have already X v4l cards, then set this to X. This way 66/* If you have already X v4l cards, then set this to X. This way
67 the device numbers stay matched. Example: you have a WinTV card 67 the device numbers stay matched. Example: you have a WinTV card
68 without radio and a PVR-350 with. Normally this would give a 68 without radio and a PVR-350 with. Normally this would give a
69 video1 device together with a radio0 device for the PVR. By 69 video1 device together with a radio0 device for the PVR. By
70 setting this to 1 you ensure that radio0 is now also radio1. */ 70 setting this to 1 you ensure that radio0 is now also radio1. */
71int ivtv_first_minor = 0; 71int ivtv_first_minor;
72 72
73/* Master variable for all ivtv info */ 73/* Master variable for all ivtv info */
74struct ivtv *ivtv_cards[IVTV_MAX_CARDS]; 74struct ivtv *ivtv_cards[IVTV_MAX_CARDS];
@@ -251,7 +251,7 @@ MODULE_PARM_DESC(newi2c,
251 "\t\t\t-1 is autodetect, 0 is off, 1 is on\n" 251 "\t\t\t-1 is autodetect, 0 is off, 1 is on\n"
252 "\t\t\tDefault is autodetect"); 252 "\t\t\tDefault is autodetect");
253 253
254MODULE_PARM_DESC(ivtv_first_minor, "Set minor assigned to first card"); 254MODULE_PARM_DESC(ivtv_first_minor, "Set kernel number assigned to first card");
255 255
256MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); 256MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil");
257MODULE_DESCRIPTION("CX23415/CX23416 driver"); 257MODULE_DESCRIPTION("CX23415/CX23416 driver");
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 730e85d86fc8..24273fbea470 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -75,7 +75,7 @@ static const struct file_operations ivtv_v4l2_dec_fops = {
75static struct { 75static struct {
76 const char *name; 76 const char *name;
77 int vfl_type; 77 int vfl_type;
78 int minor_offset; 78 int num_offset;
79 int dma, pio; 79 int dma, pio;
80 enum v4l2_buf_type buf_type; 80 enum v4l2_buf_type buf_type;
81 const struct file_operations *fops; 81 const struct file_operations *fops;
@@ -171,8 +171,8 @@ static void ivtv_stream_init(struct ivtv *itv, int type)
171static int ivtv_prep_dev(struct ivtv *itv, int type) 171static int ivtv_prep_dev(struct ivtv *itv, int type)
172{ 172{
173 struct ivtv_stream *s = &itv->streams[type]; 173 struct ivtv_stream *s = &itv->streams[type];
174 int minor_offset = ivtv_stream_info[type].minor_offset; 174 int num_offset = ivtv_stream_info[type].num_offset;
175 int minor; 175 int num = itv->num + ivtv_first_minor + num_offset;
176 176
177 /* These four fields are always initialized. If v4l2dev == NULL, then 177 /* These four fields are always initialized. If v4l2dev == NULL, then
178 this stream is not in use. In that case no other fields but these 178 this stream is not in use. In that case no other fields but these
@@ -188,9 +188,6 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
188 if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) 188 if (type >= IVTV_DEC_STREAM_TYPE_MPG && !(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
189 return 0; 189 return 0;
190 190
191 /* card number + user defined offset + device offset */
192 minor = itv->num + ivtv_first_minor + minor_offset;
193
194 /* User explicitly selected 0 buffers for these streams, so don't 191 /* User explicitly selected 0 buffers for these streams, so don't
195 create them. */ 192 create them. */
196 if (ivtv_stream_info[type].dma != PCI_DMA_NONE && 193 if (ivtv_stream_info[type].dma != PCI_DMA_NONE &&
@@ -211,7 +208,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
211 snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s", 208 snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s",
212 itv->num, s->name); 209 itv->num, s->name);
213 210
214 s->v4l2dev->minor = minor; 211 s->v4l2dev->num = num;
215 s->v4l2dev->parent = &itv->dev->dev; 212 s->v4l2dev->parent = &itv->dev->dev;
216 s->v4l2dev->fops = ivtv_stream_info[type].fops; 213 s->v4l2dev->fops = ivtv_stream_info[type].fops;
217 s->v4l2dev->release = video_device_release; 214 s->v4l2dev->release = video_device_release;
@@ -250,39 +247,46 @@ static int ivtv_reg_dev(struct ivtv *itv, int type)
250{ 247{
251 struct ivtv_stream *s = &itv->streams[type]; 248 struct ivtv_stream *s = &itv->streams[type];
252 int vfl_type = ivtv_stream_info[type].vfl_type; 249 int vfl_type = ivtv_stream_info[type].vfl_type;
253 int minor; 250 int num;
254 251
255 if (s->v4l2dev == NULL) 252 if (s->v4l2dev == NULL)
256 return 0; 253 return 0;
257 254
258 minor = s->v4l2dev->minor; 255 num = s->v4l2dev->num;
256 /* card number + user defined offset + device offset */
257 if (type != IVTV_ENC_STREAM_TYPE_MPG) {
258 struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG];
259
260 if (s_mpg->v4l2dev)
261 num = s_mpg->v4l2dev->num + ivtv_stream_info[type].num_offset;
262 }
263
259 /* Register device. First try the desired minor, then any free one. */ 264 /* Register device. First try the desired minor, then any free one. */
260 if (video_register_device(s->v4l2dev, vfl_type, minor) && 265 if (video_register_device(s->v4l2dev, vfl_type, num)) {
261 video_register_device(s->v4l2dev, vfl_type, -1)) { 266 IVTV_ERR("Couldn't register v4l2 device for %s kernel number %d\n",
262 IVTV_ERR("Couldn't register v4l2 device for %s minor %d\n", 267 s->name, num);
263 s->name, minor);
264 video_device_release(s->v4l2dev); 268 video_device_release(s->v4l2dev);
265 s->v4l2dev = NULL; 269 s->v4l2dev = NULL;
266 return -ENOMEM; 270 return -ENOMEM;
267 } 271 }
272 num = s->v4l2dev->num;
268 273
269 switch (vfl_type) { 274 switch (vfl_type) {
270 case VFL_TYPE_GRABBER: 275 case VFL_TYPE_GRABBER:
271 IVTV_INFO("Registered device video%d for %s (%d kB)\n", 276 IVTV_INFO("Registered device video%d for %s (%d kB)\n",
272 s->v4l2dev->minor, s->name, itv->options.kilobytes[type]); 277 num, s->name, itv->options.kilobytes[type]);
273 break; 278 break;
274 case VFL_TYPE_RADIO: 279 case VFL_TYPE_RADIO:
275 IVTV_INFO("Registered device radio%d for %s\n", 280 IVTV_INFO("Registered device radio%d for %s\n",
276 s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); 281 num, s->name);
277 break; 282 break;
278 case VFL_TYPE_VBI: 283 case VFL_TYPE_VBI:
279 if (itv->options.kilobytes[type]) 284 if (itv->options.kilobytes[type])
280 IVTV_INFO("Registered device vbi%d for %s (%d kB)\n", 285 IVTV_INFO("Registered device vbi%d for %s (%d kB)\n",
281 s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, 286 num, s->name, itv->options.kilobytes[type]);
282 s->name, itv->options.kilobytes[type]);
283 else 287 else
284 IVTV_INFO("Registered device vbi%d for %s\n", 288 IVTV_INFO("Registered device vbi%d for %s\n",
285 s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name); 289 num, s->name);
286 break; 290 break;
287 } 291 }
288 return 0; 292 return 0;
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;
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index d129b56e1a9f..a0a6b41c5e09 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -18,20 +18,11 @@
18 18
19#define VIDEO_MAJOR 81 19#define VIDEO_MAJOR 81
20 20
21/* Minor device allocation */
22#define MINOR_VFL_TYPE_GRABBER_MIN 0
23#define MINOR_VFL_TYPE_GRABBER_MAX 63
24#define MINOR_VFL_TYPE_RADIO_MIN 64
25#define MINOR_VFL_TYPE_RADIO_MAX 127
26#define MINOR_VFL_TYPE_VTX_MIN 192
27#define MINOR_VFL_TYPE_VTX_MAX 223
28#define MINOR_VFL_TYPE_VBI_MIN 224
29#define MINOR_VFL_TYPE_VBI_MAX 255
30
31#define VFL_TYPE_GRABBER 0 21#define VFL_TYPE_GRABBER 0
32#define VFL_TYPE_VBI 1 22#define VFL_TYPE_VBI 1
33#define VFL_TYPE_RADIO 2 23#define VFL_TYPE_RADIO 2
34#define VFL_TYPE_VTX 3 24#define VFL_TYPE_VTX 3
25#define VFL_TYPE_MAX 4
35 26
36struct v4l2_ioctl_callbacks; 27struct v4l2_ioctl_callbacks;
37 28
@@ -56,6 +47,7 @@ struct video_device
56 char name[32]; 47 char name[32];
57 int vfl_type; 48 int vfl_type;
58 int minor; 49 int minor;
50 u16 num;
59 /* attribute to differentiate multiple indices on one physical device */ 51 /* attribute to differentiate multiple indices on one physical device */
60 int index; 52 int index;
61 53