diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2008-10-04 07:36:54 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-10-12 07:37:16 -0400 |
commit | dd89601d47e2eeab7c17b25f2549444751bcffe4 (patch) | |
tree | da21e8b17e49d175f5b8cbd14a772bf00f7fb63a /drivers | |
parent | e86a93dc3c870c412592c1f298c1425d80c58c6e (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')
-rw-r--r-- | drivers/media/video/Kconfig | 9 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 4 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-streams.c | 41 | ||||
-rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 8 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-driver.c | 6 | ||||
-rw-r--r-- | drivers/media/video/ivtv/ivtv-streams.c | 40 | ||||
-rw-r--r-- | drivers/media/video/v4l2-dev.c | 96 |
7 files changed, 126 insertions, 78 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 | ||
75 | config 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 | |||
75 | config VIDEO_HELPER_CHIPS_AUTO | 84 | config 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 | ||
178 | MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card"); | 178 | MODULE_PARM_DESC(cx18_first_minor, "Set kernel number assigned to first card"); |
179 | 179 | ||
180 | MODULE_AUTHOR("Hans Verkuil"); | 180 | MODULE_AUTHOR("Hans Verkuil"); |
181 | MODULE_DESCRIPTION("CX23418 driver"); | 181 | MODULE_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 = { | |||
57 | static struct { | 57 | static 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 */ |
64 | int ivtv_cards_active = 0; | 64 | int 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. */ |
71 | int ivtv_first_minor = 0; | 71 | int ivtv_first_minor; |
72 | 72 | ||
73 | /* Master variable for all ivtv info */ | 73 | /* Master variable for all ivtv info */ |
74 | struct ivtv *ivtv_cards[IVTV_MAX_CARDS]; | 74 | struct 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 | ||
254 | MODULE_PARM_DESC(ivtv_first_minor, "Set minor assigned to first card"); | 254 | MODULE_PARM_DESC(ivtv_first_minor, "Set kernel number assigned to first card"); |
255 | 255 | ||
256 | MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); | 256 | MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); |
257 | MODULE_DESCRIPTION("CX23415/CX23416 driver"); | 257 | MODULE_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 = { | |||
75 | static struct { | 75 | static 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) | |||
171 | static int ivtv_prep_dev(struct ivtv *itv, int type) | 171 | static 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 | */ |
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; |