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