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

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

DEFINITIONS

This source file includes following definitions.
  1. rds_waitread
  2. rds_rawwrite
  3. rds_write
  4. rds_readcycle_nowait
  5. rds_readcycle
  6. rds_ack
  7. rds_cmd
  8. pcm20_setfreq
  9. vidioc_querycap
  10. sanitize
  11. vidioc_g_tuner
  12. vidioc_s_tuner
  13. vidioc_g_frequency
  14. vidioc_s_frequency
  15. pcm20_s_ctrl
  16. pcm20_thread
  17. pcm20_open
  18. pcm20_release
  19. pcm20_init
  20. pcm20_cleanup

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Miro PCM20 radio driver for Linux radio support
   4  * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
   5  * Thanks to Norberto Pellici for the ACI device interface specification
   6  * The API part is based on the radiotrack driver by M. Kirkwood
   7  * This driver relies on the aci mixer provided by the snd-miro
   8  * ALSA driver.
   9  * Look there for further info...
  10  *
  11  * From the original miro RDS sources:
  12  *
  13  *  (c) 2001 Robert Siemer <Robert.Siemer@gmx.de>
  14  *
  15  *  Many thanks to Fred Seidel <seidel@metabox.de>, the
  16  *  designer of the RDS decoder hardware. With his help
  17  *  I was able to code this driver.
  18  *  Thanks also to Norberto Pellicci, Dominic Mounteney
  19  *  <DMounteney@pinnaclesys.com> and www.teleauskunft.de
  20  *  for good hints on finding Fred. It was somewhat hard
  21  *  to locate him here in Germany... [:
  22  *
  23  * This code has been reintroduced and converted to use
  24  * the new V4L2 RDS API by:
  25  *
  26  * Hans Verkuil <hans.verkuil@cisco.com>
  27  */
  28 
  29 #include <linux/module.h>
  30 #include <linux/init.h>
  31 #include <linux/io.h>
  32 #include <linux/delay.h>
  33 #include <linux/videodev2.h>
  34 #include <linux/kthread.h>
  35 #include <media/v4l2-device.h>
  36 #include <media/v4l2-ioctl.h>
  37 #include <media/v4l2-ctrls.h>
  38 #include <media/v4l2-fh.h>
  39 #include <media/v4l2-event.h>
  40 #include <sound/aci.h>
  41 
  42 #define RDS_DATASHIFT          2   /* Bit 2 */
  43 #define RDS_DATAMASK        (1 << RDS_DATASHIFT)
  44 #define RDS_BUSYMASK        0x10   /* Bit 4 */
  45 #define RDS_CLOCKMASK       0x08   /* Bit 3 */
  46 #define RDS_DATA(x)         (((x) >> RDS_DATASHIFT) & 1)
  47 
  48 #define RDS_STATUS      0x01
  49 #define RDS_STATIONNAME 0x02
  50 #define RDS_TEXT        0x03
  51 #define RDS_ALTFREQ     0x04
  52 #define RDS_TIMEDATE    0x05
  53 #define RDS_PI_CODE     0x06
  54 #define RDS_PTYTATP     0x07
  55 #define RDS_RESET       0x08
  56 #define RDS_RXVALUE     0x09
  57 
  58 static int radio_nr = -1;
  59 module_param(radio_nr, int, 0);
  60 MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX).  Default: -1 (autodetect)");
  61 
  62 struct pcm20 {
  63         struct v4l2_device v4l2_dev;
  64         struct video_device vdev;
  65         struct v4l2_ctrl_handler ctrl_handler;
  66         struct v4l2_ctrl *rds_pty;
  67         struct v4l2_ctrl *rds_ps_name;
  68         struct v4l2_ctrl *rds_radio_test;
  69         struct v4l2_ctrl *rds_ta;
  70         struct v4l2_ctrl *rds_tp;
  71         struct v4l2_ctrl *rds_ms;
  72         /* thread for periodic RDS status checking */
  73         struct task_struct *kthread;
  74         unsigned long freq;
  75         u32 audmode;
  76         struct snd_miro_aci *aci;
  77         struct mutex lock;
  78 };
  79 
  80 static struct pcm20 pcm20_card = {
  81         .freq = 87 * 16000,
  82         .audmode = V4L2_TUNER_MODE_STEREO,
  83 };
  84 
  85 
  86 static int rds_waitread(struct snd_miro_aci *aci)
  87 {
  88         u8 byte;
  89         int i = 2000;
  90 
  91         do {
  92                 byte = inb(aci->aci_port + ACI_REG_RDS);
  93                 i--;
  94         } while ((byte & RDS_BUSYMASK) && i);
  95 
  96         /*
  97          * It's magic, but without this the data that you read later on
  98          * is unreliable and full of bit errors. With this 1 usec delay
  99          * everything is fine.
 100          */
 101         udelay(1);
 102         return i ? byte : -1;
 103 }
 104 
 105 static int rds_rawwrite(struct snd_miro_aci *aci, u8 byte)
 106 {
 107         if (rds_waitread(aci) >= 0) {
 108                 outb(byte, aci->aci_port + ACI_REG_RDS);
 109                 return 0;
 110         }
 111         return -1;
 112 }
 113 
 114 static int rds_write(struct snd_miro_aci *aci, u8 byte)
 115 {
 116         u8 sendbuffer[8];
 117         int i;
 118 
 119         for (i = 7; i >= 0; i--)
 120                 sendbuffer[7 - i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
 121         sendbuffer[0] |= RDS_CLOCKMASK;
 122 
 123         for (i = 0; i < 8; i++)
 124                 rds_rawwrite(aci, sendbuffer[i]);
 125         return 0;
 126 }
 127 
 128 static int rds_readcycle_nowait(struct snd_miro_aci *aci)
 129 {
 130         outb(0, aci->aci_port + ACI_REG_RDS);
 131         return rds_waitread(aci);
 132 }
 133 
 134 static int rds_readcycle(struct snd_miro_aci *aci)
 135 {
 136         if (rds_rawwrite(aci, 0) < 0)
 137                 return -1;
 138         return rds_waitread(aci);
 139 }
 140 
 141 static int rds_ack(struct snd_miro_aci *aci)
 142 {
 143         int i = rds_readcycle(aci);
 144 
 145         if (i < 0)
 146                 return -1;
 147         if (i & RDS_DATAMASK)
 148                 return 0;  /* ACK  */
 149         return 1;  /* NACK */
 150 }
 151 
 152 static int rds_cmd(struct snd_miro_aci *aci, u8 cmd, u8 databuffer[], u8 datasize)
 153 {
 154         int i, j;
 155 
 156         rds_write(aci, cmd);
 157 
 158         /* RDS_RESET doesn't need further processing */
 159         if (cmd == RDS_RESET)
 160                 return 0;
 161         if (rds_ack(aci))
 162                 return -EIO;
 163         if (datasize == 0)
 164                 return 0;
 165 
 166         /* to be able to use rds_readcycle_nowait()
 167            I have to waitread() here */
 168         if (rds_waitread(aci) < 0)
 169                 return -1;
 170 
 171         memset(databuffer, 0, datasize);
 172 
 173         for (i = 0; i < 8 * datasize; i++) {
 174                 j = rds_readcycle_nowait(aci);
 175                 if (j < 0)
 176                         return -EIO;
 177                 databuffer[i / 8] |= RDS_DATA(j) << (7 - (i % 8));
 178         }
 179         return 0;
 180 }
 181 
 182 static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
 183 {
 184         unsigned char freql;
 185         unsigned char freqh;
 186         struct snd_miro_aci *aci = dev->aci;
 187 
 188         freq /= 160;
 189         if (!(aci->aci_version == 0x07 || aci->aci_version >= 0xb0))
 190                 freq /= 10;  /* I don't know exactly which version
 191                               * needs this hack */
 192         freql = freq & 0xff;
 193         freqh = freq >> 8;
 194 
 195         rds_cmd(aci, RDS_RESET, NULL, 0);
 196         return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh);
 197 }
 198 
 199 static int vidioc_querycap(struct file *file, void *priv,
 200                                 struct v4l2_capability *v)
 201 {
 202         struct pcm20 *dev = video_drvdata(file);
 203 
 204         strscpy(v->driver, "Miro PCM20", sizeof(v->driver));
 205         strscpy(v->card, "Miro PCM20", sizeof(v->card));
 206         snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name);
 207         return 0;
 208 }
 209 
 210 static bool sanitize(char *p, int size)
 211 {
 212         int i;
 213         bool ret = true;
 214 
 215         for (i = 0; i < size; i++) {
 216                 if (p[i] < 32) {
 217                         p[i] = ' ';
 218                         ret = false;
 219                 }
 220         }
 221         return ret;
 222 }
 223 
 224 static int vidioc_g_tuner(struct file *file, void *priv,
 225                                 struct v4l2_tuner *v)
 226 {
 227         struct pcm20 *dev = video_drvdata(file);
 228         int res;
 229         u8 buf;
 230 
 231         if (v->index)
 232                 return -EINVAL;
 233         strscpy(v->name, "FM", sizeof(v->name));
 234         v->type = V4L2_TUNER_RADIO;
 235         v->rangelow = 87*16000;
 236         v->rangehigh = 108*16000;
 237         res = snd_aci_cmd(dev->aci, ACI_READ_TUNERSTATION, -1, -1);
 238         v->signal = (res & 0x80) ? 0 : 0xffff;
 239         /* Note: stereo detection does not work if the audio is muted,
 240            it will default to mono in that case. */
 241         res = snd_aci_cmd(dev->aci, ACI_READ_TUNERSTEREO, -1, -1);
 242         v->rxsubchans = (res & 0x40) ? V4L2_TUNER_SUB_MONO :
 243                                         V4L2_TUNER_SUB_STEREO;
 244         v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
 245                         V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS;
 246         v->audmode = dev->audmode;
 247         res = rds_cmd(dev->aci, RDS_RXVALUE, &buf, 1);
 248         if (res >= 0 && buf)
 249                 v->rxsubchans |= V4L2_TUNER_SUB_RDS;
 250         return 0;
 251 }
 252 
 253 static int vidioc_s_tuner(struct file *file, void *priv,
 254                                 const struct v4l2_tuner *v)
 255 {
 256         struct pcm20 *dev = video_drvdata(file);
 257 
 258         if (v->index)
 259                 return -EINVAL;
 260         if (v->audmode > V4L2_TUNER_MODE_STEREO)
 261                 dev->audmode = V4L2_TUNER_MODE_STEREO;
 262         else
 263                 dev->audmode = v->audmode;
 264         snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO,
 265                         dev->audmode == V4L2_TUNER_MODE_MONO, -1);
 266         return 0;
 267 }
 268 
 269 static int vidioc_g_frequency(struct file *file, void *priv,
 270                                 struct v4l2_frequency *f)
 271 {
 272         struct pcm20 *dev = video_drvdata(file);
 273 
 274         if (f->tuner != 0)
 275                 return -EINVAL;
 276 
 277         f->type = V4L2_TUNER_RADIO;
 278         f->frequency = dev->freq;
 279         return 0;
 280 }
 281 
 282 
 283 static int vidioc_s_frequency(struct file *file, void *priv,
 284                                 const struct v4l2_frequency *f)
 285 {
 286         struct pcm20 *dev = video_drvdata(file);
 287 
 288         if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
 289                 return -EINVAL;
 290 
 291         dev->freq = clamp_t(u32, f->frequency, 87 * 16000U, 108 * 16000U);
 292         pcm20_setfreq(dev, dev->freq);
 293         return 0;
 294 }
 295 
 296 static int pcm20_s_ctrl(struct v4l2_ctrl *ctrl)
 297 {
 298         struct pcm20 *dev = container_of(ctrl->handler, struct pcm20, ctrl_handler);
 299 
 300         switch (ctrl->id) {
 301         case V4L2_CID_AUDIO_MUTE:
 302                 snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, ctrl->val, -1);
 303                 return 0;
 304         }
 305         return -EINVAL;
 306 }
 307 
 308 static int pcm20_thread(void *data)
 309 {
 310         struct pcm20 *dev = data;
 311         const unsigned no_rds_start_counter = 5;
 312         const unsigned sleep_msecs = 2000;
 313         unsigned no_rds_counter = no_rds_start_counter;
 314 
 315         for (;;) {
 316                 char text_buffer[66];
 317                 u8 buf;
 318                 int res;
 319 
 320                 msleep_interruptible(sleep_msecs);
 321 
 322                 if (kthread_should_stop())
 323                         break;
 324 
 325                 res = rds_cmd(dev->aci, RDS_RXVALUE, &buf, 1);
 326                 if (res)
 327                         continue;
 328                 if (buf == 0) {
 329                         if (no_rds_counter == 0)
 330                                 continue;
 331                         no_rds_counter--;
 332                         if (no_rds_counter)
 333                                 continue;
 334 
 335                         /*
 336                          * No RDS seen for no_rds_start_counter * sleep_msecs
 337                          * milliseconds, clear all RDS controls to their
 338                          * default values.
 339                          */
 340                         v4l2_ctrl_s_ctrl_string(dev->rds_ps_name, "");
 341                         v4l2_ctrl_s_ctrl(dev->rds_ms, 1);
 342                         v4l2_ctrl_s_ctrl(dev->rds_ta, 0);
 343                         v4l2_ctrl_s_ctrl(dev->rds_tp, 0);
 344                         v4l2_ctrl_s_ctrl(dev->rds_pty, 0);
 345                         v4l2_ctrl_s_ctrl_string(dev->rds_radio_test, "");
 346                         continue;
 347                 }
 348                 no_rds_counter = no_rds_start_counter;
 349 
 350                 res = rds_cmd(dev->aci, RDS_STATUS, &buf, 1);
 351                 if (res)
 352                         continue;
 353                 if ((buf >> 3) & 1) {
 354                         res = rds_cmd(dev->aci, RDS_STATIONNAME, text_buffer, 8);
 355                         text_buffer[8] = 0;
 356                         if (!res && sanitize(text_buffer, 8))
 357                                 v4l2_ctrl_s_ctrl_string(dev->rds_ps_name, text_buffer);
 358                 }
 359                 if ((buf >> 6) & 1) {
 360                         u8 pty;
 361 
 362                         res = rds_cmd(dev->aci, RDS_PTYTATP, &pty, 1);
 363                         if (!res) {
 364                                 v4l2_ctrl_s_ctrl(dev->rds_ms, !!(pty & 0x01));
 365                                 v4l2_ctrl_s_ctrl(dev->rds_ta, !!(pty & 0x02));
 366                                 v4l2_ctrl_s_ctrl(dev->rds_tp, !!(pty & 0x80));
 367                                 v4l2_ctrl_s_ctrl(dev->rds_pty, (pty >> 2) & 0x1f);
 368                         }
 369                 }
 370                 if ((buf >> 4) & 1) {
 371                         res = rds_cmd(dev->aci, RDS_TEXT, text_buffer, 65);
 372                         text_buffer[65] = 0;
 373                         if (!res && sanitize(text_buffer + 1, 64))
 374                                 v4l2_ctrl_s_ctrl_string(dev->rds_radio_test, text_buffer + 1);
 375                 }
 376         }
 377         return 0;
 378 }
 379 
 380 static int pcm20_open(struct file *file)
 381 {
 382         struct pcm20 *dev = video_drvdata(file);
 383         int res = v4l2_fh_open(file);
 384 
 385         if (!res && v4l2_fh_is_singular_file(file) &&
 386             IS_ERR_OR_NULL(dev->kthread)) {
 387                 dev->kthread = kthread_run(pcm20_thread, dev, "%s",
 388                                            dev->v4l2_dev.name);
 389                 if (IS_ERR(dev->kthread)) {
 390                         v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
 391                         v4l2_fh_release(file);
 392                         return PTR_ERR(dev->kthread);
 393                 }
 394         }
 395         return res;
 396 }
 397 
 398 static int pcm20_release(struct file *file)
 399 {
 400         struct pcm20 *dev = video_drvdata(file);
 401 
 402         if (v4l2_fh_is_singular_file(file) && !IS_ERR_OR_NULL(dev->kthread)) {
 403                 kthread_stop(dev->kthread);
 404                 dev->kthread = NULL;
 405         }
 406         return v4l2_fh_release(file);
 407 }
 408 
 409 static const struct v4l2_file_operations pcm20_fops = {
 410         .owner          = THIS_MODULE,
 411         .open           = pcm20_open,
 412         .poll           = v4l2_ctrl_poll,
 413         .release        = pcm20_release,
 414         .unlocked_ioctl = video_ioctl2,
 415 };
 416 
 417 static const struct v4l2_ioctl_ops pcm20_ioctl_ops = {
 418         .vidioc_querycap    = vidioc_querycap,
 419         .vidioc_g_tuner     = vidioc_g_tuner,
 420         .vidioc_s_tuner     = vidioc_s_tuner,
 421         .vidioc_g_frequency = vidioc_g_frequency,
 422         .vidioc_s_frequency = vidioc_s_frequency,
 423         .vidioc_log_status  = v4l2_ctrl_log_status,
 424         .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 425         .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 426 };
 427 
 428 static const struct v4l2_ctrl_ops pcm20_ctrl_ops = {
 429         .s_ctrl = pcm20_s_ctrl,
 430 };
 431 
 432 static int __init pcm20_init(void)
 433 {
 434         struct pcm20 *dev = &pcm20_card;
 435         struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
 436         struct v4l2_ctrl_handler *hdl;
 437         int res;
 438 
 439         dev->aci = snd_aci_get_aci();
 440         if (dev->aci == NULL) {
 441                 v4l2_err(v4l2_dev,
 442                          "you must load the snd-miro driver first!\n");
 443                 return -ENODEV;
 444         }
 445         strscpy(v4l2_dev->name, "radio-miropcm20", sizeof(v4l2_dev->name));
 446         mutex_init(&dev->lock);
 447 
 448         res = v4l2_device_register(NULL, v4l2_dev);
 449         if (res < 0) {
 450                 v4l2_err(v4l2_dev, "could not register v4l2_device\n");
 451                 return -EINVAL;
 452         }
 453 
 454         hdl = &dev->ctrl_handler;
 455         v4l2_ctrl_handler_init(hdl, 7);
 456         v4l2_ctrl_new_std(hdl, &pcm20_ctrl_ops,
 457                         V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
 458         dev->rds_pty = v4l2_ctrl_new_std(hdl, NULL,
 459                         V4L2_CID_RDS_RX_PTY, 0, 0x1f, 1, 0);
 460         dev->rds_ps_name = v4l2_ctrl_new_std(hdl, NULL,
 461                         V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0);
 462         dev->rds_radio_test = v4l2_ctrl_new_std(hdl, NULL,
 463                         V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0);
 464         dev->rds_ta = v4l2_ctrl_new_std(hdl, NULL,
 465                         V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
 466         dev->rds_tp = v4l2_ctrl_new_std(hdl, NULL,
 467                         V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0);
 468         dev->rds_ms = v4l2_ctrl_new_std(hdl, NULL,
 469                         V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1);
 470         v4l2_dev->ctrl_handler = hdl;
 471         if (hdl->error) {
 472                 res = hdl->error;
 473                 v4l2_err(v4l2_dev, "Could not register control\n");
 474                 goto err_hdl;
 475         }
 476         strscpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
 477         dev->vdev.v4l2_dev = v4l2_dev;
 478         dev->vdev.fops = &pcm20_fops;
 479         dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
 480         dev->vdev.release = video_device_release_empty;
 481         dev->vdev.lock = &dev->lock;
 482         dev->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
 483                                 V4L2_CAP_RDS_CAPTURE;
 484         video_set_drvdata(&dev->vdev, dev);
 485         snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO,
 486                         dev->audmode == V4L2_TUNER_MODE_MONO, -1);
 487         pcm20_setfreq(dev, dev->freq);
 488 
 489         if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
 490                 goto err_hdl;
 491 
 492         v4l2_info(v4l2_dev, "Mirosound PCM20 Radio tuner\n");
 493         return 0;
 494 err_hdl:
 495         v4l2_ctrl_handler_free(hdl);
 496         v4l2_device_unregister(v4l2_dev);
 497         return -EINVAL;
 498 }
 499 
 500 MODULE_AUTHOR("Ruurd Reitsma, Krzysztof Helt");
 501 MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
 502 MODULE_LICENSE("GPL");
 503 
 504 static void __exit pcm20_cleanup(void)
 505 {
 506         struct pcm20 *dev = &pcm20_card;
 507 
 508         video_unregister_device(&dev->vdev);
 509         snd_aci_cmd(dev->aci, ACI_SET_TUNERMUTE, 1, -1);
 510         v4l2_ctrl_handler_free(&dev->ctrl_handler);
 511         v4l2_device_unregister(&dev->v4l2_dev);
 512 }
 513 
 514 module_init(pcm20_init);
 515 module_exit(pcm20_cleanup);

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