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

vp702x-fe.c (8854B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0
      3 * DVB-S receiver.
      4 *
      5 * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
      6 *                    Metzler Brothers Systementwicklung GbR
      7 *
      8 * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
      9 *
     10 * Thanks to Twinhan who kindly provided hardware and information.
     11 *
     12 * This file can be removed soon, after the DST-driver is rewritten to provice
     13 * the frontend-controlling separately.
     14 *
     15 * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
     16 */
     17#include "vp702x.h"
     18
     19struct vp702x_fe_state {
     20	struct dvb_frontend fe;
     21	struct dvb_usb_device *d;
     22
     23	struct dvb_frontend_ops ops;
     24
     25	enum fe_sec_voltage voltage;
     26	enum fe_sec_tone_mode tone_mode;
     27
     28	u8 lnb_buf[8];
     29
     30	u8 lock;
     31	u8 sig;
     32	u8 snr;
     33
     34	unsigned long next_status_check;
     35	unsigned long status_check_interval;
     36};
     37
     38static int vp702x_fe_refresh_state(struct vp702x_fe_state *st)
     39{
     40	struct vp702x_device_state *dst = st->d->priv;
     41	u8 *buf;
     42
     43	if (time_after(jiffies, st->next_status_check)) {
     44		mutex_lock(&dst->buf_mutex);
     45		buf = dst->buf;
     46
     47		vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10);
     48		st->lock = buf[4];
     49
     50		vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1);
     51		st->snr = buf[0];
     52
     53		vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1);
     54		st->sig = buf[0];
     55
     56		mutex_unlock(&dst->buf_mutex);
     57		st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
     58	}
     59	return 0;
     60}
     61
     62static u8 vp702x_chksum(u8 *buf,int f, int count)
     63{
     64	u8 s = 0;
     65	int i;
     66	for (i = f; i < f+count; i++)
     67		s += buf[i];
     68	return ~s+1;
     69}
     70
     71static int vp702x_fe_read_status(struct dvb_frontend *fe,
     72				 enum fe_status *status)
     73{
     74	struct vp702x_fe_state *st = fe->demodulator_priv;
     75	vp702x_fe_refresh_state(st);
     76	deb_fe("%s\n",__func__);
     77
     78	if (st->lock == 0)
     79		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
     80	else
     81		*status = 0;
     82
     83	if (*status & FE_HAS_LOCK)
     84		st->status_check_interval = 1000;
     85	else
     86		st->status_check_interval = 250;
     87	return 0;
     88}
     89
     90/* not supported by this Frontend */
     91static int vp702x_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
     92{
     93	struct vp702x_fe_state *st = fe->demodulator_priv;
     94	vp702x_fe_refresh_state(st);
     95	*ber = 0;
     96	return 0;
     97}
     98
     99/* not supported by this Frontend */
    100static int vp702x_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
    101{
    102	struct vp702x_fe_state *st = fe->demodulator_priv;
    103	vp702x_fe_refresh_state(st);
    104	*unc = 0;
    105	return 0;
    106}
    107
    108static int vp702x_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
    109{
    110	struct vp702x_fe_state *st = fe->demodulator_priv;
    111	vp702x_fe_refresh_state(st);
    112
    113	*strength = (st->sig << 8) | st->sig;
    114	return 0;
    115}
    116
    117static int vp702x_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
    118{
    119	u8 _snr;
    120	struct vp702x_fe_state *st = fe->demodulator_priv;
    121	vp702x_fe_refresh_state(st);
    122
    123	_snr = (st->snr & 0x1f) * 0xff / 0x1f;
    124	*snr = (_snr << 8) | _snr;
    125	return 0;
    126}
    127
    128static int vp702x_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
    129{
    130	deb_fe("%s\n",__func__);
    131	tune->min_delay_ms = 2000;
    132	return 0;
    133}
    134
    135static int vp702x_fe_set_frontend(struct dvb_frontend *fe)
    136{
    137	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
    138	struct vp702x_fe_state *st = fe->demodulator_priv;
    139	struct vp702x_device_state *dst = st->d->priv;
    140	u32 freq = fep->frequency/1000;
    141	/*CalFrequency*/
    142/*	u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
    143	u64 sr;
    144	u8 *cmd;
    145
    146	mutex_lock(&dst->buf_mutex);
    147
    148	cmd = dst->buf;
    149	memset(cmd, 0, 10);
    150
    151	cmd[0] = (freq >> 8) & 0x7f;
    152	cmd[1] =  freq       & 0xff;
    153	cmd[2] = 1; /* divrate == 4 -> frequencyRef[1] -> 1 here */
    154
    155	sr = (u64) (fep->symbol_rate/1000) << 20;
    156	do_div(sr,88000);
    157	cmd[3] = (sr >> 12) & 0xff;
    158	cmd[4] = (sr >> 4)  & 0xff;
    159	cmd[5] = (sr << 4)  & 0xf0;
    160
    161	deb_fe("setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx)\n",
    162			fep->frequency, freq, freq, fep->symbol_rate,
    163			(unsigned long) sr, (unsigned long) sr);
    164
    165/*	if (fep->inversion == INVERSION_ON)
    166		cmd[6] |= 0x80; */
    167
    168	if (st->voltage == SEC_VOLTAGE_18)
    169		cmd[6] |= 0x40;
    170
    171/*	if (fep->symbol_rate > 8000000)
    172		cmd[6] |= 0x20;
    173
    174	if (fep->frequency < 1531000)
    175		cmd[6] |= 0x04;
    176
    177	if (st->tone_mode == SEC_TONE_ON)
    178		cmd[6] |= 0x01;*/
    179
    180	cmd[7] = vp702x_chksum(cmd,0,7);
    181
    182	st->status_check_interval = 250;
    183	st->next_status_check = jiffies;
    184
    185	vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
    186
    187	if (cmd[2] == 0 && cmd[3] == 0)
    188		deb_fe("tuning failed.\n");
    189	else
    190		deb_fe("tuning succeeded.\n");
    191
    192	mutex_unlock(&dst->buf_mutex);
    193
    194	return 0;
    195}
    196
    197static int vp702x_fe_init(struct dvb_frontend *fe)
    198{
    199	struct vp702x_fe_state *st = fe->demodulator_priv;
    200	deb_fe("%s\n",__func__);
    201	vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
    202	return 0;
    203}
    204
    205static int vp702x_fe_sleep(struct dvb_frontend *fe)
    206{
    207	deb_fe("%s\n",__func__);
    208	return 0;
    209}
    210
    211static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
    212				    struct dvb_diseqc_master_cmd *m)
    213{
    214	u8 *cmd;
    215	struct vp702x_fe_state *st = fe->demodulator_priv;
    216	struct vp702x_device_state *dst = st->d->priv;
    217
    218	deb_fe("%s\n",__func__);
    219
    220	if (m->msg_len > 4)
    221		return -EINVAL;
    222
    223	mutex_lock(&dst->buf_mutex);
    224
    225	cmd = dst->buf;
    226	cmd[1] = SET_DISEQC_CMD;
    227	cmd[2] = m->msg_len;
    228	memcpy(&cmd[3], m->msg, m->msg_len);
    229	cmd[7] = vp702x_chksum(cmd, 0, 7);
    230
    231	vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
    232
    233	if (cmd[2] == 0 && cmd[3] == 0)
    234		deb_fe("diseqc cmd failed.\n");
    235	else
    236		deb_fe("diseqc cmd succeeded.\n");
    237
    238	mutex_unlock(&dst->buf_mutex);
    239
    240	return 0;
    241}
    242
    243static int vp702x_fe_send_diseqc_burst(struct dvb_frontend *fe,
    244				       enum fe_sec_mini_cmd burst)
    245{
    246	deb_fe("%s\n",__func__);
    247	return 0;
    248}
    249
    250static int vp702x_fe_set_tone(struct dvb_frontend *fe,
    251			      enum fe_sec_tone_mode tone)
    252{
    253	struct vp702x_fe_state *st = fe->demodulator_priv;
    254	struct vp702x_device_state *dst = st->d->priv;
    255	u8 *buf;
    256
    257	deb_fe("%s\n",__func__);
    258
    259	st->tone_mode = tone;
    260
    261	if (tone == SEC_TONE_ON)
    262		st->lnb_buf[2] = 0x02;
    263	else
    264		st->lnb_buf[2] = 0x00;
    265
    266	st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
    267
    268	mutex_lock(&dst->buf_mutex);
    269
    270	buf = dst->buf;
    271	memcpy(buf, st->lnb_buf, 8);
    272
    273	vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
    274	if (buf[2] == 0 && buf[3] == 0)
    275		deb_fe("set_tone cmd failed.\n");
    276	else
    277		deb_fe("set_tone cmd succeeded.\n");
    278
    279	mutex_unlock(&dst->buf_mutex);
    280
    281	return 0;
    282}
    283
    284static int vp702x_fe_set_voltage(struct dvb_frontend *fe,
    285				 enum fe_sec_voltage voltage)
    286{
    287	struct vp702x_fe_state *st = fe->demodulator_priv;
    288	struct vp702x_device_state *dst = st->d->priv;
    289	u8 *buf;
    290	deb_fe("%s\n",__func__);
    291
    292	st->voltage = voltage;
    293
    294	if (voltage != SEC_VOLTAGE_OFF)
    295		st->lnb_buf[4] = 0x01;
    296	else
    297		st->lnb_buf[4] = 0x00;
    298
    299	st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
    300
    301	mutex_lock(&dst->buf_mutex);
    302
    303	buf = dst->buf;
    304	memcpy(buf, st->lnb_buf, 8);
    305
    306	vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
    307	if (buf[2] == 0 && buf[3] == 0)
    308		deb_fe("set_voltage cmd failed.\n");
    309	else
    310		deb_fe("set_voltage cmd succeeded.\n");
    311
    312	mutex_unlock(&dst->buf_mutex);
    313	return 0;
    314}
    315
    316static void vp702x_fe_release(struct dvb_frontend* fe)
    317{
    318	struct vp702x_fe_state *st = fe->demodulator_priv;
    319	kfree(st);
    320}
    321
    322static const struct dvb_frontend_ops vp702x_fe_ops;
    323
    324struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d)
    325{
    326	struct vp702x_fe_state *s = kzalloc(sizeof(struct vp702x_fe_state), GFP_KERNEL);
    327	if (s == NULL)
    328		goto error;
    329
    330	s->d = d;
    331
    332	memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
    333	s->fe.demodulator_priv = s;
    334
    335	s->lnb_buf[1] = SET_LNB_POWER;
    336	s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
    337
    338	return &s->fe;
    339error:
    340	return NULL;
    341}
    342
    343
    344static const struct dvb_frontend_ops vp702x_fe_ops = {
    345	.delsys = { SYS_DVBS },
    346	.info = {
    347		.name           = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S",
    348		.frequency_min_hz       =  950 * MHz,
    349		.frequency_max_hz       = 2150 * MHz,
    350		.frequency_stepsize_hz  =    1 * MHz,
    351		.symbol_rate_min     = 1000000,
    352		.symbol_rate_max     = 45000000,
    353		.symbol_rate_tolerance = 500,  /* ppm */
    354		.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
    355		FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
    356		FE_CAN_QPSK |
    357		FE_CAN_FEC_AUTO
    358	},
    359	.release = vp702x_fe_release,
    360
    361	.init  = vp702x_fe_init,
    362	.sleep = vp702x_fe_sleep,
    363
    364	.set_frontend = vp702x_fe_set_frontend,
    365	.get_tune_settings = vp702x_fe_get_tune_settings,
    366
    367	.read_status = vp702x_fe_read_status,
    368	.read_ber = vp702x_fe_read_ber,
    369	.read_signal_strength = vp702x_fe_read_signal_strength,
    370	.read_snr = vp702x_fe_read_snr,
    371	.read_ucblocks = vp702x_fe_read_unc_blocks,
    372
    373	.diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg,
    374	.diseqc_send_burst = vp702x_fe_send_diseqc_burst,
    375	.set_tone = vp702x_fe_set_tone,
    376	.set_voltage = vp702x_fe_set_voltage,
    377};