vp702x.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /* DVB USB compliant Linux driver for the TwinhanDTV StarBox USB2.0 DVB-S
  2. * receiver.
  3. *
  4. * Copyright (C) 2005 Ralph Metzler <rjkm@metzlerbros.de>
  5. * Metzler Brothers Systementwicklung GbR
  6. *
  7. * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
  8. *
  9. * Thanks to Twinhan who kindly provided hardware and information.
  10. *
  11. * This program is free software; you can redistribute it and/or modify it
  12. * under the terms of the GNU General Public License as published by the Free
  13. * Software Foundation, version 2.
  14. *
  15. * see Documentation/dvb/README.dvb-usb for more information
  16. */
  17. #include "vp702x.h"
  18. /* debug */
  19. int dvb_usb_vp702x_debug;
  20. module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
  21. MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
  22. DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  23. struct vp702x_state {
  24. int pid_filter_count;
  25. int pid_filter_can_bypass;
  26. u8 pid_filter_state;
  27. };
  28. struct vp702x_device_state {
  29. u8 power_state;
  30. };
  31. /* check for mutex FIXME */
  32. int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
  33. {
  34. int ret = -1;
  35. ret = usb_control_msg(d->udev,
  36. usb_rcvctrlpipe(d->udev,0),
  37. req,
  38. USB_TYPE_VENDOR | USB_DIR_IN,
  39. value,index,b,blen,
  40. 2000);
  41. if (ret < 0) {
  42. warn("usb in operation failed. (%d)", ret);
  43. ret = -EIO;
  44. } else
  45. ret = 0;
  46. deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
  47. debug_dump(b,blen,deb_xfer);
  48. return ret;
  49. }
  50. static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
  51. u16 index, u8 *b, int blen)
  52. {
  53. int ret;
  54. deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
  55. debug_dump(b,blen,deb_xfer);
  56. if ((ret = usb_control_msg(d->udev,
  57. usb_sndctrlpipe(d->udev,0),
  58. req,
  59. USB_TYPE_VENDOR | USB_DIR_OUT,
  60. value,index,b,blen,
  61. 2000)) != blen) {
  62. warn("usb out operation failed. (%d)",ret);
  63. return -EIO;
  64. } else
  65. return 0;
  66. }
  67. int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
  68. {
  69. int ret;
  70. if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
  71. return ret;
  72. ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen);
  73. msleep(msec);
  74. ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
  75. mutex_unlock(&d->usb_mutex);
  76. return ret;
  77. }
  78. static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
  79. int olen, u8 *i, int ilen, int msec)
  80. {
  81. u8 bout[olen+2];
  82. u8 bin[ilen+1];
  83. int ret = 0;
  84. bout[0] = 0x00;
  85. bout[1] = cmd;
  86. memcpy(&bout[2],o,olen);
  87. ret = vp702x_usb_inout_op(d, bout, olen+2, bin, ilen+1,msec);
  88. if (ret == 0)
  89. memcpy(i,&bin[1],ilen);
  90. return ret;
  91. }
  92. static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
  93. {
  94. u8 buf[16] = { 0 };
  95. return vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, 0, buf, 16);
  96. }
  97. static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
  98. {
  99. u8 buf[16] = { 0 };
  100. return vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, 0, buf, 16);
  101. }
  102. static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
  103. {
  104. struct vp702x_state *st = adap->priv;
  105. u8 buf[16] = { 0 };
  106. if (onoff)
  107. st->pid_filter_state |= (1 << id);
  108. else {
  109. st->pid_filter_state &= ~(1 << id);
  110. pid = 0xffff;
  111. }
  112. id = 0x10 + id*2;
  113. vp702x_set_pld_state(adap, st->pid_filter_state);
  114. vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
  115. vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16);
  116. return 0;
  117. }
  118. static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
  119. {
  120. struct vp702x_state *st = adap->priv;
  121. int i;
  122. u8 b[10] = { 0 };
  123. st->pid_filter_count = 8;
  124. st->pid_filter_can_bypass = 1;
  125. st->pid_filter_state = 0x00;
  126. vp702x_set_pld_mode(adap, 1); // bypass
  127. for (i = 0; i < st->pid_filter_count; i++)
  128. vp702x_set_pid(adap, 0xffff, i, 1);
  129. vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
  130. vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
  131. vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
  132. //vp702x_set_pld_mode(d, 0); // filter
  133. return 0;
  134. }
  135. static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
  136. {
  137. return 0;
  138. }
  139. /* keys for the enclosed remote control */
  140. static struct dvb_usb_rc_key vp702x_rc_keys[] = {
  141. { 0x0001, KEY_1 },
  142. { 0x0002, KEY_2 },
  143. };
  144. /* remote control stuff (does not work with my box) */
  145. static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
  146. {
  147. u8 key[10];
  148. int i;
  149. /* remove the following return to enabled remote querying */
  150. return 0;
  151. vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
  152. deb_rc("remote query key: %x %d\n",key[1],key[1]);
  153. if (key[1] == 0x44) {
  154. *state = REMOTE_NO_KEY_PRESSED;
  155. return 0;
  156. }
  157. for (i = 0; i < ARRAY_SIZE(vp702x_rc_keys); i++)
  158. if (rc5_custom(&vp702x_rc_keys[i]) == key[1]) {
  159. *state = REMOTE_KEY_PRESSED;
  160. *event = vp702x_rc_keys[i].event;
  161. break;
  162. }
  163. return 0;
  164. }
  165. static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
  166. {
  167. u8 i;
  168. for (i = 6; i < 12; i++)
  169. vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &mac[i - 6], 1);
  170. return 0;
  171. }
  172. static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
  173. {
  174. u8 buf[10] = { 0 };
  175. vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
  176. if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, buf, 10, 10))
  177. return -EIO;
  178. buf[9] = '\0';
  179. info("system string: %s",&buf[1]);
  180. vp702x_init_pid_filter(adap);
  181. adap->fe = vp702x_fe_attach(adap->dev);
  182. vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
  183. return 0;
  184. }
  185. static struct dvb_usb_device_properties vp702x_properties;
  186. static int vp702x_usb_probe(struct usb_interface *intf,
  187. const struct usb_device_id *id)
  188. {
  189. return dvb_usb_device_init(intf, &vp702x_properties,
  190. THIS_MODULE, NULL, adapter_nr);
  191. }
  192. static struct usb_device_id vp702x_usb_table [] = {
  193. { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
  194. // { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
  195. // { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
  196. { 0 },
  197. };
  198. MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
  199. static struct dvb_usb_device_properties vp702x_properties = {
  200. .usb_ctrl = CYPRESS_FX2,
  201. .firmware = "dvb-usb-vp702x-02.fw",
  202. .no_reconnect = 1,
  203. .size_of_priv = sizeof(struct vp702x_device_state),
  204. .num_adapters = 1,
  205. .adapter = {
  206. {
  207. .caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
  208. .streaming_ctrl = vp702x_streaming_ctrl,
  209. .frontend_attach = vp702x_frontend_attach,
  210. /* parameter for the MPEG2-data transfer */
  211. .stream = {
  212. .type = USB_BULK,
  213. .count = 10,
  214. .endpoint = 0x02,
  215. .u = {
  216. .bulk = {
  217. .buffersize = 4096,
  218. }
  219. }
  220. },
  221. .size_of_priv = sizeof(struct vp702x_state),
  222. }
  223. },
  224. .read_mac_address = vp702x_read_mac_addr,
  225. .rc_key_map = vp702x_rc_keys,
  226. .rc_key_map_size = ARRAY_SIZE(vp702x_rc_keys),
  227. .rc_interval = 400,
  228. .rc_query = vp702x_rc_query,
  229. .num_device_descs = 1,
  230. .devices = {
  231. { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
  232. .cold_ids = { &vp702x_usb_table[0], NULL },
  233. .warm_ids = { NULL },
  234. },
  235. /* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
  236. .cold_ids = { &vp702x_usb_table[2], NULL },
  237. .warm_ids = { &vp702x_usb_table[3], NULL },
  238. },
  239. */ { NULL },
  240. }
  241. };
  242. /* usb specific object needed to register this driver with the usb subsystem */
  243. static struct usb_driver vp702x_usb_driver = {
  244. .name = "dvb_usb_vp702x",
  245. .probe = vp702x_usb_probe,
  246. .disconnect = dvb_usb_device_exit,
  247. .id_table = vp702x_usb_table,
  248. };
  249. /* module stuff */
  250. static int __init vp702x_usb_module_init(void)
  251. {
  252. int result;
  253. if ((result = usb_register(&vp702x_usb_driver))) {
  254. err("usb_register failed. (%d)",result);
  255. return result;
  256. }
  257. return 0;
  258. }
  259. static void __exit vp702x_usb_module_exit(void)
  260. {
  261. /* deregister this driver from the USB subsystem */
  262. usb_deregister(&vp702x_usb_driver);
  263. }
  264. module_init(vp702x_usb_module_init);
  265. module_exit(vp702x_usb_module_exit);
  266. MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
  267. MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
  268. MODULE_VERSION("1.0");
  269. MODULE_LICENSE("GPL");