18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
38c2ecf20Sopenharmony_ci * receiver.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
68c2ecf20Sopenharmony_ci *                    Metzler Brothers Systementwicklung GbR
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Thanks to Twinhan who kindly provided hardware and information.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
138c2ecf20Sopenharmony_ci */
148c2ecf20Sopenharmony_ci#include "vp702x.h"
158c2ecf20Sopenharmony_ci#include <linux/mutex.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* debug */
188c2ecf20Sopenharmony_ciint dvb_usb_vp702x_debug;
198c2ecf20Sopenharmony_cimodule_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
208c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct vp702x_adapter_state {
258c2ecf20Sopenharmony_ci	int pid_filter_count;
268c2ecf20Sopenharmony_ci	int pid_filter_can_bypass;
278c2ecf20Sopenharmony_ci	u8  pid_filter_state;
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
318c2ecf20Sopenharmony_ci				     u16 value, u16 index, u8 *b, int blen)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	int ret;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	ret = usb_control_msg(d->udev,
368c2ecf20Sopenharmony_ci		usb_rcvctrlpipe(d->udev, 0),
378c2ecf20Sopenharmony_ci		req,
388c2ecf20Sopenharmony_ci		USB_TYPE_VENDOR | USB_DIR_IN,
398c2ecf20Sopenharmony_ci		value, index, b, blen,
408c2ecf20Sopenharmony_ci		2000);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	if (ret < 0) {
438c2ecf20Sopenharmony_ci		warn("usb in operation failed. (%d)", ret);
448c2ecf20Sopenharmony_ci		ret = -EIO;
458c2ecf20Sopenharmony_ci	} else
468c2ecf20Sopenharmony_ci		ret = 0;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
508c2ecf20Sopenharmony_ci	debug_dump(b,blen,deb_xfer);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	return ret;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ciint vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
568c2ecf20Sopenharmony_ci		     u16 index, u8 *b, int blen)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	int ret;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	mutex_lock(&d->usb_mutex);
618c2ecf20Sopenharmony_ci	ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
628c2ecf20Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return ret;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req,
688c2ecf20Sopenharmony_ci				      u16 value, u16 index, u8 *b, int blen)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	int ret;
718c2ecf20Sopenharmony_ci	deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
728c2ecf20Sopenharmony_ci	debug_dump(b,blen,deb_xfer);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	if ((ret = usb_control_msg(d->udev,
758c2ecf20Sopenharmony_ci			usb_sndctrlpipe(d->udev,0),
768c2ecf20Sopenharmony_ci			req,
778c2ecf20Sopenharmony_ci			USB_TYPE_VENDOR | USB_DIR_OUT,
788c2ecf20Sopenharmony_ci			value,index,b,blen,
798c2ecf20Sopenharmony_ci			2000)) != blen) {
808c2ecf20Sopenharmony_ci		warn("usb out operation failed. (%d)",ret);
818c2ecf20Sopenharmony_ci		return -EIO;
828c2ecf20Sopenharmony_ci	} else
838c2ecf20Sopenharmony_ci		return 0;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
878c2ecf20Sopenharmony_ci			     u16 index, u8 *b, int blen)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	int ret;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	mutex_lock(&d->usb_mutex);
928c2ecf20Sopenharmony_ci	ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
938c2ecf20Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return ret;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ciint vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	int ret;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
1038c2ecf20Sopenharmony_ci		return ret;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
1068c2ecf20Sopenharmony_ci	msleep(msec);
1078c2ecf20Sopenharmony_ci	ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
1108c2ecf20Sopenharmony_ci	return ret;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
1148c2ecf20Sopenharmony_ci				int olen, u8 *i, int ilen, int msec)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct vp702x_device_state *st = d->priv;
1178c2ecf20Sopenharmony_ci	int ret = 0;
1188c2ecf20Sopenharmony_ci	u8 *buf;
1198c2ecf20Sopenharmony_ci	int buflen = max(olen + 2, ilen + 1);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	ret = mutex_lock_interruptible(&st->buf_mutex);
1228c2ecf20Sopenharmony_ci	if (ret < 0)
1238c2ecf20Sopenharmony_ci		return ret;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	if (buflen > st->buf_len) {
1268c2ecf20Sopenharmony_ci		buf = kmalloc(buflen, GFP_KERNEL);
1278c2ecf20Sopenharmony_ci		if (!buf) {
1288c2ecf20Sopenharmony_ci			mutex_unlock(&st->buf_mutex);
1298c2ecf20Sopenharmony_ci			return -ENOMEM;
1308c2ecf20Sopenharmony_ci		}
1318c2ecf20Sopenharmony_ci		info("successfully reallocated a bigger buffer");
1328c2ecf20Sopenharmony_ci		kfree(st->buf);
1338c2ecf20Sopenharmony_ci		st->buf = buf;
1348c2ecf20Sopenharmony_ci		st->buf_len = buflen;
1358c2ecf20Sopenharmony_ci	} else {
1368c2ecf20Sopenharmony_ci		buf = st->buf;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	buf[0] = 0x00;
1408c2ecf20Sopenharmony_ci	buf[1] = cmd;
1418c2ecf20Sopenharmony_ci	memcpy(&buf[2], o, olen);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (ret == 0)
1468c2ecf20Sopenharmony_ci		memcpy(i, &buf[1], ilen);
1478c2ecf20Sopenharmony_ci	mutex_unlock(&st->buf_mutex);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	return ret;
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	int ret;
1558c2ecf20Sopenharmony_ci	struct vp702x_device_state *st = adap->dev->priv;
1568c2ecf20Sopenharmony_ci	u8 *buf;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	mutex_lock(&st->buf_mutex);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	buf = st->buf;
1618c2ecf20Sopenharmony_ci	memset(buf, 0, 16);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
1648c2ecf20Sopenharmony_ci			0, buf, 16);
1658c2ecf20Sopenharmony_ci	mutex_unlock(&st->buf_mutex);
1668c2ecf20Sopenharmony_ci	return ret;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	int ret;
1728c2ecf20Sopenharmony_ci	struct vp702x_device_state *st = adap->dev->priv;
1738c2ecf20Sopenharmony_ci	u8 *buf;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	mutex_lock(&st->buf_mutex);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	buf = st->buf;
1788c2ecf20Sopenharmony_ci	memset(buf, 0, 16);
1798c2ecf20Sopenharmony_ci	ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
1808c2ecf20Sopenharmony_ci			0, buf, 16);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	mutex_unlock(&st->buf_mutex);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return ret;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct vp702x_adapter_state *st = adap->priv;
1908c2ecf20Sopenharmony_ci	struct vp702x_device_state *dst = adap->dev->priv;
1918c2ecf20Sopenharmony_ci	u8 *buf;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (onoff)
1948c2ecf20Sopenharmony_ci		st->pid_filter_state |=  (1 << id);
1958c2ecf20Sopenharmony_ci	else {
1968c2ecf20Sopenharmony_ci		st->pid_filter_state &= ~(1 << id);
1978c2ecf20Sopenharmony_ci		pid = 0xffff;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	id = 0x10 + id*2;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	vp702x_set_pld_state(adap, st->pid_filter_state);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	mutex_lock(&dst->buf_mutex);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	buf = dst->buf;
2078c2ecf20Sopenharmony_ci	memset(buf, 0, 16);
2088c2ecf20Sopenharmony_ci	vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
2098c2ecf20Sopenharmony_ci	vp702x_usb_in_op(adap->dev, 0xe0, (((pid     ) & 0xff) << 8) | (id+1), 0, buf, 16);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	mutex_unlock(&dst->buf_mutex);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	return 0;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct vp702x_adapter_state *st = adap->priv;
2208c2ecf20Sopenharmony_ci	struct vp702x_device_state *dst = adap->dev->priv;
2218c2ecf20Sopenharmony_ci	int i;
2228c2ecf20Sopenharmony_ci	u8 *b;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	st->pid_filter_count = 8;
2258c2ecf20Sopenharmony_ci	st->pid_filter_can_bypass = 1;
2268c2ecf20Sopenharmony_ci	st->pid_filter_state = 0x00;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	vp702x_set_pld_mode(adap, 1); /* bypass */
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	for (i = 0; i < st->pid_filter_count; i++)
2318c2ecf20Sopenharmony_ci		vp702x_set_pid(adap, 0xffff, i, 1);
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	mutex_lock(&dst->buf_mutex);
2348c2ecf20Sopenharmony_ci	b = dst->buf;
2358c2ecf20Sopenharmony_ci	memset(b, 0, 10);
2368c2ecf20Sopenharmony_ci	vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
2378c2ecf20Sopenharmony_ci	vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
2388c2ecf20Sopenharmony_ci	vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
2398c2ecf20Sopenharmony_ci	mutex_unlock(&dst->buf_mutex);
2408c2ecf20Sopenharmony_ci	/*vp702x_set_pld_mode(d, 0); // filter */
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	return 0;
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	return 0;
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci/* keys for the enclosed remote control */
2518c2ecf20Sopenharmony_cistatic struct rc_map_table rc_map_vp702x_table[] = {
2528c2ecf20Sopenharmony_ci	{ 0x0001, KEY_1 },
2538c2ecf20Sopenharmony_ci	{ 0x0002, KEY_2 },
2548c2ecf20Sopenharmony_ci};
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci/* remote control stuff (does not work with my box) */
2578c2ecf20Sopenharmony_cistatic int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci/* remove the following return to enabled remote querying */
2608c2ecf20Sopenharmony_ci#if 0
2618c2ecf20Sopenharmony_ci	u8 *key;
2628c2ecf20Sopenharmony_ci	int i;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	key = kmalloc(10, GFP_KERNEL);
2658c2ecf20Sopenharmony_ci	if (!key)
2668c2ecf20Sopenharmony_ci		return -ENOMEM;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	deb_rc("remote query key: %x %d\n",key[1],key[1]);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (key[1] == 0x44) {
2738c2ecf20Sopenharmony_ci		*state = REMOTE_NO_KEY_PRESSED;
2748c2ecf20Sopenharmony_ci		kfree(key);
2758c2ecf20Sopenharmony_ci		return 0;
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
2798c2ecf20Sopenharmony_ci		if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
2808c2ecf20Sopenharmony_ci			*state = REMOTE_KEY_PRESSED;
2818c2ecf20Sopenharmony_ci			*event = rc_map_vp702x_table[i].keycode;
2828c2ecf20Sopenharmony_ci			break;
2838c2ecf20Sopenharmony_ci		}
2848c2ecf20Sopenharmony_ci	kfree(key);
2858c2ecf20Sopenharmony_ci#endif
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	return 0;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	u8 i, *buf;
2948c2ecf20Sopenharmony_ci	int ret;
2958c2ecf20Sopenharmony_ci	struct vp702x_device_state *st = d->priv;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	mutex_lock(&st->buf_mutex);
2988c2ecf20Sopenharmony_ci	buf = st->buf;
2998c2ecf20Sopenharmony_ci	for (i = 6; i < 12; i++) {
3008c2ecf20Sopenharmony_ci		ret = vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1,
3018c2ecf20Sopenharmony_ci				       &buf[i - 6], 1);
3028c2ecf20Sopenharmony_ci		if (ret < 0)
3038c2ecf20Sopenharmony_ci			goto err;
3048c2ecf20Sopenharmony_ci	}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	memcpy(mac, buf, 6);
3078c2ecf20Sopenharmony_cierr:
3088c2ecf20Sopenharmony_ci	mutex_unlock(&st->buf_mutex);
3098c2ecf20Sopenharmony_ci	return ret;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_cistatic int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	u8 buf[10] = { 0 };
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
3198c2ecf20Sopenharmony_ci				   buf, 10, 10))
3208c2ecf20Sopenharmony_ci		return -EIO;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	buf[9] = '\0';
3238c2ecf20Sopenharmony_ci	info("system string: %s",&buf[1]);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	vp702x_init_pid_filter(adap);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
3288c2ecf20Sopenharmony_ci	vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	return 0;
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties vp702x_properties;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic int vp702x_usb_probe(struct usb_interface *intf,
3368c2ecf20Sopenharmony_ci		const struct usb_device_id *id)
3378c2ecf20Sopenharmony_ci{
3388c2ecf20Sopenharmony_ci	struct dvb_usb_device *d;
3398c2ecf20Sopenharmony_ci	struct vp702x_device_state *st;
3408c2ecf20Sopenharmony_ci	int ret;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	ret = dvb_usb_device_init(intf, &vp702x_properties,
3438c2ecf20Sopenharmony_ci				   THIS_MODULE, &d, adapter_nr);
3448c2ecf20Sopenharmony_ci	if (ret)
3458c2ecf20Sopenharmony_ci		goto out;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	st = d->priv;
3488c2ecf20Sopenharmony_ci	st->buf_len = 16;
3498c2ecf20Sopenharmony_ci	st->buf = kmalloc(st->buf_len, GFP_KERNEL);
3508c2ecf20Sopenharmony_ci	if (!st->buf) {
3518c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3528c2ecf20Sopenharmony_ci		dvb_usb_device_exit(intf);
3538c2ecf20Sopenharmony_ci		goto out;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci	mutex_init(&st->buf_mutex);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ciout:
3588c2ecf20Sopenharmony_ci	return ret;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic void vp702x_usb_disconnect(struct usb_interface *intf)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = usb_get_intfdata(intf);
3658c2ecf20Sopenharmony_ci	struct vp702x_device_state *st = d->priv;
3668c2ecf20Sopenharmony_ci	mutex_lock(&st->buf_mutex);
3678c2ecf20Sopenharmony_ci	kfree(st->buf);
3688c2ecf20Sopenharmony_ci	mutex_unlock(&st->buf_mutex);
3698c2ecf20Sopenharmony_ci	dvb_usb_device_exit(intf);
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic struct usb_device_id vp702x_usb_table [] = {
3738c2ecf20Sopenharmony_ci	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
3748c2ecf20Sopenharmony_ci//	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
3758c2ecf20Sopenharmony_ci//	    { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
3768c2ecf20Sopenharmony_ci	    { 0 },
3778c2ecf20Sopenharmony_ci};
3788c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, vp702x_usb_table);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties vp702x_properties = {
3818c2ecf20Sopenharmony_ci	.usb_ctrl = CYPRESS_FX2,
3828c2ecf20Sopenharmony_ci	.firmware            = "dvb-usb-vp702x-02.fw",
3838c2ecf20Sopenharmony_ci	.no_reconnect        = 1,
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	.size_of_priv     = sizeof(struct vp702x_device_state),
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	.num_adapters = 1,
3888c2ecf20Sopenharmony_ci	.adapter = {
3898c2ecf20Sopenharmony_ci		{
3908c2ecf20Sopenharmony_ci		.num_frontends = 1,
3918c2ecf20Sopenharmony_ci		.fe = {{
3928c2ecf20Sopenharmony_ci			.caps             = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci			.streaming_ctrl   = vp702x_streaming_ctrl,
3958c2ecf20Sopenharmony_ci			.frontend_attach  = vp702x_frontend_attach,
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci			/* parameter for the MPEG2-data transfer */
3988c2ecf20Sopenharmony_ci			.stream = {
3998c2ecf20Sopenharmony_ci				.type = USB_BULK,
4008c2ecf20Sopenharmony_ci				.count = 10,
4018c2ecf20Sopenharmony_ci				.endpoint = 0x02,
4028c2ecf20Sopenharmony_ci				.u = {
4038c2ecf20Sopenharmony_ci					.bulk = {
4048c2ecf20Sopenharmony_ci						.buffersize = 4096,
4058c2ecf20Sopenharmony_ci					}
4068c2ecf20Sopenharmony_ci				}
4078c2ecf20Sopenharmony_ci			},
4088c2ecf20Sopenharmony_ci		}},
4098c2ecf20Sopenharmony_ci			.size_of_priv     = sizeof(struct vp702x_adapter_state),
4108c2ecf20Sopenharmony_ci		}
4118c2ecf20Sopenharmony_ci	},
4128c2ecf20Sopenharmony_ci	.read_mac_address = vp702x_read_mac_addr,
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	.rc.legacy = {
4158c2ecf20Sopenharmony_ci		.rc_map_table       = rc_map_vp702x_table,
4168c2ecf20Sopenharmony_ci		.rc_map_size  = ARRAY_SIZE(rc_map_vp702x_table),
4178c2ecf20Sopenharmony_ci		.rc_interval      = 400,
4188c2ecf20Sopenharmony_ci		.rc_query         = vp702x_rc_query,
4198c2ecf20Sopenharmony_ci	},
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	.num_device_descs = 1,
4228c2ecf20Sopenharmony_ci	.devices = {
4238c2ecf20Sopenharmony_ci		{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
4248c2ecf20Sopenharmony_ci		  .cold_ids = { &vp702x_usb_table[0], NULL },
4258c2ecf20Sopenharmony_ci		  .warm_ids = { NULL },
4268c2ecf20Sopenharmony_ci		},
4278c2ecf20Sopenharmony_ci/*		{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
4288c2ecf20Sopenharmony_ci		  .cold_ids = { &vp702x_usb_table[2], NULL },
4298c2ecf20Sopenharmony_ci		  .warm_ids = { &vp702x_usb_table[3], NULL },
4308c2ecf20Sopenharmony_ci		},
4318c2ecf20Sopenharmony_ci*/		{ NULL },
4328c2ecf20Sopenharmony_ci	}
4338c2ecf20Sopenharmony_ci};
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci/* usb specific object needed to register this driver with the usb subsystem */
4368c2ecf20Sopenharmony_cistatic struct usb_driver vp702x_usb_driver = {
4378c2ecf20Sopenharmony_ci	.name		= "dvb_usb_vp702x",
4388c2ecf20Sopenharmony_ci	.probe		= vp702x_usb_probe,
4398c2ecf20Sopenharmony_ci	.disconnect	= vp702x_usb_disconnect,
4408c2ecf20Sopenharmony_ci	.id_table	= vp702x_usb_table,
4418c2ecf20Sopenharmony_ci};
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cimodule_usb_driver(vp702x_usb_driver);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@posteo.de>");
4468c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
4478c2ecf20Sopenharmony_ciMODULE_VERSION("1.0");
4488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
449