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

as102_drv.c (9704B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Abilis Systems Single DVB-T Receiver
      4 * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
      5 * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
      6 */
      7#include <linux/kernel.h>
      8#include <linux/errno.h>
      9#include <linux/slab.h>
     10#include <linux/module.h>
     11#include <linux/mm.h>
     12#include <linux/kref.h>
     13#include <linux/uaccess.h>
     14#include <linux/usb.h>
     15
     16/* header file for usb device driver*/
     17#include "as102_drv.h"
     18#include "as10x_cmd.h"
     19#include "as102_fe.h"
     20#include "as102_fw.h"
     21#include <media/dvbdev.h>
     22
     23int dual_tuner;
     24module_param_named(dual_tuner, dual_tuner, int, 0644);
     25MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)");
     26
     27static int fw_upload = 1;
     28module_param_named(fw_upload, fw_upload, int, 0644);
     29MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");
     30
     31static int pid_filtering;
     32module_param_named(pid_filtering, pid_filtering, int, 0644);
     33MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");
     34
     35static int ts_auto_disable;
     36module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
     37MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");
     38
     39int elna_enable = 1;
     40module_param_named(elna_enable, elna_enable, int, 0644);
     41MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
     42
     43DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
     44
     45static void as102_stop_stream(struct as102_dev_t *dev)
     46{
     47	struct as10x_bus_adapter_t *bus_adap;
     48
     49	if (dev != NULL)
     50		bus_adap = &dev->bus_adap;
     51	else
     52		return;
     53
     54	if (bus_adap->ops->stop_stream != NULL)
     55		bus_adap->ops->stop_stream(dev);
     56
     57	if (ts_auto_disable) {
     58		if (mutex_lock_interruptible(&dev->bus_adap.lock))
     59			return;
     60
     61		if (as10x_cmd_stop_streaming(bus_adap) < 0)
     62			dev_dbg(&dev->bus_adap.usb_dev->dev,
     63				"as10x_cmd_stop_streaming failed\n");
     64
     65		mutex_unlock(&dev->bus_adap.lock);
     66	}
     67}
     68
     69static int as102_start_stream(struct as102_dev_t *dev)
     70{
     71	struct as10x_bus_adapter_t *bus_adap;
     72	int ret = -EFAULT;
     73
     74	if (dev != NULL)
     75		bus_adap = &dev->bus_adap;
     76	else
     77		return ret;
     78
     79	if (bus_adap->ops->start_stream != NULL)
     80		ret = bus_adap->ops->start_stream(dev);
     81
     82	if (ts_auto_disable) {
     83		if (mutex_lock_interruptible(&dev->bus_adap.lock))
     84			return -EFAULT;
     85
     86		ret = as10x_cmd_start_streaming(bus_adap);
     87
     88		mutex_unlock(&dev->bus_adap.lock);
     89	}
     90
     91	return ret;
     92}
     93
     94static int as10x_pid_filter(struct as102_dev_t *dev,
     95			    int index, u16 pid, int onoff) {
     96
     97	struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap;
     98	int ret = -EFAULT;
     99
    100	if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
    101		dev_dbg(&dev->bus_adap.usb_dev->dev,
    102			"amutex_lock_interruptible(lock) failed !\n");
    103		return -EBUSY;
    104	}
    105
    106	switch (onoff) {
    107	case 0:
    108		ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
    109		dev_dbg(&dev->bus_adap.usb_dev->dev,
    110			"DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
    111			index, pid, ret);
    112		break;
    113	case 1:
    114	{
    115		struct as10x_ts_filter filter;
    116
    117		filter.type = TS_PID_TYPE_TS;
    118		filter.idx = 0xFF;
    119		filter.pid = pid;
    120
    121		ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
    122		dev_dbg(&dev->bus_adap.usb_dev->dev,
    123			"ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
    124			index, filter.idx, filter.pid, ret);
    125		break;
    126	}
    127	}
    128
    129	mutex_unlock(&dev->bus_adap.lock);
    130	return ret;
    131}
    132
    133static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
    134{
    135	int ret = 0;
    136	struct dvb_demux *demux = dvbdmxfeed->demux;
    137	struct as102_dev_t *as102_dev = demux->priv;
    138
    139	if (mutex_lock_interruptible(&as102_dev->sem))
    140		return -ERESTARTSYS;
    141
    142	if (pid_filtering)
    143		as10x_pid_filter(as102_dev, dvbdmxfeed->index,
    144				 dvbdmxfeed->pid, 1);
    145
    146	if (as102_dev->streaming++ == 0)
    147		ret = as102_start_stream(as102_dev);
    148
    149	mutex_unlock(&as102_dev->sem);
    150	return ret;
    151}
    152
    153static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
    154{
    155	struct dvb_demux *demux = dvbdmxfeed->demux;
    156	struct as102_dev_t *as102_dev = demux->priv;
    157
    158	if (mutex_lock_interruptible(&as102_dev->sem))
    159		return -ERESTARTSYS;
    160
    161	if (--as102_dev->streaming == 0)
    162		as102_stop_stream(as102_dev);
    163
    164	if (pid_filtering)
    165		as10x_pid_filter(as102_dev, dvbdmxfeed->index,
    166				 dvbdmxfeed->pid, 0);
    167
    168	mutex_unlock(&as102_dev->sem);
    169	return 0;
    170}
    171
    172static int as102_set_tune(void *priv, struct as10x_tune_args *tune_args)
    173{
    174	struct as10x_bus_adapter_t *bus_adap = priv;
    175	int ret;
    176
    177	/* Set frontend arguments */
    178	if (mutex_lock_interruptible(&bus_adap->lock))
    179		return -EBUSY;
    180
    181	ret =  as10x_cmd_set_tune(bus_adap, tune_args);
    182	if (ret != 0)
    183		dev_dbg(&bus_adap->usb_dev->dev,
    184			"as10x_cmd_set_tune failed. (err = %d)\n", ret);
    185
    186	mutex_unlock(&bus_adap->lock);
    187
    188	return ret;
    189}
    190
    191static int as102_get_tps(void *priv, struct as10x_tps *tps)
    192{
    193	struct as10x_bus_adapter_t *bus_adap = priv;
    194	int ret;
    195
    196	if (mutex_lock_interruptible(&bus_adap->lock))
    197		return -EBUSY;
    198
    199	/* send abilis command: GET_TPS */
    200	ret = as10x_cmd_get_tps(bus_adap, tps);
    201
    202	mutex_unlock(&bus_adap->lock);
    203
    204	return ret;
    205}
    206
    207static int as102_get_status(void *priv, struct as10x_tune_status *tstate)
    208{
    209	struct as10x_bus_adapter_t *bus_adap = priv;
    210	int ret;
    211
    212	if (mutex_lock_interruptible(&bus_adap->lock))
    213		return -EBUSY;
    214
    215	/* send abilis command: GET_TUNE_STATUS */
    216	ret = as10x_cmd_get_tune_status(bus_adap, tstate);
    217	if (ret < 0) {
    218		dev_dbg(&bus_adap->usb_dev->dev,
    219			"as10x_cmd_get_tune_status failed (err = %d)\n",
    220			ret);
    221	}
    222
    223	mutex_unlock(&bus_adap->lock);
    224
    225	return ret;
    226}
    227
    228static int as102_get_stats(void *priv, struct as10x_demod_stats *demod_stats)
    229{
    230	struct as10x_bus_adapter_t *bus_adap = priv;
    231	int ret;
    232
    233	if (mutex_lock_interruptible(&bus_adap->lock))
    234		return -EBUSY;
    235
    236	/* send abilis command: GET_TUNE_STATUS */
    237	ret = as10x_cmd_get_demod_stats(bus_adap, demod_stats);
    238	if (ret < 0) {
    239		dev_dbg(&bus_adap->usb_dev->dev,
    240			"as10x_cmd_get_demod_stats failed (probably not tuned)\n");
    241	} else {
    242		dev_dbg(&bus_adap->usb_dev->dev,
    243			"demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n",
    244			demod_stats->frame_count,
    245			demod_stats->bad_frame_count,
    246			demod_stats->bytes_fixed_by_rs,
    247			demod_stats->mer);
    248	}
    249	mutex_unlock(&bus_adap->lock);
    250
    251	return ret;
    252}
    253
    254static int as102_stream_ctrl(void *priv, int acquire, uint32_t elna_cfg)
    255{
    256	struct as10x_bus_adapter_t *bus_adap = priv;
    257	int ret;
    258
    259	if (mutex_lock_interruptible(&bus_adap->lock))
    260		return -EBUSY;
    261
    262	if (acquire) {
    263		if (elna_enable)
    264			as10x_cmd_set_context(bus_adap,
    265					      CONTEXT_LNA, elna_cfg);
    266
    267		ret = as10x_cmd_turn_on(bus_adap);
    268	} else {
    269		ret = as10x_cmd_turn_off(bus_adap);
    270	}
    271
    272	mutex_unlock(&bus_adap->lock);
    273
    274	return ret;
    275}
    276
    277static const struct as102_fe_ops as102_fe_ops = {
    278	.set_tune = as102_set_tune,
    279	.get_tps  = as102_get_tps,
    280	.get_status = as102_get_status,
    281	.get_stats = as102_get_stats,
    282	.stream_ctrl = as102_stream_ctrl,
    283};
    284
    285int as102_dvb_register(struct as102_dev_t *as102_dev)
    286{
    287	struct device *dev = &as102_dev->bus_adap.usb_dev->dev;
    288	int ret;
    289
    290	ret = dvb_register_adapter(&as102_dev->dvb_adap,
    291			   as102_dev->name, THIS_MODULE,
    292			   dev, adapter_nr);
    293	if (ret < 0) {
    294		dev_err(dev, "%s: dvb_register_adapter() failed: %d\n",
    295			__func__, ret);
    296		return ret;
    297	}
    298
    299	as102_dev->dvb_dmx.priv = as102_dev;
    300	as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256;
    301	as102_dev->dvb_dmx.feednum = 256;
    302	as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed;
    303	as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed;
    304
    305	as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING |
    306					      DMX_SECTION_FILTERING;
    307
    308	as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum;
    309	as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx;
    310	as102_dev->dvb_dmxdev.capabilities = 0;
    311
    312	ret = dvb_dmx_init(&as102_dev->dvb_dmx);
    313	if (ret < 0) {
    314		dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret);
    315		goto edmxinit;
    316	}
    317
    318	ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
    319	if (ret < 0) {
    320		dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n",
    321			__func__, ret);
    322		goto edmxdinit;
    323	}
    324
    325	/* Attach the frontend */
    326	as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name,
    327				       &as102_fe_ops,
    328				       &as102_dev->bus_adap,
    329				       as102_dev->elna_cfg);
    330	if (!as102_dev->dvb_fe) {
    331		ret = -ENODEV;
    332		dev_err(dev, "%s: as102_attach() failed: %d",
    333		    __func__, ret);
    334		goto efereg;
    335	}
    336
    337	ret =  dvb_register_frontend(&as102_dev->dvb_adap, as102_dev->dvb_fe);
    338	if (ret < 0) {
    339		dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d",
    340		    __func__, ret);
    341		goto efereg;
    342	}
    343
    344	/* init bus mutex for token locking */
    345	mutex_init(&as102_dev->bus_adap.lock);
    346
    347	/* init start / stop stream mutex */
    348	mutex_init(&as102_dev->sem);
    349
    350	/*
    351	 * try to load as102 firmware. If firmware upload failed, we'll be
    352	 * able to upload it later.
    353	 */
    354	if (fw_upload)
    355		try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
    356				"firmware_class");
    357
    358	pr_info("Registered device %s", as102_dev->name);
    359	return 0;
    360
    361efereg:
    362	dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
    363edmxdinit:
    364	dvb_dmx_release(&as102_dev->dvb_dmx);
    365edmxinit:
    366	dvb_unregister_adapter(&as102_dev->dvb_adap);
    367	return ret;
    368}
    369
    370void as102_dvb_unregister(struct as102_dev_t *as102_dev)
    371{
    372	/* unregister as102 frontend */
    373	dvb_unregister_frontend(as102_dev->dvb_fe);
    374
    375	/* detach frontend */
    376	dvb_frontend_detach(as102_dev->dvb_fe);
    377
    378	/* unregister demux device */
    379	dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
    380	dvb_dmx_release(&as102_dev->dvb_dmx);
    381
    382	/* unregister dvb adapter */
    383	dvb_unregister_adapter(&as102_dev->dvb_adap);
    384
    385	pr_info("Unregistered device %s", as102_dev->name);
    386}
    387
    388module_usb_driver(as102_usb_driver);
    389
    390/* modinfo details */
    391MODULE_DESCRIPTION(DRIVER_FULL_NAME);
    392MODULE_LICENSE("GPL");
    393MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");