Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1101 lines
24 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. USBLOG.c
  5. Abstract:
  6. WinDbg Extension Api
  7. Author:
  8. Chris Robinson (crobins) February 1999
  9. Environment:
  10. User Mode.
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #ifndef MAKE_SYMBOL
  15. #define MAKE_SYMBOL(m, s) #m "!" #s
  16. #endif
  17. #define DUMP_STRING(s) dprintf((s))
  18. #define DUMP_DWORD(d) dprintf("0x%08x", (d))
  19. #define DUMP_ADDRESS(a) dprintf("0x%08p", (a))
  20. #define END_LINE() dprintf("\n")
  21. #define TRACE_SPEW
  22. #define DECLARE_LOG(logname, name, start, end, ptr, lines, desc) \
  23. static struct _USB_LOG logname = { name, start, end, ptr, \
  24. 0, 0, 0, 0, \
  25. 0, 0, lines, desc };
  26. #define DEFAULT_LINES_TO_DUMP 16
  27. #define TAG_CHAR_LENGTH 4
  28. #define TAG_STRING_LENGTH TAG_CHAR_LENGTH+1
  29. #define LOG_SEARCH_DELIMS ","
  30. #define LogHasRolledOver(log) (IsValidEntry((log) -> LogStart) && ((log) -> LogStart != (log) -> LogPtr))
  31. #define CalcNumberLines(pe1, pe2) (((pe2) - (pe1)) + 1)
  32. #define TAG(str) dprintf("%-6s", str)
  33. #define PARAM(str) dprintf("%-12s", str)
  34. #define DESC(str) dprintf("%-12s", str)
  35. #define USBHUB_LOG_NAME USBHUBLog
  36. #define USBD_LOG_NAME USBDLog
  37. #define OHCI_LOG_NAME OHCILog
  38. #define UHCD_LOG_NAME UHCDLog
  39. #define USBHUB_LNAME "USBHUB"
  40. #define USBHUB_START MAKE_SYMBOL(usbhub, hublstart)
  41. #define USBHUB_END MAKE_SYMBOL(usbhub, hublend)
  42. #define USBHUB_PTR MAKE_SYMBOL(usbhub, hublptr)
  43. #define USBD_LNAME "USBD"
  44. #define USBD_START MAKE_SYMBOL(usbd, lstart)
  45. #define USBD_END MAKE_SYMBOL(usbd, lend)
  46. #define USBD_PTR MAKE_SYMBOL(usbd, lptr)
  47. #define OHCI_LNAME "OpenHCI"
  48. #define OHCI_START MAKE_SYMBOL(openhci, ohcilstart)
  49. #define OHCI_END MAKE_SYMBOL(openhci, ohcilend)
  50. #define OHCI_PTR MAKE_SYMBOL(openhci, ohcilptr)
  51. #define UHCD_LNAME "UHCD"
  52. #define UHCD_START MAKE_SYMBOL(uhcd, HCDLStart)
  53. #define UHCD_END MAKE_SYMBOL(uhcd, HCDLEnd)
  54. #define UHCD_PTR MAKE_SYMBOL(uhcd, HCDLPtr)
  55. //
  56. // USBLOG typedefs
  57. //
  58. typedef union {
  59. ULONG TagValue;
  60. CHAR TagChars[TAG_CHAR_LENGTH];
  61. } USBLOG_TAG_READ, *PUSBLOG_TAG_READ;
  62. typedef struct _usb_log_entry {
  63. USBLOG_TAG_READ Tag;
  64. DWORD Param1;
  65. DWORD Param2;
  66. DWORD Param3;
  67. } USB_LOG_ENTRY, *PUSB_LOG_ENTRY;
  68. typedef PCHAR (DESC_ROUTINE) (
  69. ULONG64 Entry
  70. );
  71. typedef DESC_ROUTINE *PDESC_ROUTINE;
  72. typedef struct _USB_LOG {
  73. PCHAR LogName;
  74. PCHAR LogStartName;
  75. PCHAR LogEndName;
  76. PCHAR LogPtrName;
  77. ULONG64 LogStart;
  78. ULONG64 LogEnd;
  79. ULONG64 LogPtr;
  80. ULONG64 LastSearchResult;
  81. ULONG64 LogCurrViewTop;
  82. ULONG64 LogCurrViewBottom;
  83. LONG LinesToDump;
  84. PDESC_ROUTINE DescRoutine;
  85. } USB_LOG, *PUSB_LOG;
  86. typedef struct _USBLOG_ARGS {
  87. ULONG64 Address;
  88. LONG NumberLines;
  89. PCHAR SearchString;
  90. BOOLEAN ResetLog;
  91. BOOLEAN SearchLog;
  92. } USBLOG_ARGS, *PUSBLOG_ARGS;
  93. //
  94. // Add logging function declarations
  95. //
  96. VOID USBLOG_DoLog(PUSB_LOG LogToDump, PCSTR Args);
  97. VOID USBLOG_Usage(void);
  98. VOID USBLOG_GetParams(PCSTR Args, PUSBLOG_ARGS ParsedArgs);
  99. ULONG64 USBLOG_SearchLog(PUSB_LOG Log, ULONG64 SearchBegin, PCHAR SearchString);
  100. VOID DumpDefaultLogHeader(VOID);
  101. BOOLEAN DumpLog(PUSB_LOG, BOOLEAN, BOOLEAN);
  102. BOOLEAN ResetLog(PUSB_LOG);
  103. #define GetMostRecentEntry(l) ((l) -> LogPtr)
  104. ULONG64 GetEntryBefore(PUSB_LOG, ULONG64);
  105. ULONG64 GetEntryAfter(PUSB_LOG, ULONG64);
  106. #define IsMostRecentEntry(l, e) ((e) == (l) -> LogPtr)
  107. #define IsLeastRecentEntry(l, e) (((LogHasRolledOver((l))) \
  108. ? ( (e) == ((l) -> LogPtr - 1)) \
  109. : ( (e) == ((l) -> LogEnd))) )
  110. VOID GetLogEntryTag(ULONG64, PUSBLOG_TAG_READ);
  111. VOID GetLogEntryParams(ULONG64, ULONG64 *, ULONG64 *, ULONG64 *);
  112. ULONG64 SearchLogForTag(PUSB_LOG, ULONG64, ULONG, USBLOG_TAG_READ[]);
  113. #define GetLastSearchResult(l) ((l) -> LastSearchResult)
  114. #define SetLastSearchResult(l, a) ((l) -> LastSearchResult = (a))
  115. #define SetLinesToDump(l, n) ((l) -> LinesToDump = (n))
  116. #define GetLinesToDump(l) ((l) -> LinesToDump)
  117. VOID ConvertStringToTag(PCHAR, PUSBLOG_TAG_READ);
  118. VOID ConvertTagToString(PUSBLOG_TAG_READ, PCHAR, ULONG);
  119. BOOLEAN IsValidEntry(ULONG64);
  120. VOID GetCurrentView(PUSB_LOG, ULONG64 *, ULONG64 *);
  121. VOID SetCurrentView(PUSB_LOG, ULONG64, ULONG64);
  122. VOID LogViewScrollUp(PUSB_LOG);
  123. VOID LogViewScrollDown(PUSB_LOG);
  124. VOID DisplayCurrentView(PUSB_LOG);
  125. VOID DisplayHeader();
  126. //
  127. // Global log structure declarations
  128. //
  129. DECLARE_LOG(USBHUB_LOG_NAME, USBHUB_LNAME, USBHUB_START, USBHUB_END, USBHUB_PTR,
  130. DEFAULT_LINES_TO_DUMP, NULL);
  131. DECLARE_LOG(USBD_LOG_NAME, USBD_LNAME, USBD_START, USBD_END, USBD_PTR,
  132. DEFAULT_LINES_TO_DUMP, NULL);
  133. DECLARE_LOG(OHCI_LOG_NAME, OHCI_LNAME, OHCI_START, OHCI_END, OHCI_PTR,
  134. DEFAULT_LINES_TO_DUMP, NULL);
  135. DECLARE_LOG(UHCD_LOG_NAME, UHCD_LNAME, UHCD_START, UHCD_END, UHCD_PTR,
  136. DEFAULT_LINES_TO_DUMP, NULL);
  137. //
  138. // Define each of these, which is relatively simple
  139. //
  140. DECLARE_API( usblog )
  141. /*++
  142. Routine Description:
  143. Dumps a HID Preparsed Data blob
  144. Arguments:
  145. args - Address flags
  146. Return Value:
  147. None
  148. --*/
  149. {
  150. ULONG index;
  151. UCHAR logName[32];
  152. UCHAR buffer[256];
  153. logName[0] = '\0';
  154. memset(buffer, '\0', sizeof(buffer));
  155. if (!*args)
  156. {
  157. USBLOG_Usage();
  158. }
  159. else
  160. {
  161. if (!sscanf(args, "%s %256c", logName, buffer)) {
  162. USBLOG_Usage();
  163. }
  164. }
  165. index = 0;
  166. while ('\0' != logName[index])
  167. {
  168. logName[index] = (UCHAR) toupper(logName[index]);
  169. index++;
  170. }
  171. if (!strcmp(logName, "USBHUB"))
  172. {
  173. USBLOG_DoLog(&(USBHUB_LOG_NAME), buffer);
  174. }
  175. else if (!strcmp(logName, "USBD"))
  176. {
  177. USBLOG_DoLog(&(USBD_LOG_NAME), buffer);
  178. }
  179. else if (!strcmp(logName, "OPENHCI"))
  180. {
  181. USBLOG_DoLog(&(OHCI_LOG_NAME), buffer);
  182. }
  183. else if (!strcmp(logName, "UHCD"))
  184. {
  185. USBLOG_DoLog(&(UHCD_LOG_NAME), buffer);
  186. }
  187. else
  188. {
  189. dprintf("Unknown USB log type!\n");
  190. USBLOG_Usage();
  191. }
  192. return S_OK;
  193. }
  194. VOID
  195. USBLOG_DoLog(
  196. PUSB_LOG LogToDump,
  197. PCSTR Args
  198. )
  199. {
  200. BOOLEAN atEnd;
  201. BOOLEAN dumpSuccess;
  202. USBLOG_ARGS logArgs;
  203. BOOLEAN doDump;
  204. BOOLEAN doScroll;
  205. ULONG64 searchAddress;
  206. TRACE_SPEW("Entering USBLOG_DoLog with args %s\n", Args);
  207. doDump = TRUE;
  208. doScroll = TRUE;
  209. //
  210. // Parse the arguments to the logging function
  211. //
  212. USBLOG_GetParams(Args, &logArgs);
  213. //
  214. // Analyze the params and modify the log structure if need be
  215. //
  216. if (0 != logArgs.NumberLines)
  217. {
  218. SetLinesToDump(LogToDump, logArgs.NumberLines);
  219. }
  220. if (0 != logArgs.Address)
  221. {
  222. if (!logArgs.SearchLog)
  223. {
  224. if (GetLinesToDump(LogToDump) > 0)
  225. {
  226. SetCurrentView(LogToDump, logArgs.Address, 0);
  227. }
  228. else
  229. {
  230. SetCurrentView(LogToDump, 0, logArgs.Address);
  231. }
  232. doScroll = FALSE;
  233. }
  234. }
  235. if (logArgs.ResetLog)
  236. {
  237. ResetLog(LogToDump);
  238. doScroll = FALSE;
  239. }
  240. if (logArgs.SearchLog)
  241. {
  242. if (0 == logArgs.Address)
  243. {
  244. searchAddress = GetLastSearchResult(LogToDump);
  245. if (0 == searchAddress)
  246. {
  247. searchAddress = GetMostRecentEntry(LogToDump);
  248. }
  249. }
  250. else
  251. {
  252. searchAddress = logArgs.Address;
  253. }
  254. searchAddress = USBLOG_SearchLog(LogToDump,
  255. searchAddress,
  256. logArgs.SearchString);
  257. if (0 != searchAddress)
  258. {
  259. SetLastSearchResult(LogToDump, searchAddress);
  260. SetCurrentView(LogToDump, searchAddress, 0);
  261. doScroll = FALSE;
  262. }
  263. else
  264. {
  265. dprintf("Couldn't find any such tag(s)\n");
  266. doDump = FALSE;
  267. }
  268. }
  269. if (doDump)
  270. {
  271. dumpSuccess = DumpLog(LogToDump, FALSE, doScroll);
  272. if (!dumpSuccess)
  273. {
  274. dprintf("Error dumping log\n");
  275. }
  276. }
  277. return;
  278. }
  279. VOID
  280. USBLOG_GetParams(
  281. IN PCSTR Args,
  282. OUT PUSBLOG_ARGS ParsedArgs
  283. )
  284. {
  285. PCHAR arg;
  286. PCHAR args;
  287. CHAR argDelims[] = " \t\n";
  288. //
  289. // Initialize the arguments structure first
  290. //
  291. memset(ParsedArgs, 0x00, sizeof(USBLOG_ARGS));
  292. //
  293. // Setup the argument string so that it's not a const anymore which
  294. // eliminates compiler errors.
  295. //
  296. args = (PCHAR) Args;
  297. //
  298. // The command line for !log is the following:
  299. // !log [address] [-r] [-s searchstring] [-l n]
  300. //
  301. // The argument parsing will assume these can be entered in any order,
  302. // so we'll simply examine each argument until there are no more
  303. // arguments. The main loop will look for either an address or an
  304. // option. If it finds either, it processes as necessary. Otherwise,
  305. // the argument is simply ignored.
  306. //
  307. arg = strtok(args, argDelims);
  308. while (NULL != arg) {
  309. TRACE_SPEW("Analyzing usblog arg: %s\n", arg);
  310. //
  311. // Check to see if this is an option or not
  312. //
  313. if ('-' != *arg)
  314. {
  315. //
  316. // No, then it must be an address, call GetExpression
  317. //
  318. ParsedArgs -> Address = GetExpression(arg);
  319. //
  320. // Assume user competence and store the result...
  321. // Add the value to the the ParsedArgs structure.
  322. // Note that if > 1 address is given, this function
  323. // simply uses the last one specified
  324. //
  325. }
  326. else
  327. {
  328. //
  329. // OK, it's an option...Process appropriately
  330. //
  331. switch (*(arg+1))
  332. {
  333. //
  334. // Reset Log
  335. //
  336. case 'r':
  337. ParsedArgs -> ResetLog = TRUE;
  338. break;
  339. //
  340. // Set lines to display
  341. //
  342. case 'l':
  343. arg = strtok(NULL, argDelims);
  344. if (NULL != arg)
  345. {
  346. //
  347. // Assume user competence and get the decimal string
  348. //
  349. if (!sscanf(arg, "%d", &(ParsedArgs -> NumberLines))) {
  350. ParsedArgs -> NumberLines = 0;
  351. }
  352. TRACE_SPEW("Parsed -l command with %d lines\n",
  353. ParsedArgs -> NumberLines);
  354. }
  355. break;
  356. //
  357. // Search the log
  358. //
  359. case 's':
  360. ParsedArgs -> SearchLog = TRUE;
  361. ParsedArgs -> SearchString = strtok(NULL, argDelims);
  362. break;
  363. default:
  364. dprintf("Unknown option %c\n", *(arg+1));
  365. break;
  366. }
  367. }
  368. arg = strtok(NULL, argDelims);
  369. }
  370. return;
  371. }
  372. ULONG64
  373. USBLOG_SearchLog(
  374. PUSB_LOG Log,
  375. ULONG64 SearchBegin,
  376. PCHAR SearchString
  377. )
  378. {
  379. ULONG64 firstFoundEntry;
  380. USBLOG_TAG_READ tagArray[32];
  381. ULONG index;
  382. PCHAR searchToken;
  383. TRACE_SPEW("Entering USBLOG_SearchLog looking for %s\n", SearchString);
  384. index = 0;
  385. firstFoundEntry = 0;
  386. searchToken = strtok(SearchString, LOG_SEARCH_DELIMS);
  387. while (index < 32 && NULL != searchToken)
  388. {
  389. TRACE_SPEW("Adding %s to tag array\n", searchToken);
  390. ConvertStringToTag(searchToken, &(tagArray[index++]));
  391. searchToken = strtok(NULL, LOG_SEARCH_DELIMS);
  392. }
  393. if (index > 0)
  394. {
  395. firstFoundEntry = SearchLogForTag(Log, SearchBegin, index, tagArray);
  396. }
  397. return (firstFoundEntry);
  398. }
  399. //
  400. // Local logging function definitions.
  401. //
  402. BOOLEAN
  403. DumpLog(
  404. IN PUSB_LOG Log,
  405. IN BOOLEAN StartFromTop,
  406. IN BOOLEAN Scroll
  407. )
  408. {
  409. ULONG lineCount;
  410. BOOLEAN resetStatus;
  411. ULONG64 currViewTop;
  412. ULONG64 currViewBottom;
  413. //
  414. // Check if the log has been opened/reset yet
  415. //
  416. GetCurrentView(Log, &currViewTop, &currViewBottom);
  417. if (0 == currViewTop || StartFromTop)
  418. {
  419. //
  420. // Reset the log and return FALSE if the reset failed
  421. //
  422. resetStatus = ResetLog(Log);
  423. if (!resetStatus)
  424. {
  425. return (FALSE);
  426. }
  427. Scroll = FALSE;
  428. }
  429. //
  430. // Call the log's dump routine based on the direction
  431. //
  432. if (Scroll)
  433. {
  434. TRACE_SPEW("Checking lines to dump: %d\n", Log -> LinesToDump);
  435. if (Log -> LinesToDump < 0)
  436. {
  437. LogViewScrollUp(Log);
  438. }
  439. else
  440. {
  441. LogViewScrollDown(Log);
  442. }
  443. }
  444. DisplayCurrentView(Log);
  445. return (TRUE);
  446. }
  447. BOOLEAN
  448. ResetLog(
  449. IN PUSB_LOG Log
  450. )
  451. {
  452. ULONG bytesRead;
  453. ULONG64 symbolAddress;
  454. ULONG readStatus;
  455. //
  456. // Get the address of the start symbol, the end symbol, and the
  457. // current pointer symbol
  458. //
  459. symbolAddress = GetExpression(Log -> LogStartName);
  460. if (0 != symbolAddress)
  461. {
  462. if (!ReadPointer(symbolAddress, &(Log -> LogStart)))
  463. {
  464. dprintf("Unable to read %p\n", symbolAddress);
  465. Log -> LogStart = 0;
  466. }
  467. }
  468. symbolAddress = GetExpression(Log -> LogEndName);
  469. if (0 != symbolAddress)
  470. {
  471. if (!ReadPointer(symbolAddress, &(Log -> LogEnd)))
  472. {
  473. dprintf("Unable to read %p\n", symbolAddress);
  474. Log -> LogEnd = 0;
  475. }
  476. }
  477. symbolAddress = GetExpression(Log -> LogPtrName);
  478. if (0 != symbolAddress)
  479. {
  480. if (!ReadPointer(symbolAddress, &(Log -> LogPtr)))
  481. {
  482. dprintf("Unable to read %p\n", symbolAddress);
  483. Log -> LogPtr= 0;
  484. }
  485. }
  486. if ( (0 == Log -> LogStart) ||
  487. (0 == Log -> LogEnd) ||
  488. (0 == Log -> LogPtr) )
  489. {
  490. dprintf("Unable to reset log\n");
  491. return (FALSE);
  492. }
  493. SetCurrentView(Log, Log -> LogPtr, 0);
  494. return (TRUE);
  495. }
  496. VOID
  497. GetCurrentView(
  498. IN PUSB_LOG Log,
  499. OUT ULONG64 *CurrTop,
  500. OUT ULONG64 *CurrBottom
  501. )
  502. {
  503. *CurrTop = Log -> LogCurrViewTop;
  504. *CurrBottom = Log -> LogCurrViewBottom;
  505. return;
  506. }
  507. VOID
  508. SetCurrentView(
  509. IN PUSB_LOG Log,
  510. IN ULONG64 NewTop,
  511. IN ULONG64 NewBottom
  512. )
  513. {
  514. LONG lineCount;
  515. if (0 == NewTop && 0 == NewBottom)
  516. {
  517. return;
  518. }
  519. lineCount = abs(Log -> LinesToDump);
  520. if (0 == NewBottom)
  521. {
  522. //
  523. // Calculate the new bottom based on NewTop and the number of lines to
  524. // be displayed in the log.
  525. //
  526. NewBottom = NewTop + lineCount;
  527. if (NewTop >= Log -> LogPtr)
  528. {
  529. lineCount -= (ULONG) CalcNumberLines(NewTop, Log -> LogEnd);
  530. if (lineCount > 0)
  531. {
  532. if (LogHasRolledOver(Log))
  533. {
  534. NewBottom = Log -> LogStart + lineCount - 1;
  535. if (NewBottom >= Log -> LogPtr)
  536. {
  537. NewBottom = Log -> LogPtr - 1;
  538. }
  539. }
  540. else
  541. {
  542. NewBottom = Log -> LogEnd;
  543. }
  544. }
  545. }
  546. else
  547. {
  548. if (lineCount > CalcNumberLines(NewTop, Log -> LogPtr - 1))
  549. {
  550. NewBottom = Log -> LogPtr - 1;
  551. }
  552. }
  553. }
  554. else if (0 == NewTop)
  555. {
  556. //
  557. // NULL == NewTop -- Need to calculate the NewTop of the view
  558. //
  559. NewTop = NewBottom - lineCount;
  560. if (NewBottom <= Log -> LogPtr - 1)
  561. {
  562. lineCount -= (ULONG) CalcNumberLines(Log -> LogStart, NewBottom);
  563. if (lineCount > 0)
  564. {
  565. NewTop = Log -> LogEnd - lineCount + 1;
  566. if (NewTop < Log -> LogPtr)
  567. {
  568. NewTop = Log -> LogPtr;
  569. }
  570. }
  571. }
  572. else
  573. {
  574. if (NewTop < Log -> LogPtr)
  575. {
  576. NewTop = Log -> LogPtr;
  577. }
  578. }
  579. }
  580. TRACE_SPEW("Set CurrentView NewTop (0x%08x) NewBottom(0x%08x)\n",
  581. NewTop, NewBottom);
  582. Log -> LogCurrViewTop = NewTop;
  583. Log -> LogCurrViewBottom = NewBottom;
  584. return;
  585. }
  586. ULONG64
  587. GetEntryBefore(
  588. IN PUSB_LOG Log,
  589. IN ULONG64 Entry
  590. )
  591. {
  592. if (Entry == Log -> LogEnd)
  593. {
  594. if (LogHasRolledOver(Log))
  595. {
  596. return (Log -> LogStart);
  597. }
  598. return (0);
  599. }
  600. //
  601. // Check to see if we hit the most recent entry in the log. If so we've
  602. // hit the end of the log and will loop again. return NULL.
  603. //
  604. return ( ((Entry + 1) == Log -> LogPtr) ? 0 : Entry+1);
  605. }
  606. ULONG64
  607. GetEntryAfter(
  608. IN PUSB_LOG Log,
  609. IN ULONG64 Entry
  610. )
  611. {
  612. if (Entry == Log -> LogPtr)
  613. {
  614. return (0);
  615. }
  616. if (Entry == Log -> LogStart)
  617. {
  618. return (Log -> LogEnd);
  619. }
  620. return (Entry-1);
  621. }
  622. VOID
  623. GetLogEntryTag(
  624. IN ULONG64 Entry,
  625. OUT PUSBLOG_TAG_READ Tag
  626. )
  627. {
  628. ULONG bytesRead;
  629. InitTypeRead(Entry, uhcd!USB_LOG_ENTRY);
  630. // ReadMemory( Entry + (ULONG64) &(((PUSB_LOG_ENTRY) 0) -> Tag), Tag, sizeof(*Tag), &bytesRead);
  631. Tag->TagValue = (ULONG) ReadField(Tag.TagValue);
  632. return;
  633. }
  634. VOID
  635. GetLogEntryParams(
  636. IN ULONG64 Entry,
  637. OUT ULONG64 *Param1,
  638. OUT ULONG64 *Param2,
  639. OUT ULONG64 *Param3
  640. )
  641. {
  642. ULONG bytesRead;
  643. InitTypeRead(Entry, uhcd!USB_LOG_ENTRY);
  644. *Param1 = ReadField(Param1);
  645. *Param2 = ReadField(Param2);
  646. *Param3 = ReadField(Param3);
  647. // ReadMemory(Entry + (ULONG64) &(((PUSB_LOG_ENTRY) 0)-> Param1), Param1, sizeof(*Param1), &bytesRead);
  648. // ReadMemory(Entry + (ULONG64) &(((PUSB_LOG_ENTRY) 0)-> Param3), Param2, sizeof(*Param2), &bytesRead);
  649. // ReadMemory(Entry + (ULONG64) &(((PUSB_LOG_ENTRY) 0)-> Param2), Param3, sizeof(*Param3), &bytesRead);
  650. return;
  651. }
  652. ULONG64
  653. SearchLogForTag(
  654. IN PUSB_LOG Log,
  655. IN ULONG64 SearchBegin,
  656. IN ULONG TagCount,
  657. IN USBLOG_TAG_READ TagArray[]
  658. )
  659. {
  660. ULONG tagIndex;
  661. ULONG64 currEntry;
  662. USBLOG_TAG_READ currTag;
  663. //
  664. // Start the search at the most recent log entry
  665. //
  666. currEntry = SearchBegin;
  667. while (currEntry != 0) {
  668. GetLogEntryTag(currEntry, &currTag);
  669. for (tagIndex = 0; tagIndex < TagCount; tagIndex++) {
  670. if (TagArray[tagIndex].TagValue == currTag.TagValue) {
  671. return (currEntry);
  672. }
  673. }
  674. currEntry = GetEntryBefore(Log, currEntry);
  675. }
  676. return (0);
  677. }
  678. VOID
  679. ConvertStringToTag(
  680. IN PCHAR TagString,
  681. OUT PUSBLOG_TAG_READ Tag
  682. )
  683. {
  684. USBLOG_TAG_READ tag;
  685. ULONG shiftAmount;
  686. //
  687. // Since a Tag is four characters long, this routine will convert only
  688. // the first four characters even though the string might be longer
  689. //
  690. tag.TagValue = 0;
  691. shiftAmount = 0;
  692. while (tag.TagValue < 0x01000000 && *TagString) {
  693. tag.TagValue += (*TagString) << shiftAmount;
  694. TagString++;
  695. shiftAmount += 8;
  696. }
  697. *Tag = tag;
  698. return;
  699. }
  700. VOID
  701. ConvertTagToString(
  702. IN PUSBLOG_TAG_READ Tag,
  703. IN PCHAR String,
  704. IN ULONG StringLength
  705. )
  706. {
  707. ULONG tagIndex;
  708. for (tagIndex = 0; tagIndex < 4 && tagIndex < StringLength-1; tagIndex++) {
  709. *String = Tag -> TagChars[tagIndex];
  710. *String++;
  711. }
  712. *String = '\0';
  713. return;
  714. }
  715. BOOLEAN
  716. IsValidEntry(
  717. ULONG64 Entry
  718. )
  719. {
  720. USBLOG_TAG_READ tag;
  721. GetLogEntryTag(Entry, &tag);
  722. return (0 != tag.TagValue);
  723. }
  724. VOID
  725. LogViewScrollUp(
  726. IN PUSB_LOG Log
  727. )
  728. {
  729. ULONG64 newBottom;
  730. TRACE_SPEW("In ScrollUp routine\n");
  731. newBottom = GetEntryAfter(Log, Log -> LogCurrViewTop);
  732. if (newBottom)
  733. {
  734. SetCurrentView(Log, 0, newBottom);
  735. }
  736. return;
  737. }
  738. VOID
  739. LogViewScrollDown(
  740. IN PUSB_LOG Log
  741. )
  742. {
  743. ULONG64 newTop;
  744. TRACE_SPEW("In ScrollDown routine\n");
  745. newTop = GetEntryBefore(Log, Log -> LogCurrViewBottom);
  746. if (newTop)
  747. {
  748. SetCurrentView(Log, newTop, 0);
  749. }
  750. return;
  751. }
  752. VOID
  753. DisplayCurrentView(
  754. IN PUSB_LOG Log
  755. )
  756. {
  757. ULONG64 viewTop;
  758. ULONG64 viewBottom;
  759. ULONG64 currEntry;
  760. USBLOG_TAG_READ currTag;
  761. CHAR TagString[TAG_STRING_LENGTH];
  762. ULONG lineCount;
  763. ULONG64 param1;
  764. ULONG64 param2;
  765. ULONG64 param3;
  766. PCHAR desc;
  767. //
  768. // Display the header
  769. //
  770. DisplayHeader();
  771. //
  772. // Determine which line of the log to begin displaying
  773. //
  774. GetCurrentView(Log, &viewTop, &viewBottom);
  775. //
  776. // Start displaying lines and stop when we hit the end of the log
  777. // or we have displayed the requested number of lines
  778. //
  779. //
  780. // Check first to see if the top of the view is the most recent entry
  781. //
  782. if (IsMostRecentEntry(Log, viewTop))
  783. {
  784. dprintf("Top of log...\n");
  785. }
  786. currEntry = viewTop;
  787. while (1)
  788. {
  789. //
  790. // Display a line of the log
  791. //
  792. GetLogEntryTag(currEntry, &currTag);
  793. ConvertTagToString(&currTag,
  794. TagString,
  795. TAG_STRING_LENGTH);
  796. GetLogEntryParams(currEntry, &param1, &param2, &param3);
  797. DUMP_ADDRESS(currEntry);
  798. DUMP_STRING(" ");
  799. DUMP_STRING(TagString);
  800. DUMP_STRING(" ");
  801. DUMP_DWORD(param1);
  802. DUMP_STRING(" ");
  803. DUMP_DWORD(param2);
  804. DUMP_STRING(" ");
  805. DUMP_DWORD(param3);
  806. DUMP_STRING(" ");
  807. if (0 != Log -> DescRoutine)
  808. {
  809. desc = Log -> DescRoutine(currEntry);
  810. if (0 != desc)
  811. {
  812. DUMP_STRING(desc);
  813. }
  814. }
  815. END_LINE();
  816. if (currEntry == viewBottom)
  817. {
  818. break;
  819. }
  820. currEntry = GetEntryBefore(Log, currEntry);
  821. }
  822. if (IsLeastRecentEntry(Log, currEntry))
  823. {
  824. dprintf("Bottom of log...\n");
  825. }
  826. return;
  827. }
  828. //
  829. // Local Function Definitions
  830. //
  831. VOID
  832. DisplayHeader(
  833. VOID
  834. )
  835. {
  836. TRACE_SPEW("Entering dump default log header\n");
  837. END_LINE();
  838. PARAM("Entry");
  839. TAG("Tag");
  840. PARAM("Param1");
  841. PARAM("Param2");
  842. PARAM("Param3");
  843. DESC("Description");
  844. END_LINE();
  845. DUMP_STRING("------------------------------------------------------------------");
  846. END_LINE();
  847. return;
  848. }
  849. VOID
  850. USBLOG_Usage(
  851. VOID
  852. )
  853. {
  854. dprintf("!usblog <log> [addr] [-r] [-s str] [-l n]\n"
  855. " <log> - {USBHUB | USBD | UHCD | OpenHCI}\n"
  856. " [addr] - address to begin dumping from in <log>\n"
  857. " [-r] - reset the log to dump from most recent entry\n"
  858. " [-s str] - search for first instance of a particular tag\n"
  859. " from the current position; str should be a list\n"
  860. " of tags delimited by comma's with no whitespace\n"
  861. " [-l n] - set the number of lines to display at a time to n\n");
  862. dprintf("\n");
  863. return;
  864. }