12aa72f3bSAlexey Klimov /* 22aa72f3bSAlexey Klimov * A driver for the AverMedia MR 800 USB FM radio. This device plugs 32aa72f3bSAlexey Klimov * into both the USB and an analog audio input, so this thing 42aa72f3bSAlexey Klimov * only deals with initialization and frequency setting, the 52aa72f3bSAlexey Klimov * audio data has to be handled by a sound driver. 62aa72f3bSAlexey Klimov * 72aa72f3bSAlexey Klimov * Copyright (c) 2008 Alexey Klimov <klimov.linux@gmail.com> 82aa72f3bSAlexey Klimov * 92aa72f3bSAlexey Klimov * This program is free software; you can redistribute it and/or modify 102aa72f3bSAlexey Klimov * it under the terms of the GNU General Public License as published by 112aa72f3bSAlexey Klimov * the Free Software Foundation; either version 2 of the License, or 122aa72f3bSAlexey Klimov * (at your option) any later version. 132aa72f3bSAlexey Klimov * 142aa72f3bSAlexey Klimov * This program is distributed in the hope that it will be useful, 152aa72f3bSAlexey Klimov * but WITHOUT ANY WARRANTY; without even the implied warranty of 162aa72f3bSAlexey Klimov * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 172aa72f3bSAlexey Klimov * GNU General Public License for more details. 182aa72f3bSAlexey Klimov * 192aa72f3bSAlexey Klimov * You should have received a copy of the GNU General Public License 202aa72f3bSAlexey Klimov * along with this program; if not, write to the Free Software 212aa72f3bSAlexey Klimov * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 222aa72f3bSAlexey Klimov */ 232aa72f3bSAlexey Klimov 242aa72f3bSAlexey Klimov /* 2571f07d94SAlexey Klimov * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c 262aa72f3bSAlexey Klimov * 272aa72f3bSAlexey Klimov * When work was looked pretty good, i discover this: 282aa72f3bSAlexey Klimov * http://av-usbradio.sourceforge.net/index.php 292aa72f3bSAlexey Klimov * http://sourceforge.net/projects/av-usbradio/ 302aa72f3bSAlexey Klimov * Latest release of theirs project was in 2005. 31*af901ca1SAndré Goddard Rosa * Probably, this driver could be improved through using their 322aa72f3bSAlexey Klimov * achievements (specifications given). 3371f07d94SAlexey Klimov * Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio 3471f07d94SAlexey Klimov * in 2007. He allowed to use his driver to improve current mr800 radio driver. 3571f07d94SAlexey Klimov * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492 362aa72f3bSAlexey Klimov * 372aa72f3bSAlexey Klimov * Version 0.01: First working version. 382aa72f3bSAlexey Klimov * It's required to blacklist AverMedia USB Radio 392aa72f3bSAlexey Klimov * in usbhid/hid-quirks.c 4071f07d94SAlexey Klimov * Version 0.10: A lot of cleanups and fixes: unpluging the device, 4171f07d94SAlexey Klimov * few mutex locks were added, codinstyle issues, etc. 4271f07d94SAlexey Klimov * Added stereo support. Thanks to 4371f07d94SAlexey Klimov * Douglas Schilling Landgraf <dougsland@gmail.com> and 4471f07d94SAlexey Klimov * David Ellingsworth <david@identd.dyndns.org> 4571f07d94SAlexey Klimov * for discussion, help and support. 46b466248dSAlexey Klimov * Version 0.11: Converted to v4l2_device. 472aa72f3bSAlexey Klimov * 482aa72f3bSAlexey Klimov * Many things to do: 493dbda77eSUwe Kleine-Koenig * - Correct power management of device (suspend & resume) 502aa72f3bSAlexey Klimov * - Add code for scanning and smooth tuning 512aa72f3bSAlexey Klimov * - Add code for sensitivity value 522aa72f3bSAlexey Klimov * - Correct mistakes 532aa72f3bSAlexey Klimov * - In Japan another FREQ_MIN and FREQ_MAX 542aa72f3bSAlexey Klimov */ 552aa72f3bSAlexey Klimov 562aa72f3bSAlexey Klimov /* kernel includes */ 572aa72f3bSAlexey Klimov #include <linux/kernel.h> 582aa72f3bSAlexey Klimov #include <linux/module.h> 592aa72f3bSAlexey Klimov #include <linux/init.h> 602aa72f3bSAlexey Klimov #include <linux/slab.h> 61405f5571SAlexey Dobriyan #include <linux/smp_lock.h> 622aa72f3bSAlexey Klimov #include <linux/input.h> 632aa72f3bSAlexey Klimov #include <linux/videodev2.h> 64b466248dSAlexey Klimov #include <media/v4l2-device.h> 652aa72f3bSAlexey Klimov #include <media/v4l2-ioctl.h> 662aa72f3bSAlexey Klimov #include <linux/usb.h> 672aa72f3bSAlexey Klimov #include <linux/version.h> /* for KERNEL_VERSION MACRO */ 6824c44d85SAlessio Igor Bogani #include <linux/mutex.h> 692aa72f3bSAlexey Klimov 702aa72f3bSAlexey Klimov /* driver and module definitions */ 712aa72f3bSAlexey Klimov #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>" 722aa72f3bSAlexey Klimov #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver" 73b466248dSAlexey Klimov #define DRIVER_VERSION "0.11" 74b466248dSAlexey Klimov #define RADIO_VERSION KERNEL_VERSION(0, 1, 1) 752aa72f3bSAlexey Klimov 762aa72f3bSAlexey Klimov MODULE_AUTHOR(DRIVER_AUTHOR); 772aa72f3bSAlexey Klimov MODULE_DESCRIPTION(DRIVER_DESC); 782aa72f3bSAlexey Klimov MODULE_LICENSE("GPL"); 792aa72f3bSAlexey Klimov 802aa72f3bSAlexey Klimov #define USB_AMRADIO_VENDOR 0x07ca 812aa72f3bSAlexey Klimov #define USB_AMRADIO_PRODUCT 0xb800 822aa72f3bSAlexey Klimov 83e60b022eSAlexey Klimov /* dev_warn macro with driver name */ 84e60b022eSAlexey Klimov #define MR800_DRIVER_NAME "radio-mr800" 85e60b022eSAlexey Klimov #define amradio_dev_warn(dev, fmt, arg...) \ 86e60b022eSAlexey Klimov dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg) 87e60b022eSAlexey Klimov 882aa72f3bSAlexey Klimov /* Probably USB_TIMEOUT should be modified in module parameter */ 892aa72f3bSAlexey Klimov #define BUFFER_LENGTH 8 902aa72f3bSAlexey Klimov #define USB_TIMEOUT 500 912aa72f3bSAlexey Klimov 922aa72f3bSAlexey Klimov /* Frequency limits in MHz -- these are European values. For Japanese 932aa72f3bSAlexey Klimov devices, that would be 76 and 91. */ 942aa72f3bSAlexey Klimov #define FREQ_MIN 87.5 952aa72f3bSAlexey Klimov #define FREQ_MAX 108.0 962aa72f3bSAlexey Klimov #define FREQ_MUL 16000 972aa72f3bSAlexey Klimov 98db821804SAlexey Klimov /* 99db821804SAlexey Klimov * Commands that device should understand 100db821804SAlexey Klimov * List isnt full and will be updated with implementation of new functions 101db821804SAlexey Klimov */ 102f7c1a380SAlexey Klimov #define AMRADIO_SET_FREQ 0xa4 103db821804SAlexey Klimov #define AMRADIO_SET_MUTE 0xab 1041bb16d71SAlexey Klimov #define AMRADIO_SET_MONO 0xae 105db821804SAlexey Klimov 106db821804SAlexey Klimov /* Comfortable defines for amradio_set_mute */ 107db821804SAlexey Klimov #define AMRADIO_START 0x00 108db821804SAlexey Klimov #define AMRADIO_STOP 0x01 109db821804SAlexey Klimov 1101bb16d71SAlexey Klimov /* Comfortable defines for amradio_set_stereo */ 1111bb16d71SAlexey Klimov #define WANT_STEREO 0x00 1121bb16d71SAlexey Klimov #define WANT_MONO 0x01 1131bb16d71SAlexey Klimov 1142aa72f3bSAlexey Klimov /* module parameter */ 1152aa72f3bSAlexey Klimov static int radio_nr = -1; 1162aa72f3bSAlexey Klimov module_param(radio_nr, int, 0); 1172aa72f3bSAlexey Klimov MODULE_PARM_DESC(radio_nr, "Radio Nr"); 1182aa72f3bSAlexey Klimov 1192aa72f3bSAlexey Klimov static int usb_amradio_probe(struct usb_interface *intf, 1202aa72f3bSAlexey Klimov const struct usb_device_id *id); 1212aa72f3bSAlexey Klimov static void usb_amradio_disconnect(struct usb_interface *intf); 122bec43661SHans Verkuil static int usb_amradio_open(struct file *file); 123bec43661SHans Verkuil static int usb_amradio_close(struct file *file); 1242aa72f3bSAlexey Klimov static int usb_amradio_suspend(struct usb_interface *intf, 1252aa72f3bSAlexey Klimov pm_message_t message); 1262aa72f3bSAlexey Klimov static int usb_amradio_resume(struct usb_interface *intf); 1272aa72f3bSAlexey Klimov 1282aa72f3bSAlexey Klimov /* Data for one (physical) device */ 1292aa72f3bSAlexey Klimov struct amradio_device { 1302aa72f3bSAlexey Klimov /* reference to USB and video device */ 1312aa72f3bSAlexey Klimov struct usb_device *usbdev; 1322aa72f3bSAlexey Klimov struct video_device *videodev; 133b466248dSAlexey Klimov struct v4l2_device v4l2_dev; 1342aa72f3bSAlexey Klimov 1352aa72f3bSAlexey Klimov unsigned char *buffer; 1362aa72f3bSAlexey Klimov struct mutex lock; /* buffer locking */ 1372aa72f3bSAlexey Klimov int curfreq; 1382aa72f3bSAlexey Klimov int stereo; 1392aa72f3bSAlexey Klimov int users; 1402aa72f3bSAlexey Klimov int removed; 1412aa72f3bSAlexey Klimov int muted; 1422aa72f3bSAlexey Klimov }; 1432aa72f3bSAlexey Klimov 1442aa72f3bSAlexey Klimov /* USB Device ID List */ 1452aa72f3bSAlexey Klimov static struct usb_device_id usb_amradio_device_table[] = { 1462aa72f3bSAlexey Klimov {USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT, 1472aa72f3bSAlexey Klimov USB_CLASS_HID, 0, 0) }, 1482aa72f3bSAlexey Klimov { } /* Terminating entry */ 1492aa72f3bSAlexey Klimov }; 1502aa72f3bSAlexey Klimov 1512aa72f3bSAlexey Klimov MODULE_DEVICE_TABLE(usb, usb_amradio_device_table); 1522aa72f3bSAlexey Klimov 1532aa72f3bSAlexey Klimov /* USB subsystem interface */ 1542aa72f3bSAlexey Klimov static struct usb_driver usb_amradio_driver = { 155e60b022eSAlexey Klimov .name = MR800_DRIVER_NAME, 1562aa72f3bSAlexey Klimov .probe = usb_amradio_probe, 1572aa72f3bSAlexey Klimov .disconnect = usb_amradio_disconnect, 1582aa72f3bSAlexey Klimov .suspend = usb_amradio_suspend, 1592aa72f3bSAlexey Klimov .resume = usb_amradio_resume, 1602aa72f3bSAlexey Klimov .reset_resume = usb_amradio_resume, 1612aa72f3bSAlexey Klimov .id_table = usb_amradio_device_table, 162f2ce9179SAlexey Klimov .supports_autosuspend = 0, 1632aa72f3bSAlexey Klimov }; 1642aa72f3bSAlexey Klimov 165db821804SAlexey Klimov /* switch on/off the radio. Send 8 bytes to device */ 166db821804SAlexey Klimov static int amradio_set_mute(struct amradio_device *radio, char argument) 1672aa72f3bSAlexey Klimov { 1682aa72f3bSAlexey Klimov int retval; 1692aa72f3bSAlexey Klimov int size; 1702aa72f3bSAlexey Klimov 1713480130aSAlexey Klimov /* safety check */ 1723480130aSAlexey Klimov if (radio->removed) 1733480130aSAlexey Klimov return -EIO; 1743480130aSAlexey Klimov 1752aa72f3bSAlexey Klimov mutex_lock(&radio->lock); 1762aa72f3bSAlexey Klimov 1772aa72f3bSAlexey Klimov radio->buffer[0] = 0x00; 1782aa72f3bSAlexey Klimov radio->buffer[1] = 0x55; 1792aa72f3bSAlexey Klimov radio->buffer[2] = 0xaa; 1802aa72f3bSAlexey Klimov radio->buffer[3] = 0x00; 181db821804SAlexey Klimov radio->buffer[4] = AMRADIO_SET_MUTE; 182db821804SAlexey Klimov radio->buffer[5] = argument; 1832aa72f3bSAlexey Klimov radio->buffer[6] = 0x00; 1842aa72f3bSAlexey Klimov radio->buffer[7] = 0x00; 1852aa72f3bSAlexey Klimov 1862aa72f3bSAlexey Klimov retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 1872aa72f3bSAlexey Klimov (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 1882aa72f3bSAlexey Klimov 189e57458dcSAlexey Klimov if (retval < 0 || size != BUFFER_LENGTH) { 1902aa72f3bSAlexey Klimov mutex_unlock(&radio->lock); 1912aa72f3bSAlexey Klimov return retval; 1922aa72f3bSAlexey Klimov } 1932aa72f3bSAlexey Klimov 194db821804SAlexey Klimov radio->muted = argument; 1952aa72f3bSAlexey Klimov 1967f03a585SAlexey Klimov mutex_unlock(&radio->lock); 1977f03a585SAlexey Klimov 1982aa72f3bSAlexey Klimov return retval; 1992aa72f3bSAlexey Klimov } 2002aa72f3bSAlexey Klimov 2012aa72f3bSAlexey Klimov /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ 2022aa72f3bSAlexey Klimov static int amradio_setfreq(struct amradio_device *radio, int freq) 2032aa72f3bSAlexey Klimov { 2042aa72f3bSAlexey Klimov int retval; 2052aa72f3bSAlexey Klimov int size; 206f7c1a380SAlexey Klimov unsigned short freq_send = 0x10 + (freq >> 3) / 25; 2072aa72f3bSAlexey Klimov 2083480130aSAlexey Klimov /* safety check */ 2093480130aSAlexey Klimov if (radio->removed) 2103480130aSAlexey Klimov return -EIO; 2113480130aSAlexey Klimov 2122aa72f3bSAlexey Klimov mutex_lock(&radio->lock); 2132aa72f3bSAlexey Klimov 2142aa72f3bSAlexey Klimov radio->buffer[0] = 0x00; 2152aa72f3bSAlexey Klimov radio->buffer[1] = 0x55; 2162aa72f3bSAlexey Klimov radio->buffer[2] = 0xaa; 2172aa72f3bSAlexey Klimov radio->buffer[3] = 0x03; 218f7c1a380SAlexey Klimov radio->buffer[4] = AMRADIO_SET_FREQ; 2192aa72f3bSAlexey Klimov radio->buffer[5] = 0x00; 2202aa72f3bSAlexey Klimov radio->buffer[6] = 0x00; 2212aa72f3bSAlexey Klimov radio->buffer[7] = 0x08; 2222aa72f3bSAlexey Klimov 2232aa72f3bSAlexey Klimov retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 2242aa72f3bSAlexey Klimov (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 2252aa72f3bSAlexey Klimov 226e57458dcSAlexey Klimov if (retval < 0 || size != BUFFER_LENGTH) { 2272aa72f3bSAlexey Klimov mutex_unlock(&radio->lock); 2282aa72f3bSAlexey Klimov return retval; 2292aa72f3bSAlexey Klimov } 2302aa72f3bSAlexey Klimov 2312aa72f3bSAlexey Klimov /* frequency is calculated from freq_send and placed in first 2 bytes */ 2322aa72f3bSAlexey Klimov radio->buffer[0] = (freq_send >> 8) & 0xff; 2332aa72f3bSAlexey Klimov radio->buffer[1] = freq_send & 0xff; 2342aa72f3bSAlexey Klimov radio->buffer[2] = 0x01; 2352aa72f3bSAlexey Klimov radio->buffer[3] = 0x00; 2362aa72f3bSAlexey Klimov radio->buffer[4] = 0x00; 2372aa72f3bSAlexey Klimov /* 5 and 6 bytes of buffer already = 0x00 */ 2382aa72f3bSAlexey Klimov radio->buffer[7] = 0x00; 2392aa72f3bSAlexey Klimov 2402aa72f3bSAlexey Klimov retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 2412aa72f3bSAlexey Klimov (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 2422aa72f3bSAlexey Klimov 243e57458dcSAlexey Klimov if (retval < 0 || size != BUFFER_LENGTH) { 2442aa72f3bSAlexey Klimov mutex_unlock(&radio->lock); 2452aa72f3bSAlexey Klimov return retval; 2462aa72f3bSAlexey Klimov } 2472aa72f3bSAlexey Klimov 2481bb16d71SAlexey Klimov mutex_unlock(&radio->lock); 2491bb16d71SAlexey Klimov 2501bb16d71SAlexey Klimov return retval; 2511bb16d71SAlexey Klimov } 2521bb16d71SAlexey Klimov 2531bb16d71SAlexey Klimov static int amradio_set_stereo(struct amradio_device *radio, char argument) 2541bb16d71SAlexey Klimov { 2551bb16d71SAlexey Klimov int retval; 2561bb16d71SAlexey Klimov int size; 2571bb16d71SAlexey Klimov 2581bb16d71SAlexey Klimov /* safety check */ 2591bb16d71SAlexey Klimov if (radio->removed) 2601bb16d71SAlexey Klimov return -EIO; 2611bb16d71SAlexey Klimov 2621bb16d71SAlexey Klimov mutex_lock(&radio->lock); 2631bb16d71SAlexey Klimov 2641bb16d71SAlexey Klimov radio->buffer[0] = 0x00; 2651bb16d71SAlexey Klimov radio->buffer[1] = 0x55; 2661bb16d71SAlexey Klimov radio->buffer[2] = 0xaa; 2671bb16d71SAlexey Klimov radio->buffer[3] = 0x00; 2681bb16d71SAlexey Klimov radio->buffer[4] = AMRADIO_SET_MONO; 2691bb16d71SAlexey Klimov radio->buffer[5] = argument; 2701bb16d71SAlexey Klimov radio->buffer[6] = 0x00; 2711bb16d71SAlexey Klimov radio->buffer[7] = 0x00; 2721bb16d71SAlexey Klimov 2731bb16d71SAlexey Klimov retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), 2741bb16d71SAlexey Klimov (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); 2751bb16d71SAlexey Klimov 2761bb16d71SAlexey Klimov if (retval < 0 || size != BUFFER_LENGTH) { 2771bb16d71SAlexey Klimov radio->stereo = -1; 2781bb16d71SAlexey Klimov mutex_unlock(&radio->lock); 2791bb16d71SAlexey Klimov return retval; 2801bb16d71SAlexey Klimov } 2811bb16d71SAlexey Klimov 2821bb16d71SAlexey Klimov radio->stereo = 1; 2832aa72f3bSAlexey Klimov 2847f03a585SAlexey Klimov mutex_unlock(&radio->lock); 2857f03a585SAlexey Klimov 2862aa72f3bSAlexey Klimov return retval; 2872aa72f3bSAlexey Klimov } 2882aa72f3bSAlexey Klimov 28971f07d94SAlexey Klimov /* Handle unplugging the device. 29071f07d94SAlexey Klimov * We call video_unregister_device in any case. 29171f07d94SAlexey Klimov * The last function called in this procedure is 29271f07d94SAlexey Klimov * usb_amradio_device_release. 29371f07d94SAlexey Klimov */ 2942aa72f3bSAlexey Klimov static void usb_amradio_disconnect(struct usb_interface *intf) 2952aa72f3bSAlexey Klimov { 2962aa72f3bSAlexey Klimov struct amradio_device *radio = usb_get_intfdata(intf); 2972aa72f3bSAlexey Klimov 298f4e9043eSAlexey Klimov mutex_lock(&radio->lock); 2993480130aSAlexey Klimov radio->removed = 1; 300f4e9043eSAlexey Klimov mutex_unlock(&radio->lock); 3012aa72f3bSAlexey Klimov 302f4e9043eSAlexey Klimov usb_set_intfdata(intf, NULL); 3032aa72f3bSAlexey Klimov video_unregister_device(radio->videodev); 304b466248dSAlexey Klimov v4l2_device_disconnect(&radio->v4l2_dev); 3052aa72f3bSAlexey Klimov } 3062aa72f3bSAlexey Klimov 3072aa72f3bSAlexey Klimov /* vidioc_querycap - query device capabilities */ 3082aa72f3bSAlexey Klimov static int vidioc_querycap(struct file *file, void *priv, 3092aa72f3bSAlexey Klimov struct v4l2_capability *v) 3102aa72f3bSAlexey Klimov { 311c7181cfaSAlexey Klimov struct amradio_device *radio = video_drvdata(file); 312c7181cfaSAlexey Klimov 3132aa72f3bSAlexey Klimov strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); 3142aa72f3bSAlexey Klimov strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); 315c7181cfaSAlexey Klimov usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); 3162aa72f3bSAlexey Klimov v->version = RADIO_VERSION; 3172aa72f3bSAlexey Klimov v->capabilities = V4L2_CAP_TUNER; 3182aa72f3bSAlexey Klimov return 0; 3192aa72f3bSAlexey Klimov } 3202aa72f3bSAlexey Klimov 3212aa72f3bSAlexey Klimov /* vidioc_g_tuner - get tuner attributes */ 3222aa72f3bSAlexey Klimov static int vidioc_g_tuner(struct file *file, void *priv, 3232aa72f3bSAlexey Klimov struct v4l2_tuner *v) 3242aa72f3bSAlexey Klimov { 3252aa72f3bSAlexey Klimov struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 3261bb16d71SAlexey Klimov int retval; 3272aa72f3bSAlexey Klimov 3283480130aSAlexey Klimov /* safety check */ 3293480130aSAlexey Klimov if (radio->removed) 3303480130aSAlexey Klimov return -EIO; 3313480130aSAlexey Klimov 3322aa72f3bSAlexey Klimov if (v->index > 0) 3332aa72f3bSAlexey Klimov return -EINVAL; 3342aa72f3bSAlexey Klimov 3352aa72f3bSAlexey Klimov /* TODO: Add function which look is signal stereo or not 3362aa72f3bSAlexey Klimov * amradio_getstat(radio); 3372aa72f3bSAlexey Klimov */ 3381bb16d71SAlexey Klimov 3391bb16d71SAlexey Klimov /* we call amradio_set_stereo to set radio->stereo 3401bb16d71SAlexey Klimov * Honestly, amradio_getstat should cover this in future and 3411bb16d71SAlexey Klimov * amradio_set_stereo shouldn't be here 3421bb16d71SAlexey Klimov */ 3431bb16d71SAlexey Klimov retval = amradio_set_stereo(radio, WANT_STEREO); 3441bb16d71SAlexey Klimov if (retval < 0) 3451bb16d71SAlexey Klimov amradio_dev_warn(&radio->videodev->dev, 3461bb16d71SAlexey Klimov "set stereo failed\n"); 3471bb16d71SAlexey Klimov 3482aa72f3bSAlexey Klimov strcpy(v->name, "FM"); 3492aa72f3bSAlexey Klimov v->type = V4L2_TUNER_RADIO; 3502aa72f3bSAlexey Klimov v->rangelow = FREQ_MIN * FREQ_MUL; 3512aa72f3bSAlexey Klimov v->rangehigh = FREQ_MAX * FREQ_MUL; 3522aa72f3bSAlexey Klimov v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; 3532aa72f3bSAlexey Klimov v->capability = V4L2_TUNER_CAP_LOW; 3542aa72f3bSAlexey Klimov if (radio->stereo) 3552aa72f3bSAlexey Klimov v->audmode = V4L2_TUNER_MODE_STEREO; 3562aa72f3bSAlexey Klimov else 3572aa72f3bSAlexey Klimov v->audmode = V4L2_TUNER_MODE_MONO; 3582aa72f3bSAlexey Klimov v->signal = 0xffff; /* Can't get the signal strength, sad.. */ 3592aa72f3bSAlexey Klimov v->afc = 0; /* Don't know what is this */ 3602aa72f3bSAlexey Klimov return 0; 3612aa72f3bSAlexey Klimov } 3622aa72f3bSAlexey Klimov 3632aa72f3bSAlexey Klimov /* vidioc_s_tuner - set tuner attributes */ 3642aa72f3bSAlexey Klimov static int vidioc_s_tuner(struct file *file, void *priv, 3652aa72f3bSAlexey Klimov struct v4l2_tuner *v) 3662aa72f3bSAlexey Klimov { 3673480130aSAlexey Klimov struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 3681bb16d71SAlexey Klimov int retval; 3693480130aSAlexey Klimov 3703480130aSAlexey Klimov /* safety check */ 3713480130aSAlexey Klimov if (radio->removed) 3723480130aSAlexey Klimov return -EIO; 3733480130aSAlexey Klimov 3742aa72f3bSAlexey Klimov if (v->index > 0) 3752aa72f3bSAlexey Klimov return -EINVAL; 3761bb16d71SAlexey Klimov 3771bb16d71SAlexey Klimov /* mono/stereo selector */ 3781bb16d71SAlexey Klimov switch (v->audmode) { 3791bb16d71SAlexey Klimov case V4L2_TUNER_MODE_MONO: 3801bb16d71SAlexey Klimov retval = amradio_set_stereo(radio, WANT_MONO); 3811bb16d71SAlexey Klimov if (retval < 0) 3821bb16d71SAlexey Klimov amradio_dev_warn(&radio->videodev->dev, 3831bb16d71SAlexey Klimov "set mono failed\n"); 3841bb16d71SAlexey Klimov break; 3851bb16d71SAlexey Klimov case V4L2_TUNER_MODE_STEREO: 3861bb16d71SAlexey Klimov retval = amradio_set_stereo(radio, WANT_STEREO); 3871bb16d71SAlexey Klimov if (retval < 0) 3881bb16d71SAlexey Klimov amradio_dev_warn(&radio->videodev->dev, 3891bb16d71SAlexey Klimov "set stereo failed\n"); 3901bb16d71SAlexey Klimov break; 3911bb16d71SAlexey Klimov default: 3921bb16d71SAlexey Klimov return -EINVAL; 3931bb16d71SAlexey Klimov } 3941bb16d71SAlexey Klimov 3952aa72f3bSAlexey Klimov return 0; 3962aa72f3bSAlexey Klimov } 3972aa72f3bSAlexey Klimov 3982aa72f3bSAlexey Klimov /* vidioc_s_frequency - set tuner radio frequency */ 3992aa72f3bSAlexey Klimov static int vidioc_s_frequency(struct file *file, void *priv, 4002aa72f3bSAlexey Klimov struct v4l2_frequency *f) 4012aa72f3bSAlexey Klimov { 4022aa72f3bSAlexey Klimov struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 403a5d69475SAlexey Klimov int retval; 4042aa72f3bSAlexey Klimov 4053480130aSAlexey Klimov /* safety check */ 4063480130aSAlexey Klimov if (radio->removed) 4073480130aSAlexey Klimov return -EIO; 4083480130aSAlexey Klimov 40952433bbbSAlexey Klimov mutex_lock(&radio->lock); 4102aa72f3bSAlexey Klimov radio->curfreq = f->frequency; 41152433bbbSAlexey Klimov mutex_unlock(&radio->lock); 41252433bbbSAlexey Klimov 413a5d69475SAlexey Klimov retval = amradio_setfreq(radio, radio->curfreq); 414a5d69475SAlexey Klimov if (retval < 0) 415e60b022eSAlexey Klimov amradio_dev_warn(&radio->videodev->dev, 416e60b022eSAlexey Klimov "set frequency failed\n"); 4172aa72f3bSAlexey Klimov return 0; 4182aa72f3bSAlexey Klimov } 4192aa72f3bSAlexey Klimov 4202aa72f3bSAlexey Klimov /* vidioc_g_frequency - get tuner radio frequency */ 4212aa72f3bSAlexey Klimov static int vidioc_g_frequency(struct file *file, void *priv, 4222aa72f3bSAlexey Klimov struct v4l2_frequency *f) 4232aa72f3bSAlexey Klimov { 4242aa72f3bSAlexey Klimov struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 4252aa72f3bSAlexey Klimov 4263480130aSAlexey Klimov /* safety check */ 4273480130aSAlexey Klimov if (radio->removed) 4283480130aSAlexey Klimov return -EIO; 4293480130aSAlexey Klimov 4302aa72f3bSAlexey Klimov f->type = V4L2_TUNER_RADIO; 4312aa72f3bSAlexey Klimov f->frequency = radio->curfreq; 4322aa72f3bSAlexey Klimov return 0; 4332aa72f3bSAlexey Klimov } 4342aa72f3bSAlexey Klimov 4352aa72f3bSAlexey Klimov /* vidioc_queryctrl - enumerate control items */ 4362aa72f3bSAlexey Klimov static int vidioc_queryctrl(struct file *file, void *priv, 4372aa72f3bSAlexey Klimov struct v4l2_queryctrl *qc) 4382aa72f3bSAlexey Klimov { 439b466248dSAlexey Klimov switch (qc->id) { 440b466248dSAlexey Klimov case V4L2_CID_AUDIO_MUTE: 441b466248dSAlexey Klimov return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); 442b466248dSAlexey Klimov } 4432aa72f3bSAlexey Klimov 4442aa72f3bSAlexey Klimov return -EINVAL; 4452aa72f3bSAlexey Klimov } 4462aa72f3bSAlexey Klimov 4472aa72f3bSAlexey Klimov /* vidioc_g_ctrl - get the value of a control */ 4482aa72f3bSAlexey Klimov static int vidioc_g_ctrl(struct file *file, void *priv, 4492aa72f3bSAlexey Klimov struct v4l2_control *ctrl) 4502aa72f3bSAlexey Klimov { 4512aa72f3bSAlexey Klimov struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 4522aa72f3bSAlexey Klimov 4533480130aSAlexey Klimov /* safety check */ 4543480130aSAlexey Klimov if (radio->removed) 4553480130aSAlexey Klimov return -EIO; 4563480130aSAlexey Klimov 4572aa72f3bSAlexey Klimov switch (ctrl->id) { 4582aa72f3bSAlexey Klimov case V4L2_CID_AUDIO_MUTE: 4592aa72f3bSAlexey Klimov ctrl->value = radio->muted; 4602aa72f3bSAlexey Klimov return 0; 4612aa72f3bSAlexey Klimov } 4622aa72f3bSAlexey Klimov return -EINVAL; 4632aa72f3bSAlexey Klimov } 4642aa72f3bSAlexey Klimov 4652aa72f3bSAlexey Klimov /* vidioc_s_ctrl - set the value of a control */ 4662aa72f3bSAlexey Klimov static int vidioc_s_ctrl(struct file *file, void *priv, 4672aa72f3bSAlexey Klimov struct v4l2_control *ctrl) 4682aa72f3bSAlexey Klimov { 4692aa72f3bSAlexey Klimov struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 470a5d69475SAlexey Klimov int retval; 4712aa72f3bSAlexey Klimov 4723480130aSAlexey Klimov /* safety check */ 4733480130aSAlexey Klimov if (radio->removed) 4743480130aSAlexey Klimov return -EIO; 4753480130aSAlexey Klimov 4762aa72f3bSAlexey Klimov switch (ctrl->id) { 4772aa72f3bSAlexey Klimov case V4L2_CID_AUDIO_MUTE: 4782aa72f3bSAlexey Klimov if (ctrl->value) { 479db821804SAlexey Klimov retval = amradio_set_mute(radio, AMRADIO_STOP); 480a5d69475SAlexey Klimov if (retval < 0) { 481e60b022eSAlexey Klimov amradio_dev_warn(&radio->videodev->dev, 482e60b022eSAlexey Klimov "amradio_stop failed\n"); 4832aa72f3bSAlexey Klimov return -1; 4842aa72f3bSAlexey Klimov } 4852aa72f3bSAlexey Klimov } else { 486db821804SAlexey Klimov retval = amradio_set_mute(radio, AMRADIO_START); 487a5d69475SAlexey Klimov if (retval < 0) { 488e60b022eSAlexey Klimov amradio_dev_warn(&radio->videodev->dev, 489e60b022eSAlexey Klimov "amradio_start failed\n"); 4902aa72f3bSAlexey Klimov return -1; 4912aa72f3bSAlexey Klimov } 4922aa72f3bSAlexey Klimov } 4932aa72f3bSAlexey Klimov return 0; 4942aa72f3bSAlexey Klimov } 4952aa72f3bSAlexey Klimov return -EINVAL; 4962aa72f3bSAlexey Klimov } 4972aa72f3bSAlexey Klimov 4982aa72f3bSAlexey Klimov /* vidioc_g_audio - get audio attributes */ 4992aa72f3bSAlexey Klimov static int vidioc_g_audio(struct file *file, void *priv, 5002aa72f3bSAlexey Klimov struct v4l2_audio *a) 5012aa72f3bSAlexey Klimov { 5022aa72f3bSAlexey Klimov if (a->index > 1) 5032aa72f3bSAlexey Klimov return -EINVAL; 5042aa72f3bSAlexey Klimov 5052aa72f3bSAlexey Klimov strcpy(a->name, "Radio"); 5062aa72f3bSAlexey Klimov a->capability = V4L2_AUDCAP_STEREO; 5072aa72f3bSAlexey Klimov return 0; 5082aa72f3bSAlexey Klimov } 5092aa72f3bSAlexey Klimov 5102aa72f3bSAlexey Klimov /* vidioc_s_audio - set audio attributes */ 5112aa72f3bSAlexey Klimov static int vidioc_s_audio(struct file *file, void *priv, 5122aa72f3bSAlexey Klimov struct v4l2_audio *a) 5132aa72f3bSAlexey Klimov { 5142aa72f3bSAlexey Klimov if (a->index != 0) 5152aa72f3bSAlexey Klimov return -EINVAL; 5162aa72f3bSAlexey Klimov return 0; 5172aa72f3bSAlexey Klimov } 5182aa72f3bSAlexey Klimov 5192aa72f3bSAlexey Klimov /* vidioc_g_input - get input */ 5202aa72f3bSAlexey Klimov static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) 5212aa72f3bSAlexey Klimov { 5222aa72f3bSAlexey Klimov *i = 0; 5232aa72f3bSAlexey Klimov return 0; 5242aa72f3bSAlexey Klimov } 5252aa72f3bSAlexey Klimov 5262aa72f3bSAlexey Klimov /* vidioc_s_input - set input */ 5272aa72f3bSAlexey Klimov static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) 5282aa72f3bSAlexey Klimov { 5292aa72f3bSAlexey Klimov if (i != 0) 5302aa72f3bSAlexey Klimov return -EINVAL; 5312aa72f3bSAlexey Klimov return 0; 5322aa72f3bSAlexey Klimov } 5332aa72f3bSAlexey Klimov 5342aa72f3bSAlexey Klimov /* open device - amradio_start() and amradio_setfreq() */ 535bec43661SHans Verkuil static int usb_amradio_open(struct file *file) 5362aa72f3bSAlexey Klimov { 5372aa72f3bSAlexey Klimov struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 538a5d69475SAlexey Klimov int retval; 5392aa72f3bSAlexey Klimov 5400fabb783SAlexey Klimov lock_kernel(); 5410fabb783SAlexey Klimov 5422aa72f3bSAlexey Klimov radio->users = 1; 5432aa72f3bSAlexey Klimov radio->muted = 1; 5442aa72f3bSAlexey Klimov 545db821804SAlexey Klimov retval = amradio_set_mute(radio, AMRADIO_START); 546a5d69475SAlexey Klimov if (retval < 0) { 547e60b022eSAlexey Klimov amradio_dev_warn(&radio->videodev->dev, 548e60b022eSAlexey Klimov "radio did not start up properly\n"); 5492aa72f3bSAlexey Klimov radio->users = 0; 5500fabb783SAlexey Klimov unlock_kernel(); 5512aa72f3bSAlexey Klimov return -EIO; 5522aa72f3bSAlexey Klimov } 553a5d69475SAlexey Klimov 5541bb16d71SAlexey Klimov retval = amradio_set_stereo(radio, WANT_STEREO); 5551bb16d71SAlexey Klimov if (retval < 0) 5561bb16d71SAlexey Klimov amradio_dev_warn(&radio->videodev->dev, 5571bb16d71SAlexey Klimov "set stereo failed\n"); 5581bb16d71SAlexey Klimov 559a5d69475SAlexey Klimov retval = amradio_setfreq(radio, radio->curfreq); 560a5d69475SAlexey Klimov if (retval < 0) 561e60b022eSAlexey Klimov amradio_dev_warn(&radio->videodev->dev, 562e60b022eSAlexey Klimov "set frequency failed\n"); 5630fabb783SAlexey Klimov 5640fabb783SAlexey Klimov unlock_kernel(); 5652aa72f3bSAlexey Klimov return 0; 5662aa72f3bSAlexey Klimov } 5672aa72f3bSAlexey Klimov 568f4e9043eSAlexey Klimov /*close device */ 569bec43661SHans Verkuil static int usb_amradio_close(struct file *file) 5702aa72f3bSAlexey Klimov { 5712aa72f3bSAlexey Klimov struct amradio_device *radio = video_get_drvdata(video_devdata(file)); 5723480130aSAlexey Klimov int retval; 5732aa72f3bSAlexey Klimov 5742aa72f3bSAlexey Klimov if (!radio) 5752aa72f3bSAlexey Klimov return -ENODEV; 5763480130aSAlexey Klimov 57752433bbbSAlexey Klimov mutex_lock(&radio->lock); 5782aa72f3bSAlexey Klimov radio->users = 0; 57952433bbbSAlexey Klimov mutex_unlock(&radio->lock); 5803480130aSAlexey Klimov 581f4e9043eSAlexey Klimov if (!radio->removed) { 582db821804SAlexey Klimov retval = amradio_set_mute(radio, AMRADIO_STOP); 5833480130aSAlexey Klimov if (retval < 0) 5843480130aSAlexey Klimov amradio_dev_warn(&radio->videodev->dev, 5853480130aSAlexey Klimov "amradio_stop failed\n"); 5862aa72f3bSAlexey Klimov } 5873480130aSAlexey Klimov 5882aa72f3bSAlexey Klimov return 0; 5892aa72f3bSAlexey Klimov } 5902aa72f3bSAlexey Klimov 5912aa72f3bSAlexey Klimov /* Suspend device - stop device. Need to be checked and fixed */ 5922aa72f3bSAlexey Klimov static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) 5932aa72f3bSAlexey Klimov { 5942aa72f3bSAlexey Klimov struct amradio_device *radio = usb_get_intfdata(intf); 595a5d69475SAlexey Klimov int retval; 5962aa72f3bSAlexey Klimov 597db821804SAlexey Klimov retval = amradio_set_mute(radio, AMRADIO_STOP); 598a5d69475SAlexey Klimov if (retval < 0) 599e60b022eSAlexey Klimov dev_warn(&intf->dev, "amradio_stop failed\n"); 6002aa72f3bSAlexey Klimov 601e60b022eSAlexey Klimov dev_info(&intf->dev, "going into suspend..\n"); 6022aa72f3bSAlexey Klimov 6032aa72f3bSAlexey Klimov return 0; 6042aa72f3bSAlexey Klimov } 6052aa72f3bSAlexey Klimov 6062aa72f3bSAlexey Klimov /* Resume device - start device. Need to be checked and fixed */ 6072aa72f3bSAlexey Klimov static int usb_amradio_resume(struct usb_interface *intf) 6082aa72f3bSAlexey Klimov { 6092aa72f3bSAlexey Klimov struct amradio_device *radio = usb_get_intfdata(intf); 610a5d69475SAlexey Klimov int retval; 6112aa72f3bSAlexey Klimov 612db821804SAlexey Klimov retval = amradio_set_mute(radio, AMRADIO_START); 613a5d69475SAlexey Klimov if (retval < 0) 614e60b022eSAlexey Klimov dev_warn(&intf->dev, "amradio_start failed\n"); 6152aa72f3bSAlexey Klimov 616e60b022eSAlexey Klimov dev_info(&intf->dev, "coming out of suspend..\n"); 6172aa72f3bSAlexey Klimov 6182aa72f3bSAlexey Klimov return 0; 6192aa72f3bSAlexey Klimov } 6202aa72f3bSAlexey Klimov 6212aa72f3bSAlexey Klimov /* File system interface */ 622bec43661SHans Verkuil static const struct v4l2_file_operations usb_amradio_fops = { 6232aa72f3bSAlexey Klimov .owner = THIS_MODULE, 6242aa72f3bSAlexey Klimov .open = usb_amradio_open, 6252aa72f3bSAlexey Klimov .release = usb_amradio_close, 6262aa72f3bSAlexey Klimov .ioctl = video_ioctl2, 6272aa72f3bSAlexey Klimov }; 6282aa72f3bSAlexey Klimov 6292aa72f3bSAlexey Klimov static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { 6302aa72f3bSAlexey Klimov .vidioc_querycap = vidioc_querycap, 6312aa72f3bSAlexey Klimov .vidioc_g_tuner = vidioc_g_tuner, 6322aa72f3bSAlexey Klimov .vidioc_s_tuner = vidioc_s_tuner, 6332aa72f3bSAlexey Klimov .vidioc_g_frequency = vidioc_g_frequency, 6342aa72f3bSAlexey Klimov .vidioc_s_frequency = vidioc_s_frequency, 6352aa72f3bSAlexey Klimov .vidioc_queryctrl = vidioc_queryctrl, 6362aa72f3bSAlexey Klimov .vidioc_g_ctrl = vidioc_g_ctrl, 6372aa72f3bSAlexey Klimov .vidioc_s_ctrl = vidioc_s_ctrl, 6382aa72f3bSAlexey Klimov .vidioc_g_audio = vidioc_g_audio, 6392aa72f3bSAlexey Klimov .vidioc_s_audio = vidioc_s_audio, 6402aa72f3bSAlexey Klimov .vidioc_g_input = vidioc_g_input, 6412aa72f3bSAlexey Klimov .vidioc_s_input = vidioc_s_input, 6422aa72f3bSAlexey Klimov }; 6432aa72f3bSAlexey Klimov 644b466248dSAlexey Klimov static void usb_amradio_video_device_release(struct video_device *videodev) 645f4e9043eSAlexey Klimov { 646f4e9043eSAlexey Klimov struct amradio_device *radio = video_get_drvdata(videodev); 647f4e9043eSAlexey Klimov 648f4e9043eSAlexey Klimov /* we call v4l to free radio->videodev */ 649f4e9043eSAlexey Klimov video_device_release(videodev); 650f4e9043eSAlexey Klimov 651b466248dSAlexey Klimov v4l2_device_unregister(&radio->v4l2_dev); 652b466248dSAlexey Klimov 653f4e9043eSAlexey Klimov /* free rest memory */ 654f4e9043eSAlexey Klimov kfree(radio->buffer); 655f4e9043eSAlexey Klimov kfree(radio); 656f4e9043eSAlexey Klimov } 657f4e9043eSAlexey Klimov 658a5d69475SAlexey Klimov /* check if the device is present and register with v4l and usb if it is */ 6592aa72f3bSAlexey Klimov static int usb_amradio_probe(struct usb_interface *intf, 6602aa72f3bSAlexey Klimov const struct usb_device_id *id) 6612aa72f3bSAlexey Klimov { 6622aa72f3bSAlexey Klimov struct amradio_device *radio; 663b466248dSAlexey Klimov struct v4l2_device *v4l2_dev; 664a5d69475SAlexey Klimov int retval; 6652aa72f3bSAlexey Klimov 666b466248dSAlexey Klimov radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); 6672aa72f3bSAlexey Klimov 6688edafcc6SAlexey Klimov if (!radio) { 6698edafcc6SAlexey Klimov dev_err(&intf->dev, "kmalloc for amradio_device failed\n"); 6702aa72f3bSAlexey Klimov return -ENOMEM; 6718edafcc6SAlexey Klimov } 6722aa72f3bSAlexey Klimov 6732aa72f3bSAlexey Klimov radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); 6742aa72f3bSAlexey Klimov 6758edafcc6SAlexey Klimov if (!radio->buffer) { 6768edafcc6SAlexey Klimov dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); 6772aa72f3bSAlexey Klimov kfree(radio); 6782aa72f3bSAlexey Klimov return -ENOMEM; 6792aa72f3bSAlexey Klimov } 6802aa72f3bSAlexey Klimov 681b466248dSAlexey Klimov v4l2_dev = &radio->v4l2_dev; 682b466248dSAlexey Klimov retval = v4l2_device_register(&intf->dev, v4l2_dev); 683b466248dSAlexey Klimov if (retval < 0) { 684b466248dSAlexey Klimov dev_err(&intf->dev, "couldn't register v4l2_device\n"); 685b466248dSAlexey Klimov kfree(radio->buffer); 686b466248dSAlexey Klimov kfree(radio); 687b466248dSAlexey Klimov return retval; 688b466248dSAlexey Klimov } 689b466248dSAlexey Klimov 6902aa72f3bSAlexey Klimov radio->videodev = video_device_alloc(); 6912aa72f3bSAlexey Klimov 6928edafcc6SAlexey Klimov if (!radio->videodev) { 6938edafcc6SAlexey Klimov dev_err(&intf->dev, "video_device_alloc failed\n"); 6942aa72f3bSAlexey Klimov kfree(radio->buffer); 6952aa72f3bSAlexey Klimov kfree(radio); 6962aa72f3bSAlexey Klimov return -ENOMEM; 6972aa72f3bSAlexey Klimov } 6982aa72f3bSAlexey Klimov 699b466248dSAlexey Klimov strlcpy(radio->videodev->name, v4l2_dev->name, sizeof(radio->videodev->name)); 700b466248dSAlexey Klimov radio->videodev->v4l2_dev = v4l2_dev; 701b466248dSAlexey Klimov radio->videodev->fops = &usb_amradio_fops; 702b466248dSAlexey Klimov radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops; 703b466248dSAlexey Klimov radio->videodev->release = usb_amradio_video_device_release; 7042aa72f3bSAlexey Klimov 7052aa72f3bSAlexey Klimov radio->removed = 0; 7062aa72f3bSAlexey Klimov radio->users = 0; 7072aa72f3bSAlexey Klimov radio->usbdev = interface_to_usbdev(intf); 7082aa72f3bSAlexey Klimov radio->curfreq = 95.16 * FREQ_MUL; 7091bb16d71SAlexey Klimov radio->stereo = -1; 7102aa72f3bSAlexey Klimov 7112aa72f3bSAlexey Klimov mutex_init(&radio->lock); 7122aa72f3bSAlexey Klimov 7132aa72f3bSAlexey Klimov video_set_drvdata(radio->videodev, radio); 714b466248dSAlexey Klimov 715a5d69475SAlexey Klimov retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); 716a5d69475SAlexey Klimov if (retval < 0) { 71765c51dc9SAlexey Klimov dev_err(&intf->dev, "could not register video device\n"); 7182aa72f3bSAlexey Klimov video_device_release(radio->videodev); 719b466248dSAlexey Klimov v4l2_device_unregister(v4l2_dev); 7202aa72f3bSAlexey Klimov kfree(radio->buffer); 7212aa72f3bSAlexey Klimov kfree(radio); 7222aa72f3bSAlexey Klimov return -EIO; 7232aa72f3bSAlexey Klimov } 7242aa72f3bSAlexey Klimov 7252aa72f3bSAlexey Klimov usb_set_intfdata(intf, radio); 7262aa72f3bSAlexey Klimov return 0; 7272aa72f3bSAlexey Klimov } 7282aa72f3bSAlexey Klimov 7292aa72f3bSAlexey Klimov static int __init amradio_init(void) 7302aa72f3bSAlexey Klimov { 7312aa72f3bSAlexey Klimov int retval = usb_register(&usb_amradio_driver); 7322aa72f3bSAlexey Klimov 733e60b022eSAlexey Klimov pr_info(KBUILD_MODNAME 734e60b022eSAlexey Klimov ": version " DRIVER_VERSION " " DRIVER_DESC "\n"); 735e60b022eSAlexey Klimov 7362aa72f3bSAlexey Klimov if (retval) 737e60b022eSAlexey Klimov pr_err(KBUILD_MODNAME 738e60b022eSAlexey Klimov ": usb_register failed. Error number %d\n", retval); 739e60b022eSAlexey Klimov 7402aa72f3bSAlexey Klimov return retval; 7412aa72f3bSAlexey Klimov } 7422aa72f3bSAlexey Klimov 7432aa72f3bSAlexey Klimov static void __exit amradio_exit(void) 7442aa72f3bSAlexey Klimov { 7452aa72f3bSAlexey Klimov usb_deregister(&usb_amradio_driver); 7462aa72f3bSAlexey Klimov } 7472aa72f3bSAlexey Klimov 7482aa72f3bSAlexey Klimov module_init(amradio_init); 7492aa72f3bSAlexey Klimov module_exit(amradio_exit); 7502aa72f3bSAlexey Klimov 751