radio-mr800.c revision 4e3616576e9e65d53f9381b9f334257299c7262e
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 and contributors 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 * Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio 34 * in 2007. He allowed to use his driver to improve current mr800 radio driver. 35 * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492 36 * 37 * Version 0.01: First working version. 38 * It's required to blacklist AverMedia USB Radio 39 * in usbhid/hid-quirks.c 40 * Version 0.10: A lot of cleanups and fixes: unpluging the device, 41 * few mutex locks were added, codinstyle issues, etc. 42 * Added stereo support. Thanks to 43 * Douglas Schilling Landgraf <dougsland@gmail.com> and 44 * David Ellingsworth <david@identd.dyndns.org> 45 * for discussion, help and support. 46 * Version 0.11: Converted to v4l2_device. 47 * 48 * Many things to do: 49 * - Correct power management of device (suspend & resume) 50 * - Add code for scanning and smooth tuning 51 * - Add code for sensitivity value 52 * - Correct mistakes 53 * - In Japan another FREQ_MIN and FREQ_MAX 54 */ 55 56/* kernel includes */ 57#include <linux/kernel.h> 58#include <linux/module.h> 59#include <linux/init.h> 60#include <linux/slab.h> 61#include <linux/smp_lock.h> 62#include <linux/input.h> 63#include <linux/videodev2.h> 64#include <media/v4l2-device.h> 65#include <media/v4l2-ioctl.h> 66#include <linux/usb.h> 67#include <linux/version.h> /* for KERNEL_VERSION MACRO */ 68#include <linux/mutex.h> 69 70/* driver and module definitions */ 71#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>" 72#define DRIVER_DESC "AverMedia MR 800 USB FM radio driver" 73#define DRIVER_VERSION "0.11" 74#define RADIO_VERSION KERNEL_VERSION(0, 1, 1) 75 76MODULE_AUTHOR(DRIVER_AUTHOR); 77MODULE_DESCRIPTION(DRIVER_DESC); 78MODULE_LICENSE("GPL"); 79 80#define USB_AMRADIO_VENDOR 0x07ca 81#define USB_AMRADIO_PRODUCT 0xb800 82 83/* dev_warn macro with driver name */ 84#define MR800_DRIVER_NAME "radio-mr800" 85#define amradio_dev_warn(dev, fmt, arg...) \ 86 dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg) 87 88/* Probably USB_TIMEOUT should be modified in module parameter */ 89#define BUFFER_LENGTH 8 90#define USB_TIMEOUT 500 91 92/* Frequency limits in MHz -- these are European values. For Japanese 93devices, that would be 76 and 91. */ 94#define FREQ_MIN 87.5 95#define FREQ_MAX 108.0 96#define FREQ_MUL 16000 97 98/* 99 * Commands that device should understand 100 * List isnt full and will be updated with implementation of new functions 101 */ 102#define AMRADIO_SET_FREQ 0xa4 103#define AMRADIO_SET_MUTE 0xab 104#define AMRADIO_SET_MONO 0xae 105 106/* Comfortable defines for amradio_set_mute */ 107#define AMRADIO_START 0x00 108#define AMRADIO_STOP 0x01 109 110/* Comfortable defines for amradio_set_stereo */ 111#define WANT_STEREO 0x00 112#define WANT_MONO 0x01 113 114/* module parameter */ 115static int radio_nr = -1; 116module_param(radio_nr, int, 0); 117MODULE_PARM_DESC(radio_nr, "Radio Nr"); 118 119static int usb_amradio_probe(struct usb_interface *intf, 120 const struct usb_device_id *id); 121static void usb_amradio_disconnect(struct usb_interface *intf); 122static int usb_amradio_open(struct file *file); 123static int usb_amradio_close(struct file *file); 124static int usb_amradio_suspend(struct usb_interface *intf, 125 pm_message_t message); 126static int usb_amradio_resume(struct usb_interface *intf); 127 128/* Data for one (physical) device */ 129struct amradio_device { 130 /* reference to USB and video device */ 131 struct usb_device *usbdev; 132 struct video_device videodev; 133 struct v4l2_device v4l2_dev; 134 135 unsigned char *buffer; 136 struct mutex lock; /* buffer locking */ 137 int curfreq; 138 int stereo; 139 int users; 140 int muted; 141}; 142 143#define vdev_to_amradio(r) container_of(r, struct amradio_device, videodev) 144 145/* USB Device ID List */ 146static struct usb_device_id usb_amradio_device_table[] = { 147 {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, 148 USB_CLASS_HID, 0, 0) }, 149 { } /* Terminating entry */ 150}; 151 152MODULE_DEVICE_TABLE(usb, usb_amradio_device_table); 153 154/* USB subsystem interface */ 155static struct usb_driver usb_amradio_driver = { 156 .name = MR800_DRIVER_NAME, 157 .probe = usb_amradio_probe, 158 .disconnect = usb_amradio_disconnect, 159 .suspend = usb_amradio_suspend, 160 .resume = usb_amradio_resume, 161 .reset_resume = usb_amradio_resume, 162 .id_table = usb_amradio_device_table, 163 .supports_autosuspend = 0, 164}; 165 166/* switch on/off the radio. Send 8 bytes to device */ 167static int amradio_set_mute(struct amradio_device *radio, char argument) 168{ 169 int retval; 170 int size; 171 172 BUG_ON(!mutex_is_locked(&radio->lock)); 173 174 radio->buffer[0] = 0x00; 175 radio->buffer[1] = 0x55; 176 radio->buffer[2] = 0xaa; 177 radio->buffer[3] = 0x00; 178 radio->buffer[4] = AMRADIO_SET_MUTE; 179 radio->buffer[5] = argument; 180 radio->buffer[6] = 0x00; 181 radio->buffer[7] = 0x00; 182 183 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 184 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 185 186 if (retval < 0 || size != BUFFER_LENGTH) 187 return retval; 188 189 radio->muted = argument; 190 191 return retval; 192} 193 194/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ 195static int amradio_setfreq(struct amradio_device *radio, int freq) 196{ 197 int retval; 198 int size; 199 unsigned short freq_send = 0x10 + (freq >> 3) / 25; 200 201 BUG_ON(!mutex_is_locked(&radio->lock)); 202 203 radio->buffer[0] = 0x00; 204 radio->buffer[1] = 0x55; 205 radio->buffer[2] = 0xaa; 206 radio->buffer[3] = 0x03; 207 radio->buffer[4] = AMRADIO_SET_FREQ; 208 radio->buffer[5] = 0x00; 209 radio->buffer[6] = 0x00; 210 radio->buffer[7] = 0x08; 211 212 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 213 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 214 215 if (retval < 0 || size != BUFFER_LENGTH) 216 return retval; 217 218 /* frequency is calculated from freq_send and placed in first 2 bytes */ 219 radio->buffer[0] = (freq_send >> 8) & 0xff; 220 radio->buffer[1] = freq_send & 0xff; 221 radio->buffer[2] = 0x01; 222 radio->buffer[3] = 0x00; 223 radio->buffer[4] = 0x00; 224 /* 5 and 6 bytes of buffer already = 0x00 */ 225 radio->buffer[7] = 0x00; 226 227 retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 228 (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 229 230 return retval; 231} 232 233static int amradio_set_stereo(struct amradio_device *radio, char argument) 234{ 235 int retval; 236 int size; 237 238 BUG_ON(!mutex_is_locked(&radio->lock)); 239 240 radio->buffer[0] = 0x00; 241 radio->buffer[1] = 0x55; 242 radio->buffer[2] = 0xaa; 243 radio->buffer[3] = 0x00; 244 radio->buffer[4] = AMRADIO_SET_MONO; 245 radio->buffer[5] = argument; 246 radio->buffer[6] = 0x00; 247 radio->buffer[7] = 0x00; 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 < 0 || size != BUFFER_LENGTH) { 253 radio->stereo = -1; 254 return retval; 255 } 256 257 radio->stereo = 1; 258 259 return retval; 260} 261 262/* Handle unplugging the device. 263 * We call video_unregister_device in any case. 264 * The last function called in this procedure is 265 * usb_amradio_device_release. 266 */ 267static void usb_amradio_disconnect(struct usb_interface *intf) 268{ 269 struct amradio_device *radio = usb_get_intfdata(intf); 270 271 mutex_lock(&radio->lock); 272 radio->usbdev = NULL; 273 mutex_unlock(&radio->lock); 274 275 usb_set_intfdata(intf, NULL); 276 v4l2_device_disconnect(&radio->v4l2_dev); 277 video_unregister_device(&radio->videodev); 278} 279 280/* vidioc_querycap - query device capabilities */ 281static int vidioc_querycap(struct file *file, void *priv, 282 struct v4l2_capability *v) 283{ 284 struct amradio_device *radio = file->private_data; 285 286 strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); 287 strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); 288 usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); 289 v->version = RADIO_VERSION; 290 v->capabilities = V4L2_CAP_TUNER; 291 return 0; 292} 293 294/* vidioc_g_tuner - get tuner attributes */ 295static int vidioc_g_tuner(struct file *file, void *priv, 296 struct v4l2_tuner *v) 297{ 298 struct amradio_device *radio = file->private_data; 299 int retval; 300 301 if (v->index > 0) 302 return -EINVAL; 303 304/* TODO: Add function which look is signal stereo or not 305 * amradio_getstat(radio); 306 */ 307 308/* we call amradio_set_stereo to set radio->stereo 309 * Honestly, amradio_getstat should cover this in future and 310 * amradio_set_stereo shouldn't be here 311 */ 312 retval = amradio_set_stereo(radio, WANT_STEREO); 313 if (retval < 0) 314 amradio_dev_warn(&radio->videodev.dev, 315 "set stereo failed\n"); 316 317 strcpy(v->name, "FM"); 318 v->type = V4L2_TUNER_RADIO; 319 v->rangelow = FREQ_MIN * FREQ_MUL; 320 v->rangehigh = FREQ_MAX * FREQ_MUL; 321 v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; 322 v->capability = V4L2_TUNER_CAP_LOW; 323 if (radio->stereo) 324 v->audmode = V4L2_TUNER_MODE_STEREO; 325 else 326 v->audmode = V4L2_TUNER_MODE_MONO; 327 v->signal = 0xffff; /* Can't get the signal strength, sad.. */ 328 v->afc = 0; /* Don't know what is this */ 329 330 return retval; 331} 332 333/* vidioc_s_tuner - set tuner attributes */ 334static int vidioc_s_tuner(struct file *file, void *priv, 335 struct v4l2_tuner *v) 336{ 337 struct amradio_device *radio = file->private_data; 338 int retval = -EINVAL; 339 340 if (v->index > 0) 341 return -EINVAL; 342 343 /* mono/stereo selector */ 344 switch (v->audmode) { 345 case V4L2_TUNER_MODE_MONO: 346 retval = amradio_set_stereo(radio, WANT_MONO); 347 if (retval < 0) 348 amradio_dev_warn(&radio->videodev.dev, 349 "set mono failed\n"); 350 break; 351 case V4L2_TUNER_MODE_STEREO: 352 retval = amradio_set_stereo(radio, WANT_STEREO); 353 if (retval < 0) 354 amradio_dev_warn(&radio->videodev.dev, 355 "set stereo failed\n"); 356 break; 357 } 358 359 return retval; 360} 361 362/* vidioc_s_frequency - set tuner radio frequency */ 363static int vidioc_s_frequency(struct file *file, void *priv, 364 struct v4l2_frequency *f) 365{ 366 struct amradio_device *radio = file->private_data; 367 int retval = 0; 368 369 radio->curfreq = f->frequency; 370 371 retval = amradio_setfreq(radio, radio->curfreq); 372 if (retval < 0) 373 amradio_dev_warn(&radio->videodev.dev, 374 "set frequency failed\n"); 375 376 return retval; 377} 378 379/* vidioc_g_frequency - get tuner radio frequency */ 380static int vidioc_g_frequency(struct file *file, void *priv, 381 struct v4l2_frequency *f) 382{ 383 struct amradio_device *radio = file->private_data; 384 385 f->type = V4L2_TUNER_RADIO; 386 f->frequency = radio->curfreq; 387 388 return 0; 389} 390 391/* vidioc_queryctrl - enumerate control items */ 392static int vidioc_queryctrl(struct file *file, void *priv, 393 struct v4l2_queryctrl *qc) 394{ 395 switch (qc->id) { 396 case V4L2_CID_AUDIO_MUTE: 397 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); 398 } 399 400 return -EINVAL; 401} 402 403/* vidioc_g_ctrl - get the value of a control */ 404static int vidioc_g_ctrl(struct file *file, void *priv, 405 struct v4l2_control *ctrl) 406{ 407 struct amradio_device *radio = file->private_data; 408 409 switch (ctrl->id) { 410 case V4L2_CID_AUDIO_MUTE: 411 ctrl->value = radio->muted; 412 return 0; 413 } 414 415 return -EINVAL; 416} 417 418/* vidioc_s_ctrl - set the value of a control */ 419static int vidioc_s_ctrl(struct file *file, void *priv, 420 struct v4l2_control *ctrl) 421{ 422 struct amradio_device *radio = file->private_data; 423 int retval = -EINVAL; 424 425 switch (ctrl->id) { 426 case V4L2_CID_AUDIO_MUTE: 427 if (ctrl->value) { 428 retval = amradio_set_mute(radio, AMRADIO_STOP); 429 if (retval < 0) { 430 amradio_dev_warn(&radio->videodev.dev, 431 "amradio_stop failed\n"); 432 } 433 } else { 434 retval = amradio_set_mute(radio, AMRADIO_START); 435 if (retval < 0) { 436 amradio_dev_warn(&radio->videodev.dev, 437 "amradio_start failed\n"); 438 } 439 } 440 break; 441 } 442 443 return retval; 444} 445 446/* vidioc_g_audio - get audio attributes */ 447static int vidioc_g_audio(struct file *file, void *priv, 448 struct v4l2_audio *a) 449{ 450 if (a->index > 1) 451 return -EINVAL; 452 453 strcpy(a->name, "Radio"); 454 a->capability = V4L2_AUDCAP_STEREO; 455 return 0; 456} 457 458/* vidioc_s_audio - set audio attributes */ 459static int vidioc_s_audio(struct file *file, void *priv, 460 struct v4l2_audio *a) 461{ 462 if (a->index != 0) 463 return -EINVAL; 464 return 0; 465} 466 467/* vidioc_g_input - get input */ 468static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) 469{ 470 *i = 0; 471 return 0; 472} 473 474/* vidioc_s_input - set input */ 475static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) 476{ 477 if (i != 0) 478 return -EINVAL; 479 return 0; 480} 481 482/* open device - amradio_start() and amradio_setfreq() */ 483static int usb_amradio_open(struct file *file) 484{ 485 struct amradio_device *radio = vdev_to_amradio(video_devdata(file)); 486 int retval = 0; 487 488 mutex_lock(&radio->lock); 489 490 if (!radio->usbdev) { 491 retval = -EIO; 492 goto unlock; 493 } 494 495 file->private_data = radio; 496 radio->users = 1; 497 radio->muted = 1; 498 499 retval = amradio_set_mute(radio, AMRADIO_START); 500 if (retval < 0) { 501 amradio_dev_warn(&radio->videodev.dev, 502 "radio did not start up properly\n"); 503 radio->users = 0; 504 goto unlock; 505 } 506 507 retval = amradio_set_stereo(radio, WANT_STEREO); 508 if (retval < 0) 509 amradio_dev_warn(&radio->videodev.dev, 510 "set stereo failed\n"); 511 512 retval = amradio_setfreq(radio, radio->curfreq); 513 if (retval < 0) 514 amradio_dev_warn(&radio->videodev.dev, 515 "set frequency failed\n"); 516 517unlock: 518 mutex_unlock(&radio->lock); 519 return retval; 520} 521 522/*close device */ 523static int usb_amradio_close(struct file *file) 524{ 525 struct amradio_device *radio = file->private_data; 526 int retval = 0; 527 528 mutex_lock(&radio->lock); 529 530 if (!radio->usbdev) { 531 retval = -EIO; 532 goto unlock; 533 } 534 535 radio->users = 0; 536 537 retval = amradio_set_mute(radio, AMRADIO_STOP); 538 if (retval < 0) 539 amradio_dev_warn(&radio->videodev.dev, 540 "amradio_stop failed\n"); 541 542unlock: 543 mutex_unlock(&radio->lock); 544 return retval; 545} 546 547static long usb_amradio_ioctl(struct file *file, unsigned int cmd, 548 unsigned long arg) 549{ 550 struct amradio_device *radio = file->private_data; 551 long retval = 0; 552 553 mutex_lock(&radio->lock); 554 555 if (!radio->usbdev) { 556 retval = -EIO; 557 goto unlock; 558 } 559 560 retval = video_ioctl2(file, cmd, arg); 561 562unlock: 563 mutex_unlock(&radio->lock); 564 return retval; 565} 566 567/* Suspend device - stop device. Need to be checked and fixed */ 568static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) 569{ 570 struct amradio_device *radio = usb_get_intfdata(intf); 571 int retval; 572 573 mutex_lock(&radio->lock); 574 575 retval = amradio_set_mute(radio, AMRADIO_STOP); 576 if (retval < 0) 577 dev_warn(&intf->dev, "amradio_stop failed\n"); 578 579 dev_info(&intf->dev, "going into suspend..\n"); 580 581 mutex_unlock(&radio->lock); 582 return 0; 583} 584 585/* Resume device - start device. Need to be checked and fixed */ 586static int usb_amradio_resume(struct usb_interface *intf) 587{ 588 struct amradio_device *radio = usb_get_intfdata(intf); 589 int retval; 590 591 mutex_lock(&radio->lock); 592 593 retval = amradio_set_mute(radio, AMRADIO_START); 594 if (retval < 0) 595 dev_warn(&intf->dev, "amradio_start failed\n"); 596 597 dev_info(&intf->dev, "coming out of suspend..\n"); 598 599 mutex_unlock(&radio->lock); 600 return 0; 601} 602 603/* File system interface */ 604static const struct v4l2_file_operations usb_amradio_fops = { 605 .owner = THIS_MODULE, 606 .open = usb_amradio_open, 607 .release = usb_amradio_close, 608 .ioctl = usb_amradio_ioctl, 609}; 610 611static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { 612 .vidioc_querycap = vidioc_querycap, 613 .vidioc_g_tuner = vidioc_g_tuner, 614 .vidioc_s_tuner = vidioc_s_tuner, 615 .vidioc_g_frequency = vidioc_g_frequency, 616 .vidioc_s_frequency = vidioc_s_frequency, 617 .vidioc_queryctrl = vidioc_queryctrl, 618 .vidioc_g_ctrl = vidioc_g_ctrl, 619 .vidioc_s_ctrl = vidioc_s_ctrl, 620 .vidioc_g_audio = vidioc_g_audio, 621 .vidioc_s_audio = vidioc_s_audio, 622 .vidioc_g_input = vidioc_g_input, 623 .vidioc_s_input = vidioc_s_input, 624}; 625 626static void usb_amradio_video_device_release(struct video_device *videodev) 627{ 628 struct amradio_device *radio = vdev_to_amradio(videodev); 629 630 v4l2_device_unregister(&radio->v4l2_dev); 631 632 /* free rest memory */ 633 kfree(radio->buffer); 634 kfree(radio); 635} 636 637/* check if the device is present and register with v4l and usb if it is */ 638static int usb_amradio_probe(struct usb_interface *intf, 639 const struct usb_device_id *id) 640{ 641 struct amradio_device *radio; 642 int retval = 0; 643 644 radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); 645 646 if (!radio) { 647 dev_err(&intf->dev, "kmalloc for amradio_device failed\n"); 648 retval = -ENOMEM; 649 goto err; 650 } 651 652 radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); 653 654 if (!radio->buffer) { 655 dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); 656 retval = -ENOMEM; 657 goto err_nobuf; 658 } 659 660 retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); 661 if (retval < 0) { 662 dev_err(&intf->dev, "couldn't register v4l2_device\n"); 663 goto err_v4l2; 664 } 665 666 strlcpy(radio->videodev.name, radio->v4l2_dev.name, 667 sizeof(radio->videodev.name)); 668 radio->videodev.v4l2_dev = &radio->v4l2_dev; 669 radio->videodev.fops = &usb_amradio_fops; 670 radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops; 671 radio->videodev.release = usb_amradio_video_device_release; 672 673 radio->users = 0; 674 radio->usbdev = interface_to_usbdev(intf); 675 radio->curfreq = 95.16 * FREQ_MUL; 676 radio->stereo = -1; 677 678 mutex_init(&radio->lock); 679 680 video_set_drvdata(&radio->videodev, radio); 681 682 retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, 683 radio_nr); 684 if (retval < 0) { 685 dev_err(&intf->dev, "could not register video device\n"); 686 goto err_vdev; 687 } 688 689 usb_set_intfdata(intf, radio); 690 return 0; 691 692err_vdev: 693 v4l2_device_unregister(&radio->v4l2_dev); 694err_v4l2: 695 kfree(radio->buffer); 696err_nobuf: 697 kfree(radio); 698err: 699 return retval; 700} 701 702static int __init amradio_init(void) 703{ 704 int retval = usb_register(&usb_amradio_driver); 705 706 pr_info(KBUILD_MODNAME 707 ": version " DRIVER_VERSION " " DRIVER_DESC "\n"); 708 709 if (retval) 710 pr_err(KBUILD_MODNAME 711 ": usb_register failed. Error number %d\n", retval); 712 713 return retval; 714} 715 716static void __exit amradio_exit(void) 717{ 718 usb_deregister(&usb_amradio_driver); 719} 720 721module_init(amradio_init); 722module_exit(amradio_exit); 723 724