162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
362306a36Sopenharmony_ci * receiver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
662306a36Sopenharmony_ci *                    Metzler Brothers Systementwicklung GbR
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci * Thanks to Twinhan who kindly provided hardware and information.
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci#include "vp702x.h"
1562306a36Sopenharmony_ci#include <linux/mutex.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* debug */
1862306a36Sopenharmony_ciint dvb_usb_vp702x_debug;
1962306a36Sopenharmony_cimodule_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
2062306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistruct vp702x_adapter_state {
2562306a36Sopenharmony_ci	int pid_filter_count;
2662306a36Sopenharmony_ci	int pid_filter_can_bypass;
2762306a36Sopenharmony_ci	u8  pid_filter_state;
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
3162306a36Sopenharmony_ci				     u16 value, u16 index, u8 *b, int blen)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	int ret;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	ret = usb_control_msg(d->udev,
3662306a36Sopenharmony_ci		usb_rcvctrlpipe(d->udev, 0),
3762306a36Sopenharmony_ci		req,
3862306a36Sopenharmony_ci		USB_TYPE_VENDOR | USB_DIR_IN,
3962306a36Sopenharmony_ci		value, index, b, blen,
4062306a36Sopenharmony_ci		2000);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	if (ret < 0) {
4362306a36Sopenharmony_ci		warn("usb in operation failed. (%d)", ret);
4462306a36Sopenharmony_ci		ret = -EIO;
4562306a36Sopenharmony_ci	} else
4662306a36Sopenharmony_ci		ret = 0;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
5062306a36Sopenharmony_ci	debug_dump(b,blen,deb_xfer);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	return ret;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ciint vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
5662306a36Sopenharmony_ci		     u16 index, u8 *b, int blen)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	int ret;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	mutex_lock(&d->usb_mutex);
6162306a36Sopenharmony_ci	ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
6262306a36Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return ret;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req,
6862306a36Sopenharmony_ci				      u16 value, u16 index, u8 *b, int blen)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	int ret;
7162306a36Sopenharmony_ci	deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
7262306a36Sopenharmony_ci	debug_dump(b,blen,deb_xfer);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if ((ret = usb_control_msg(d->udev,
7562306a36Sopenharmony_ci			usb_sndctrlpipe(d->udev,0),
7662306a36Sopenharmony_ci			req,
7762306a36Sopenharmony_ci			USB_TYPE_VENDOR | USB_DIR_OUT,
7862306a36Sopenharmony_ci			value,index,b,blen,
7962306a36Sopenharmony_ci			2000)) != blen) {
8062306a36Sopenharmony_ci		warn("usb out operation failed. (%d)",ret);
8162306a36Sopenharmony_ci		return -EIO;
8262306a36Sopenharmony_ci	} else
8362306a36Sopenharmony_ci		return 0;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
8762306a36Sopenharmony_ci			     u16 index, u8 *b, int blen)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	int ret;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	mutex_lock(&d->usb_mutex);
9262306a36Sopenharmony_ci	ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
9362306a36Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return ret;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ciint vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	int ret;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
10362306a36Sopenharmony_ci		return ret;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
10662306a36Sopenharmony_ci	msleep(msec);
10762306a36Sopenharmony_ci	ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
11062306a36Sopenharmony_ci	return ret;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
11462306a36Sopenharmony_ci				int olen, u8 *i, int ilen, int msec)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	struct vp702x_device_state *st = d->priv;
11762306a36Sopenharmony_ci	int ret = 0;
11862306a36Sopenharmony_ci	u8 *buf;
11962306a36Sopenharmony_ci	int buflen = max(olen + 2, ilen + 1);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	ret = mutex_lock_interruptible(&st->buf_mutex);
12262306a36Sopenharmony_ci	if (ret < 0)
12362306a36Sopenharmony_ci		return ret;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (buflen > st->buf_len) {
12662306a36Sopenharmony_ci		buf = kmalloc(buflen, GFP_KERNEL);
12762306a36Sopenharmony_ci		if (!buf) {
12862306a36Sopenharmony_ci			mutex_unlock(&st->buf_mutex);
12962306a36Sopenharmony_ci			return -ENOMEM;
13062306a36Sopenharmony_ci		}
13162306a36Sopenharmony_ci		info("successfully reallocated a bigger buffer");
13262306a36Sopenharmony_ci		kfree(st->buf);
13362306a36Sopenharmony_ci		st->buf = buf;
13462306a36Sopenharmony_ci		st->buf_len = buflen;
13562306a36Sopenharmony_ci	} else {
13662306a36Sopenharmony_ci		buf = st->buf;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	buf[0] = 0x00;
14062306a36Sopenharmony_ci	buf[1] = cmd;
14162306a36Sopenharmony_ci	memcpy(&buf[2], o, olen);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (ret == 0)
14662306a36Sopenharmony_ci		memcpy(i, &buf[1], ilen);
14762306a36Sopenharmony_ci	mutex_unlock(&st->buf_mutex);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return ret;
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	int ret;
15562306a36Sopenharmony_ci	struct vp702x_device_state *st = adap->dev->priv;
15662306a36Sopenharmony_ci	u8 *buf;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	mutex_lock(&st->buf_mutex);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	buf = st->buf;
16162306a36Sopenharmony_ci	memset(buf, 0, 16);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
16462306a36Sopenharmony_ci			0, buf, 16);
16562306a36Sopenharmony_ci	mutex_unlock(&st->buf_mutex);
16662306a36Sopenharmony_ci	return ret;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	int ret;
17262306a36Sopenharmony_ci	struct vp702x_device_state *st = adap->dev->priv;
17362306a36Sopenharmony_ci	u8 *buf;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	mutex_lock(&st->buf_mutex);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	buf = st->buf;
17862306a36Sopenharmony_ci	memset(buf, 0, 16);
17962306a36Sopenharmony_ci	ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
18062306a36Sopenharmony_ci			0, buf, 16);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	mutex_unlock(&st->buf_mutex);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return ret;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct vp702x_adapter_state *st = adap->priv;
19062306a36Sopenharmony_ci	struct vp702x_device_state *dst = adap->dev->priv;
19162306a36Sopenharmony_ci	u8 *buf;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	if (onoff)
19462306a36Sopenharmony_ci		st->pid_filter_state |=  (1 << id);
19562306a36Sopenharmony_ci	else {
19662306a36Sopenharmony_ci		st->pid_filter_state &= ~(1 << id);
19762306a36Sopenharmony_ci		pid = 0xffff;
19862306a36Sopenharmony_ci	}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	id = 0x10 + id*2;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	vp702x_set_pld_state(adap, st->pid_filter_state);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	mutex_lock(&dst->buf_mutex);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	buf = dst->buf;
20762306a36Sopenharmony_ci	memset(buf, 0, 16);
20862306a36Sopenharmony_ci	vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
20962306a36Sopenharmony_ci	vp702x_usb_in_op(adap->dev, 0xe0, (((pid     ) & 0xff) << 8) | (id+1), 0, buf, 16);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	mutex_unlock(&dst->buf_mutex);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return 0;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	struct vp702x_adapter_state *st = adap->priv;
22062306a36Sopenharmony_ci	struct vp702x_device_state *dst = adap->dev->priv;
22162306a36Sopenharmony_ci	int i;
22262306a36Sopenharmony_ci	u8 *b;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	st->pid_filter_count = 8;
22562306a36Sopenharmony_ci	st->pid_filter_can_bypass = 1;
22662306a36Sopenharmony_ci	st->pid_filter_state = 0x00;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	vp702x_set_pld_mode(adap, 1); /* bypass */
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	for (i = 0; i < st->pid_filter_count; i++)
23162306a36Sopenharmony_ci		vp702x_set_pid(adap, 0xffff, i, 1);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	mutex_lock(&dst->buf_mutex);
23462306a36Sopenharmony_ci	b = dst->buf;
23562306a36Sopenharmony_ci	memset(b, 0, 10);
23662306a36Sopenharmony_ci	vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
23762306a36Sopenharmony_ci	vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
23862306a36Sopenharmony_ci	vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
23962306a36Sopenharmony_ci	mutex_unlock(&dst->buf_mutex);
24062306a36Sopenharmony_ci	/*vp702x_set_pld_mode(d, 0); // filter */
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	return 0;
24362306a36Sopenharmony_ci}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_cistatic int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	return 0;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci/* keys for the enclosed remote control */
25162306a36Sopenharmony_cistatic struct rc_map_table rc_map_vp702x_table[] = {
25262306a36Sopenharmony_ci	{ 0x0001, KEY_1 },
25362306a36Sopenharmony_ci	{ 0x0002, KEY_2 },
25462306a36Sopenharmony_ci};
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci/* remote control stuff (does not work with my box) */
25762306a36Sopenharmony_cistatic int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci/* remove the following return to enabled remote querying */
26062306a36Sopenharmony_ci#if 0
26162306a36Sopenharmony_ci	u8 *key;
26262306a36Sopenharmony_ci	int i;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	key = kmalloc(10, GFP_KERNEL);
26562306a36Sopenharmony_ci	if (!key)
26662306a36Sopenharmony_ci		return -ENOMEM;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	deb_rc("remote query key: %x %d\n",key[1],key[1]);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	if (key[1] == 0x44) {
27362306a36Sopenharmony_ci		*state = REMOTE_NO_KEY_PRESSED;
27462306a36Sopenharmony_ci		kfree(key);
27562306a36Sopenharmony_ci		return 0;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
27962306a36Sopenharmony_ci		if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
28062306a36Sopenharmony_ci			*state = REMOTE_KEY_PRESSED;
28162306a36Sopenharmony_ci			*event = rc_map_vp702x_table[i].keycode;
28262306a36Sopenharmony_ci			break;
28362306a36Sopenharmony_ci		}
28462306a36Sopenharmony_ci	kfree(key);
28562306a36Sopenharmony_ci#endif
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	return 0;
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	u8 i, *buf;
29462306a36Sopenharmony_ci	int ret;
29562306a36Sopenharmony_ci	struct vp702x_device_state *st = d->priv;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	mutex_lock(&st->buf_mutex);
29862306a36Sopenharmony_ci	buf = st->buf;
29962306a36Sopenharmony_ci	for (i = 6; i < 12; i++) {
30062306a36Sopenharmony_ci		ret = vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1,
30162306a36Sopenharmony_ci				       &buf[i - 6], 1);
30262306a36Sopenharmony_ci		if (ret < 0)
30362306a36Sopenharmony_ci			goto err;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	memcpy(mac, buf, 6);
30762306a36Sopenharmony_cierr:
30862306a36Sopenharmony_ci	mutex_unlock(&st->buf_mutex);
30962306a36Sopenharmony_ci	return ret;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	u8 buf[10] = { 0 };
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
31962306a36Sopenharmony_ci				   buf, 10, 10))
32062306a36Sopenharmony_ci		return -EIO;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	buf[9] = '\0';
32362306a36Sopenharmony_ci	info("system string: %s",&buf[1]);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	vp702x_init_pid_filter(adap);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
32862306a36Sopenharmony_ci	vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return 0;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic struct dvb_usb_device_properties vp702x_properties;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cistatic int vp702x_usb_probe(struct usb_interface *intf,
33662306a36Sopenharmony_ci		const struct usb_device_id *id)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	struct dvb_usb_device *d;
33962306a36Sopenharmony_ci	struct vp702x_device_state *st;
34062306a36Sopenharmony_ci	int ret;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	ret = dvb_usb_device_init(intf, &vp702x_properties,
34362306a36Sopenharmony_ci				   THIS_MODULE, &d, adapter_nr);
34462306a36Sopenharmony_ci	if (ret)
34562306a36Sopenharmony_ci		goto out;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	st = d->priv;
34862306a36Sopenharmony_ci	st->buf_len = 16;
34962306a36Sopenharmony_ci	st->buf = kmalloc(st->buf_len, GFP_KERNEL);
35062306a36Sopenharmony_ci	if (!st->buf) {
35162306a36Sopenharmony_ci		ret = -ENOMEM;
35262306a36Sopenharmony_ci		dvb_usb_device_exit(intf);
35362306a36Sopenharmony_ci		goto out;
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci	mutex_init(&st->buf_mutex);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ciout:
35862306a36Sopenharmony_ci	return ret;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic void vp702x_usb_disconnect(struct usb_interface *intf)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	struct dvb_usb_device *d = usb_get_intfdata(intf);
36562306a36Sopenharmony_ci	struct vp702x_device_state *st = d->priv;
36662306a36Sopenharmony_ci	mutex_lock(&st->buf_mutex);
36762306a36Sopenharmony_ci	kfree(st->buf);
36862306a36Sopenharmony_ci	mutex_unlock(&st->buf_mutex);
36962306a36Sopenharmony_ci	dvb_usb_device_exit(intf);
37062306a36Sopenharmony_ci}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_cienum {
37362306a36Sopenharmony_ci	VISIONPLUS_VP7021_COLD,
37462306a36Sopenharmony_ci	VISIONPLUS_VP7020_COLD,
37562306a36Sopenharmony_ci	VISIONPLUS_VP7020_WARM,
37662306a36Sopenharmony_ci};
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic struct usb_device_id vp702x_usb_table[] = {
37962306a36Sopenharmony_ci	DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7021_COLD),
38062306a36Sopenharmony_ci//	DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_COLD),
38162306a36Sopenharmony_ci//	DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_WARM),
38262306a36Sopenharmony_ci	{ }
38362306a36Sopenharmony_ci};
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, vp702x_usb_table);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic struct dvb_usb_device_properties vp702x_properties = {
38862306a36Sopenharmony_ci	.usb_ctrl = CYPRESS_FX2,
38962306a36Sopenharmony_ci	.firmware            = "dvb-usb-vp702x-02.fw",
39062306a36Sopenharmony_ci	.no_reconnect        = 1,
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	.size_of_priv     = sizeof(struct vp702x_device_state),
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	.num_adapters = 1,
39562306a36Sopenharmony_ci	.adapter = {
39662306a36Sopenharmony_ci		{
39762306a36Sopenharmony_ci		.num_frontends = 1,
39862306a36Sopenharmony_ci		.fe = {{
39962306a36Sopenharmony_ci			.caps             = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci			.streaming_ctrl   = vp702x_streaming_ctrl,
40262306a36Sopenharmony_ci			.frontend_attach  = vp702x_frontend_attach,
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
40562306a36Sopenharmony_ci			.stream = {
40662306a36Sopenharmony_ci				.type = USB_BULK,
40762306a36Sopenharmony_ci				.count = 10,
40862306a36Sopenharmony_ci				.endpoint = 0x02,
40962306a36Sopenharmony_ci				.u = {
41062306a36Sopenharmony_ci					.bulk = {
41162306a36Sopenharmony_ci						.buffersize = 4096,
41262306a36Sopenharmony_ci					}
41362306a36Sopenharmony_ci				}
41462306a36Sopenharmony_ci			},
41562306a36Sopenharmony_ci		}},
41662306a36Sopenharmony_ci			.size_of_priv     = sizeof(struct vp702x_adapter_state),
41762306a36Sopenharmony_ci		}
41862306a36Sopenharmony_ci	},
41962306a36Sopenharmony_ci	.read_mac_address = vp702x_read_mac_addr,
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	.rc.legacy = {
42262306a36Sopenharmony_ci		.rc_map_table       = rc_map_vp702x_table,
42362306a36Sopenharmony_ci		.rc_map_size  = ARRAY_SIZE(rc_map_vp702x_table),
42462306a36Sopenharmony_ci		.rc_interval      = 400,
42562306a36Sopenharmony_ci		.rc_query         = vp702x_rc_query,
42662306a36Sopenharmony_ci	},
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	.num_device_descs = 1,
42962306a36Sopenharmony_ci	.devices = {
43062306a36Sopenharmony_ci		{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
43162306a36Sopenharmony_ci		  .cold_ids = { &vp702x_usb_table[VISIONPLUS_VP7021_COLD], NULL },
43262306a36Sopenharmony_ci		  .warm_ids = { NULL },
43362306a36Sopenharmony_ci		},
43462306a36Sopenharmony_ci/*		{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
43562306a36Sopenharmony_ci		  .cold_ids = { &vp702x_usb_table[VISIONPLUS_VP7020_COLD], NULL },
43662306a36Sopenharmony_ci		  .warm_ids = { &vp702x_usb_table[VISIONPLUS_VP7020_WARM], NULL },
43762306a36Sopenharmony_ci		},
43862306a36Sopenharmony_ci*/		{ NULL },
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci};
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci/* usb specific object needed to register this driver with the usb subsystem */
44362306a36Sopenharmony_cistatic struct usb_driver vp702x_usb_driver = {
44462306a36Sopenharmony_ci	.name		= "dvb_usb_vp702x",
44562306a36Sopenharmony_ci	.probe		= vp702x_usb_probe,
44662306a36Sopenharmony_ci	.disconnect	= vp702x_usb_disconnect,
44762306a36Sopenharmony_ci	.id_table	= vp702x_usb_table,
44862306a36Sopenharmony_ci};
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cimodule_usb_driver(vp702x_usb_driver);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
45362306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
45462306a36Sopenharmony_ciMODULE_VERSION("1.0");
45562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
456