root/drivers/media/radio/radio-cadet.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cadet_getstereo
  2. cadet_gettune
  3. cadet_getfreq
  4. cadet_settune
  5. cadet_setfreq
  6. cadet_has_rds_data
  7. cadet_handler
  8. cadet_start_rds
  9. cadet_read
  10. vidioc_querycap
  11. vidioc_g_tuner
  12. vidioc_s_tuner
  13. vidioc_enum_freq_bands
  14. vidioc_g_frequency
  15. vidioc_s_frequency
  16. cadet_s_ctrl
  17. cadet_open
  18. cadet_release
  19. cadet_poll
  20. cadet_pnp_probe
  21. cadet_probe
  22. cadet_init
  23. cadet_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card
   3  *
   4  * by Fred Gleason <fredg@wava.com>
   5  * Version 0.3.3
   6  *
   7  * (Loosely) based on code for the Aztech radio card by
   8  *
   9  * Russell Kroll    (rkroll@exploits.org)
  10  * Quay Ly
  11  * Donald Song
  12  * Jason Lewis      (jlewis@twilight.vtc.vsc.edu)
  13  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
  14  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
  15  *
  16  * History:
  17  * 2000-04-29   Russell Kroll <rkroll@exploits.org>
  18  *              Added ISAPnP detection for Linux 2.3/2.4
  19  *
  20  * 2001-01-10   Russell Kroll <rkroll@exploits.org>
  21  *              Removed dead CONFIG_RADIO_CADET_PORT code
  22  *              PnP detection on load is now default (no args necessary)
  23  *
  24  * 2002-01-17   Adam Belay <ambx1@neo.rr.com>
  25  *              Updated to latest pnp code
  26  *
  27  * 2003-01-31   Alan Cox <alan@lxorguk.ukuu.org.uk>
  28  *              Cleaned up locking, delay code, general odds and ends
  29  *
  30  * 2006-07-30   Hans J. Koch <koch@hjk-az.de>
  31  *              Changed API to V4L2
  32  */
  33 
  34 #include <linux/module.h>       /* Modules                      */
  35 #include <linux/init.h>         /* Initdata                     */
  36 #include <linux/ioport.h>       /* request_region               */
  37 #include <linux/delay.h>        /* udelay                       */
  38 #include <linux/videodev2.h>    /* V4L2 API defs                */
  39 #include <linux/param.h>
  40 #include <linux/pnp.h>
  41 #include <linux/sched.h>
  42 #include <linux/io.h>           /* outb, outb_p                 */
  43 #include <media/v4l2-device.h>
  44 #include <media/v4l2-ioctl.h>
  45 #include <media/v4l2-ctrls.h>
  46 #include <media/v4l2-fh.h>
  47 #include <media/v4l2-event.h>
  48 
  49 MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
  50 MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
  51 MODULE_LICENSE("GPL");
  52 MODULE_VERSION("0.3.4");
  53 
  54 static int io = -1;             /* default to isapnp activation */
  55 static int radio_nr = -1;
  56 
  57 module_param(io, int, 0);
  58 MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
  59 module_param(radio_nr, int, 0);
  60 
  61 #define RDS_BUFFER 256
  62 #define RDS_RX_FLAG 1
  63 #define MBS_RX_FLAG 2
  64 
  65 struct cadet {
  66         struct v4l2_device v4l2_dev;
  67         struct video_device vdev;
  68         struct v4l2_ctrl_handler ctrl_handler;
  69         int io;
  70         bool is_fm_band;
  71         u32 curfreq;
  72         int tunestat;
  73         int sigstrength;
  74         wait_queue_head_t read_queue;
  75         struct timer_list readtimer;
  76         u8 rdsin, rdsout, rdsstat;
  77         unsigned char rdsbuf[RDS_BUFFER];
  78         struct mutex lock;
  79         int reading;
  80 };
  81 
  82 static struct cadet cadet_card;
  83 
  84 /*
  85  * Signal Strength Threshold Values
  86  * The V4L API spec does not define any particular unit for the signal
  87  * strength value.  These values are in microvolts of RF at the tuner's input.
  88  */
  89 static u16 sigtable[2][4] = {
  90         { 1835, 2621,  4128, 65535 },
  91         { 2185, 4369, 13107, 65535 },
  92 };
  93 
  94 static const struct v4l2_frequency_band bands[] = {
  95         {
  96                 .index = 0,
  97                 .type = V4L2_TUNER_RADIO,
  98                 .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
  99                 .rangelow = 8320,      /* 520 kHz */
 100                 .rangehigh = 26400,    /* 1650 kHz */
 101                 .modulation = V4L2_BAND_MODULATION_AM,
 102         }, {
 103                 .index = 1,
 104                 .type = V4L2_TUNER_RADIO,
 105                 .capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
 106                         V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW |
 107                         V4L2_TUNER_CAP_FREQ_BANDS,
 108                 .rangelow = 1400000,   /* 87.5 MHz */
 109                 .rangehigh = 1728000,  /* 108.0 MHz */
 110                 .modulation = V4L2_BAND_MODULATION_FM,
 111         },
 112 };
 113 
 114 
 115 static int cadet_getstereo(struct cadet *dev)
 116 {
 117         int ret = V4L2_TUNER_SUB_MONO;
 118 
 119         if (!dev->is_fm_band)   /* Only FM has stereo capability! */
 120                 return V4L2_TUNER_SUB_MONO;
 121 
 122         outb(7, dev->io);          /* Select tuner control */
 123         if ((inb(dev->io + 1) & 0x40) == 0)
 124                 ret = V4L2_TUNER_SUB_STEREO;
 125         return ret;
 126 }
 127 
 128 static unsigned cadet_gettune(struct cadet *dev)
 129 {
 130         int curvol, i;
 131         unsigned fifo = 0;
 132 
 133         /*
 134          * Prepare for read
 135          */
 136 
 137         outb(7, dev->io);       /* Select tuner control */
 138         curvol = inb(dev->io + 1); /* Save current volume/mute setting */
 139         outb(0x00, dev->io + 1);  /* Ensure WRITE-ENABLE is LOW */
 140         dev->tunestat = 0xffff;
 141 
 142         /*
 143          * Read the shift register
 144          */
 145         for (i = 0; i < 25; i++) {
 146                 fifo = (fifo << 1) | ((inb(dev->io + 1) >> 7) & 0x01);
 147                 if (i < 24) {
 148                         outb(0x01, dev->io + 1);
 149                         dev->tunestat &= inb(dev->io + 1);
 150                         outb(0x00, dev->io + 1);
 151                 }
 152         }
 153 
 154         /*
 155          * Restore volume/mute setting
 156          */
 157         outb(curvol, dev->io + 1);
 158         return fifo;
 159 }
 160 
 161 static unsigned cadet_getfreq(struct cadet *dev)
 162 {
 163         int i;
 164         unsigned freq = 0, test, fifo = 0;
 165 
 166         /*
 167          * Read current tuning
 168          */
 169         fifo = cadet_gettune(dev);
 170 
 171         /*
 172          * Convert to actual frequency
 173          */
 174         if (!dev->is_fm_band)    /* AM */
 175                 return ((fifo & 0x7fff) - 450) * 16;
 176 
 177         test = 12500;
 178         for (i = 0; i < 14; i++) {
 179                 if ((fifo & 0x01) != 0)
 180                         freq += test;
 181                 test = test << 1;
 182                 fifo = fifo >> 1;
 183         }
 184         freq -= 10700000;           /* IF frequency is 10.7 MHz */
 185         freq = (freq * 16) / 1000;   /* Make it 1/16 kHz */
 186         return freq;
 187 }
 188 
 189 static void cadet_settune(struct cadet *dev, unsigned fifo)
 190 {
 191         int i;
 192         unsigned test;
 193 
 194         outb(7, dev->io);                /* Select tuner control */
 195         /*
 196          * Write the shift register
 197          */
 198         test = 0;
 199         test = (fifo >> 23) & 0x02;      /* Align data for SDO */
 200         test |= 0x1c;                /* SDM=1, SWE=1, SEN=1, SCK=0 */
 201         outb(7, dev->io);                /* Select tuner control */
 202         outb(test, dev->io + 1);           /* Initialize for write */
 203         for (i = 0; i < 25; i++) {
 204                 test |= 0x01;              /* Toggle SCK High */
 205                 outb(test, dev->io + 1);
 206                 test &= 0xfe;              /* Toggle SCK Low */
 207                 outb(test, dev->io + 1);
 208                 fifo = fifo << 1;            /* Prepare the next bit */
 209                 test = 0x1c | ((fifo >> 23) & 0x02);
 210                 outb(test, dev->io + 1);
 211         }
 212 }
 213 
 214 static void cadet_setfreq(struct cadet *dev, unsigned freq)
 215 {
 216         unsigned fifo;
 217         int i, j, test;
 218         int curvol;
 219 
 220         freq = clamp(freq, bands[dev->is_fm_band].rangelow,
 221                            bands[dev->is_fm_band].rangehigh);
 222         dev->curfreq = freq;
 223         /*
 224          * Formulate a fifo command
 225          */
 226         fifo = 0;
 227         if (dev->is_fm_band) {    /* FM */
 228                 test = 102400;
 229                 freq = freq / 16;       /* Make it kHz */
 230                 freq += 10700;               /* IF is 10700 kHz */
 231                 for (i = 0; i < 14; i++) {
 232                         fifo = fifo << 1;
 233                         if (freq >= test) {
 234                                 fifo |= 0x01;
 235                                 freq -= test;
 236                         }
 237                         test = test >> 1;
 238                 }
 239         } else {        /* AM */
 240                 fifo = (freq / 16) + 450;       /* Make it kHz */
 241                 fifo |= 0x100000;               /* Select AM Band */
 242         }
 243 
 244         /*
 245          * Save current volume/mute setting
 246          */
 247 
 248         outb(7, dev->io);                /* Select tuner control */
 249         curvol = inb(dev->io + 1);
 250 
 251         /*
 252          * Tune the card
 253          */
 254         for (j = 3; j > -1; j--) {
 255                 cadet_settune(dev, fifo | (j << 16));
 256 
 257                 outb(7, dev->io);         /* Select tuner control */
 258                 outb(curvol, dev->io + 1);
 259 
 260                 msleep(100);
 261 
 262                 cadet_gettune(dev);
 263                 if ((dev->tunestat & 0x40) == 0) {   /* Tuned */
 264                         dev->sigstrength = sigtable[dev->is_fm_band][j];
 265                         goto reset_rds;
 266                 }
 267         }
 268         dev->sigstrength = 0;
 269 reset_rds:
 270         outb(3, dev->io);
 271         outb(inb(dev->io + 1) & 0x7f, dev->io + 1);
 272 }
 273 
 274 static bool cadet_has_rds_data(struct cadet *dev)
 275 {
 276         bool result;
 277 
 278         mutex_lock(&dev->lock);
 279         result = dev->rdsin != dev->rdsout;
 280         mutex_unlock(&dev->lock);
 281         return result;
 282 }
 283 
 284 
 285 static void cadet_handler(struct timer_list *t)
 286 {
 287         struct cadet *dev = from_timer(dev, t, readtimer);
 288 
 289         /* Service the RDS fifo */
 290         if (mutex_trylock(&dev->lock)) {
 291                 outb(0x3, dev->io);       /* Select RDS Decoder Control */
 292                 if ((inb(dev->io + 1) & 0x20) != 0)
 293                         pr_err("cadet: RDS fifo overflow\n");
 294                 outb(0x80, dev->io);      /* Select RDS fifo */
 295 
 296                 while ((inb(dev->io) & 0x80) != 0) {
 297                         dev->rdsbuf[dev->rdsin] = inb(dev->io + 1);
 298                         if (dev->rdsin + 1 != dev->rdsout)
 299                                 dev->rdsin++;
 300                 }
 301                 mutex_unlock(&dev->lock);
 302         }
 303 
 304         /*
 305          * Service pending read
 306          */
 307         if (cadet_has_rds_data(dev))
 308                 wake_up_interruptible(&dev->read_queue);
 309 
 310         /*
 311          * Clean up and exit
 312          */
 313         dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
 314         add_timer(&dev->readtimer);
 315 }
 316 
 317 static void cadet_start_rds(struct cadet *dev)
 318 {
 319         dev->rdsstat = 1;
 320         outb(0x80, dev->io);        /* Select RDS fifo */
 321         timer_setup(&dev->readtimer, cadet_handler, 0);
 322         dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
 323         add_timer(&dev->readtimer);
 324 }
 325 
 326 static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 327 {
 328         struct cadet *dev = video_drvdata(file);
 329         unsigned char readbuf[RDS_BUFFER];
 330         int i = 0;
 331 
 332         mutex_lock(&dev->lock);
 333         if (dev->rdsstat == 0)
 334                 cadet_start_rds(dev);
 335         mutex_unlock(&dev->lock);
 336 
 337         if (!cadet_has_rds_data(dev) && (file->f_flags & O_NONBLOCK))
 338                 return -EWOULDBLOCK;
 339         i = wait_event_interruptible(dev->read_queue, cadet_has_rds_data(dev));
 340         if (i)
 341                 return i;
 342 
 343         mutex_lock(&dev->lock);
 344         while (i < count && dev->rdsin != dev->rdsout)
 345                 readbuf[i++] = dev->rdsbuf[dev->rdsout++];
 346         mutex_unlock(&dev->lock);
 347 
 348         if (i && copy_to_user(data, readbuf, i))
 349                 return -EFAULT;
 350         return i;
 351 }
 352 
 353 
 354 static int vidioc_querycap(struct file *file, void *priv,
 355                                 struct v4l2_capability *v)
 356 {
 357         strscpy(v->driver, "ADS Cadet", sizeof(v->driver));
 358         strscpy(v->card, "ADS Cadet", sizeof(v->card));
 359         strscpy(v->bus_info, "ISA:radio-cadet", sizeof(v->bus_info));
 360         return 0;
 361 }
 362 
 363 static int vidioc_g_tuner(struct file *file, void *priv,
 364                                 struct v4l2_tuner *v)
 365 {
 366         struct cadet *dev = video_drvdata(file);
 367 
 368         if (v->index)
 369                 return -EINVAL;
 370         v->type = V4L2_TUNER_RADIO;
 371         strscpy(v->name, "Radio", sizeof(v->name));
 372         v->capability = bands[0].capability | bands[1].capability;
 373         v->rangelow = bands[0].rangelow;           /* 520 kHz (start of AM band) */
 374         v->rangehigh = bands[1].rangehigh;    /* 108.0 MHz (end of FM band) */
 375         if (dev->is_fm_band) {
 376                 v->rxsubchans = cadet_getstereo(dev);
 377                 outb(3, dev->io);
 378                 outb(inb(dev->io + 1) & 0x7f, dev->io + 1);
 379                 mdelay(100);
 380                 outb(3, dev->io);
 381                 if (inb(dev->io + 1) & 0x80)
 382                         v->rxsubchans |= V4L2_TUNER_SUB_RDS;
 383         } else {
 384                 v->rangelow = 8320;      /* 520 kHz */
 385                 v->rangehigh = 26400;    /* 1650 kHz */
 386                 v->rxsubchans = V4L2_TUNER_SUB_MONO;
 387         }
 388         v->audmode = V4L2_TUNER_MODE_STEREO;
 389         v->signal = dev->sigstrength; /* We might need to modify scaling of this */
 390         return 0;
 391 }
 392 
 393 static int vidioc_s_tuner(struct file *file, void *priv,
 394                                 const struct v4l2_tuner *v)
 395 {
 396         return v->index ? -EINVAL : 0;
 397 }
 398 
 399 static int vidioc_enum_freq_bands(struct file *file, void *priv,
 400                                 struct v4l2_frequency_band *band)
 401 {
 402         if (band->tuner)
 403                 return -EINVAL;
 404         if (band->index >= ARRAY_SIZE(bands))
 405                 return -EINVAL;
 406         *band = bands[band->index];
 407         return 0;
 408 }
 409 
 410 static int vidioc_g_frequency(struct file *file, void *priv,
 411                                 struct v4l2_frequency *f)
 412 {
 413         struct cadet *dev = video_drvdata(file);
 414 
 415         if (f->tuner)
 416                 return -EINVAL;
 417         f->type = V4L2_TUNER_RADIO;
 418         f->frequency = dev->curfreq;
 419         return 0;
 420 }
 421 
 422 
 423 static int vidioc_s_frequency(struct file *file, void *priv,
 424                                 const struct v4l2_frequency *f)
 425 {
 426         struct cadet *dev = video_drvdata(file);
 427 
 428         if (f->tuner)
 429                 return -EINVAL;
 430         dev->is_fm_band =
 431                 f->frequency >= (bands[0].rangehigh + bands[1].rangelow) / 2;
 432         cadet_setfreq(dev, f->frequency);
 433         return 0;
 434 }
 435 
 436 static int cadet_s_ctrl(struct v4l2_ctrl *ctrl)
 437 {
 438         struct cadet *dev = container_of(ctrl->handler, struct cadet, ctrl_handler);
 439 
 440         switch (ctrl->id) {
 441         case V4L2_CID_AUDIO_MUTE:
 442                 outb(7, dev->io);                /* Select tuner control */
 443                 if (ctrl->val)
 444                         outb(0x00, dev->io + 1);
 445                 else
 446                         outb(0x20, dev->io + 1);
 447                 return 0;
 448         }
 449         return -EINVAL;
 450 }
 451 
 452 static int cadet_open(struct file *file)
 453 {
 454         struct cadet *dev = video_drvdata(file);
 455         int err;
 456 
 457         mutex_lock(&dev->lock);
 458         err = v4l2_fh_open(file);
 459         if (err)
 460                 goto fail;
 461         if (v4l2_fh_is_singular_file(file))
 462                 init_waitqueue_head(&dev->read_queue);
 463 fail:
 464         mutex_unlock(&dev->lock);
 465         return err;
 466 }
 467 
 468 static int cadet_release(struct file *file)
 469 {
 470         struct cadet *dev = video_drvdata(file);
 471 
 472         mutex_lock(&dev->lock);
 473         if (v4l2_fh_is_singular_file(file) && dev->rdsstat) {
 474                 del_timer_sync(&dev->readtimer);
 475                 dev->rdsstat = 0;
 476         }
 477         v4l2_fh_release(file);
 478         mutex_unlock(&dev->lock);
 479         return 0;
 480 }
 481 
 482 static __poll_t cadet_poll(struct file *file, struct poll_table_struct *wait)
 483 {
 484         struct cadet *dev = video_drvdata(file);
 485         __poll_t req_events = poll_requested_events(wait);
 486         __poll_t res = v4l2_ctrl_poll(file, wait);
 487 
 488         poll_wait(file, &dev->read_queue, wait);
 489         if (dev->rdsstat == 0 && (req_events & (EPOLLIN | EPOLLRDNORM))) {
 490                 mutex_lock(&dev->lock);
 491                 if (dev->rdsstat == 0)
 492                         cadet_start_rds(dev);
 493                 mutex_unlock(&dev->lock);
 494         }
 495         if (cadet_has_rds_data(dev))
 496                 res |= EPOLLIN | EPOLLRDNORM;
 497         return res;
 498 }
 499 
 500 
 501 static const struct v4l2_file_operations cadet_fops = {
 502         .owner          = THIS_MODULE,
 503         .open           = cadet_open,
 504         .release        = cadet_release,
 505         .read           = cadet_read,
 506         .unlocked_ioctl = video_ioctl2,
 507         .poll           = cadet_poll,
 508 };
 509 
 510 static const struct v4l2_ioctl_ops cadet_ioctl_ops = {
 511         .vidioc_querycap    = vidioc_querycap,
 512         .vidioc_g_tuner     = vidioc_g_tuner,
 513         .vidioc_s_tuner     = vidioc_s_tuner,
 514         .vidioc_g_frequency = vidioc_g_frequency,
 515         .vidioc_s_frequency = vidioc_s_frequency,
 516         .vidioc_enum_freq_bands = vidioc_enum_freq_bands,
 517         .vidioc_log_status  = v4l2_ctrl_log_status,
 518         .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 519         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 520 };
 521 
 522 static const struct v4l2_ctrl_ops cadet_ctrl_ops = {
 523         .s_ctrl = cadet_s_ctrl,
 524 };
 525 
 526 #ifdef CONFIG_PNP
 527 
 528 static const struct pnp_device_id cadet_pnp_devices[] = {
 529         /* ADS Cadet AM/FM Radio Card */
 530         {.id = "MSM0c24", .driver_data = 0},
 531         {.id = ""}
 532 };
 533 
 534 MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices);
 535 
 536 static int cadet_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 537 {
 538         if (!dev)
 539                 return -ENODEV;
 540         /* only support one device */
 541         if (io > 0)
 542                 return -EBUSY;
 543 
 544         if (!pnp_port_valid(dev, 0))
 545                 return -ENODEV;
 546 
 547         io = pnp_port_start(dev, 0);
 548 
 549         printk(KERN_INFO "radio-cadet: PnP reports device at %#x\n", io);
 550 
 551         return io;
 552 }
 553 
 554 static struct pnp_driver cadet_pnp_driver = {
 555         .name           = "radio-cadet",
 556         .id_table       = cadet_pnp_devices,
 557         .probe          = cadet_pnp_probe,
 558         .remove         = NULL,
 559 };
 560 
 561 #else
 562 static struct pnp_driver cadet_pnp_driver;
 563 #endif
 564 
 565 static void cadet_probe(struct cadet *dev)
 566 {
 567         static int iovals[8] = { 0x330, 0x332, 0x334, 0x336, 0x338, 0x33a, 0x33c, 0x33e };
 568         int i;
 569 
 570         for (i = 0; i < 8; i++) {
 571                 dev->io = iovals[i];
 572                 if (request_region(dev->io, 2, "cadet-probe")) {
 573                         cadet_setfreq(dev, bands[1].rangelow);
 574                         if (cadet_getfreq(dev) == bands[1].rangelow) {
 575                                 release_region(dev->io, 2);
 576                                 return;
 577                         }
 578                         release_region(dev->io, 2);
 579                 }
 580         }
 581         dev->io = -1;
 582 }
 583 
 584 /*
 585  * io should only be set if the user has used something like
 586  * isapnp (the userspace program) to initialize this card for us
 587  */
 588 
 589 static int __init cadet_init(void)
 590 {
 591         struct cadet *dev = &cadet_card;
 592         struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
 593         struct v4l2_ctrl_handler *hdl;
 594         int res = -ENODEV;
 595 
 596         strscpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name));
 597         mutex_init(&dev->lock);
 598 
 599         /* If a probe was requested then probe ISAPnP first (safest) */
 600         if (io < 0)
 601                 pnp_register_driver(&cadet_pnp_driver);
 602         dev->io = io;
 603 
 604         /* If that fails then probe unsafely if probe is requested */
 605         if (dev->io < 0)
 606                 cadet_probe(dev);
 607 
 608         /* Else we bail out */
 609         if (dev->io < 0) {
 610 #ifdef MODULE
 611                 v4l2_err(v4l2_dev, "you must set an I/O address with io=0x330, 0x332, 0x334,\n");
 612                 v4l2_err(v4l2_dev, "0x336, 0x338, 0x33a, 0x33c or 0x33e\n");
 613 #endif
 614                 goto fail;
 615         }
 616         if (!request_region(dev->io, 2, "cadet"))
 617                 goto fail;
 618 
 619         res = v4l2_device_register(NULL, v4l2_dev);
 620         if (res < 0) {
 621                 release_region(dev->io, 2);
 622                 v4l2_err(v4l2_dev, "could not register v4l2_device\n");
 623                 goto fail;
 624         }
 625 
 626         hdl = &dev->ctrl_handler;
 627         v4l2_ctrl_handler_init(hdl, 2);
 628         v4l2_ctrl_new_std(hdl, &cadet_ctrl_ops,
 629                         V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
 630         v4l2_dev->ctrl_handler = hdl;
 631         if (hdl->error) {
 632                 res = hdl->error;
 633                 v4l2_err(v4l2_dev, "Could not register controls\n");
 634                 goto err_hdl;
 635         }
 636 
 637         dev->is_fm_band = true;
 638         dev->curfreq = bands[dev->is_fm_band].rangelow;
 639         cadet_setfreq(dev, dev->curfreq);
 640         strscpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
 641         dev->vdev.v4l2_dev = v4l2_dev;
 642         dev->vdev.fops = &cadet_fops;
 643         dev->vdev.ioctl_ops = &cadet_ioctl_ops;
 644         dev->vdev.release = video_device_release_empty;
 645         dev->vdev.lock = &dev->lock;
 646         dev->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
 647                                 V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
 648         video_set_drvdata(&dev->vdev, dev);
 649 
 650         res = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
 651         if (res < 0)
 652                 goto err_hdl;
 653         v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io);
 654         return 0;
 655 err_hdl:
 656         v4l2_ctrl_handler_free(hdl);
 657         v4l2_device_unregister(v4l2_dev);
 658         release_region(dev->io, 2);
 659 fail:
 660         pnp_unregister_driver(&cadet_pnp_driver);
 661         return res;
 662 }
 663 
 664 static void __exit cadet_exit(void)
 665 {
 666         struct cadet *dev = &cadet_card;
 667 
 668         video_unregister_device(&dev->vdev);
 669         v4l2_ctrl_handler_free(&dev->ctrl_handler);
 670         v4l2_device_unregister(&dev->v4l2_dev);
 671         outb(7, dev->io);       /* Mute */
 672         outb(0x00, dev->io + 1);
 673         release_region(dev->io, 2);
 674         pnp_unregister_driver(&cadet_pnp_driver);
 675 }
 676 
 677 module_init(cadet_init);
 678 module_exit(cadet_exit);
 679 

/* [<][>][^][v][top][bottom][index][help] */