uhci-debug.h
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:13k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * UHCI-specific debugging code. Invaluable when something
  3.  * goes wrong, but don't get in my face.
  4.  *
  5.  * Kernel visible pointers are surrounded in []'s and bus
  6.  * visible pointers are surrounded in ()'s
  7.  *
  8.  * (C) Copyright 1999 Linus Torvalds
  9.  * (C) Copyright 1999-2001 Johannes Erdfelt
  10.  */
  11. #include <linux/config.h>
  12. #include <linux/kernel.h>
  13. #include <linux/proc_fs.h>
  14. #include <asm/io.h>
  15. #include "uhci.h"
  16. /* Handle REALLY large printk's so we don't overflow buffers */
  17. static void inline lprintk(char *buf)
  18. {
  19. char *p;
  20. /* Just write one line at a time */
  21. while (buf) {
  22. p = strchr(buf, 'n');
  23. if (p)
  24. *p = 0;
  25. printk("%sn", buf);
  26. buf = p;
  27. if (buf)
  28. buf++;
  29. }
  30. }
  31. static int inline uhci_is_skeleton_td(struct uhci *uhci, struct uhci_td *td)
  32. {
  33. int i;
  34. for (i = 0; i < UHCI_NUM_SKELTD; i++)
  35. if (td == uhci->skeltd[i])
  36. return 1;
  37. return 0;
  38. }
  39. static int inline uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
  40. {
  41. int i;
  42. for (i = 0; i < UHCI_NUM_SKELQH; i++)
  43. if (qh == uhci->skelqh[i])
  44. return 1;
  45. return 0;
  46. }
  47. static int uhci_show_td(struct uhci_td *td, char *buf, int len, int space)
  48. {
  49. char *out = buf;
  50. char *spid;
  51. /* Try to make sure there's enough memory */
  52. if (len < 160)
  53. return 0;
  54. out += sprintf(out, "%*s[%p] link (%08x) ", space, "", td, td->link);
  55. out += sprintf(out, "e%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
  56. ((td->status >> 27) & 3),
  57. (td->status & TD_CTRL_SPD) ?      "SPD " : "",
  58. (td->status & TD_CTRL_LS) ?       "LS " : "",
  59. (td->status & TD_CTRL_IOC) ?      "IOC " : "",
  60. (td->status & TD_CTRL_ACTIVE) ?   "Active " : "",
  61. (td->status & TD_CTRL_STALLED) ?  "Stalled " : "",
  62. (td->status & TD_CTRL_DBUFERR) ?  "DataBufErr " : "",
  63. (td->status & TD_CTRL_BABBLE) ?   "Babble " : "",
  64. (td->status & TD_CTRL_NAK) ?      "NAK " : "",
  65. (td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "",
  66. (td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "",
  67. td->status & 0x7ff);
  68. switch (td->info & 0xff) {
  69. case USB_PID_SETUP:
  70. spid = "SETUP";
  71. break;
  72. case USB_PID_OUT:
  73. spid = "OUT";
  74. break;
  75. case USB_PID_IN:
  76. spid = "IN";
  77. break;
  78. default:
  79. spid = "?";
  80. break;
  81. }
  82. out += sprintf(out, "MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ",
  83. td->info >> 21,
  84. ((td->info >> 19) & 1),
  85. (td->info >> 15) & 15,
  86. (td->info >> 8) & 127,
  87. (td->info & 0xff),
  88. spid);
  89. out += sprintf(out, "(buf=%08x)n", td->buffer);
  90. return out - buf;
  91. }
  92. static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
  93. {
  94. char *out = buf;
  95. /* Try to make sure there's enough memory */
  96. if (len < 80)
  97. return 0;
  98. out += sprintf(out, "  stat%d     =     %04x   %s%s%s%s%s%s%s%sn",
  99. port,
  100. status,
  101. (status & USBPORTSC_SUSP) ? "PortSuspend " : "",
  102. (status & USBPORTSC_PR) ?   "PortReset " : "",
  103. (status & USBPORTSC_LSDA) ? "LowSpeed " : "",
  104. (status & USBPORTSC_RD) ?   "ResumeDetect " : "",
  105. (status & USBPORTSC_PEC) ?  "EnableChange " : "",
  106. (status & USBPORTSC_PE) ?   "PortEnabled " : "",
  107. (status & USBPORTSC_CSC) ?  "ConnectChange " : "",
  108. (status & USBPORTSC_CCS) ?  "PortConnected " : "");
  109. return out - buf;
  110. }
  111. static int uhci_show_status(struct uhci *uhci, char *buf, int len)
  112. {
  113. char *out = buf;
  114. unsigned int io_addr = uhci->io_addr;
  115. unsigned short usbcmd, usbstat, usbint, usbfrnum;
  116. unsigned int flbaseadd;
  117. unsigned char sof;
  118. unsigned short portsc1, portsc2;
  119. /* Try to make sure there's enough memory */
  120. if (len < 80 * 6)
  121. return 0;
  122. usbcmd    = inw(io_addr + 0);
  123. usbstat   = inw(io_addr + 2);
  124. usbint    = inw(io_addr + 4);
  125. usbfrnum  = inw(io_addr + 6);
  126. flbaseadd = inl(io_addr + 8);
  127. sof       = inb(io_addr + 12);
  128. portsc1   = inw(io_addr + 16);
  129. portsc2   = inw(io_addr + 18);
  130. out += sprintf(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%sn",
  131. usbcmd,
  132. (usbcmd & USBCMD_MAXP) ?    "Maxp64 " : "Maxp32 ",
  133. (usbcmd & USBCMD_CF) ?      "CF " : "",
  134. (usbcmd & USBCMD_SWDBG) ?   "SWDBG " : "",
  135. (usbcmd & USBCMD_FGR) ?     "FGR " : "",
  136. (usbcmd & USBCMD_EGSM) ?    "EGSM " : "",
  137. (usbcmd & USBCMD_GRESET) ?  "GRESET " : "",
  138. (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "",
  139. (usbcmd & USBCMD_RS) ?      "RS " : "");
  140. out += sprintf(out, "  usbstat   =     %04x   %s%s%s%s%s%sn",
  141. usbstat,
  142. (usbstat & USBSTS_HCH) ?    "HCHalted " : "",
  143. (usbstat & USBSTS_HCPE) ?   "HostControllerProcessError " : "",
  144. (usbstat & USBSTS_HSE) ?    "HostSystemError " : "",
  145. (usbstat & USBSTS_RD) ?     "ResumeDetect " : "",
  146. (usbstat & USBSTS_ERROR) ?  "USBError " : "",
  147. (usbstat & USBSTS_USBINT) ? "USBINT " : "");
  148. out += sprintf(out, "  usbint    =     %04xn", usbint);
  149. out += sprintf(out, "  usbfrnum  =   (%d)%03xn", (usbfrnum >> 10) & 1,
  150. 0xfff & (4*(unsigned int)usbfrnum));
  151. out += sprintf(out, "  flbaseadd = %08xn", flbaseadd);
  152. out += sprintf(out, "  sof       =       %02xn", sof);
  153. out += uhci_show_sc(1, portsc1, out, len - (out - buf));
  154. out += uhci_show_sc(2, portsc2, out, len - (out - buf));
  155. return out - buf;
  156. }
  157. static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
  158. {
  159. char *out = buf;
  160. struct urb_priv *urbp;
  161. struct list_head *head, *tmp;
  162. struct uhci_td *td;
  163. int i = 0, checked = 0, prevactive = 0;
  164. /* Try to make sure there's enough memory */
  165. if (len < 80 * 6)
  166. return 0;
  167. out += sprintf(out, "%*s[%p] link (%08x) element (%08x)n", space, "",
  168. qh, qh->link, qh->element);
  169. if (qh->element & UHCI_PTR_QH)
  170. out += sprintf(out, "%*s  Element points to QH (bug?)n", space, "");
  171. if (qh->element & UHCI_PTR_DEPTH)
  172. out += sprintf(out, "%*s  Depth traversen", space, "");
  173. if (qh->element & 8)
  174. out += sprintf(out, "%*s  Bit 3 set (bug?)n", space, "");
  175. if (!(qh->element & ~(UHCI_PTR_QH | UHCI_PTR_DEPTH)))
  176. out += sprintf(out, "%*s  Element is NULL (bug?)n", space, "");
  177. if (!qh->urbp) {
  178. out += sprintf(out, "%*s  urbp == NULLn", space, "");
  179. goto out;
  180. }
  181. urbp = qh->urbp;
  182. head = &urbp->td_list;
  183. tmp = head->next;
  184. td = list_entry(tmp, struct uhci_td, list);
  185. if (td->dma_handle != (qh->element & ~UHCI_PTR_BITS))
  186. out += sprintf(out, "%*s Element != First TDn", space, "");
  187. while (tmp != head) {
  188. struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
  189. tmp = tmp->next;
  190. out += sprintf(out, "%*s%d: ", space + 2, "", i++);
  191. out += uhci_show_td(td, out, len - (out - buf), 0);
  192. if (i > 10 && !checked && prevactive && tmp != head &&
  193.     debug <= 2) {
  194. struct list_head *ntmp = tmp;
  195. struct uhci_td *ntd = td;
  196. int active = 1, ni = i;
  197. checked = 1;
  198. while (ntmp != head && ntmp->next != head && active) {
  199. ntd = list_entry(ntmp, struct uhci_td, list);
  200. ntmp = ntmp->next;
  201. active = ntd->status & TD_CTRL_ACTIVE;
  202. ni++;
  203. }
  204. if (active && ni > i) {
  205. out += sprintf(out, "%*s[skipped %d active TD's]n", space, "", ni - i);
  206. tmp = ntmp;
  207. td = ntd;
  208. i = ni;
  209. }
  210. }
  211. prevactive = td->status & TD_CTRL_ACTIVE;
  212. }
  213. if (list_empty(&urbp->queue_list) || urbp->queued)
  214. goto out;
  215. out += sprintf(out, "%*sQueued QH's:n", -space, "--");
  216. head = &urbp->queue_list;
  217. tmp = head->next;
  218. while (tmp != head) {
  219. struct urb_priv *nurbp = list_entry(tmp, struct urb_priv,
  220. queue_list);
  221. tmp = tmp->next;
  222. out += uhci_show_qh(nurbp->qh, out, len - (out - buf), space);
  223. }
  224. out:
  225. return out - buf;
  226. }
  227. static const char *td_names[] = {"skel_int1_td", "skel_int2_td",
  228.  "skel_int4_td", "skel_int8_td",
  229.  "skel_int16_td", "skel_int32_td",
  230.  "skel_int64_td", "skel_int128_td",
  231.  "skel_int256_td", "skel_term_td" };
  232. static const char *qh_names[] = { "skel_ls_control_qh", "skel_hs_control_qh",
  233.   "skel_bulk_qh", "skel_term_qh" };
  234. #define show_frame_num()
  235. if (!shown) {
  236.   shown = 1;
  237.   out += sprintf(out, "- Frame %dn", i); 
  238. }
  239. #define show_td_name()
  240. if (!shown) {
  241.   shown = 1;
  242.   out += sprintf(out, "- %sn", td_names[i]); 
  243. }
  244. #define show_qh_name()
  245. if (!shown) {
  246.   shown = 1;
  247.   out += sprintf(out, "- %sn", qh_names[i]); 
  248. }
  249. static int uhci_sprint_schedule(struct uhci *uhci, char *buf, int len)
  250. {
  251. char *out = buf;
  252. int i;
  253. struct uhci_qh *qh;
  254. struct uhci_td *td;
  255. struct list_head *tmp, *head;
  256. out += sprintf(out, "HC statusn");
  257. out += uhci_show_status(uhci, out, len - (out - buf));
  258. out += sprintf(out, "Frame Listn");
  259. for (i = 0; i < UHCI_NUMFRAMES; ++i) {
  260. int shown = 0;
  261. td = uhci->fl->frame_cpu[i];
  262. if (!td)
  263. continue;
  264. if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) {
  265. show_frame_num();
  266. out += sprintf(out, "    frame list does not match td->dma_handle!n");
  267. }
  268. if (uhci_is_skeleton_td(uhci, td))
  269. continue;
  270. show_frame_num();
  271. head = &td->fl_list;
  272. tmp = head;
  273. do {
  274. td = list_entry(tmp, struct uhci_td, fl_list);
  275. tmp = tmp->next;
  276. out += uhci_show_td(td, out, len - (out - buf), 4);
  277. } while (tmp != head);
  278. }
  279. out += sprintf(out, "Skeleton TD'sn");
  280. for (i = UHCI_NUM_SKELTD - 1; i >= 0; i--) {
  281. int shown = 0;
  282. td = uhci->skeltd[i];
  283. if (debug > 1) {
  284. show_td_name();
  285. out += uhci_show_td(td, out, len - (out - buf), 4);
  286. }
  287. if (list_empty(&td->fl_list)) {
  288. /* TD 0 is the int1 TD and links to control_ls_qh */
  289. if (!i) {
  290. if (td->link !=
  291.     (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH)) {
  292. show_td_name();
  293. out += sprintf(out, "    skeleton TD not linked to ls_control QH!n");
  294. }
  295. } else if (i < 9) {
  296. if (td->link != uhci->skeltd[i - 1]->dma_handle) {
  297. show_td_name();
  298. out += sprintf(out, "    skeleton TD not linked to next skeleton TD!n");
  299. }
  300. } else {
  301. show_td_name();
  302. if (td->link != td->dma_handle)
  303. out += sprintf(out, "    skel_term_td does not link to selfn");
  304. /* Don't show it twice */
  305. if (debug <= 1)
  306. out += uhci_show_td(td, out, len - (out - buf), 4);
  307. }
  308. continue;
  309. }
  310. show_td_name();
  311. head = &td->fl_list;
  312. tmp = head->next;
  313. while (tmp != head) {
  314. td = list_entry(tmp, struct uhci_td, fl_list);
  315. tmp = tmp->next;
  316. out += uhci_show_td(td, out, len - (out - buf), 4);
  317. }
  318. if (!i) {
  319. if (td->link !=
  320.     (uhci->skel_ls_control_qh->dma_handle | UHCI_PTR_QH))
  321. out += sprintf(out, "    last TD not linked to ls_control QH!n");
  322. } else if (i < 9) {
  323. if (td->link != uhci->skeltd[i - 1]->dma_handle)
  324. out += sprintf(out, "    last TD not linked to next skeleton!n");
  325. }
  326. }
  327. out += sprintf(out, "Skeleton QH'sn");
  328. for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
  329. int shown = 0;
  330. qh = uhci->skelqh[i];
  331. if (debug > 1) {
  332. show_qh_name();
  333. out += uhci_show_qh(qh, out, len - (out - buf), 4);
  334. }
  335. /* QH 3 is the Terminating QH, it's different */
  336. if (i == 3) {
  337. if (qh->link != UHCI_PTR_TERM) {
  338. show_qh_name();
  339. out += sprintf(out, "    bandwidth reclamation on!n");
  340. }
  341. if (qh->element != uhci->skel_term_td->dma_handle) {
  342. show_qh_name();
  343. out += sprintf(out, "    skel_term_qh element is not set to skel_term_tdn");
  344. }
  345. }
  346. if (list_empty(&qh->list)) {
  347. if (i < 3) {
  348. if (qh->link !=
  349.     (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH)) {
  350. show_qh_name();
  351. out += sprintf(out, "    skeleton QH not linked to next skeleton QH!n");
  352. }
  353. }
  354. continue;
  355. }
  356. show_qh_name();
  357. head = &qh->list;
  358. tmp = head->next;
  359. while (tmp != head) {
  360. qh = list_entry(tmp, struct uhci_qh, list);
  361. tmp = tmp->next;
  362. out += uhci_show_qh(qh, out, len - (out - buf), 4);
  363. }
  364. if (i < 3) {
  365. if (qh->link !=
  366.     (uhci->skelqh[i + 1]->dma_handle | UHCI_PTR_QH))
  367. out += sprintf(out, "    last QH not linked to next skeleton!n");
  368. }
  369. }
  370. return out - buf;
  371. }
  372. #ifdef CONFIG_PROC_FS
  373. #define MAX_OUTPUT (PAGE_SIZE * 8)
  374. static struct proc_dir_entry *uhci_proc_root = NULL;
  375. struct uhci_proc {
  376. int size;
  377. char *data;
  378. struct uhci *uhci;
  379. };
  380. static int uhci_proc_open(struct inode *inode, struct file *file)
  381. {
  382. const struct proc_dir_entry *dp = inode->u.generic_ip;
  383. struct uhci *uhci = dp->data;
  384. struct uhci_proc *up;
  385. unsigned long flags;
  386. int ret = -ENOMEM;
  387. lock_kernel();
  388. up = kmalloc(sizeof(*up), GFP_KERNEL);
  389. if (!up)
  390. goto out;
  391. up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
  392. if (!up->data) {
  393. kfree(up);
  394. goto out;
  395. }
  396. spin_lock_irqsave(&uhci->frame_list_lock, flags);
  397. up->size = uhci_sprint_schedule(uhci, up->data, MAX_OUTPUT);
  398. spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
  399. file->private_data = up;
  400. ret = 0;
  401. out:
  402. unlock_kernel();
  403. return ret;
  404. }
  405. static loff_t uhci_proc_lseek(struct file *file, loff_t off, int whence)
  406. {
  407. struct uhci_proc *up = file->private_data;
  408. loff_t new;
  409. switch (whence) {
  410. case 0:
  411. new = off;
  412. break;
  413. case 1:
  414. new = file->f_pos + off;
  415. break;
  416. case 2:
  417. default:
  418. return -EINVAL;
  419. }
  420. if (new < 0 || new > up->size)
  421. return -EINVAL;
  422. return (file->f_pos = new);
  423. }
  424. static ssize_t uhci_proc_read(struct file *file, char *buf, size_t nbytes,
  425. loff_t *ppos)
  426. {
  427. struct uhci_proc *up = file->private_data;
  428. unsigned int pos;
  429. unsigned int size;
  430. pos = *ppos;
  431. size = up->size;
  432. if (pos >= size)
  433. return 0;
  434. if (nbytes >= size)
  435. nbytes = size;
  436. if (pos + nbytes > size)
  437. nbytes = size - pos;
  438. if (!access_ok(VERIFY_WRITE, buf, nbytes))
  439. return -EINVAL;
  440. copy_to_user(buf, up->data + pos, nbytes);
  441. *ppos += nbytes;
  442. return nbytes;
  443. }
  444. static int uhci_proc_release(struct inode *inode, struct file *file)
  445. {
  446. struct uhci_proc *up = file->private_data;
  447. kfree(up->data);
  448. kfree(up);
  449. return 0;
  450. }
  451. static struct file_operations uhci_proc_operations = {
  452. open: uhci_proc_open,
  453. llseek: uhci_proc_lseek,
  454. read: uhci_proc_read,
  455. // write: uhci_proc_write,
  456. release: uhci_proc_release,
  457. };
  458. #endif