vp702x.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
  3. * receiver.
  4. *
  5. * Copyright (C) 2005 Ralph Metzler <[email protected]>
  6. * Metzler Brothers Systementwicklung GbR
  7. *
  8. * Copyright (C) 2005 Patrick Boettcher <[email protected]>
  9. *
  10. * Thanks to Twinhan who kindly provided hardware and information.
  11. *
  12. * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
  13. */
  14. #include "vp702x.h"
  15. #include <linux/mutex.h>
  16. /* debug */
  17. int dvb_usb_vp702x_debug;
  18. module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
  19. MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
  20. DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  21. struct vp702x_adapter_state {
  22. int pid_filter_count;
  23. int pid_filter_can_bypass;
  24. u8 pid_filter_state;
  25. };
  26. static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
  27. u16 value, u16 index, u8 *b, int blen)
  28. {
  29. int ret;
  30. ret = usb_control_msg(d->udev,
  31. usb_rcvctrlpipe(d->udev, 0),
  32. req,
  33. USB_TYPE_VENDOR | USB_DIR_IN,
  34. value, index, b, blen,
  35. 2000);
  36. if (ret < 0) {
  37. warn("usb in operation failed. (%d)", ret);
  38. ret = -EIO;
  39. } else
  40. ret = 0;
  41. deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
  42. debug_dump(b,blen,deb_xfer);
  43. return ret;
  44. }
  45. int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
  46. u16 index, u8 *b, int blen)
  47. {
  48. int ret;
  49. mutex_lock(&d->usb_mutex);
  50. ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
  51. mutex_unlock(&d->usb_mutex);
  52. return ret;
  53. }
  54. static int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req,
  55. u16 value, u16 index, u8 *b, int blen)
  56. {
  57. int ret;
  58. deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
  59. debug_dump(b,blen,deb_xfer);
  60. if ((ret = usb_control_msg(d->udev,
  61. usb_sndctrlpipe(d->udev,0),
  62. req,
  63. USB_TYPE_VENDOR | USB_DIR_OUT,
  64. value,index,b,blen,
  65. 2000)) != blen) {
  66. warn("usb out operation failed. (%d)",ret);
  67. return -EIO;
  68. } else
  69. return 0;
  70. }
  71. static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
  72. u16 index, u8 *b, int blen)
  73. {
  74. int ret;
  75. mutex_lock(&d->usb_mutex);
  76. ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
  77. mutex_unlock(&d->usb_mutex);
  78. return ret;
  79. }
  80. int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
  81. {
  82. int ret;
  83. if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
  84. return ret;
  85. ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
  86. msleep(msec);
  87. ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
  88. mutex_unlock(&d->usb_mutex);
  89. return ret;
  90. }
  91. static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
  92. int olen, u8 *i, int ilen, int msec)
  93. {
  94. struct vp702x_device_state *st = d->priv;
  95. int ret = 0;
  96. u8 *buf;
  97. int buflen = max(olen + 2, ilen + 1);
  98. ret = mutex_lock_interruptible(&st->buf_mutex);
  99. if (ret < 0)
  100. return ret;
  101. if (buflen > st->buf_len) {
  102. buf = kmalloc(buflen, GFP_KERNEL);
  103. if (!buf) {
  104. mutex_unlock(&st->buf_mutex);
  105. return -ENOMEM;
  106. }
  107. info("successfully reallocated a bigger buffer");
  108. kfree(st->buf);
  109. st->buf = buf;
  110. st->buf_len = buflen;
  111. } else {
  112. buf = st->buf;
  113. }
  114. buf[0] = 0x00;
  115. buf[1] = cmd;
  116. memcpy(&buf[2], o, olen);
  117. ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
  118. if (ret == 0)
  119. memcpy(i, &buf[1], ilen);
  120. mutex_unlock(&st->buf_mutex);
  121. return ret;
  122. }
  123. static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
  124. {
  125. int ret;
  126. struct vp702x_device_state *st = adap->dev->priv;
  127. u8 *buf;
  128. mutex_lock(&st->buf_mutex);
  129. buf = st->buf;
  130. memset(buf, 0, 16);
  131. ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
  132. 0, buf, 16);
  133. mutex_unlock(&st->buf_mutex);
  134. return ret;
  135. }
  136. static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
  137. {
  138. int ret;
  139. struct vp702x_device_state *st = adap->dev->priv;
  140. u8 *buf;
  141. mutex_lock(&st->buf_mutex);
  142. buf = st->buf;
  143. memset(buf, 0, 16);
  144. ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
  145. 0, buf, 16);
  146. mutex_unlock(&st->buf_mutex);
  147. return ret;
  148. }
  149. static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
  150. {
  151. struct vp702x_adapter_state *st = adap->priv;
  152. struct vp702x_device_state *dst = adap->dev->priv;
  153. u8 *buf;
  154. if (onoff)
  155. st->pid_filter_state |= (1 << id);
  156. else {
  157. st->pid_filter_state &= ~(1 << id);
  158. pid = 0xffff;
  159. }
  160. id = 0x10 + id*2;
  161. vp702x_set_pld_state(adap, st->pid_filter_state);
  162. mutex_lock(&dst->buf_mutex);
  163. buf = dst->buf;
  164. memset(buf, 0, 16);
  165. vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
  166. vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16);
  167. mutex_unlock(&dst->buf_mutex);
  168. return 0;
  169. }
  170. static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
  171. {
  172. struct vp702x_adapter_state *st = adap->priv;
  173. struct vp702x_device_state *dst = adap->dev->priv;
  174. int i;
  175. u8 *b;
  176. st->pid_filter_count = 8;
  177. st->pid_filter_can_bypass = 1;
  178. st->pid_filter_state = 0x00;
  179. vp702x_set_pld_mode(adap, 1); /* bypass */
  180. for (i = 0; i < st->pid_filter_count; i++)
  181. vp702x_set_pid(adap, 0xffff, i, 1);
  182. mutex_lock(&dst->buf_mutex);
  183. b = dst->buf;
  184. memset(b, 0, 10);
  185. vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
  186. vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
  187. vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
  188. mutex_unlock(&dst->buf_mutex);
  189. /*vp702x_set_pld_mode(d, 0); // filter */
  190. return 0;
  191. }
  192. static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
  193. {
  194. return 0;
  195. }
  196. /* keys for the enclosed remote control */
  197. static struct rc_map_table rc_map_vp702x_table[] = {
  198. { 0x0001, KEY_1 },
  199. { 0x0002, KEY_2 },
  200. };
  201. /* remote control stuff (does not work with my box) */
  202. static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
  203. {
  204. /* remove the following return to enabled remote querying */
  205. #if 0
  206. u8 *key;
  207. int i;
  208. key = kmalloc(10, GFP_KERNEL);
  209. if (!key)
  210. return -ENOMEM;
  211. vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
  212. deb_rc("remote query key: %x %d\n",key[1],key[1]);
  213. if (key[1] == 0x44) {
  214. *state = REMOTE_NO_KEY_PRESSED;
  215. kfree(key);
  216. return 0;
  217. }
  218. for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
  219. if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
  220. *state = REMOTE_KEY_PRESSED;
  221. *event = rc_map_vp702x_table[i].keycode;
  222. break;
  223. }
  224. kfree(key);
  225. #endif
  226. return 0;
  227. }
  228. static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
  229. {
  230. u8 i, *buf;
  231. int ret;
  232. struct vp702x_device_state *st = d->priv;
  233. mutex_lock(&st->buf_mutex);
  234. buf = st->buf;
  235. for (i = 6; i < 12; i++) {
  236. ret = vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1,
  237. &buf[i - 6], 1);
  238. if (ret < 0)
  239. goto err;
  240. }
  241. memcpy(mac, buf, 6);
  242. err:
  243. mutex_unlock(&st->buf_mutex);
  244. return ret;
  245. }
  246. static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
  247. {
  248. u8 buf[10] = { 0 };
  249. vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
  250. if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
  251. buf, 10, 10))
  252. return -EIO;
  253. buf[9] = '\0';
  254. info("system string: %s",&buf[1]);
  255. vp702x_init_pid_filter(adap);
  256. adap->fe_adap[0].fe = vp702x_fe_attach(adap->dev);
  257. vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
  258. return 0;
  259. }
  260. static struct dvb_usb_device_properties vp702x_properties;
  261. static int vp702x_usb_probe(struct usb_interface *intf,
  262. const struct usb_device_id *id)
  263. {
  264. struct dvb_usb_device *d;
  265. struct vp702x_device_state *st;
  266. int ret;
  267. ret = dvb_usb_device_init(intf, &vp702x_properties,
  268. THIS_MODULE, &d, adapter_nr);
  269. if (ret)
  270. goto out;
  271. st = d->priv;
  272. st->buf_len = 16;
  273. st->buf = kmalloc(st->buf_len, GFP_KERNEL);
  274. if (!st->buf) {
  275. ret = -ENOMEM;
  276. dvb_usb_device_exit(intf);
  277. goto out;
  278. }
  279. mutex_init(&st->buf_mutex);
  280. out:
  281. return ret;
  282. }
  283. static void vp702x_usb_disconnect(struct usb_interface *intf)
  284. {
  285. struct dvb_usb_device *d = usb_get_intfdata(intf);
  286. struct vp702x_device_state *st = d->priv;
  287. mutex_lock(&st->buf_mutex);
  288. kfree(st->buf);
  289. mutex_unlock(&st->buf_mutex);
  290. dvb_usb_device_exit(intf);
  291. }
  292. enum {
  293. VISIONPLUS_VP7021_COLD,
  294. VISIONPLUS_VP7020_COLD,
  295. VISIONPLUS_VP7020_WARM,
  296. };
  297. static struct usb_device_id vp702x_usb_table[] = {
  298. DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7021_COLD),
  299. // DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_COLD),
  300. // DVB_USB_DEV(VISIONPLUS, VISIONPLUS_VP7020_WARM),
  301. { }
  302. };
  303. MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
  304. static struct dvb_usb_device_properties vp702x_properties = {
  305. .usb_ctrl = CYPRESS_FX2,
  306. .firmware = "dvb-usb-vp702x-02.fw",
  307. .no_reconnect = 1,
  308. .size_of_priv = sizeof(struct vp702x_device_state),
  309. .num_adapters = 1,
  310. .adapter = {
  311. {
  312. .num_frontends = 1,
  313. .fe = {{
  314. .caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
  315. .streaming_ctrl = vp702x_streaming_ctrl,
  316. .frontend_attach = vp702x_frontend_attach,
  317. /* parameter for the MPEG2-data transfer */
  318. .stream = {
  319. .type = USB_BULK,
  320. .count = 10,
  321. .endpoint = 0x02,
  322. .u = {
  323. .bulk = {
  324. .buffersize = 4096,
  325. }
  326. }
  327. },
  328. }},
  329. .size_of_priv = sizeof(struct vp702x_adapter_state),
  330. }
  331. },
  332. .read_mac_address = vp702x_read_mac_addr,
  333. .rc.legacy = {
  334. .rc_map_table = rc_map_vp702x_table,
  335. .rc_map_size = ARRAY_SIZE(rc_map_vp702x_table),
  336. .rc_interval = 400,
  337. .rc_query = vp702x_rc_query,
  338. },
  339. .num_device_descs = 1,
  340. .devices = {
  341. { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
  342. .cold_ids = { &vp702x_usb_table[VISIONPLUS_VP7021_COLD], NULL },
  343. .warm_ids = { NULL },
  344. },
  345. /* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
  346. .cold_ids = { &vp702x_usb_table[VISIONPLUS_VP7020_COLD], NULL },
  347. .warm_ids = { &vp702x_usb_table[VISIONPLUS_VP7020_WARM], NULL },
  348. },
  349. */ { NULL },
  350. }
  351. };
  352. /* usb specific object needed to register this driver with the usb subsystem */
  353. static struct usb_driver vp702x_usb_driver = {
  354. .name = "dvb_usb_vp702x",
  355. .probe = vp702x_usb_probe,
  356. .disconnect = vp702x_usb_disconnect,
  357. .id_table = vp702x_usb_table,
  358. };
  359. module_usb_driver(vp702x_usb_driver);
  360. MODULE_AUTHOR("Patrick Boettcher <[email protected]>");
  361. MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
  362. MODULE_VERSION("1.0");
  363. MODULE_LICENSE("GPL");