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 57 static int radio_nr = -1; 58 module_param(radio_nr, int, 0); 59 MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); 60 61 struct 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 79 static struct pcm20 pcm20_card = { 80 .freq = 87 * 16000, 81 .audmode = V4L2_TUNER_MODE_STEREO, 82 }; 83 84 85 static 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 104 static 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 113 static 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 127 static 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 133 static 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 140 static 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 151 static 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 181 static 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 198 static 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 211 static 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 225 static 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 254 static 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 270 static 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 284 static 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 297 static 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 309 static 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 381 static 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 399 static 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 410 static 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 418 static 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 429 static const struct v4l2_ctrl_ops pcm20_ctrl_ops = { 430 .s_ctrl = pcm20_s_ctrl, 431 }; 432 433 static 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; 493 err_hdl: 494 v4l2_ctrl_handler_free(hdl); 495 v4l2_device_unregister(v4l2_dev); 496 return -EINVAL; 497 } 498 499 MODULE_AUTHOR("Ruurd Reitsma, Krzysztof Helt"); 500 MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card."); 501 MODULE_LICENSE("GPL"); 502 503 static 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 513 module_init(pcm20_init); 514 module_exit(pcm20_cleanup); 515