1 /* 2 * A driver for the AverMedia MR 800 USB FM radio. This device plugs 3 * into both the USB and an analog audio input, so this thing 4 * only deals with initialization and frequency setting, the 5 * audio data has to be handled by a sound driver. 6 * 7 * Copyright (c) 2008 Alexey Klimov <klimov.linux@gmail.com> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 */ 23 24 /* 25 * Big thanks to authors of dsbr100.c and radio-si470x.c 26 * 27 * When work was looked pretty good, i discover this: 28 * http://av-usbradio.sourceforge.net/index.php 29 * http://sourceforge.net/projects/av-usbradio/ 30 * Latest release of theirs project was in 2005. 31 * Probably, this driver could be improved trough using their 32 * achievements (specifications given). 33 * So, we have smth to begin with. 34 * 35 * History: 36 * Version 0.01: First working version. 37 * It's required to blacklist AverMedia USB Radio 38 * in usbhid/hid-quirks.c 39 * 40 * Many things to do: 41 * - Correct power managment of device (suspend & resume) 42 * - Make x86 independance (little-endian and big-endian stuff) 43 * - Add code for scanning and smooth tuning 44 * - Checked and add stereo&mono stuff 45 * - Add code for sensitivity value 46 * - Correct mistakes 47 * - In Japan another FREQ_MIN and FREQ_MAX 48 */ 49 50 /* kernel includes */ 51 #include <linux/kernel.h> 52 #include <linux/module.h> 53 #include <linux/init.h> 54 #include <linux/slab.h> 55 #include <linux/input.h> 56 #include <linux/videodev2.h> 57 #include <media/v4l2-common.h> 58 #include <media/v4l2-ioctl.h> 59 #include <linux/usb.h> 60 #include <linux/version.h> /* for KERNEL_VERSION MACRO */ 61 62 /* driver and module definitions */ 63 #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>" 64 #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver" 65 #define DRIVER_VERSION "0.01" 66 #define RADIO_VERSION KERNEL_VERSION(0, 0, 1) 67 68 MODULE_AUTHOR(DRIVER_AUTHOR); 69 MODULE_DESCRIPTION(DRIVER_DESC); 70 MODULE_LICENSE("GPL"); 71 72 #define USB_AMRADIO_VENDOR 0x07ca 73 #define USB_AMRADIO_PRODUCT 0xb800 74 75 /* Probably USB_TIMEOUT should be modified in module parameter */ 76 #define BUFFER_LENGTH 8 77 #define USB_TIMEOUT 500 78 79 /* Frequency limits in MHz -- these are European values. For Japanese 80 devices, that would be 76 and 91. */ 81 #define FREQ_MIN 87.5 82 #define FREQ_MAX 108.0 83 #define FREQ_MUL 16000 84 85 /* module parameter */ 86 static int radio_nr = -1; 87 module_param(radio_nr, int, 0); 88 MODULE_PARM_DESC(radio_nr, "Radio Nr"); 89 90 static struct v4l2_queryctrl radio_qctrl[] = { 91 { 92 .id = V4L2_CID_AUDIO_MUTE, 93 .name = "Mute", 94 .minimum = 0, 95 .maximum = 1, 96 .step = 1, 97 .default_value = 1, 98 .type = V4L2_CTRL_TYPE_BOOLEAN, 99 }, 100 /* HINT: the disabled controls are only here to satify kradio and such apps */ 101 { .id = V4L2_CID_AUDIO_VOLUME, 102 .flags = V4L2_CTRL_FLAG_DISABLED, 103 }, 104 { 105 .id = V4L2_CID_AUDIO_BALANCE, 106 .flags = V4L2_CTRL_FLAG_DISABLED, 107 }, 108 { 109 .id = V4L2_CID_AUDIO_BASS, 110 .flags = V4L2_CTRL_FLAG_DISABLED, 111 }, 112 { 113 .id = V4L2_CID_AUDIO_TREBLE, 114 .flags = V4L2_CTRL_FLAG_DISABLED, 115 }, 116 { 117 .id = V4L2_CID_AUDIO_LOUDNESS, 118 .flags = V4L2_CTRL_FLAG_DISABLED, 119 }, 120 }; 121 122 static int usb_amradio_probe(struct usb_interface *intf, 123 const struct usb_device_id *id); 124 static void usb_amradio_disconnect(struct usb_interface *intf); 125 static int usb_amradio_open(struct inode *inode, struct file *file); 126 static int usb_amradio_close(struct inode *inode, struct file *file); 127 static int usb_amradio_suspend(struct usb_interface *intf, 128 pm_message_t message); 129 static int usb_amradio_resume(struct usb_interface *intf); 130 131 /* Data for one (physical) device */ 132 struct amradio_device { 133 /* reference to USB and video device */ 134 struct usb_device *usbdev; 135 struct video_device *videodev; 136 137 unsigned char *buffer; 138 struct mutex lock; /* buffer locking */ 139 int curfreq; 140 int stereo; 141 int users; 142 int removed; 143 int muted; 144 }; 145 146 /* USB Device ID List */ 147 static struct usb_device_id usb_amradio_device_table[] = { 148 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, 149 USB_CLASS_HID, 0, 0) }, 150 { } /* Terminating entry */ 151 }; 152 153 MODULE_DEVICE_TABLE(usb, usb_amradio_device_table); 154 155 /* USB subsystem interface */ 156 static struct usb_driver usb_amradio_driver = { 157 .name = "radio-mr800", 158 .probe = usb_amradio_probe, 159 .disconnect = usb_amradio_disconnect, 160 .suspend = usb_amradio_suspend, 161 .resume = usb_amradio_resume, 162 .reset_resume = usb_amradio_resume, 163 .id_table = usb_amradio_device_table, 164 .supports_autosuspend = 1, 165 }; 166 167 /* switch on radio. Send 8 bytes to device. */ 168 static int amradio_start(struct amradio_device *radio) 169 { 170 int retval; 171 int size; 172 173 mutex_lock(&radio->lock); 174 175 radio->buffer[0] = 0x00; 176 radio->buffer[1] = 0x55; 177 radio->buffer[2] = 0xaa; 178 radio->buffer[3] = 0x00; 179 radio->buffer[4] = 0xab; 180 radio->buffer[5] = 0x00; 181 radio->buffer[6] = 0x00; 182 radio->buffer[7] = 0x00; 183 184 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 185 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 186 187 if (retval) { 188 mutex_unlock(&radio->lock); 189 return retval; 190 } 191 192 mutex_unlock(&radio->lock); 193 194 radio->muted = 0; 195 196 return retval; 197 } 198 199 /* switch off radio */ 200 static int amradio_stop(struct amradio_device *radio) 201 { 202 int retval; 203 int size; 204 205 mutex_lock(&radio->lock); 206 207 radio->buffer[0] = 0x00; 208 radio->buffer[1] = 0x55; 209 radio->buffer[2] = 0xaa; 210 radio->buffer[3] = 0x00; 211 radio->buffer[4] = 0xab; 212 radio->buffer[5] = 0x01; 213 radio->buffer[6] = 0x00; 214 radio->buffer[7] = 0x00; 215 216 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 217 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 218 219 if (retval) { 220 mutex_unlock(&radio->lock); 221 return retval; 222 } 223 224 mutex_unlock(&radio->lock); 225 226 radio->muted = 1; 227 228 return retval; 229 } 230 231 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ 232 static int amradio_setfreq(struct amradio_device *radio, int freq) 233 { 234 int retval; 235 int size; 236 unsigned short freq_send = 0x13 + (freq >> 3) / 25; 237 238 mutex_lock(&radio->lock); 239 240 radio->buffer[0] = 0x00; 241 radio->buffer[1] = 0x55; 242 radio->buffer[2] = 0xaa; 243 radio->buffer[3] = 0x03; 244 radio->buffer[4] = 0xa4; 245 radio->buffer[5] = 0x00; 246 radio->buffer[6] = 0x00; 247 radio->buffer[7] = 0x08; 248 249 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 250 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 251 252 if (retval) { 253 mutex_unlock(&radio->lock); 254 return retval; 255 } 256 257 /* frequency is calculated from freq_send and placed in first 2 bytes */ 258 radio->buffer[0] = (freq_send >> 8) & 0xff; 259 radio->buffer[1] = freq_send & 0xff; 260 radio->buffer[2] = 0x01; 261 radio->buffer[3] = 0x00; 262 radio->buffer[4] = 0x00; 263 /* 5 and 6 bytes of buffer already = 0x00 */ 264 radio->buffer[7] = 0x00; 265 266 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 267 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 268 269 if (retval) { 270 mutex_unlock(&radio->lock); 271 return retval; 272 } 273 274 mutex_unlock(&radio->lock); 275 276 radio->stereo = 0; 277 278 return retval; 279 } 280 281 /* USB subsystem interface begins here */ 282 283 /* handle unplugging of the device, release data structures 284 if nothing keeps us from doing it. If something is still 285 keeping us busy, the release callback of v4l will take care 286 of releasing it. */ 287 static void usb_amradio_disconnect(struct usb_interface *intf) 288 { 289 struct amradio_device *radio = usb_get_intfdata(intf); 290 291 usb_set_intfdata(intf, NULL); 292 293 if (radio) { 294 video_unregister_device(radio->videodev); 295 radio->videodev = NULL; 296 if (radio->users) { 297 kfree(radio->buffer); 298 kfree(radio); 299 } else { 300 radio->removed = 1; 301 } 302 } 303 } 304 305 /* vidioc_querycap - query device capabilities */ 306 static int vidioc_querycap(struct file *file, void *priv, 307 struct v4l2_capability *v) 308 { 309 strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); 310 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); 311 sprintf(v->bus_info, "USB"); 312 v->version = RADIO_VERSION; 313 v->capabilities = V4L2_CAP_TUNER; 314 return 0; 315 } 316 317 /* vidioc_g_tuner - get tuner attributes */ 318 static int vidioc_g_tuner(struct file *file, void *priv, 319 struct v4l2_tuner *v) 320 { 321 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 322 323 if (v->index > 0) 324 return -EINVAL; 325 326 /* TODO: Add function which look is signal stereo or not 327 * amradio_getstat(radio); 328 */ 329 radio->stereo = -1; 330 strcpy(v->name, "FM"); 331 v->type = V4L2_TUNER_RADIO; 332 v->rangelow = FREQ_MIN * FREQ_MUL; 333 v->rangehigh = FREQ_MAX * FREQ_MUL; 334 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; 335 v->capability = V4L2_TUNER_CAP_LOW; 336 if (radio->stereo) 337 v->audmode = V4L2_TUNER_MODE_STEREO; 338 else 339 v->audmode = V4L2_TUNER_MODE_MONO; 340 v->signal = 0xffff; /* Can't get the signal strength, sad.. */ 341 v->afc = 0; /* Don't know what is this */ 342 return 0; 343 } 344 345 /* vidioc_s_tuner - set tuner attributes */ 346 static int vidioc_s_tuner(struct file *file, void *priv, 347 struct v4l2_tuner *v) 348 { 349 if (v->index > 0) 350 return -EINVAL; 351 return 0; 352 } 353 354 /* vidioc_s_frequency - set tuner radio frequency */ 355 static int vidioc_s_frequency(struct file *file, void *priv, 356 struct v4l2_frequency *f) 357 { 358 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 359 360 radio->curfreq = f->frequency; 361 if (amradio_setfreq(radio, radio->curfreq) < 0) 362 warn("Set frequency failed"); 363 return 0; 364 } 365 366 /* vidioc_g_frequency - get tuner radio frequency */ 367 static int vidioc_g_frequency(struct file *file, void *priv, 368 struct v4l2_frequency *f) 369 { 370 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 371 372 f->type = V4L2_TUNER_RADIO; 373 f->frequency = radio->curfreq; 374 return 0; 375 } 376 377 /* vidioc_queryctrl - enumerate control items */ 378 static int vidioc_queryctrl(struct file *file, void *priv, 379 struct v4l2_queryctrl *qc) 380 { 381 int i; 382 383 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { 384 if (qc->id && qc->id == radio_qctrl[i].id) { 385 memcpy(qc, &(radio_qctrl[i]), 386 sizeof(*qc)); 387 return 0; 388 } 389 } 390 return -EINVAL; 391 } 392 393 /* vidioc_g_ctrl - get the value of a control */ 394 static int vidioc_g_ctrl(struct file *file, void *priv, 395 struct v4l2_control *ctrl) 396 { 397 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 398 399 switch (ctrl->id) { 400 case V4L2_CID_AUDIO_MUTE: 401 ctrl->value = radio->muted; 402 return 0; 403 } 404 return -EINVAL; 405 } 406 407 /* vidioc_s_ctrl - set the value of a control */ 408 static int vidioc_s_ctrl(struct file *file, void *priv, 409 struct v4l2_control *ctrl) 410 { 411 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 412 413 switch (ctrl->id) { 414 case V4L2_CID_AUDIO_MUTE: 415 if (ctrl->value) { 416 if (amradio_stop(radio) < 0) { 417 warn("amradio_stop() failed"); 418 return -1; 419 } 420 } else { 421 if (amradio_start(radio) < 0) { 422 warn("amradio_start() failed"); 423 return -1; 424 } 425 } 426 return 0; 427 } 428 return -EINVAL; 429 } 430 431 /* vidioc_g_audio - get audio attributes */ 432 static int vidioc_g_audio(struct file *file, void *priv, 433 struct v4l2_audio *a) 434 { 435 if (a->index > 1) 436 return -EINVAL; 437 438 strcpy(a->name, "Radio"); 439 a->capability = V4L2_AUDCAP_STEREO; 440 return 0; 441 } 442 443 /* vidioc_s_audio - set audio attributes */ 444 static int vidioc_s_audio(struct file *file, void *priv, 445 struct v4l2_audio *a) 446 { 447 if (a->index != 0) 448 return -EINVAL; 449 return 0; 450 } 451 452 /* vidioc_g_input - get input */ 453 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) 454 { 455 *i = 0; 456 return 0; 457 } 458 459 /* vidioc_s_input - set input */ 460 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) 461 { 462 if (i != 0) 463 return -EINVAL; 464 return 0; 465 } 466 467 /* open device - amradio_start() and amradio_setfreq() */ 468 static int usb_amradio_open(struct inode *inode, struct file *file) 469 { 470 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 471 472 lock_kernel(); 473 474 radio->users = 1; 475 radio->muted = 1; 476 477 if (amradio_start(radio) < 0) { 478 warn("Radio did not start up properly"); 479 radio->users = 0; 480 unlock_kernel(); 481 return -EIO; 482 } 483 if (amradio_setfreq(radio, radio->curfreq) < 0) 484 warn("Set frequency failed"); 485 486 unlock_kernel(); 487 return 0; 488 } 489 490 /*close device - free driver structures */ 491 static int usb_amradio_close(struct inode *inode, struct file *file) 492 { 493 struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 494 495 if (!radio) 496 return -ENODEV; 497 radio->users = 0; 498 if (radio->removed) { 499 kfree(radio->buffer); 500 kfree(radio); 501 } 502 return 0; 503 } 504 505 /* Suspend device - stop device. Need to be checked and fixed */ 506 static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) 507 { 508 struct amradio_device *radio = usb_get_intfdata(intf); 509 510 if (amradio_stop(radio) < 0) 511 warn("amradio_stop() failed"); 512 513 info("radio-mr800: Going into suspend.."); 514 515 return 0; 516 } 517 518 /* Resume device - start device. Need to be checked and fixed */ 519 static int usb_amradio_resume(struct usb_interface *intf) 520 { 521 struct amradio_device *radio = usb_get_intfdata(intf); 522 523 if (amradio_start(radio) < 0) 524 warn("amradio_start() failed"); 525 526 info("radio-mr800: Coming out of suspend.."); 527 528 return 0; 529 } 530 531 /* File system interface */ 532 static const struct file_operations usb_amradio_fops = { 533 .owner = THIS_MODULE, 534 .open = usb_amradio_open, 535 .release = usb_amradio_close, 536 .ioctl = video_ioctl2, 537 #ifdef CONFIG_COMPAT 538 .compat_ioctl = v4l_compat_ioctl32, 539 #endif 540 .llseek = no_llseek, 541 }; 542 543 static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { 544 .vidioc_querycap = vidioc_querycap, 545 .vidioc_g_tuner = vidioc_g_tuner, 546 .vidioc_s_tuner = vidioc_s_tuner, 547 .vidioc_g_frequency = vidioc_g_frequency, 548 .vidioc_s_frequency = vidioc_s_frequency, 549 .vidioc_queryctrl = vidioc_queryctrl, 550 .vidioc_g_ctrl = vidioc_g_ctrl, 551 .vidioc_s_ctrl = vidioc_s_ctrl, 552 .vidioc_g_audio = vidioc_g_audio, 553 .vidioc_s_audio = vidioc_s_audio, 554 .vidioc_g_input = vidioc_g_input, 555 .vidioc_s_input = vidioc_s_input, 556 }; 557 558 /* V4L2 interface */ 559 static struct video_device amradio_videodev_template = { 560 .name = "AverMedia MR 800 USB FM Radio", 561 .fops = &usb_amradio_fops, 562 .ioctl_ops = &usb_amradio_ioctl_ops, 563 .release = video_device_release, 564 }; 565 566 /* check if the device is present and register with v4l and 567 usb if it is */ 568 static int usb_amradio_probe(struct usb_interface *intf, 569 const struct usb_device_id *id) 570 { 571 struct amradio_device *radio; 572 573 radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL); 574 575 if (!(radio)) 576 return -ENOMEM; 577 578 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); 579 580 if (!(radio->buffer)) { 581 kfree(radio); 582 return -ENOMEM; 583 } 584 585 radio->videodev = video_device_alloc(); 586 587 if (!(radio->videodev)) { 588 kfree(radio->buffer); 589 kfree(radio); 590 return -ENOMEM; 591 } 592 593 memcpy(radio->videodev, &amradio_videodev_template, 594 sizeof(amradio_videodev_template)); 595 596 radio->removed = 0; 597 radio->users = 0; 598 radio->usbdev = interface_to_usbdev(intf); 599 radio->curfreq = 95.16 * FREQ_MUL; 600 601 mutex_init(&radio->lock); 602 603 video_set_drvdata(radio->videodev, radio); 604 if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { 605 warn("Could not register video device"); 606 video_device_release(radio->videodev); 607 kfree(radio->buffer); 608 kfree(radio); 609 return -EIO; 610 } 611 612 usb_set_intfdata(intf, radio); 613 return 0; 614 } 615 616 static int __init amradio_init(void) 617 { 618 int retval = usb_register(&usb_amradio_driver); 619 620 info(DRIVER_VERSION " " DRIVER_DESC); 621 if (retval) 622 err("usb_register failed. Error number %d", retval); 623 return retval; 624 } 625 626 static void __exit amradio_exit(void) 627 { 628 usb_deregister(&usb_amradio_driver); 629 } 630 631 module_init(amradio_init); 632 module_exit(amradio_exit); 633 634