0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 #include <linux/module.h> /* Modules */
0035 #include <linux/init.h> /* Initdata */
0036 #include <linux/ioport.h> /* request_region */
0037 #include <linux/delay.h> /* udelay */
0038 #include <linux/videodev2.h> /* V4L2 API defs */
0039 #include <linux/param.h>
0040 #include <linux/pnp.h>
0041 #include <linux/sched.h>
0042 #include <linux/io.h> /* outb, outb_p */
0043 #include <media/v4l2-device.h>
0044 #include <media/v4l2-ioctl.h>
0045 #include <media/v4l2-ctrls.h>
0046 #include <media/v4l2-fh.h>
0047 #include <media/v4l2-event.h>
0048
0049 MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
0050 MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card.");
0051 MODULE_LICENSE("GPL");
0052 MODULE_VERSION("0.3.4");
0053
0054 static int io = -1;
0055 static int radio_nr = -1;
0056
0057 module_param(io, int, 0);
0058 MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)");
0059 module_param(radio_nr, int, 0);
0060
0061 #define RDS_BUFFER 256
0062 #define RDS_RX_FLAG 1
0063 #define MBS_RX_FLAG 2
0064
0065 struct cadet {
0066 struct v4l2_device v4l2_dev;
0067 struct video_device vdev;
0068 struct v4l2_ctrl_handler ctrl_handler;
0069 int io;
0070 bool is_fm_band;
0071 u32 curfreq;
0072 int tunestat;
0073 int sigstrength;
0074 wait_queue_head_t read_queue;
0075 struct timer_list readtimer;
0076 u8 rdsin, rdsout, rdsstat;
0077 unsigned char rdsbuf[RDS_BUFFER];
0078 struct mutex lock;
0079 int reading;
0080 };
0081
0082 static struct cadet cadet_card;
0083
0084
0085
0086
0087
0088
0089 static u16 sigtable[2][4] = {
0090 { 1835, 2621, 4128, 65535 },
0091 { 2185, 4369, 13107, 65535 },
0092 };
0093
0094 static const struct v4l2_frequency_band bands[] = {
0095 {
0096 .index = 0,
0097 .type = V4L2_TUNER_RADIO,
0098 .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
0099 .rangelow = 8320,
0100 .rangehigh = 26400,
0101 .modulation = V4L2_BAND_MODULATION_AM,
0102 }, {
0103 .index = 1,
0104 .type = V4L2_TUNER_RADIO,
0105 .capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
0106 V4L2_TUNER_CAP_RDS_BLOCK_IO | V4L2_TUNER_CAP_LOW |
0107 V4L2_TUNER_CAP_FREQ_BANDS,
0108 .rangelow = 1400000,
0109 .rangehigh = 1728000,
0110 .modulation = V4L2_BAND_MODULATION_FM,
0111 },
0112 };
0113
0114
0115 static int cadet_getstereo(struct cadet *dev)
0116 {
0117 int ret = V4L2_TUNER_SUB_MONO;
0118
0119 if (!dev->is_fm_band)
0120 return V4L2_TUNER_SUB_MONO;
0121
0122 outb(7, dev->io);
0123 if ((inb(dev->io + 1) & 0x40) == 0)
0124 ret = V4L2_TUNER_SUB_STEREO;
0125 return ret;
0126 }
0127
0128 static unsigned cadet_gettune(struct cadet *dev)
0129 {
0130 int curvol, i;
0131 unsigned fifo = 0;
0132
0133
0134
0135
0136
0137 outb(7, dev->io);
0138 curvol = inb(dev->io + 1);
0139 outb(0x00, dev->io + 1);
0140 dev->tunestat = 0xffff;
0141
0142
0143
0144
0145 for (i = 0; i < 25; i++) {
0146 fifo = (fifo << 1) | ((inb(dev->io + 1) >> 7) & 0x01);
0147 if (i < 24) {
0148 outb(0x01, dev->io + 1);
0149 dev->tunestat &= inb(dev->io + 1);
0150 outb(0x00, dev->io + 1);
0151 }
0152 }
0153
0154
0155
0156
0157 outb(curvol, dev->io + 1);
0158 return fifo;
0159 }
0160
0161 static unsigned cadet_getfreq(struct cadet *dev)
0162 {
0163 int i;
0164 unsigned freq = 0, test, fifo = 0;
0165
0166
0167
0168
0169 fifo = cadet_gettune(dev);
0170
0171
0172
0173
0174 if (!dev->is_fm_band)
0175 return ((fifo & 0x7fff) - 450) * 16;
0176
0177 test = 12500;
0178 for (i = 0; i < 14; i++) {
0179 if ((fifo & 0x01) != 0)
0180 freq += test;
0181 test = test << 1;
0182 fifo = fifo >> 1;
0183 }
0184 freq -= 10700000;
0185 freq = (freq * 16) / 1000;
0186 return freq;
0187 }
0188
0189 static void cadet_settune(struct cadet *dev, unsigned fifo)
0190 {
0191 int i;
0192 unsigned test;
0193
0194 outb(7, dev->io);
0195
0196
0197
0198 test = 0;
0199 test = (fifo >> 23) & 0x02;
0200 test |= 0x1c;
0201 outb(7, dev->io);
0202 outb(test, dev->io + 1);
0203 for (i = 0; i < 25; i++) {
0204 test |= 0x01;
0205 outb(test, dev->io + 1);
0206 test &= 0xfe;
0207 outb(test, dev->io + 1);
0208 fifo = fifo << 1;
0209 test = 0x1c | ((fifo >> 23) & 0x02);
0210 outb(test, dev->io + 1);
0211 }
0212 }
0213
0214 static void cadet_setfreq(struct cadet *dev, unsigned freq)
0215 {
0216 unsigned fifo;
0217 int i, j, test;
0218 int curvol;
0219
0220 freq = clamp(freq, bands[dev->is_fm_band].rangelow,
0221 bands[dev->is_fm_band].rangehigh);
0222 dev->curfreq = freq;
0223
0224
0225
0226 fifo = 0;
0227 if (dev->is_fm_band) {
0228 test = 102400;
0229 freq = freq / 16;
0230 freq += 10700;
0231 for (i = 0; i < 14; i++) {
0232 fifo = fifo << 1;
0233 if (freq >= test) {
0234 fifo |= 0x01;
0235 freq -= test;
0236 }
0237 test = test >> 1;
0238 }
0239 } else {
0240 fifo = (freq / 16) + 450;
0241 fifo |= 0x100000;
0242 }
0243
0244
0245
0246
0247
0248 outb(7, dev->io);
0249 curvol = inb(dev->io + 1);
0250
0251
0252
0253
0254 for (j = 3; j > -1; j--) {
0255 cadet_settune(dev, fifo | (j << 16));
0256
0257 outb(7, dev->io);
0258 outb(curvol, dev->io + 1);
0259
0260 msleep(100);
0261
0262 cadet_gettune(dev);
0263 if ((dev->tunestat & 0x40) == 0) {
0264 dev->sigstrength = sigtable[dev->is_fm_band][j];
0265 goto reset_rds;
0266 }
0267 }
0268 dev->sigstrength = 0;
0269 reset_rds:
0270 outb(3, dev->io);
0271 outb(inb(dev->io + 1) & 0x7f, dev->io + 1);
0272 }
0273
0274 static bool cadet_has_rds_data(struct cadet *dev)
0275 {
0276 bool result;
0277
0278 mutex_lock(&dev->lock);
0279 result = dev->rdsin != dev->rdsout;
0280 mutex_unlock(&dev->lock);
0281 return result;
0282 }
0283
0284
0285 static void cadet_handler(struct timer_list *t)
0286 {
0287 struct cadet *dev = from_timer(dev, t, readtimer);
0288
0289
0290 if (mutex_trylock(&dev->lock)) {
0291 outb(0x3, dev->io);
0292 if ((inb(dev->io + 1) & 0x20) != 0)
0293 pr_err("cadet: RDS fifo overflow\n");
0294 outb(0x80, dev->io);
0295
0296 while ((inb(dev->io) & 0x80) != 0) {
0297 dev->rdsbuf[dev->rdsin] = inb(dev->io + 1);
0298 if (dev->rdsin + 1 != dev->rdsout)
0299 dev->rdsin++;
0300 }
0301 mutex_unlock(&dev->lock);
0302 }
0303
0304
0305
0306
0307 if (cadet_has_rds_data(dev))
0308 wake_up_interruptible(&dev->read_queue);
0309
0310
0311
0312
0313 dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
0314 add_timer(&dev->readtimer);
0315 }
0316
0317 static void cadet_start_rds(struct cadet *dev)
0318 {
0319 dev->rdsstat = 1;
0320 outb(0x80, dev->io);
0321 timer_setup(&dev->readtimer, cadet_handler, 0);
0322 dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
0323 add_timer(&dev->readtimer);
0324 }
0325
0326 static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
0327 {
0328 struct cadet *dev = video_drvdata(file);
0329 unsigned char readbuf[RDS_BUFFER];
0330 int i = 0;
0331
0332 mutex_lock(&dev->lock);
0333 if (dev->rdsstat == 0)
0334 cadet_start_rds(dev);
0335 mutex_unlock(&dev->lock);
0336
0337 if (!cadet_has_rds_data(dev) && (file->f_flags & O_NONBLOCK))
0338 return -EWOULDBLOCK;
0339 i = wait_event_interruptible(dev->read_queue, cadet_has_rds_data(dev));
0340 if (i)
0341 return i;
0342
0343 mutex_lock(&dev->lock);
0344 while (i < count && dev->rdsin != dev->rdsout)
0345 readbuf[i++] = dev->rdsbuf[dev->rdsout++];
0346 mutex_unlock(&dev->lock);
0347
0348 if (i && copy_to_user(data, readbuf, i))
0349 return -EFAULT;
0350 return i;
0351 }
0352
0353
0354 static int vidioc_querycap(struct file *file, void *priv,
0355 struct v4l2_capability *v)
0356 {
0357 strscpy(v->driver, "ADS Cadet", sizeof(v->driver));
0358 strscpy(v->card, "ADS Cadet", sizeof(v->card));
0359 strscpy(v->bus_info, "ISA:radio-cadet", sizeof(v->bus_info));
0360 return 0;
0361 }
0362
0363 static int vidioc_g_tuner(struct file *file, void *priv,
0364 struct v4l2_tuner *v)
0365 {
0366 struct cadet *dev = video_drvdata(file);
0367
0368 if (v->index)
0369 return -EINVAL;
0370 v->type = V4L2_TUNER_RADIO;
0371 strscpy(v->name, "Radio", sizeof(v->name));
0372 v->capability = bands[0].capability | bands[1].capability;
0373 v->rangelow = bands[0].rangelow;
0374 v->rangehigh = bands[1].rangehigh;
0375 if (dev->is_fm_band) {
0376 v->rxsubchans = cadet_getstereo(dev);
0377 outb(3, dev->io);
0378 outb(inb(dev->io + 1) & 0x7f, dev->io + 1);
0379 mdelay(100);
0380 outb(3, dev->io);
0381 if (inb(dev->io + 1) & 0x80)
0382 v->rxsubchans |= V4L2_TUNER_SUB_RDS;
0383 } else {
0384 v->rangelow = 8320;
0385 v->rangehigh = 26400;
0386 v->rxsubchans = V4L2_TUNER_SUB_MONO;
0387 }
0388 v->audmode = V4L2_TUNER_MODE_STEREO;
0389 v->signal = dev->sigstrength;
0390 return 0;
0391 }
0392
0393 static int vidioc_s_tuner(struct file *file, void *priv,
0394 const struct v4l2_tuner *v)
0395 {
0396 return v->index ? -EINVAL : 0;
0397 }
0398
0399 static int vidioc_enum_freq_bands(struct file *file, void *priv,
0400 struct v4l2_frequency_band *band)
0401 {
0402 if (band->tuner)
0403 return -EINVAL;
0404 if (band->index >= ARRAY_SIZE(bands))
0405 return -EINVAL;
0406 *band = bands[band->index];
0407 return 0;
0408 }
0409
0410 static int vidioc_g_frequency(struct file *file, void *priv,
0411 struct v4l2_frequency *f)
0412 {
0413 struct cadet *dev = video_drvdata(file);
0414
0415 if (f->tuner)
0416 return -EINVAL;
0417 f->type = V4L2_TUNER_RADIO;
0418 f->frequency = dev->curfreq;
0419 return 0;
0420 }
0421
0422
0423 static int vidioc_s_frequency(struct file *file, void *priv,
0424 const struct v4l2_frequency *f)
0425 {
0426 struct cadet *dev = video_drvdata(file);
0427
0428 if (f->tuner)
0429 return -EINVAL;
0430 dev->is_fm_band =
0431 f->frequency >= (bands[0].rangehigh + bands[1].rangelow) / 2;
0432 cadet_setfreq(dev, f->frequency);
0433 return 0;
0434 }
0435
0436 static int cadet_s_ctrl(struct v4l2_ctrl *ctrl)
0437 {
0438 struct cadet *dev = container_of(ctrl->handler, struct cadet, ctrl_handler);
0439
0440 switch (ctrl->id) {
0441 case V4L2_CID_AUDIO_MUTE:
0442 outb(7, dev->io);
0443 if (ctrl->val)
0444 outb(0x00, dev->io + 1);
0445 else
0446 outb(0x20, dev->io + 1);
0447 return 0;
0448 }
0449 return -EINVAL;
0450 }
0451
0452 static int cadet_open(struct file *file)
0453 {
0454 struct cadet *dev = video_drvdata(file);
0455 int err;
0456
0457 mutex_lock(&dev->lock);
0458 err = v4l2_fh_open(file);
0459 if (err)
0460 goto fail;
0461 if (v4l2_fh_is_singular_file(file))
0462 init_waitqueue_head(&dev->read_queue);
0463 fail:
0464 mutex_unlock(&dev->lock);
0465 return err;
0466 }
0467
0468 static int cadet_release(struct file *file)
0469 {
0470 struct cadet *dev = video_drvdata(file);
0471
0472 mutex_lock(&dev->lock);
0473 if (v4l2_fh_is_singular_file(file) && dev->rdsstat) {
0474 del_timer_sync(&dev->readtimer);
0475 dev->rdsstat = 0;
0476 }
0477 v4l2_fh_release(file);
0478 mutex_unlock(&dev->lock);
0479 return 0;
0480 }
0481
0482 static __poll_t cadet_poll(struct file *file, struct poll_table_struct *wait)
0483 {
0484 struct cadet *dev = video_drvdata(file);
0485 __poll_t req_events = poll_requested_events(wait);
0486 __poll_t res = v4l2_ctrl_poll(file, wait);
0487
0488 poll_wait(file, &dev->read_queue, wait);
0489 if (dev->rdsstat == 0 && (req_events & (EPOLLIN | EPOLLRDNORM))) {
0490 mutex_lock(&dev->lock);
0491 if (dev->rdsstat == 0)
0492 cadet_start_rds(dev);
0493 mutex_unlock(&dev->lock);
0494 }
0495 if (cadet_has_rds_data(dev))
0496 res |= EPOLLIN | EPOLLRDNORM;
0497 return res;
0498 }
0499
0500
0501 static const struct v4l2_file_operations cadet_fops = {
0502 .owner = THIS_MODULE,
0503 .open = cadet_open,
0504 .release = cadet_release,
0505 .read = cadet_read,
0506 .unlocked_ioctl = video_ioctl2,
0507 .poll = cadet_poll,
0508 };
0509
0510 static const struct v4l2_ioctl_ops cadet_ioctl_ops = {
0511 .vidioc_querycap = vidioc_querycap,
0512 .vidioc_g_tuner = vidioc_g_tuner,
0513 .vidioc_s_tuner = vidioc_s_tuner,
0514 .vidioc_g_frequency = vidioc_g_frequency,
0515 .vidioc_s_frequency = vidioc_s_frequency,
0516 .vidioc_enum_freq_bands = vidioc_enum_freq_bands,
0517 .vidioc_log_status = v4l2_ctrl_log_status,
0518 .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
0519 .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
0520 };
0521
0522 static const struct v4l2_ctrl_ops cadet_ctrl_ops = {
0523 .s_ctrl = cadet_s_ctrl,
0524 };
0525
0526 #ifdef CONFIG_PNP
0527
0528 static const struct pnp_device_id cadet_pnp_devices[] = {
0529
0530 {.id = "MSM0c24", .driver_data = 0},
0531 {.id = ""}
0532 };
0533
0534 MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices);
0535
0536 static int cadet_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
0537 {
0538 if (!dev)
0539 return -ENODEV;
0540
0541 if (io > 0)
0542 return -EBUSY;
0543
0544 if (!pnp_port_valid(dev, 0))
0545 return -ENODEV;
0546
0547 io = pnp_port_start(dev, 0);
0548
0549 printk(KERN_INFO "radio-cadet: PnP reports device at %#x\n", io);
0550
0551 return io;
0552 }
0553
0554 static struct pnp_driver cadet_pnp_driver = {
0555 .name = "radio-cadet",
0556 .id_table = cadet_pnp_devices,
0557 .probe = cadet_pnp_probe,
0558 .remove = NULL,
0559 };
0560
0561 #else
0562 static struct pnp_driver cadet_pnp_driver;
0563 #endif
0564
0565 static void cadet_probe(struct cadet *dev)
0566 {
0567 static int iovals[8] = { 0x330, 0x332, 0x334, 0x336, 0x338, 0x33a, 0x33c, 0x33e };
0568 int i;
0569
0570 for (i = 0; i < 8; i++) {
0571 dev->io = iovals[i];
0572 if (request_region(dev->io, 2, "cadet-probe")) {
0573 cadet_setfreq(dev, bands[1].rangelow);
0574 if (cadet_getfreq(dev) == bands[1].rangelow) {
0575 release_region(dev->io, 2);
0576 return;
0577 }
0578 release_region(dev->io, 2);
0579 }
0580 }
0581 dev->io = -1;
0582 }
0583
0584
0585
0586
0587
0588
0589 static int __init cadet_init(void)
0590 {
0591 struct cadet *dev = &cadet_card;
0592 struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
0593 struct v4l2_ctrl_handler *hdl;
0594 int res = -ENODEV;
0595
0596 strscpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name));
0597 mutex_init(&dev->lock);
0598
0599
0600 if (io < 0)
0601 pnp_register_driver(&cadet_pnp_driver);
0602 dev->io = io;
0603
0604
0605 if (dev->io < 0)
0606 cadet_probe(dev);
0607
0608
0609 if (dev->io < 0) {
0610 #ifdef MODULE
0611 v4l2_err(v4l2_dev, "you must set an I/O address with io=0x330, 0x332, 0x334,\n");
0612 v4l2_err(v4l2_dev, "0x336, 0x338, 0x33a, 0x33c or 0x33e\n");
0613 #endif
0614 goto fail;
0615 }
0616 if (!request_region(dev->io, 2, "cadet"))
0617 goto fail;
0618
0619 res = v4l2_device_register(NULL, v4l2_dev);
0620 if (res < 0) {
0621 release_region(dev->io, 2);
0622 v4l2_err(v4l2_dev, "could not register v4l2_device\n");
0623 goto fail;
0624 }
0625
0626 hdl = &dev->ctrl_handler;
0627 v4l2_ctrl_handler_init(hdl, 2);
0628 v4l2_ctrl_new_std(hdl, &cadet_ctrl_ops,
0629 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
0630 v4l2_dev->ctrl_handler = hdl;
0631 if (hdl->error) {
0632 res = hdl->error;
0633 v4l2_err(v4l2_dev, "Could not register controls\n");
0634 goto err_hdl;
0635 }
0636
0637 dev->is_fm_band = true;
0638 dev->curfreq = bands[dev->is_fm_band].rangelow;
0639 cadet_setfreq(dev, dev->curfreq);
0640 strscpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
0641 dev->vdev.v4l2_dev = v4l2_dev;
0642 dev->vdev.fops = &cadet_fops;
0643 dev->vdev.ioctl_ops = &cadet_ioctl_ops;
0644 dev->vdev.release = video_device_release_empty;
0645 dev->vdev.lock = &dev->lock;
0646 dev->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
0647 V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
0648 video_set_drvdata(&dev->vdev, dev);
0649
0650 res = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
0651 if (res < 0)
0652 goto err_hdl;
0653 v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io);
0654 return 0;
0655 err_hdl:
0656 v4l2_ctrl_handler_free(hdl);
0657 v4l2_device_unregister(v4l2_dev);
0658 release_region(dev->io, 2);
0659 fail:
0660 pnp_unregister_driver(&cadet_pnp_driver);
0661 return res;
0662 }
0663
0664 static void __exit cadet_exit(void)
0665 {
0666 struct cadet *dev = &cadet_card;
0667
0668 video_unregister_device(&dev->vdev);
0669 v4l2_ctrl_handler_free(&dev->ctrl_handler);
0670 v4l2_device_unregister(&dev->v4l2_dev);
0671 outb(7, dev->io);
0672 outb(0x00, dev->io + 1);
0673 release_region(dev->io, 2);
0674 pnp_unregister_driver(&cadet_pnp_driver);
0675 }
0676
0677 module_init(cadet_init);
0678 module_exit(cadet_exit);
0679