diff options
Diffstat (limited to 'drivers/media/radio')
-rw-r--r-- | drivers/media/radio/radio-cadet.c | 243 |
1 files changed, 83 insertions, 160 deletions
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 16a089fad909..93536b7e75c7 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c | |||
@@ -41,6 +41,9 @@ | |||
41 | #include <linux/io.h> /* outb, outb_p */ | 41 | #include <linux/io.h> /* outb, outb_p */ |
42 | #include <media/v4l2-device.h> | 42 | #include <media/v4l2-device.h> |
43 | #include <media/v4l2-ioctl.h> | 43 | #include <media/v4l2-ioctl.h> |
44 | #include <media/v4l2-ctrls.h> | ||
45 | #include <media/v4l2-fh.h> | ||
46 | #include <media/v4l2-event.h> | ||
44 | 47 | ||
45 | MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); | 48 | MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); |
46 | MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); | 49 | MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); |
@@ -61,8 +64,8 @@ module_param(radio_nr, int, 0); | |||
61 | struct cadet { | 64 | struct cadet { |
62 | struct v4l2_device v4l2_dev; | 65 | struct v4l2_device v4l2_dev; |
63 | struct video_device vdev; | 66 | struct video_device vdev; |
67 | struct v4l2_ctrl_handler ctrl_handler; | ||
64 | int io; | 68 | int io; |
65 | int users; | ||
66 | int curtuner; | 69 | int curtuner; |
67 | int tunestat; | 70 | int tunestat; |
68 | int sigstrength; | 71 | int sigstrength; |
@@ -94,11 +97,9 @@ static int cadet_getstereo(struct cadet *dev) | |||
94 | if (dev->curtuner != 0) /* Only FM has stereo capability! */ | 97 | if (dev->curtuner != 0) /* Only FM has stereo capability! */ |
95 | return V4L2_TUNER_SUB_MONO; | 98 | return V4L2_TUNER_SUB_MONO; |
96 | 99 | ||
97 | mutex_lock(&dev->lock); | ||
98 | outb(7, dev->io); /* Select tuner control */ | 100 | outb(7, dev->io); /* Select tuner control */ |
99 | if ((inb(dev->io + 1) & 0x40) == 0) | 101 | if ((inb(dev->io + 1) & 0x40) == 0) |
100 | ret = V4L2_TUNER_SUB_STEREO; | 102 | ret = V4L2_TUNER_SUB_STEREO; |
101 | mutex_unlock(&dev->lock); | ||
102 | return ret; | 103 | return ret; |
103 | } | 104 | } |
104 | 105 | ||
@@ -111,8 +112,6 @@ static unsigned cadet_gettune(struct cadet *dev) | |||
111 | * Prepare for read | 112 | * Prepare for read |
112 | */ | 113 | */ |
113 | 114 | ||
114 | mutex_lock(&dev->lock); | ||
115 | |||
116 | outb(7, dev->io); /* Select tuner control */ | 115 | outb(7, dev->io); /* Select tuner control */ |
117 | curvol = inb(dev->io + 1); /* Save current volume/mute setting */ | 116 | curvol = inb(dev->io + 1); /* Save current volume/mute setting */ |
118 | outb(0x00, dev->io + 1); /* Ensure WRITE-ENABLE is LOW */ | 117 | outb(0x00, dev->io + 1); /* Ensure WRITE-ENABLE is LOW */ |
@@ -134,8 +133,6 @@ static unsigned cadet_gettune(struct cadet *dev) | |||
134 | * Restore volume/mute setting | 133 | * Restore volume/mute setting |
135 | */ | 134 | */ |
136 | outb(curvol, dev->io + 1); | 135 | outb(curvol, dev->io + 1); |
137 | mutex_unlock(&dev->lock); | ||
138 | |||
139 | return fifo; | 136 | return fifo; |
140 | } | 137 | } |
141 | 138 | ||
@@ -161,7 +158,7 @@ static unsigned cadet_getfreq(struct cadet *dev) | |||
161 | fifo = fifo >> 1; | 158 | fifo = fifo >> 1; |
162 | } | 159 | } |
163 | freq -= 10700000; /* IF frequency is 10.7 MHz */ | 160 | freq -= 10700000; /* IF frequency is 10.7 MHz */ |
164 | freq = (freq * 16) / 1000000; /* Make it 1/16 MHz */ | 161 | freq = (freq * 16) / 1000; /* Make it 1/16 kHz */ |
165 | } | 162 | } |
166 | if (dev->curtuner == 1) /* AM */ | 163 | if (dev->curtuner == 1) /* AM */ |
167 | freq = ((fifo & 0x7fff) - 2010) * 16; | 164 | freq = ((fifo & 0x7fff) - 2010) * 16; |
@@ -174,8 +171,6 @@ static void cadet_settune(struct cadet *dev, unsigned fifo) | |||
174 | int i; | 171 | int i; |
175 | unsigned test; | 172 | unsigned test; |
176 | 173 | ||
177 | mutex_lock(&dev->lock); | ||
178 | |||
179 | outb(7, dev->io); /* Select tuner control */ | 174 | outb(7, dev->io); /* Select tuner control */ |
180 | /* | 175 | /* |
181 | * Write the shift register | 176 | * Write the shift register |
@@ -194,7 +189,6 @@ static void cadet_settune(struct cadet *dev, unsigned fifo) | |||
194 | test = 0x1c | ((fifo >> 23) & 0x02); | 189 | test = 0x1c | ((fifo >> 23) & 0x02); |
195 | outb(test, dev->io + 1); | 190 | outb(test, dev->io + 1); |
196 | } | 191 | } |
197 | mutex_unlock(&dev->lock); | ||
198 | } | 192 | } |
199 | 193 | ||
200 | static void cadet_setfreq(struct cadet *dev, unsigned freq) | 194 | static void cadet_setfreq(struct cadet *dev, unsigned freq) |
@@ -209,7 +203,7 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) | |||
209 | fifo = 0; | 203 | fifo = 0; |
210 | if (dev->curtuner == 0) { /* FM */ | 204 | if (dev->curtuner == 0) { /* FM */ |
211 | test = 102400; | 205 | test = 102400; |
212 | freq = (freq * 1000) / 16; /* Make it kHz */ | 206 | freq = freq / 16; /* Make it kHz */ |
213 | freq += 10700; /* IF is 10700 kHz */ | 207 | freq += 10700; /* IF is 10700 kHz */ |
214 | for (i = 0; i < 14; i++) { | 208 | for (i = 0; i < 14; i++) { |
215 | fifo = fifo << 1; | 209 | fifo = fifo << 1; |
@@ -229,10 +223,8 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) | |||
229 | * Save current volume/mute setting | 223 | * Save current volume/mute setting |
230 | */ | 224 | */ |
231 | 225 | ||
232 | mutex_lock(&dev->lock); | ||
233 | outb(7, dev->io); /* Select tuner control */ | 226 | outb(7, dev->io); /* Select tuner control */ |
234 | curvol = inb(dev->io + 1); | 227 | curvol = inb(dev->io + 1); |
235 | mutex_unlock(&dev->lock); | ||
236 | 228 | ||
237 | /* | 229 | /* |
238 | * Tune the card | 230 | * Tune the card |
@@ -240,10 +232,8 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) | |||
240 | for (j = 3; j > -1; j--) { | 232 | for (j = 3; j > -1; j--) { |
241 | cadet_settune(dev, fifo | (j << 16)); | 233 | cadet_settune(dev, fifo | (j << 16)); |
242 | 234 | ||
243 | mutex_lock(&dev->lock); | ||
244 | outb(7, dev->io); /* Select tuner control */ | 235 | outb(7, dev->io); /* Select tuner control */ |
245 | outb(curvol, dev->io + 1); | 236 | outb(curvol, dev->io + 1); |
246 | mutex_unlock(&dev->lock); | ||
247 | 237 | ||
248 | msleep(100); | 238 | msleep(100); |
249 | 239 | ||
@@ -257,32 +247,6 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) | |||
257 | } | 247 | } |
258 | 248 | ||
259 | 249 | ||
260 | static int cadet_getvol(struct cadet *dev) | ||
261 | { | ||
262 | int ret = 0; | ||
263 | |||
264 | mutex_lock(&dev->lock); | ||
265 | |||
266 | outb(7, dev->io); /* Select tuner control */ | ||
267 | if ((inb(dev->io + 1) & 0x20) != 0) | ||
268 | ret = 0xffff; | ||
269 | |||
270 | mutex_unlock(&dev->lock); | ||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | |||
275 | static void cadet_setvol(struct cadet *dev, int vol) | ||
276 | { | ||
277 | mutex_lock(&dev->lock); | ||
278 | outb(7, dev->io); /* Select tuner control */ | ||
279 | if (vol > 0) | ||
280 | outb(0x20, dev->io + 1); | ||
281 | else | ||
282 | outb(0x00, dev->io + 1); | ||
283 | mutex_unlock(&dev->lock); | ||
284 | } | ||
285 | |||
286 | static void cadet_handler(unsigned long data) | 250 | static void cadet_handler(unsigned long data) |
287 | { | 251 | { |
288 | struct cadet *dev = (void *)data; | 252 | struct cadet *dev = (void *)data; |
@@ -337,18 +301,19 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo | |||
337 | add_timer(&dev->readtimer); | 301 | add_timer(&dev->readtimer); |
338 | } | 302 | } |
339 | if (dev->rdsin == dev->rdsout) { | 303 | if (dev->rdsin == dev->rdsout) { |
340 | mutex_unlock(&dev->lock); | 304 | if (file->f_flags & O_NONBLOCK) { |
341 | if (file->f_flags & O_NONBLOCK) | 305 | i = -EWOULDBLOCK; |
342 | return -EWOULDBLOCK; | 306 | goto unlock; |
307 | } | ||
343 | interruptible_sleep_on(&dev->read_queue); | 308 | interruptible_sleep_on(&dev->read_queue); |
344 | mutex_lock(&dev->lock); | ||
345 | } | 309 | } |
346 | while (i < count && dev->rdsin != dev->rdsout) | 310 | while (i < count && dev->rdsin != dev->rdsout) |
347 | readbuf[i++] = dev->rdsbuf[dev->rdsout++]; | 311 | readbuf[i++] = dev->rdsbuf[dev->rdsout++]; |
348 | mutex_unlock(&dev->lock); | ||
349 | 312 | ||
350 | if (copy_to_user(data, readbuf, i)) | 313 | if (copy_to_user(data, readbuf, i)) |
351 | return -EFAULT; | 314 | i = -EFAULT; |
315 | unlock: | ||
316 | mutex_unlock(&dev->lock); | ||
352 | return i; | 317 | return i; |
353 | } | 318 | } |
354 | 319 | ||
@@ -359,8 +324,9 @@ static int vidioc_querycap(struct file *file, void *priv, | |||
359 | strlcpy(v->driver, "ADS Cadet", sizeof(v->driver)); | 324 | strlcpy(v->driver, "ADS Cadet", sizeof(v->driver)); |
360 | strlcpy(v->card, "ADS Cadet", sizeof(v->card)); | 325 | strlcpy(v->card, "ADS Cadet", sizeof(v->card)); |
361 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); | 326 | strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); |
362 | v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | | 327 | v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | |
363 | V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; | 328 | V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; |
329 | v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; | ||
364 | return 0; | 330 | return 0; |
365 | } | 331 | } |
366 | 332 | ||
@@ -374,20 +340,11 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
374 | case 0: | 340 | case 0: |
375 | strlcpy(v->name, "FM", sizeof(v->name)); | 341 | strlcpy(v->name, "FM", sizeof(v->name)); |
376 | v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | | 342 | v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS | |
377 | V4L2_TUNER_CAP_RDS_BLOCK_IO; | 343 | V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW; |
378 | v->rangelow = 1400; /* 87.5 MHz */ | 344 | v->rangelow = 1400000; /* 87.5 MHz */ |
379 | v->rangehigh = 1728; /* 108.0 MHz */ | 345 | v->rangehigh = 1728000; /* 108.0 MHz */ |
380 | v->rxsubchans = cadet_getstereo(dev); | 346 | v->rxsubchans = cadet_getstereo(dev); |
381 | switch (v->rxsubchans) { | 347 | v->audmode = V4L2_TUNER_MODE_STEREO; |
382 | case V4L2_TUNER_SUB_MONO: | ||
383 | v->audmode = V4L2_TUNER_MODE_MONO; | ||
384 | break; | ||
385 | case V4L2_TUNER_SUB_STEREO: | ||
386 | v->audmode = V4L2_TUNER_MODE_STEREO; | ||
387 | break; | ||
388 | default: | ||
389 | break; | ||
390 | } | ||
391 | v->rxsubchans |= V4L2_TUNER_SUB_RDS; | 348 | v->rxsubchans |= V4L2_TUNER_SUB_RDS; |
392 | break; | 349 | break; |
393 | case 1: | 350 | case 1: |
@@ -408,11 +365,8 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
408 | static int vidioc_s_tuner(struct file *file, void *priv, | 365 | static int vidioc_s_tuner(struct file *file, void *priv, |
409 | struct v4l2_tuner *v) | 366 | struct v4l2_tuner *v) |
410 | { | 367 | { |
411 | struct cadet *dev = video_drvdata(file); | ||
412 | |||
413 | if (v->index != 0 && v->index != 1) | 368 | if (v->index != 0 && v->index != 1) |
414 | return -EINVAL; | 369 | return -EINVAL; |
415 | dev->curtuner = v->index; | ||
416 | return 0; | 370 | return 0; |
417 | } | 371 | } |
418 | 372 | ||
@@ -421,7 +375,8 @@ static int vidioc_g_frequency(struct file *file, void *priv, | |||
421 | { | 375 | { |
422 | struct cadet *dev = video_drvdata(file); | 376 | struct cadet *dev = video_drvdata(file); |
423 | 377 | ||
424 | f->tuner = dev->curtuner; | 378 | if (f->tuner > 1) |
379 | return -EINVAL; | ||
425 | f->type = V4L2_TUNER_RADIO; | 380 | f->type = V4L2_TUNER_RADIO; |
426 | f->frequency = cadet_getfreq(dev); | 381 | f->frequency = cadet_getfreq(dev); |
427 | return 0; | 382 | return 0; |
@@ -435,101 +390,52 @@ static int vidioc_s_frequency(struct file *file, void *priv, | |||
435 | 390 | ||
436 | if (f->type != V4L2_TUNER_RADIO) | 391 | if (f->type != V4L2_TUNER_RADIO) |
437 | return -EINVAL; | 392 | return -EINVAL; |
438 | if (dev->curtuner == 0 && (f->frequency < 1400 || f->frequency > 1728)) | 393 | if (f->tuner == 0) { |
439 | return -EINVAL; | 394 | if (f->frequency < 1400000) |
440 | if (dev->curtuner == 1 && (f->frequency < 8320 || f->frequency > 26400)) | 395 | f->frequency = 1400000; |
396 | else if (f->frequency > 1728000) | ||
397 | f->frequency = 1728000; | ||
398 | } else if (f->tuner == 1) { | ||
399 | if (f->frequency < 8320) | ||
400 | f->frequency = 8320; | ||
401 | else if (f->frequency > 26400) | ||
402 | f->frequency = 26400; | ||
403 | } else | ||
441 | return -EINVAL; | 404 | return -EINVAL; |
442 | cadet_setfreq(dev, f->frequency); | 405 | cadet_setfreq(dev, f->frequency); |
443 | return 0; | 406 | return 0; |
444 | } | 407 | } |
445 | 408 | ||
446 | static int vidioc_queryctrl(struct file *file, void *priv, | 409 | static int cadet_s_ctrl(struct v4l2_ctrl *ctrl) |
447 | struct v4l2_queryctrl *qc) | ||
448 | { | 410 | { |
449 | switch (qc->id) { | 411 | struct cadet *dev = container_of(ctrl->handler, struct cadet, ctrl_handler); |
450 | case V4L2_CID_AUDIO_MUTE: | ||
451 | return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); | ||
452 | case V4L2_CID_AUDIO_VOLUME: | ||
453 | return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); | ||
454 | } | ||
455 | return -EINVAL; | ||
456 | } | ||
457 | |||
458 | static int vidioc_g_ctrl(struct file *file, void *priv, | ||
459 | struct v4l2_control *ctrl) | ||
460 | { | ||
461 | struct cadet *dev = video_drvdata(file); | ||
462 | 412 | ||
463 | switch (ctrl->id) { | 413 | switch (ctrl->id) { |
464 | case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */ | 414 | case V4L2_CID_AUDIO_MUTE: |
465 | ctrl->value = (cadet_getvol(dev) == 0); | 415 | outb(7, dev->io); /* Select tuner control */ |
466 | break; | 416 | if (ctrl->val) |
467 | case V4L2_CID_AUDIO_VOLUME: | 417 | outb(0x00, dev->io + 1); |
468 | ctrl->value = cadet_getvol(dev); | ||
469 | break; | ||
470 | default: | ||
471 | return -EINVAL; | ||
472 | } | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int vidioc_s_ctrl(struct file *file, void *priv, | ||
477 | struct v4l2_control *ctrl) | ||
478 | { | ||
479 | struct cadet *dev = video_drvdata(file); | ||
480 | |||
481 | switch (ctrl->id){ | ||
482 | case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */ | ||
483 | if (ctrl->value) | ||
484 | cadet_setvol(dev, 0); | ||
485 | else | 418 | else |
486 | cadet_setvol(dev, 0xffff); | 419 | outb(0x20, dev->io + 1); |
487 | break; | 420 | return 0; |
488 | case V4L2_CID_AUDIO_VOLUME: | ||
489 | cadet_setvol(dev, ctrl->value); | ||
490 | break; | ||
491 | default: | ||
492 | return -EINVAL; | ||
493 | } | 421 | } |
494 | return 0; | 422 | return -EINVAL; |
495 | } | ||
496 | |||
497 | static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) | ||
498 | { | ||
499 | *i = 0; | ||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) | ||
504 | { | ||
505 | return i ? -EINVAL : 0; | ||
506 | } | ||
507 | |||
508 | static int vidioc_g_audio(struct file *file, void *priv, | ||
509 | struct v4l2_audio *a) | ||
510 | { | ||
511 | a->index = 0; | ||
512 | strlcpy(a->name, "Radio", sizeof(a->name)); | ||
513 | a->capability = V4L2_AUDCAP_STEREO; | ||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static int vidioc_s_audio(struct file *file, void *priv, | ||
518 | struct v4l2_audio *a) | ||
519 | { | ||
520 | return a->index ? -EINVAL : 0; | ||
521 | } | 423 | } |
522 | 424 | ||
523 | static int cadet_open(struct file *file) | 425 | static int cadet_open(struct file *file) |
524 | { | 426 | { |
525 | struct cadet *dev = video_drvdata(file); | 427 | struct cadet *dev = video_drvdata(file); |
428 | int err; | ||
526 | 429 | ||
527 | mutex_lock(&dev->lock); | 430 | mutex_lock(&dev->lock); |
528 | dev->users++; | 431 | err = v4l2_fh_open(file); |
529 | if (1 == dev->users) | 432 | if (err) |
433 | goto fail; | ||
434 | if (v4l2_fh_is_singular_file(file)) | ||
530 | init_waitqueue_head(&dev->read_queue); | 435 | init_waitqueue_head(&dev->read_queue); |
436 | fail: | ||
531 | mutex_unlock(&dev->lock); | 437 | mutex_unlock(&dev->lock); |
532 | return 0; | 438 | return err; |
533 | } | 439 | } |
534 | 440 | ||
535 | static int cadet_release(struct file *file) | 441 | static int cadet_release(struct file *file) |
@@ -537,11 +443,11 @@ static int cadet_release(struct file *file) | |||
537 | struct cadet *dev = video_drvdata(file); | 443 | struct cadet *dev = video_drvdata(file); |
538 | 444 | ||
539 | mutex_lock(&dev->lock); | 445 | mutex_lock(&dev->lock); |
540 | dev->users--; | 446 | if (v4l2_fh_is_singular_file(file) && dev->rdsstat) { |
541 | if (0 == dev->users) { | ||
542 | del_timer_sync(&dev->readtimer); | 447 | del_timer_sync(&dev->readtimer); |
543 | dev->rdsstat = 0; | 448 | dev->rdsstat = 0; |
544 | } | 449 | } |
450 | v4l2_fh_release(file); | ||
545 | mutex_unlock(&dev->lock); | 451 | mutex_unlock(&dev->lock); |
546 | return 0; | 452 | return 0; |
547 | } | 453 | } |
@@ -549,11 +455,12 @@ static int cadet_release(struct file *file) | |||
549 | static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait) | 455 | static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait) |
550 | { | 456 | { |
551 | struct cadet *dev = video_drvdata(file); | 457 | struct cadet *dev = video_drvdata(file); |
458 | unsigned int res = v4l2_ctrl_poll(file, wait); | ||
552 | 459 | ||
553 | poll_wait(file, &dev->read_queue, wait); | 460 | poll_wait(file, &dev->read_queue, wait); |
554 | if (dev->rdsin != dev->rdsout) | 461 | if (dev->rdsin != dev->rdsout) |
555 | return POLLIN | POLLRDNORM; | 462 | res |= POLLIN | POLLRDNORM; |
556 | return 0; | 463 | return res; |
557 | } | 464 | } |
558 | 465 | ||
559 | 466 | ||
@@ -572,13 +479,13 @@ static const struct v4l2_ioctl_ops cadet_ioctl_ops = { | |||
572 | .vidioc_s_tuner = vidioc_s_tuner, | 479 | .vidioc_s_tuner = vidioc_s_tuner, |
573 | .vidioc_g_frequency = vidioc_g_frequency, | 480 | .vidioc_g_frequency = vidioc_g_frequency, |
574 | .vidioc_s_frequency = vidioc_s_frequency, | 481 | .vidioc_s_frequency = vidioc_s_frequency, |
575 | .vidioc_queryctrl = vidioc_queryctrl, | 482 | .vidioc_log_status = v4l2_ctrl_log_status, |
576 | .vidioc_g_ctrl = vidioc_g_ctrl, | 483 | .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, |
577 | .vidioc_s_ctrl = vidioc_s_ctrl, | 484 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, |
578 | .vidioc_g_audio = vidioc_g_audio, | 485 | }; |
579 | .vidioc_s_audio = vidioc_s_audio, | 486 | |
580 | .vidioc_g_input = vidioc_g_input, | 487 | static const struct v4l2_ctrl_ops cadet_ctrl_ops = { |
581 | .vidioc_s_input = vidioc_s_input, | 488 | .s_ctrl = cadet_s_ctrl, |
582 | }; | 489 | }; |
583 | 490 | ||
584 | #ifdef CONFIG_PNP | 491 | #ifdef CONFIG_PNP |
@@ -648,7 +555,8 @@ static int __init cadet_init(void) | |||
648 | { | 555 | { |
649 | struct cadet *dev = &cadet_card; | 556 | struct cadet *dev = &cadet_card; |
650 | struct v4l2_device *v4l2_dev = &dev->v4l2_dev; | 557 | struct v4l2_device *v4l2_dev = &dev->v4l2_dev; |
651 | int res; | 558 | struct v4l2_ctrl_handler *hdl; |
559 | int res = -ENODEV; | ||
652 | 560 | ||
653 | strlcpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name)); | 561 | strlcpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name)); |
654 | mutex_init(&dev->lock); | 562 | mutex_init(&dev->lock); |
@@ -680,23 +588,37 @@ static int __init cadet_init(void) | |||
680 | goto fail; | 588 | goto fail; |
681 | } | 589 | } |
682 | 590 | ||
591 | hdl = &dev->ctrl_handler; | ||
592 | v4l2_ctrl_handler_init(hdl, 2); | ||
593 | v4l2_ctrl_new_std(hdl, &cadet_ctrl_ops, | ||
594 | V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1); | ||
595 | v4l2_dev->ctrl_handler = hdl; | ||
596 | if (hdl->error) { | ||
597 | res = hdl->error; | ||
598 | v4l2_err(v4l2_dev, "Could not register controls\n"); | ||
599 | goto err_hdl; | ||
600 | } | ||
601 | |||
683 | strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); | 602 | strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); |
684 | dev->vdev.v4l2_dev = v4l2_dev; | 603 | dev->vdev.v4l2_dev = v4l2_dev; |
685 | dev->vdev.fops = &cadet_fops; | 604 | dev->vdev.fops = &cadet_fops; |
686 | dev->vdev.ioctl_ops = &cadet_ioctl_ops; | 605 | dev->vdev.ioctl_ops = &cadet_ioctl_ops; |
687 | dev->vdev.release = video_device_release_empty; | 606 | dev->vdev.release = video_device_release_empty; |
607 | dev->vdev.lock = &dev->lock; | ||
608 | set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); | ||
688 | video_set_drvdata(&dev->vdev, dev); | 609 | video_set_drvdata(&dev->vdev, dev); |
689 | 610 | ||
690 | if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { | 611 | if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) |
691 | v4l2_device_unregister(v4l2_dev); | 612 | goto err_hdl; |
692 | release_region(dev->io, 2); | ||
693 | goto fail; | ||
694 | } | ||
695 | v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io); | 613 | v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io); |
696 | return 0; | 614 | return 0; |
615 | err_hdl: | ||
616 | v4l2_ctrl_handler_free(hdl); | ||
617 | v4l2_device_unregister(v4l2_dev); | ||
618 | release_region(dev->io, 2); | ||
697 | fail: | 619 | fail: |
698 | pnp_unregister_driver(&cadet_pnp_driver); | 620 | pnp_unregister_driver(&cadet_pnp_driver); |
699 | return -ENODEV; | 621 | return res; |
700 | } | 622 | } |
701 | 623 | ||
702 | static void __exit cadet_exit(void) | 624 | static void __exit cadet_exit(void) |
@@ -704,6 +626,7 @@ static void __exit cadet_exit(void) | |||
704 | struct cadet *dev = &cadet_card; | 626 | struct cadet *dev = &cadet_card; |
705 | 627 | ||
706 | video_unregister_device(&dev->vdev); | 628 | video_unregister_device(&dev->vdev); |
629 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | ||
707 | v4l2_device_unregister(&dev->v4l2_dev); | 630 | v4l2_device_unregister(&dev->v4l2_dev); |
708 | release_region(dev->io, 2); | 631 | release_region(dev->io, 2); |
709 | pnp_unregister_driver(&cadet_pnp_driver); | 632 | pnp_unregister_driver(&cadet_pnp_driver); |