cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

radio-ma901.c (12795B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Driver for the MasterKit MA901 USB FM radio. This device plugs
      4 * into the USB port and an analog audio input or headphones, so this thing
      5 * only deals with initialization, frequency setting, volume.
      6 *
      7 * Copyright (c) 2012 Alexey Klimov <klimov.linux@gmail.com>
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/init.h>
     13#include <linux/slab.h>
     14#include <linux/input.h>
     15#include <linux/videodev2.h>
     16#include <media/v4l2-device.h>
     17#include <media/v4l2-ioctl.h>
     18#include <media/v4l2-ctrls.h>
     19#include <media/v4l2-event.h>
     20#include <linux/usb.h>
     21#include <linux/mutex.h>
     22
     23#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
     24#define DRIVER_DESC "Masterkit MA901 USB FM radio driver"
     25#define DRIVER_VERSION "0.0.1"
     26
     27MODULE_AUTHOR(DRIVER_AUTHOR);
     28MODULE_DESCRIPTION(DRIVER_DESC);
     29MODULE_LICENSE("GPL");
     30MODULE_VERSION(DRIVER_VERSION);
     31
     32#define USB_MA901_VENDOR  0x16c0
     33#define USB_MA901_PRODUCT 0x05df
     34
     35/* dev_warn macro with driver name */
     36#define MA901_DRIVER_NAME "radio-ma901"
     37#define ma901radio_dev_warn(dev, fmt, arg...)				\
     38		dev_warn(dev, MA901_DRIVER_NAME " - " fmt, ##arg)
     39
     40#define ma901radio_dev_err(dev, fmt, arg...) \
     41		dev_err(dev, MA901_DRIVER_NAME " - " fmt, ##arg)
     42
     43/* Probably USB_TIMEOUT should be modified in module parameter */
     44#define BUFFER_LENGTH 8
     45#define USB_TIMEOUT 500
     46
     47#define FREQ_MIN  87.5
     48#define FREQ_MAX 108.0
     49#define FREQ_MUL 16000
     50
     51#define MA901_VOLUME_MAX 16
     52#define MA901_VOLUME_MIN 0
     53
     54/* Commands that device should understand
     55 * List isn't full and will be updated with implementation of new functions
     56 */
     57#define MA901_RADIO_SET_FREQ		0x03
     58#define MA901_RADIO_SET_VOLUME		0x04
     59#define MA901_RADIO_SET_MONO_STEREO	0x05
     60
     61/* Comfortable defines for ma901radio_set_stereo */
     62#define MA901_WANT_STEREO		0x50
     63#define MA901_WANT_MONO			0xd0
     64
     65/* module parameter */
     66static int radio_nr = -1;
     67module_param(radio_nr, int, 0);
     68MODULE_PARM_DESC(radio_nr, "Radio file number");
     69
     70/* Data for one (physical) device */
     71struct ma901radio_device {
     72	/* reference to USB and video device */
     73	struct usb_device *usbdev;
     74	struct usb_interface *intf;
     75	struct video_device vdev;
     76	struct v4l2_device v4l2_dev;
     77	struct v4l2_ctrl_handler hdl;
     78
     79	u8 *buffer;
     80	struct mutex lock;	/* buffer locking */
     81	int curfreq;
     82	u16 volume;
     83	int stereo;
     84	bool muted;
     85};
     86
     87static inline struct ma901radio_device *to_ma901radio_dev(struct v4l2_device *v4l2_dev)
     88{
     89	return container_of(v4l2_dev, struct ma901radio_device, v4l2_dev);
     90}
     91
     92/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
     93static int ma901radio_set_freq(struct ma901radio_device *radio, int freq)
     94{
     95	unsigned int freq_send = 0x300 + (freq >> 5) / 25;
     96	int retval;
     97
     98	radio->buffer[0] = 0x0a;
     99	radio->buffer[1] = MA901_RADIO_SET_FREQ;
    100	radio->buffer[2] = ((freq_send >> 8) & 0xff) + 0x80;
    101	radio->buffer[3] = freq_send & 0xff;
    102	radio->buffer[4] = 0x00;
    103	radio->buffer[5] = 0x00;
    104	radio->buffer[6] = 0x00;
    105	radio->buffer[7] = 0x00;
    106
    107	retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
    108				9, 0x21, 0x0300, 0,
    109				radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
    110	if (retval < 0)
    111		return retval;
    112
    113	radio->curfreq = freq;
    114	return 0;
    115}
    116
    117static int ma901radio_set_volume(struct ma901radio_device *radio, u16 vol_to_set)
    118{
    119	int retval;
    120
    121	radio->buffer[0] = 0x0a;
    122	radio->buffer[1] = MA901_RADIO_SET_VOLUME;
    123	radio->buffer[2] = 0xc2;
    124	radio->buffer[3] = vol_to_set + 0x20;
    125	radio->buffer[4] = 0x00;
    126	radio->buffer[5] = 0x00;
    127	radio->buffer[6] = 0x00;
    128	radio->buffer[7] = 0x00;
    129
    130	retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
    131				9, 0x21, 0x0300, 0,
    132				radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
    133	if (retval < 0)
    134		return retval;
    135
    136	radio->volume = vol_to_set;
    137	return retval;
    138}
    139
    140static int ma901_set_stereo(struct ma901radio_device *radio, u8 stereo)
    141{
    142	int retval;
    143
    144	radio->buffer[0] = 0x0a;
    145	radio->buffer[1] = MA901_RADIO_SET_MONO_STEREO;
    146	radio->buffer[2] = stereo;
    147	radio->buffer[3] = 0x00;
    148	radio->buffer[4] = 0x00;
    149	radio->buffer[5] = 0x00;
    150	radio->buffer[6] = 0x00;
    151	radio->buffer[7] = 0x00;
    152
    153	retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
    154				9, 0x21, 0x0300, 0,
    155				radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
    156
    157	if (retval < 0)
    158		return retval;
    159
    160	if (stereo == MA901_WANT_STEREO)
    161		radio->stereo = V4L2_TUNER_MODE_STEREO;
    162	else
    163		radio->stereo = V4L2_TUNER_MODE_MONO;
    164
    165	return retval;
    166}
    167
    168/* Handle unplugging the device.
    169 * We call video_unregister_device in any case.
    170 * The last function called in this procedure is
    171 * usb_ma901radio_device_release.
    172 */
    173static void usb_ma901radio_disconnect(struct usb_interface *intf)
    174{
    175	struct ma901radio_device *radio = to_ma901radio_dev(usb_get_intfdata(intf));
    176
    177	mutex_lock(&radio->lock);
    178	video_unregister_device(&radio->vdev);
    179	usb_set_intfdata(intf, NULL);
    180	v4l2_device_disconnect(&radio->v4l2_dev);
    181	mutex_unlock(&radio->lock);
    182	v4l2_device_put(&radio->v4l2_dev);
    183}
    184
    185/* vidioc_querycap - query device capabilities */
    186static int vidioc_querycap(struct file *file, void *priv,
    187					struct v4l2_capability *v)
    188{
    189	struct ma901radio_device *radio = video_drvdata(file);
    190
    191	strscpy(v->driver, "radio-ma901", sizeof(v->driver));
    192	strscpy(v->card, "Masterkit MA901 USB FM Radio", sizeof(v->card));
    193	usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
    194	return 0;
    195}
    196
    197/* vidioc_g_tuner - get tuner attributes */
    198static int vidioc_g_tuner(struct file *file, void *priv,
    199				struct v4l2_tuner *v)
    200{
    201	struct ma901radio_device *radio = video_drvdata(file);
    202
    203	if (v->index > 0)
    204		return -EINVAL;
    205
    206	v->signal = 0;
    207
    208	/* TODO: the same words like in _probe() goes here.
    209	 * When receiving of stats will be implemented then we can call
    210	 * ma901radio_get_stat().
    211	 * retval = ma901radio_get_stat(radio, &is_stereo, &v->signal);
    212	 */
    213
    214	strscpy(v->name, "FM", sizeof(v->name));
    215	v->type = V4L2_TUNER_RADIO;
    216	v->rangelow = FREQ_MIN * FREQ_MUL;
    217	v->rangehigh = FREQ_MAX * FREQ_MUL;
    218	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
    219	/* v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; */
    220	v->audmode = radio->stereo ?
    221		V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
    222	return 0;
    223}
    224
    225/* vidioc_s_tuner - set tuner attributes */
    226static int vidioc_s_tuner(struct file *file, void *priv,
    227				const struct v4l2_tuner *v)
    228{
    229	struct ma901radio_device *radio = video_drvdata(file);
    230
    231	if (v->index > 0)
    232		return -EINVAL;
    233
    234	/* mono/stereo selector */
    235	switch (v->audmode) {
    236	case V4L2_TUNER_MODE_MONO:
    237		return ma901_set_stereo(radio, MA901_WANT_MONO);
    238	default:
    239		return ma901_set_stereo(radio, MA901_WANT_STEREO);
    240	}
    241}
    242
    243/* vidioc_s_frequency - set tuner radio frequency */
    244static int vidioc_s_frequency(struct file *file, void *priv,
    245				const struct v4l2_frequency *f)
    246{
    247	struct ma901radio_device *radio = video_drvdata(file);
    248
    249	if (f->tuner != 0)
    250		return -EINVAL;
    251
    252	return ma901radio_set_freq(radio, clamp_t(unsigned, f->frequency,
    253				FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL));
    254}
    255
    256/* vidioc_g_frequency - get tuner radio frequency */
    257static int vidioc_g_frequency(struct file *file, void *priv,
    258				struct v4l2_frequency *f)
    259{
    260	struct ma901radio_device *radio = video_drvdata(file);
    261
    262	if (f->tuner != 0)
    263		return -EINVAL;
    264	f->frequency = radio->curfreq;
    265
    266	return 0;
    267}
    268
    269static int usb_ma901radio_s_ctrl(struct v4l2_ctrl *ctrl)
    270{
    271	struct ma901radio_device *radio =
    272		container_of(ctrl->handler, struct ma901radio_device, hdl);
    273
    274	switch (ctrl->id) {
    275	case V4L2_CID_AUDIO_VOLUME:     /* set volume */
    276		return ma901radio_set_volume(radio, (u16)ctrl->val);
    277	}
    278
    279	return -EINVAL;
    280}
    281
    282/* TODO: Should we really need to implement suspend and resume functions?
    283 * Radio has it's own memory and will continue playing if power is present
    284 * on usb port and on resume it will start to play again based on freq, volume
    285 * values in device memory.
    286 */
    287static int usb_ma901radio_suspend(struct usb_interface *intf, pm_message_t message)
    288{
    289	return 0;
    290}
    291
    292static int usb_ma901radio_resume(struct usb_interface *intf)
    293{
    294	return 0;
    295}
    296
    297static const struct v4l2_ctrl_ops usb_ma901radio_ctrl_ops = {
    298	.s_ctrl = usb_ma901radio_s_ctrl,
    299};
    300
    301/* File system interface */
    302static const struct v4l2_file_operations usb_ma901radio_fops = {
    303	.owner		= THIS_MODULE,
    304	.open		= v4l2_fh_open,
    305	.release	= v4l2_fh_release,
    306	.poll		= v4l2_ctrl_poll,
    307	.unlocked_ioctl	= video_ioctl2,
    308};
    309
    310static const struct v4l2_ioctl_ops usb_ma901radio_ioctl_ops = {
    311	.vidioc_querycap    = vidioc_querycap,
    312	.vidioc_g_tuner     = vidioc_g_tuner,
    313	.vidioc_s_tuner     = vidioc_s_tuner,
    314	.vidioc_g_frequency = vidioc_g_frequency,
    315	.vidioc_s_frequency = vidioc_s_frequency,
    316	.vidioc_log_status  = v4l2_ctrl_log_status,
    317	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
    318	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
    319};
    320
    321static void usb_ma901radio_release(struct v4l2_device *v4l2_dev)
    322{
    323	struct ma901radio_device *radio = to_ma901radio_dev(v4l2_dev);
    324
    325	v4l2_ctrl_handler_free(&radio->hdl);
    326	v4l2_device_unregister(&radio->v4l2_dev);
    327	kfree(radio->buffer);
    328	kfree(radio);
    329}
    330
    331/* check if the device is present and register with v4l and usb if it is */
    332static int usb_ma901radio_probe(struct usb_interface *intf,
    333				const struct usb_device_id *id)
    334{
    335	struct usb_device *dev = interface_to_usbdev(intf);
    336	struct ma901radio_device *radio;
    337	int retval = 0;
    338
    339	/* Masterkit MA901 usb radio has the same USB ID as many others
    340	 * Atmel V-USB devices. Let's make additional checks to be sure
    341	 * that this is our device.
    342	 */
    343
    344	if (dev->product && dev->manufacturer &&
    345		(strncmp(dev->product, "MA901", 5) != 0
    346		|| strncmp(dev->manufacturer, "www.masterkit.ru", 16) != 0))
    347		return -ENODEV;
    348
    349	radio = kzalloc(sizeof(struct ma901radio_device), GFP_KERNEL);
    350	if (!radio) {
    351		dev_err(&intf->dev, "kzalloc for ma901radio_device failed\n");
    352		retval = -ENOMEM;
    353		goto err;
    354	}
    355
    356	radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
    357	if (!radio->buffer) {
    358		dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
    359		retval = -ENOMEM;
    360		goto err_nobuf;
    361	}
    362
    363	retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
    364	if (retval < 0) {
    365		dev_err(&intf->dev, "couldn't register v4l2_device\n");
    366		goto err_v4l2;
    367	}
    368
    369	v4l2_ctrl_handler_init(&radio->hdl, 1);
    370
    371	/* TODO:It looks like this radio doesn't have mute/unmute control
    372	 * and windows program just emulate it using volume control.
    373	 * Let's plan to do the same in this driver.
    374	 *
    375	 * v4l2_ctrl_new_std(&radio->hdl, &usb_ma901radio_ctrl_ops,
    376	 *		  V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
    377	 */
    378
    379	v4l2_ctrl_new_std(&radio->hdl, &usb_ma901radio_ctrl_ops,
    380			  V4L2_CID_AUDIO_VOLUME, MA901_VOLUME_MIN,
    381			  MA901_VOLUME_MAX, 1, MA901_VOLUME_MAX);
    382
    383	if (radio->hdl.error) {
    384		retval = radio->hdl.error;
    385		dev_err(&intf->dev, "couldn't register control\n");
    386		goto err_ctrl;
    387	}
    388	mutex_init(&radio->lock);
    389
    390	radio->v4l2_dev.ctrl_handler = &radio->hdl;
    391	radio->v4l2_dev.release = usb_ma901radio_release;
    392	strscpy(radio->vdev.name, radio->v4l2_dev.name,
    393		sizeof(radio->vdev.name));
    394	radio->vdev.v4l2_dev = &radio->v4l2_dev;
    395	radio->vdev.fops = &usb_ma901radio_fops;
    396	radio->vdev.ioctl_ops = &usb_ma901radio_ioctl_ops;
    397	radio->vdev.release = video_device_release_empty;
    398	radio->vdev.lock = &radio->lock;
    399	radio->vdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
    400
    401	radio->usbdev = interface_to_usbdev(intf);
    402	radio->intf = intf;
    403	usb_set_intfdata(intf, &radio->v4l2_dev);
    404	radio->curfreq = 95.21 * FREQ_MUL;
    405
    406	video_set_drvdata(&radio->vdev, radio);
    407
    408	/* TODO: we can get some statistics (freq, volume) from device
    409	 * but it's not implemented yet. After insertion in usb-port radio
    410	 * setups frequency and starts playing without any initialization.
    411	 * So we don't call usb_ma901radio_init/get_stat() here.
    412	 * retval = usb_ma901radio_init(radio);
    413	 */
    414
    415	retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO,
    416					radio_nr);
    417	if (retval < 0) {
    418		dev_err(&intf->dev, "could not register video device\n");
    419		goto err_vdev;
    420	}
    421
    422	return 0;
    423
    424err_vdev:
    425	v4l2_ctrl_handler_free(&radio->hdl);
    426err_ctrl:
    427	v4l2_device_unregister(&radio->v4l2_dev);
    428err_v4l2:
    429	kfree(radio->buffer);
    430err_nobuf:
    431	kfree(radio);
    432err:
    433	return retval;
    434}
    435
    436/* USB Device ID List */
    437static const struct usb_device_id usb_ma901radio_device_table[] = {
    438	{ USB_DEVICE_AND_INTERFACE_INFO(USB_MA901_VENDOR, USB_MA901_PRODUCT,
    439							USB_CLASS_HID, 0, 0) },
    440	{ }						/* Terminating entry */
    441};
    442
    443MODULE_DEVICE_TABLE(usb, usb_ma901radio_device_table);
    444
    445/* USB subsystem interface */
    446static struct usb_driver usb_ma901radio_driver = {
    447	.name			= MA901_DRIVER_NAME,
    448	.probe			= usb_ma901radio_probe,
    449	.disconnect		= usb_ma901radio_disconnect,
    450	.suspend		= usb_ma901radio_suspend,
    451	.resume			= usb_ma901radio_resume,
    452	.reset_resume		= usb_ma901radio_resume,
    453	.id_table		= usb_ma901radio_device_table,
    454};
    455
    456module_usb_driver(usb_ma901radio_driver);