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

dsbr100.c (11794B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* A driver for the D-Link DSB-R100 USB radio and Gemtek USB Radio 21.
      3 * The device plugs into both the USB and an analog audio input, so this thing
      4 * only deals with initialisation and frequency setting, the
      5 * audio data has to be handled by a sound driver.
      6 *
      7 * Major issue: I can't find out where the device reports the signal
      8 * strength, and indeed the windows software appearantly just looks
      9 * at the stereo indicator as well.  So, scanning will only find
     10 * stereo stations.  Sad, but I can't help it.
     11 *
     12 * Also, the windows program sends oodles of messages over to the
     13 * device, and I couldn't figure out their meaning.  My suspicion
     14 * is that they don't have any:-)
     15 *
     16 * You might find some interesting stuff about this module at
     17 * http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
     18 *
     19 * Fully tested with the Keene USB FM Transmitter and the v4l2-compliance tool.
     20 *
     21 * Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
     22*/
     23
     24#include <linux/kernel.h>
     25#include <linux/module.h>
     26#include <linux/init.h>
     27#include <linux/slab.h>
     28#include <linux/input.h>
     29#include <linux/videodev2.h>
     30#include <linux/usb.h>
     31#include <media/v4l2-device.h>
     32#include <media/v4l2-ioctl.h>
     33#include <media/v4l2-ctrls.h>
     34#include <media/v4l2-event.h>
     35
     36/*
     37 * Version Information
     38 */
     39MODULE_AUTHOR("Markus Demleitner <msdemlei@tucana.harvard.edu>");
     40MODULE_DESCRIPTION("D-Link DSB-R100 USB FM radio driver");
     41MODULE_LICENSE("GPL");
     42MODULE_VERSION("1.1.0");
     43
     44#define DSB100_VENDOR 0x04b4
     45#define DSB100_PRODUCT 0x1002
     46
     47/* Commands the device appears to understand */
     48#define DSB100_TUNE 1
     49#define DSB100_ONOFF 2
     50
     51#define TB_LEN 16
     52
     53/* Frequency limits in MHz -- these are European values.  For Japanese
     54devices, that would be 76 and 91.  */
     55#define FREQ_MIN  87.5
     56#define FREQ_MAX 108.0
     57#define FREQ_MUL 16000
     58
     59#define v4l2_dev_to_radio(d) container_of(d, struct dsbr100_device, v4l2_dev)
     60
     61static int radio_nr = -1;
     62module_param(radio_nr, int, 0);
     63
     64/* Data for one (physical) device */
     65struct dsbr100_device {
     66	struct usb_device *usbdev;
     67	struct video_device videodev;
     68	struct v4l2_device v4l2_dev;
     69	struct v4l2_ctrl_handler hdl;
     70
     71	u8 *transfer_buffer;
     72	struct mutex v4l2_lock;
     73	int curfreq;
     74	bool stereo;
     75	bool muted;
     76};
     77
     78/* Low-level device interface begins here */
     79
     80/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
     81static int dsbr100_setfreq(struct dsbr100_device *radio, unsigned freq)
     82{
     83	unsigned f = (freq / 16 * 80) / 1000 + 856;
     84	int retval = 0;
     85
     86	if (!radio->muted) {
     87		retval = usb_control_msg(radio->usbdev,
     88				usb_rcvctrlpipe(radio->usbdev, 0),
     89				DSB100_TUNE,
     90				USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
     91				(f >> 8) & 0x00ff, f & 0xff,
     92				radio->transfer_buffer, 8, 300);
     93		if (retval >= 0)
     94			mdelay(1);
     95	}
     96
     97	if (retval >= 0) {
     98		radio->curfreq = freq;
     99		return 0;
    100	}
    101	dev_err(&radio->usbdev->dev,
    102		"%s - usb_control_msg returned %i, request %i\n",
    103			__func__, retval, DSB100_TUNE);
    104	return retval;
    105}
    106
    107/* switch on radio */
    108static int dsbr100_start(struct dsbr100_device *radio)
    109{
    110	int retval = usb_control_msg(radio->usbdev,
    111		usb_rcvctrlpipe(radio->usbdev, 0),
    112		DSB100_ONOFF,
    113		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
    114		0x01, 0x00, radio->transfer_buffer, 8, 300);
    115
    116	if (retval >= 0)
    117		return dsbr100_setfreq(radio, radio->curfreq);
    118	dev_err(&radio->usbdev->dev,
    119		"%s - usb_control_msg returned %i, request %i\n",
    120			__func__, retval, DSB100_ONOFF);
    121	return retval;
    122
    123}
    124
    125/* switch off radio */
    126static int dsbr100_stop(struct dsbr100_device *radio)
    127{
    128	int retval = usb_control_msg(radio->usbdev,
    129		usb_rcvctrlpipe(radio->usbdev, 0),
    130		DSB100_ONOFF,
    131		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
    132		0x00, 0x00, radio->transfer_buffer, 8, 300);
    133
    134	if (retval >= 0)
    135		return 0;
    136	dev_err(&radio->usbdev->dev,
    137		"%s - usb_control_msg returned %i, request %i\n",
    138			__func__, retval, DSB100_ONOFF);
    139	return retval;
    140
    141}
    142
    143/* return the device status.  This is, in effect, just whether it
    144sees a stereo signal or not.  Pity. */
    145static void dsbr100_getstat(struct dsbr100_device *radio)
    146{
    147	int retval = usb_control_msg(radio->usbdev,
    148		usb_rcvctrlpipe(radio->usbdev, 0),
    149		USB_REQ_GET_STATUS,
    150		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
    151		0x00, 0x24, radio->transfer_buffer, 8, 300);
    152
    153	if (retval < 0) {
    154		radio->stereo = false;
    155		dev_err(&radio->usbdev->dev,
    156			"%s - usb_control_msg returned %i, request %i\n",
    157				__func__, retval, USB_REQ_GET_STATUS);
    158	} else {
    159		radio->stereo = !(radio->transfer_buffer[0] & 0x01);
    160	}
    161}
    162
    163static int vidioc_querycap(struct file *file, void *priv,
    164					struct v4l2_capability *v)
    165{
    166	struct dsbr100_device *radio = video_drvdata(file);
    167
    168	strscpy(v->driver, "dsbr100", sizeof(v->driver));
    169	strscpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
    170	usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
    171	return 0;
    172}
    173
    174static int vidioc_g_tuner(struct file *file, void *priv,
    175				struct v4l2_tuner *v)
    176{
    177	struct dsbr100_device *radio = video_drvdata(file);
    178
    179	if (v->index > 0)
    180		return -EINVAL;
    181
    182	dsbr100_getstat(radio);
    183	strscpy(v->name, "FM", sizeof(v->name));
    184	v->type = V4L2_TUNER_RADIO;
    185	v->rangelow = FREQ_MIN * FREQ_MUL;
    186	v->rangehigh = FREQ_MAX * FREQ_MUL;
    187	v->rxsubchans = radio->stereo ? V4L2_TUNER_SUB_STEREO :
    188		V4L2_TUNER_SUB_MONO;
    189	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
    190	v->audmode = V4L2_TUNER_MODE_STEREO;
    191	v->signal = radio->stereo ? 0xffff : 0;     /* We can't get the signal strength */
    192	return 0;
    193}
    194
    195static int vidioc_s_tuner(struct file *file, void *priv,
    196				const struct v4l2_tuner *v)
    197{
    198	return v->index ? -EINVAL : 0;
    199}
    200
    201static int vidioc_s_frequency(struct file *file, void *priv,
    202				const struct v4l2_frequency *f)
    203{
    204	struct dsbr100_device *radio = video_drvdata(file);
    205
    206	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
    207		return -EINVAL;
    208
    209	return dsbr100_setfreq(radio, clamp_t(unsigned, f->frequency,
    210			FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL));
    211}
    212
    213static int vidioc_g_frequency(struct file *file, void *priv,
    214				struct v4l2_frequency *f)
    215{
    216	struct dsbr100_device *radio = video_drvdata(file);
    217
    218	if (f->tuner)
    219		return -EINVAL;
    220	f->type = V4L2_TUNER_RADIO;
    221	f->frequency = radio->curfreq;
    222	return 0;
    223}
    224
    225static int usb_dsbr100_s_ctrl(struct v4l2_ctrl *ctrl)
    226{
    227	struct dsbr100_device *radio =
    228		container_of(ctrl->handler, struct dsbr100_device, hdl);
    229
    230	switch (ctrl->id) {
    231	case V4L2_CID_AUDIO_MUTE:
    232		radio->muted = ctrl->val;
    233		return radio->muted ? dsbr100_stop(radio) : dsbr100_start(radio);
    234	}
    235	return -EINVAL;
    236}
    237
    238
    239/* USB subsystem interface begins here */
    240
    241/*
    242 * Handle unplugging of the device.
    243 * We call video_unregister_device in any case.
    244 * The last function called in this procedure is
    245 * usb_dsbr100_video_device_release
    246 */
    247static void usb_dsbr100_disconnect(struct usb_interface *intf)
    248{
    249	struct dsbr100_device *radio = usb_get_intfdata(intf);
    250
    251	mutex_lock(&radio->v4l2_lock);
    252	/*
    253	 * Disconnect is also called on unload, and in that case we need to
    254	 * mute the device. This call will silently fail if it is called
    255	 * after a physical disconnect.
    256	 */
    257	usb_control_msg(radio->usbdev,
    258		usb_rcvctrlpipe(radio->usbdev, 0),
    259		DSB100_ONOFF,
    260		USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
    261		0x00, 0x00, radio->transfer_buffer, 8, 300);
    262	usb_set_intfdata(intf, NULL);
    263	video_unregister_device(&radio->videodev);
    264	v4l2_device_disconnect(&radio->v4l2_dev);
    265	mutex_unlock(&radio->v4l2_lock);
    266	v4l2_device_put(&radio->v4l2_dev);
    267}
    268
    269
    270/* Suspend device - stop device. */
    271static int usb_dsbr100_suspend(struct usb_interface *intf, pm_message_t message)
    272{
    273	struct dsbr100_device *radio = usb_get_intfdata(intf);
    274
    275	mutex_lock(&radio->v4l2_lock);
    276	if (!radio->muted && dsbr100_stop(radio) < 0)
    277		dev_warn(&intf->dev, "dsbr100_stop failed\n");
    278	mutex_unlock(&radio->v4l2_lock);
    279
    280	dev_info(&intf->dev, "going into suspend..\n");
    281	return 0;
    282}
    283
    284/* Resume device - start device. */
    285static int usb_dsbr100_resume(struct usb_interface *intf)
    286{
    287	struct dsbr100_device *radio = usb_get_intfdata(intf);
    288
    289	mutex_lock(&radio->v4l2_lock);
    290	if (!radio->muted && dsbr100_start(radio) < 0)
    291		dev_warn(&intf->dev, "dsbr100_start failed\n");
    292	mutex_unlock(&radio->v4l2_lock);
    293
    294	dev_info(&intf->dev, "coming out of suspend..\n");
    295	return 0;
    296}
    297
    298/* free data structures */
    299static void usb_dsbr100_release(struct v4l2_device *v4l2_dev)
    300{
    301	struct dsbr100_device *radio = v4l2_dev_to_radio(v4l2_dev);
    302
    303	v4l2_ctrl_handler_free(&radio->hdl);
    304	v4l2_device_unregister(&radio->v4l2_dev);
    305	kfree(radio->transfer_buffer);
    306	kfree(radio);
    307}
    308
    309static const struct v4l2_ctrl_ops usb_dsbr100_ctrl_ops = {
    310	.s_ctrl = usb_dsbr100_s_ctrl,
    311};
    312
    313/* File system interface */
    314static const struct v4l2_file_operations usb_dsbr100_fops = {
    315	.owner		= THIS_MODULE,
    316	.unlocked_ioctl	= video_ioctl2,
    317	.open           = v4l2_fh_open,
    318	.release        = v4l2_fh_release,
    319	.poll		= v4l2_ctrl_poll,
    320};
    321
    322static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = {
    323	.vidioc_querycap    = vidioc_querycap,
    324	.vidioc_g_tuner     = vidioc_g_tuner,
    325	.vidioc_s_tuner     = vidioc_s_tuner,
    326	.vidioc_g_frequency = vidioc_g_frequency,
    327	.vidioc_s_frequency = vidioc_s_frequency,
    328	.vidioc_log_status  = v4l2_ctrl_log_status,
    329	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
    330	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
    331};
    332
    333/* check if the device is present and register with v4l and usb if it is */
    334static int usb_dsbr100_probe(struct usb_interface *intf,
    335				const struct usb_device_id *id)
    336{
    337	struct dsbr100_device *radio;
    338	struct v4l2_device *v4l2_dev;
    339	int retval;
    340
    341	radio = kzalloc(sizeof(struct dsbr100_device), GFP_KERNEL);
    342
    343	if (!radio)
    344		return -ENOMEM;
    345
    346	radio->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL);
    347
    348	if (!(radio->transfer_buffer)) {
    349		kfree(radio);
    350		return -ENOMEM;
    351	}
    352
    353	v4l2_dev = &radio->v4l2_dev;
    354	v4l2_dev->release = usb_dsbr100_release;
    355
    356	retval = v4l2_device_register(&intf->dev, v4l2_dev);
    357	if (retval < 0) {
    358		v4l2_err(v4l2_dev, "couldn't register v4l2_device\n");
    359		goto err_reg_dev;
    360	}
    361
    362	v4l2_ctrl_handler_init(&radio->hdl, 1);
    363	v4l2_ctrl_new_std(&radio->hdl, &usb_dsbr100_ctrl_ops,
    364			  V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
    365	if (radio->hdl.error) {
    366		retval = radio->hdl.error;
    367		v4l2_err(v4l2_dev, "couldn't register control\n");
    368		goto err_reg_ctrl;
    369	}
    370	mutex_init(&radio->v4l2_lock);
    371	strscpy(radio->videodev.name, v4l2_dev->name,
    372		sizeof(radio->videodev.name));
    373	radio->videodev.v4l2_dev = v4l2_dev;
    374	radio->videodev.fops = &usb_dsbr100_fops;
    375	radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops;
    376	radio->videodev.release = video_device_release_empty;
    377	radio->videodev.lock = &radio->v4l2_lock;
    378	radio->videodev.ctrl_handler = &radio->hdl;
    379	radio->videodev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER;
    380
    381	radio->usbdev = interface_to_usbdev(intf);
    382	radio->curfreq = FREQ_MIN * FREQ_MUL;
    383	radio->muted = true;
    384
    385	video_set_drvdata(&radio->videodev, radio);
    386	usb_set_intfdata(intf, radio);
    387
    388	retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
    389	if (retval == 0)
    390		return 0;
    391	v4l2_err(v4l2_dev, "couldn't register video device\n");
    392
    393err_reg_ctrl:
    394	v4l2_ctrl_handler_free(&radio->hdl);
    395	v4l2_device_unregister(v4l2_dev);
    396err_reg_dev:
    397	kfree(radio->transfer_buffer);
    398	kfree(radio);
    399	return retval;
    400}
    401
    402static const struct usb_device_id usb_dsbr100_device_table[] = {
    403	{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
    404	{ }						/* Terminating entry */
    405};
    406
    407MODULE_DEVICE_TABLE(usb, usb_dsbr100_device_table);
    408
    409/* USB subsystem interface */
    410static struct usb_driver usb_dsbr100_driver = {
    411	.name			= "dsbr100",
    412	.probe			= usb_dsbr100_probe,
    413	.disconnect		= usb_dsbr100_disconnect,
    414	.id_table		= usb_dsbr100_device_table,
    415	.suspend		= usb_dsbr100_suspend,
    416	.resume			= usb_dsbr100_resume,
    417	.reset_resume		= usb_dsbr100_resume,
    418};
    419
    420module_usb_driver(usb_dsbr100_driver);