pvrusb2-debugifc.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /*
  2. *
  3. * $Id$
  4. *
  5. * Copyright (C) 2005 Mike Isely <isely@pobox.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. */
  21. #include <linux/string.h>
  22. #include <linux/slab.h>
  23. #include "pvrusb2-debugifc.h"
  24. #include "pvrusb2-hdw.h"
  25. #include "pvrusb2-debug.h"
  26. #include "pvrusb2-i2c-core.h"
  27. struct debugifc_mask_item {
  28. const char *name;
  29. unsigned long msk;
  30. };
  31. static struct debugifc_mask_item mask_items[] = {
  32. {"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)},
  33. {"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)},
  34. {"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)},
  35. {"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)},
  36. {"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)},
  37. };
  38. static unsigned int debugifc_count_whitespace(const char *buf,
  39. unsigned int count)
  40. {
  41. unsigned int scnt;
  42. char ch;
  43. for (scnt = 0; scnt < count; scnt++) {
  44. ch = buf[scnt];
  45. if (ch == ' ') continue;
  46. if (ch == '\t') continue;
  47. if (ch == '\n') continue;
  48. break;
  49. }
  50. return scnt;
  51. }
  52. static unsigned int debugifc_count_nonwhitespace(const char *buf,
  53. unsigned int count)
  54. {
  55. unsigned int scnt;
  56. char ch;
  57. for (scnt = 0; scnt < count; scnt++) {
  58. ch = buf[scnt];
  59. if (ch == ' ') break;
  60. if (ch == '\t') break;
  61. if (ch == '\n') break;
  62. }
  63. return scnt;
  64. }
  65. static unsigned int debugifc_isolate_word(const char *buf,unsigned int count,
  66. const char **wstrPtr,
  67. unsigned int *wlenPtr)
  68. {
  69. const char *wptr;
  70. unsigned int consume_cnt = 0;
  71. unsigned int wlen;
  72. unsigned int scnt;
  73. wptr = NULL;
  74. wlen = 0;
  75. scnt = debugifc_count_whitespace(buf,count);
  76. consume_cnt += scnt; count -= scnt; buf += scnt;
  77. if (!count) goto done;
  78. scnt = debugifc_count_nonwhitespace(buf,count);
  79. if (!scnt) goto done;
  80. wptr = buf;
  81. wlen = scnt;
  82. consume_cnt += scnt; count -= scnt; buf += scnt;
  83. done:
  84. *wstrPtr = wptr;
  85. *wlenPtr = wlen;
  86. return consume_cnt;
  87. }
  88. static int debugifc_parse_unsigned_number(const char *buf,unsigned int count,
  89. u32 *num_ptr)
  90. {
  91. u32 result = 0;
  92. u32 val;
  93. int ch;
  94. int radix = 10;
  95. if ((count >= 2) && (buf[0] == '0') &&
  96. ((buf[1] == 'x') || (buf[1] == 'X'))) {
  97. radix = 16;
  98. count -= 2;
  99. buf += 2;
  100. } else if ((count >= 1) && (buf[0] == '0')) {
  101. radix = 8;
  102. }
  103. while (count--) {
  104. ch = *buf++;
  105. if ((ch >= '0') && (ch <= '9')) {
  106. val = ch - '0';
  107. } else if ((ch >= 'a') && (ch <= 'f')) {
  108. val = ch - 'a' + 10;
  109. } else if ((ch >= 'A') && (ch <= 'F')) {
  110. val = ch - 'A' + 10;
  111. } else {
  112. return -EINVAL;
  113. }
  114. if (val >= radix) return -EINVAL;
  115. result *= radix;
  116. result += val;
  117. }
  118. *num_ptr = result;
  119. return 0;
  120. }
  121. static int debugifc_match_keyword(const char *buf,unsigned int count,
  122. const char *keyword)
  123. {
  124. unsigned int kl;
  125. if (!keyword) return 0;
  126. kl = strlen(keyword);
  127. if (kl != count) return 0;
  128. return !memcmp(buf,keyword,kl);
  129. }
  130. static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
  131. {
  132. struct debugifc_mask_item *mip;
  133. unsigned int idx;
  134. for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
  135. mip = mask_items + idx;
  136. if (debugifc_match_keyword(buf,count,mip->name)) {
  137. return mip->msk;
  138. }
  139. }
  140. return 0;
  141. }
  142. static int debugifc_print_mask(char *buf,unsigned int sz,
  143. unsigned long msk,unsigned long val)
  144. {
  145. struct debugifc_mask_item *mip;
  146. unsigned int idx;
  147. int bcnt = 0;
  148. int ccnt;
  149. for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
  150. mip = mask_items + idx;
  151. if (!(mip->msk & msk)) continue;
  152. ccnt = scnprintf(buf,sz,"%s%c%s",
  153. (bcnt ? " " : ""),
  154. ((mip->msk & val) ? '+' : '-'),
  155. mip->name);
  156. sz -= ccnt;
  157. buf += ccnt;
  158. bcnt += ccnt;
  159. }
  160. return bcnt;
  161. }
  162. static unsigned int debugifc_parse_subsys_mask(const char *buf,
  163. unsigned int count,
  164. unsigned long *mskPtr,
  165. unsigned long *valPtr)
  166. {
  167. const char *wptr;
  168. unsigned int consume_cnt = 0;
  169. unsigned int scnt;
  170. unsigned int wlen;
  171. int mode;
  172. unsigned long m1,msk,val;
  173. msk = 0;
  174. val = 0;
  175. while (count) {
  176. scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
  177. if (!scnt) break;
  178. consume_cnt += scnt; count -= scnt; buf += scnt;
  179. if (!wptr) break;
  180. mode = 0;
  181. if (wlen) switch (wptr[0]) {
  182. case '+':
  183. wptr++;
  184. wlen--;
  185. break;
  186. case '-':
  187. mode = 1;
  188. wptr++;
  189. wlen--;
  190. break;
  191. }
  192. if (!wlen) continue;
  193. m1 = debugifc_find_mask(wptr,wlen);
  194. if (!m1) break;
  195. msk |= m1;
  196. if (!mode) val |= m1;
  197. }
  198. *mskPtr = msk;
  199. *valPtr = val;
  200. return consume_cnt;
  201. }
  202. int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
  203. {
  204. int bcnt = 0;
  205. int ccnt;
  206. struct pvr2_hdw_debug_info dbg;
  207. pvr2_hdw_get_debug_info(hdw,&dbg);
  208. ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s",
  209. (dbg.big_lock_held ? "held" : "free"),
  210. (dbg.ctl_lock_held ? "held" : "free"));
  211. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  212. if (dbg.ctl_lock_held) {
  213. ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d"
  214. " cmd_wlen=%d cmd_rlen=%d"
  215. " wpend=%d rpend=%d tmout=%d rstatus=%d"
  216. " wstatus=%d",
  217. dbg.cmd_debug_state,dbg.cmd_code,
  218. dbg.cmd_debug_write_len,
  219. dbg.cmd_debug_read_len,
  220. dbg.cmd_debug_write_pend,
  221. dbg.cmd_debug_read_pend,
  222. dbg.cmd_debug_timeout,
  223. dbg.cmd_debug_rstatus,
  224. dbg.cmd_debug_wstatus);
  225. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  226. }
  227. ccnt = scnprintf(buf,acnt,"\n");
  228. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  229. ccnt = scnprintf(
  230. buf,acnt,"driver flags: %s %s %s\n",
  231. (dbg.flag_init_ok ? "initialized" : "uninitialized"),
  232. (dbg.flag_ok ? "ok" : "fail"),
  233. (dbg.flag_disconnected ? "disconnected" : "connected"));
  234. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  235. ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
  236. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  237. ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags);
  238. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  239. ccnt = scnprintf(buf,acnt,"\n");
  240. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  241. ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
  242. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  243. ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags);
  244. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  245. ccnt = scnprintf(buf,acnt,"\n");
  246. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  247. ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
  248. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  249. ccnt = pvr2_i2c_report(hdw,buf,acnt);
  250. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  251. return bcnt;
  252. }
  253. int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
  254. char *buf,unsigned int acnt)
  255. {
  256. int bcnt = 0;
  257. int ccnt;
  258. unsigned long msk;
  259. int ret;
  260. u32 gpio_dir,gpio_in,gpio_out;
  261. ret = pvr2_hdw_is_hsm(hdw);
  262. ccnt = scnprintf(buf,acnt,"USB link speed: %s\n",
  263. (ret < 0 ? "FAIL" : (ret ? "high" : "full")));
  264. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  265. gpio_dir = 0; gpio_in = 0; gpio_out = 0;
  266. pvr2_hdw_gpio_get_dir(hdw,&gpio_dir);
  267. pvr2_hdw_gpio_get_out(hdw,&gpio_out);
  268. pvr2_hdw_gpio_get_in(hdw,&gpio_in);
  269. ccnt = scnprintf(buf,acnt,"GPIO state: dir=0x%x in=0x%x out=0x%x\n",
  270. gpio_dir,gpio_in,gpio_out);
  271. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  272. ccnt = scnprintf(buf,acnt,"Streaming is %s\n",
  273. pvr2_hdw_get_streaming(hdw) ? "on" : "off");
  274. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  275. msk = pvr2_hdw_subsys_get(hdw);
  276. ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
  277. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  278. ccnt = debugifc_print_mask(buf,acnt,msk,msk);
  279. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  280. ccnt = scnprintf(buf,acnt,"\n");
  281. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  282. ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
  283. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  284. ccnt = debugifc_print_mask(buf,acnt,~msk,msk);
  285. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  286. ccnt = scnprintf(buf,acnt,"\n");
  287. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  288. msk = pvr2_hdw_subsys_stream_get(hdw);
  289. ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: ");
  290. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  291. ccnt = debugifc_print_mask(buf,acnt,msk,msk);
  292. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  293. ccnt = scnprintf(buf,acnt,"\n");
  294. bcnt += ccnt; acnt -= ccnt; buf += ccnt;
  295. return bcnt;
  296. }
  297. static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
  298. unsigned int count)
  299. {
  300. const char *wptr;
  301. unsigned int wlen;
  302. unsigned int scnt;
  303. scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
  304. if (!scnt) return 0;
  305. count -= scnt; buf += scnt;
  306. if (!wptr) return 0;
  307. pvr2_trace(PVR2_TRACE_DEBUGIFC,"debugifc cmd: \"%.*s\"",wlen,wptr);
  308. if (debugifc_match_keyword(wptr,wlen,"reset")) {
  309. scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
  310. if (!scnt) return -EINVAL;
  311. count -= scnt; buf += scnt;
  312. if (!wptr) return -EINVAL;
  313. if (debugifc_match_keyword(wptr,wlen,"cpu")) {
  314. pvr2_hdw_cpureset_assert(hdw,!0);
  315. pvr2_hdw_cpureset_assert(hdw,0);
  316. return 0;
  317. } else if (debugifc_match_keyword(wptr,wlen,"bus")) {
  318. pvr2_hdw_device_reset(hdw);
  319. } else if (debugifc_match_keyword(wptr,wlen,"soft")) {
  320. return pvr2_hdw_cmd_powerup(hdw);
  321. } else if (debugifc_match_keyword(wptr,wlen,"deep")) {
  322. return pvr2_hdw_cmd_deep_reset(hdw);
  323. } else if (debugifc_match_keyword(wptr,wlen,"firmware")) {
  324. return pvr2_upload_firmware2(hdw);
  325. } else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
  326. return pvr2_hdw_cmd_decoder_reset(hdw);
  327. }
  328. return -EINVAL;
  329. } else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
  330. unsigned long msk = 0;
  331. unsigned long val = 0;
  332. if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
  333. pvr2_trace(PVR2_TRACE_DEBUGIFC,
  334. "debugifc parse error on subsys mask");
  335. return -EINVAL;
  336. }
  337. pvr2_hdw_subsys_bit_chg(hdw,msk,val);
  338. return 0;
  339. } else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) {
  340. unsigned long msk = 0;
  341. unsigned long val = 0;
  342. if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
  343. pvr2_trace(PVR2_TRACE_DEBUGIFC,
  344. "debugifc parse error on stream mask");
  345. return -EINVAL;
  346. }
  347. pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val);
  348. return 0;
  349. } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
  350. scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
  351. if (!scnt) return -EINVAL;
  352. count -= scnt; buf += scnt;
  353. if (!wptr) return -EINVAL;
  354. if (debugifc_match_keyword(wptr,wlen,"fetch")) {
  355. pvr2_hdw_cpufw_set_enabled(hdw,!0);
  356. return 0;
  357. } else if (debugifc_match_keyword(wptr,wlen,"done")) {
  358. pvr2_hdw_cpufw_set_enabled(hdw,0);
  359. return 0;
  360. } else {
  361. return -EINVAL;
  362. }
  363. } else if (debugifc_match_keyword(wptr,wlen,"gpio")) {
  364. int dir_fl = 0;
  365. int ret;
  366. u32 msk,val;
  367. scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
  368. if (!scnt) return -EINVAL;
  369. count -= scnt; buf += scnt;
  370. if (!wptr) return -EINVAL;
  371. if (debugifc_match_keyword(wptr,wlen,"dir")) {
  372. dir_fl = !0;
  373. } else if (!debugifc_match_keyword(wptr,wlen,"out")) {
  374. return -EINVAL;
  375. }
  376. scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
  377. if (!scnt) return -EINVAL;
  378. count -= scnt; buf += scnt;
  379. if (!wptr) return -EINVAL;
  380. ret = debugifc_parse_unsigned_number(wptr,wlen,&msk);
  381. if (ret) return ret;
  382. scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
  383. if (wptr) {
  384. ret = debugifc_parse_unsigned_number(wptr,wlen,&val);
  385. if (ret) return ret;
  386. } else {
  387. val = msk;
  388. msk = 0xffffffff;
  389. }
  390. if (dir_fl) {
  391. ret = pvr2_hdw_gpio_chg_dir(hdw,msk,val);
  392. } else {
  393. ret = pvr2_hdw_gpio_chg_out(hdw,msk,val);
  394. }
  395. return ret;
  396. }
  397. pvr2_trace(PVR2_TRACE_DEBUGIFC,
  398. "debugifc failed to recognize cmd: \"%.*s\"",wlen,wptr);
  399. return -EINVAL;
  400. }
  401. int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf,
  402. unsigned int count)
  403. {
  404. unsigned int bcnt = 0;
  405. int ret;
  406. while (count) {
  407. for (bcnt = 0; bcnt < count; bcnt++) {
  408. if (buf[bcnt] == '\n') break;
  409. }
  410. ret = pvr2_debugifc_do1cmd(hdw,buf,bcnt);
  411. if (ret < 0) return ret;
  412. if (bcnt < count) bcnt++;
  413. buf += bcnt;
  414. count -= bcnt;
  415. }
  416. return 0;
  417. }
  418. /*
  419. Stuff for Emacs to see, in order to encourage consistent editing style:
  420. *** Local Variables: ***
  421. *** mode: c ***
  422. *** fill-column: 75 ***
  423. *** tab-width: 8 ***
  424. *** c-basic-offset: 8 ***
  425. *** End: ***
  426. */