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

dibusb-common.c (8962B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Common methods for dibusb-based-receivers.
      3 *
      4 * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@posteo.de)
      5 *
      6 * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
      7 */
      8
      9#include "dibusb.h"
     10
     11/* Max transfer size done by I2C transfer functions */
     12#define MAX_XFER_SIZE  64
     13
     14static int debug;
     15module_param(debug, int, 0644);
     16MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
     17MODULE_LICENSE("GPL");
     18
     19#define deb_info(args...) dprintk(debug,0x01,args)
     20
     21/* common stuff used by the different dibusb modules */
     22int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
     23{
     24	if (adap->priv != NULL) {
     25		struct dibusb_state *st = adap->priv;
     26		if (st->ops.fifo_ctrl != NULL)
     27			if (st->ops.fifo_ctrl(adap->fe_adap[0].fe, onoff)) {
     28				err("error while controlling the fifo of the demod.");
     29				return -ENODEV;
     30			}
     31	}
     32	return 0;
     33}
     34EXPORT_SYMBOL(dibusb_streaming_ctrl);
     35
     36int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
     37{
     38	if (adap->priv != NULL) {
     39		struct dibusb_state *st = adap->priv;
     40		if (st->ops.pid_ctrl != NULL)
     41			st->ops.pid_ctrl(adap->fe_adap[0].fe,
     42					 index, pid, onoff);
     43	}
     44	return 0;
     45}
     46EXPORT_SYMBOL(dibusb_pid_filter);
     47
     48int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
     49{
     50	if (adap->priv != NULL) {
     51		struct dibusb_state *st = adap->priv;
     52		if (st->ops.pid_parse != NULL)
     53			if (st->ops.pid_parse(adap->fe_adap[0].fe, onoff) < 0)
     54				err("could not handle pid_parser");
     55	}
     56	return 0;
     57}
     58EXPORT_SYMBOL(dibusb_pid_filter_ctrl);
     59
     60int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
     61{
     62	u8 *b;
     63	int ret;
     64
     65	b = kmalloc(3, GFP_KERNEL);
     66	if (!b)
     67		return -ENOMEM;
     68
     69	b[0] = DIBUSB_REQ_SET_IOCTL;
     70	b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
     71	b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP;
     72
     73	ret = dvb_usb_generic_write(d, b, 3);
     74
     75	kfree(b);
     76
     77	msleep(10);
     78
     79	return ret;
     80}
     81EXPORT_SYMBOL(dibusb_power_ctrl);
     82
     83int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
     84{
     85	int ret;
     86	u8 *b;
     87
     88	b = kmalloc(3, GFP_KERNEL);
     89	if (!b)
     90		return -ENOMEM;
     91
     92	if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0)
     93		goto ret;
     94
     95	if (onoff) {
     96		b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
     97		b[1] = 0x00;
     98		ret = dvb_usb_generic_write(adap->dev, b, 2);
     99		if (ret  < 0)
    100			goto ret;
    101	}
    102
    103	b[0] = DIBUSB_REQ_SET_IOCTL;
    104	b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
    105	ret = dvb_usb_generic_write(adap->dev, b, 3);
    106
    107ret:
    108	kfree(b);
    109	return ret;
    110}
    111EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
    112
    113int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff)
    114{
    115	u8 *b;
    116	int ret;
    117
    118	if (!onoff)
    119		return 0;
    120
    121	b = kmalloc(3, GFP_KERNEL);
    122	if (!b)
    123		return -ENOMEM;
    124
    125	b[0] = DIBUSB_REQ_SET_IOCTL;
    126	b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
    127	b[2] = DIBUSB_IOCTL_POWER_WAKEUP;
    128
    129	ret = dvb_usb_generic_write(d, b, 3);
    130
    131	kfree(b);
    132
    133	return ret;
    134}
    135EXPORT_SYMBOL(dibusb2_0_power_ctrl);
    136
    137static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
    138			  u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
    139{
    140	u8 *sndbuf;
    141	int ret, wo, len;
    142
    143	/* write only ? */
    144	wo = (rbuf == NULL || rlen == 0);
    145
    146	len = 2 + wlen + (wo ? 0 : 2);
    147
    148	sndbuf = kmalloc(MAX_XFER_SIZE, GFP_KERNEL);
    149	if (!sndbuf)
    150		return -ENOMEM;
    151
    152	if (4 + wlen > MAX_XFER_SIZE) {
    153		warn("i2c wr: len=%d is too big!\n", wlen);
    154		ret = -EOPNOTSUPP;
    155		goto ret;
    156	}
    157
    158	sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
    159	sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
    160
    161	memcpy(&sndbuf[2], wbuf, wlen);
    162
    163	if (!wo) {
    164		sndbuf[wlen + 2] = (rlen >> 8) & 0xff;
    165		sndbuf[wlen + 3] = rlen & 0xff;
    166	}
    167
    168	ret = dvb_usb_generic_rw(d, sndbuf, len, rbuf, rlen, 0);
    169
    170ret:
    171	kfree(sndbuf);
    172	return ret;
    173}
    174
    175/*
    176 * I2C master xfer function
    177 */
    178static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
    179{
    180	struct dvb_usb_device *d = i2c_get_adapdata(adap);
    181	int i;
    182
    183	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
    184		return -EAGAIN;
    185
    186	for (i = 0; i < num; i++) {
    187		/* write/read request */
    188		if (i+1 < num && (msg[i].flags & I2C_M_RD) == 0
    189					  && (msg[i+1].flags & I2C_M_RD)) {
    190			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
    191						msg[i+1].buf,msg[i+1].len) < 0)
    192				break;
    193			i++;
    194		} else if ((msg[i].flags & I2C_M_RD) == 0) {
    195			if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
    196				break;
    197		} else if (msg[i].addr != 0x50) {
    198			/* 0x50 is the address of the eeprom - we need to protect it
    199			 * from dibusb's bad i2c implementation: reads without
    200			 * writing the offset before are forbidden */
    201			if (dibusb_i2c_msg(d, msg[i].addr, NULL, 0, msg[i].buf, msg[i].len) < 0)
    202				break;
    203		}
    204	}
    205
    206	mutex_unlock(&d->i2c_mutex);
    207	return i;
    208}
    209
    210static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
    211{
    212	return I2C_FUNC_I2C;
    213}
    214
    215struct i2c_algorithm dibusb_i2c_algo = {
    216	.master_xfer   = dibusb_i2c_xfer,
    217	.functionality = dibusb_i2c_func,
    218};
    219EXPORT_SYMBOL(dibusb_i2c_algo);
    220
    221int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
    222{
    223	u8 *buf;
    224	int rc;
    225
    226	buf = kzalloc(2, GFP_KERNEL);
    227	if (!buf)
    228		return -ENOMEM;
    229
    230	buf[0] = offs;
    231
    232	rc = dibusb_i2c_msg(d, 0x50, &buf[0], 1, &buf[1], 1);
    233	*val = buf[1];
    234	kfree(buf);
    235
    236	return rc;
    237}
    238EXPORT_SYMBOL(dibusb_read_eeprom_byte);
    239
    240/*
    241 * common remote control stuff
    242 */
    243struct rc_map_table rc_map_dibusb_table[] = {
    244	/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
    245	{ 0x0016, KEY_POWER },
    246	{ 0x0010, KEY_MUTE },
    247	{ 0x0003, KEY_1 },
    248	{ 0x0001, KEY_2 },
    249	{ 0x0006, KEY_3 },
    250	{ 0x0009, KEY_4 },
    251	{ 0x001d, KEY_5 },
    252	{ 0x001f, KEY_6 },
    253	{ 0x000d, KEY_7 },
    254	{ 0x0019, KEY_8 },
    255	{ 0x001b, KEY_9 },
    256	{ 0x0015, KEY_0 },
    257	{ 0x0005, KEY_CHANNELUP },
    258	{ 0x0002, KEY_CHANNELDOWN },
    259	{ 0x001e, KEY_VOLUMEUP },
    260	{ 0x000a, KEY_VOLUMEDOWN },
    261	{ 0x0011, KEY_RECORD },
    262	{ 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */
    263	{ 0x0014, KEY_PLAY },
    264	{ 0x001a, KEY_STOP },
    265	{ 0x0040, KEY_REWIND },
    266	{ 0x0012, KEY_FASTFORWARD },
    267	{ 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */
    268	{ 0x004c, KEY_PAUSE },
    269	{ 0x004d, KEY_SCREEN }, /* Full screen mode. */
    270	{ 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
    271	/* additional keys TwinHan VisionPlus, the Artec seemingly not have */
    272	{ 0x000c, KEY_CANCEL }, /* Cancel */
    273	{ 0x001c, KEY_EPG }, /* EPG */
    274	{ 0x0000, KEY_TAB }, /* Tab */
    275	{ 0x0048, KEY_INFO }, /* Preview */
    276	{ 0x0004, KEY_LIST }, /* RecordList */
    277	{ 0x000f, KEY_TEXT }, /* Teletext */
    278	/* Key codes for the KWorld/ADSTech/JetWay remote. */
    279	{ 0x8612, KEY_POWER },
    280	{ 0x860f, KEY_SELECT }, /* source */
    281	{ 0x860c, KEY_UNKNOWN }, /* scan */
    282	{ 0x860b, KEY_EPG },
    283	{ 0x8610, KEY_MUTE },
    284	{ 0x8601, KEY_1 },
    285	{ 0x8602, KEY_2 },
    286	{ 0x8603, KEY_3 },
    287	{ 0x8604, KEY_4 },
    288	{ 0x8605, KEY_5 },
    289	{ 0x8606, KEY_6 },
    290	{ 0x8607, KEY_7 },
    291	{ 0x8608, KEY_8 },
    292	{ 0x8609, KEY_9 },
    293	{ 0x860a, KEY_0 },
    294	{ 0x8618, KEY_ZOOM },
    295	{ 0x861c, KEY_UNKNOWN }, /* preview */
    296	{ 0x8613, KEY_UNKNOWN }, /* snap */
    297	{ 0x8600, KEY_UNDO },
    298	{ 0x861d, KEY_RECORD },
    299	{ 0x860d, KEY_STOP },
    300	{ 0x860e, KEY_PAUSE },
    301	{ 0x8616, KEY_PLAY },
    302	{ 0x8611, KEY_BACK },
    303	{ 0x8619, KEY_FORWARD },
    304	{ 0x8614, KEY_UNKNOWN }, /* pip */
    305	{ 0x8615, KEY_ESC },
    306	{ 0x861a, KEY_UP },
    307	{ 0x861e, KEY_DOWN },
    308	{ 0x861f, KEY_LEFT },
    309	{ 0x861b, KEY_RIGHT },
    310
    311	/* Key codes for the DiBcom MOD3000 remote. */
    312	{ 0x8000, KEY_MUTE },
    313	{ 0x8001, KEY_TEXT },
    314	{ 0x8002, KEY_HOME },
    315	{ 0x8003, KEY_POWER },
    316
    317	{ 0x8004, KEY_RED },
    318	{ 0x8005, KEY_GREEN },
    319	{ 0x8006, KEY_YELLOW },
    320	{ 0x8007, KEY_BLUE },
    321
    322	{ 0x8008, KEY_DVD },
    323	{ 0x8009, KEY_AUDIO },
    324	{ 0x800a, KEY_IMAGES },      /* Pictures */
    325	{ 0x800b, KEY_VIDEO },
    326
    327	{ 0x800c, KEY_BACK },
    328	{ 0x800d, KEY_UP },
    329	{ 0x800e, KEY_RADIO },
    330	{ 0x800f, KEY_EPG },
    331
    332	{ 0x8010, KEY_LEFT },
    333	{ 0x8011, KEY_OK },
    334	{ 0x8012, KEY_RIGHT },
    335	{ 0x8013, KEY_UNKNOWN },    /* SAP */
    336
    337	{ 0x8014, KEY_TV },
    338	{ 0x8015, KEY_DOWN },
    339	{ 0x8016, KEY_MENU },       /* DVD Menu */
    340	{ 0x8017, KEY_LAST },
    341
    342	{ 0x8018, KEY_RECORD },
    343	{ 0x8019, KEY_STOP },
    344	{ 0x801a, KEY_PAUSE },
    345	{ 0x801b, KEY_PLAY },
    346
    347	{ 0x801c, KEY_PREVIOUS },
    348	{ 0x801d, KEY_REWIND },
    349	{ 0x801e, KEY_FASTFORWARD },
    350	{ 0x801f, KEY_NEXT},
    351
    352	{ 0x8040, KEY_1 },
    353	{ 0x8041, KEY_2 },
    354	{ 0x8042, KEY_3 },
    355	{ 0x8043, KEY_CHANNELUP },
    356
    357	{ 0x8044, KEY_4 },
    358	{ 0x8045, KEY_5 },
    359	{ 0x8046, KEY_6 },
    360	{ 0x8047, KEY_CHANNELDOWN },
    361
    362	{ 0x8048, KEY_7 },
    363	{ 0x8049, KEY_8 },
    364	{ 0x804a, KEY_9 },
    365	{ 0x804b, KEY_VOLUMEUP },
    366
    367	{ 0x804c, KEY_CLEAR },
    368	{ 0x804d, KEY_0 },
    369	{ 0x804e, KEY_ENTER },
    370	{ 0x804f, KEY_VOLUMEDOWN },
    371};
    372EXPORT_SYMBOL(rc_map_dibusb_table);
    373
    374int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
    375{
    376	u8 *buf;
    377	int ret;
    378
    379	buf = kmalloc(5, GFP_KERNEL);
    380	if (!buf)
    381		return -ENOMEM;
    382
    383	buf[0] = DIBUSB_REQ_POLL_REMOTE;
    384
    385	ret = dvb_usb_generic_rw(d, buf, 1, buf, 5, 0);
    386	if (ret < 0)
    387		goto ret;
    388
    389	dvb_usb_nec_rc_key_to_event(d, buf, event, state);
    390
    391	if (buf[0] != 0)
    392		deb_info("key: %*ph\n", 5, buf);
    393
    394ret:
    395	kfree(buf);
    396
    397	return ret;
    398}
    399EXPORT_SYMBOL(dibusb_rc_query);