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.

379 lines
11 KiB

  1. /*++
  2. Copyright 2000 Microsoft Corporation
  3. Module Name:
  4. usbglitch.c
  5. Abstract:
  6. This module implements the USB glitch detector consumer. It's intended
  7. for use with the Intel USB audio glitch detection hardware connected
  8. via a serial port.
  9. COM port should be specified using the USB_AUDIO_GLITCH_DETECTOR_PORT
  10. environment variable. The format is: COMn, where n = 1, 2, 3, ..., 9.
  11. See the big comment at the end.
  12. Author:
  13. Arthur Zwiegincew (arthurz) 14-Dec-00
  14. Revision History:
  15. 14-Dec-00 - Created
  16. --*/
  17. #pragma warning (disable:4201)
  18. #include <streams.h>
  19. #include <windows.h>
  20. #include <tchar.h>
  21. #include <winperf.h>
  22. #include <wmistr.h>
  23. #include <evntrace.h>
  24. #include <stdio.h>
  25. #include <initguid.h>
  26. #include "perflog.h"
  27. #include "usbglitch.h"
  28. //
  29. // Logging state.
  30. //
  31. USBAUDIOSTATE CurrentState;
  32. char* StateNames[5] =
  33. {
  34. "Disabled",
  35. "Enabled",
  36. "Stream",
  37. "Glitch",
  38. "Zero"
  39. };
  40. int NumberOfFramesInCurrentState;
  41. BOOL StreamEncountered;
  42. //
  43. // Performance logging parameters.
  44. //
  45. // {28CF047A-2437-4b24-B653-B9446A419A69}
  46. DEFINE_GUID(GUID_DSHOW_CTL,
  47. 0x28cf047a, 0x2437, 0x4b24, 0xb6, 0x53, 0xb9, 0x44, 0x6a, 0x41, 0x9a, 0x69);
  48. struct {
  49. PERFLOG_LOGGING_PARAMS Params;
  50. TRACE_GUID_REGISTRATION TraceGuids[1];
  51. } g_perflogParams;
  52. inline ULONGLONG _RDTSC( void ) {
  53. #ifdef _X86_
  54. LARGE_INTEGER li;
  55. __asm {
  56. _emit 0x0F
  57. _emit 0x31
  58. mov li.LowPart,eax
  59. mov li.HighPart,edx
  60. }
  61. return li.QuadPart;
  62. #if 0 // This isn't tested yet
  63. #elif defined (_IA64_)
  64. #define INL_REGID_APITC 3116
  65. return __getReg( INL_REGID_APITC );
  66. #endif // 0
  67. #else // unsupported platform
  68. // not implemented on non x86/IA64 platforms
  69. return 0;
  70. #endif // _X86_/_IA64_
  71. }
  72. #undef LogEvent
  73. void LogEvent (USBAUDIOSTATE State, int Frames)
  74. {
  75. _PERFINFO_WMI_USBAUDIOSTATE perfData;
  76. memset( &perfData, 0, sizeof (perfData));
  77. perfData.header.Size = sizeof (perfData);
  78. perfData.header.Flags = WNODE_FLAG_TRACED_GUID;
  79. perfData.header.Guid = GUID_DSOUNDGLITCH;
  80. perfData.data.cycleCounter = _RDTSC();
  81. perfData.data.usbAudioState = State;
  82. perfData.data.numberOfFrames = Frames;
  83. PerflogTraceEvent ((PEVENT_TRACE_HEADER) &perfData);
  84. printf ("%s: %d frames\n", StateNames[State], Frames);
  85. }
  86. void ProcessEvent (BYTE Data)
  87. {
  88. if (Data != CurrentState) {
  89. if (CurrentState == ZERO) {
  90. if (StreamEncountered && (Data == STREAM || Data == GLITCH)) {
  91. LogEvent (CurrentState, NumberOfFramesInCurrentState);
  92. }
  93. }
  94. else if (CurrentState == GLITCH) {
  95. if (Data == ZERO || Data == STREAM) {
  96. LogEvent (CurrentState, NumberOfFramesInCurrentState);
  97. }
  98. }
  99. else {
  100. LogEvent (CurrentState, NumberOfFramesInCurrentState);
  101. }
  102. CurrentState = (USBAUDIOSTATE)Data;
  103. NumberOfFramesInCurrentState = 1;
  104. if (CurrentState == STREAM) {
  105. StreamEncountered = TRUE;
  106. }
  107. }
  108. else {
  109. NumberOfFramesInCurrentState += 1;
  110. }
  111. }
  112. BOOL WINAPI ConsoleCtrlHandler (DWORD CtrlType)
  113. {
  114. PerflogShutdown();
  115. return FALSE;
  116. }
  117. void __cdecl main (void)
  118. {
  119. char PortName[5] = {0};
  120. DWORD PortNameLength;
  121. HANDLE Port;
  122. COMMCONFIG CommConfig;
  123. BOOL bstatus;
  124. DWORD EventMask;
  125. BYTE Data;
  126. DWORD BytesRead;
  127. //
  128. // Get the port name.
  129. //
  130. PortNameLength = GetEnvironmentVariable ("USB_AUDIO_GLITCH_DETECTOR_PORT",
  131. PortName, 5);
  132. if (PortNameLength != 4
  133. || _strnicmp (PortName, "COM", 3) != 0
  134. || PortName[3] < '1' || PortName[3] > '9') {
  135. printf ("Please set USB_AUDIO_GLITCH_DETECTOR_PORT environment "
  136. "variable to COM[1..9].");
  137. return;
  138. }
  139. //
  140. // Open the port.
  141. //
  142. Port = CreateFile (PortName, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  143. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  144. if (Port == INVALID_HANDLE_VALUE) {
  145. printf ("Failed to open %s. GetLastError()=>%d\n", PortName, GetLastError());
  146. return;
  147. }
  148. printf ("%s opened.\n", PortName);
  149. Sleep (10000);
  150. //
  151. // Set port configuration.
  152. //
  153. CommConfig.dwSize = sizeof (CommConfig);
  154. CommConfig.wVersion = 1;
  155. CommConfig.dcb.DCBlength = sizeof (DCB);
  156. CommConfig.dcb.BaudRate = CBR_115200;
  157. CommConfig.dcb.fBinary = 1;
  158. CommConfig.dcb.fParity = 0;
  159. CommConfig.dcb.fOutxCtsFlow = 0;
  160. CommConfig.dcb.fOutxDsrFlow = 0;
  161. CommConfig.dcb.fDtrControl = DTR_CONTROL_ENABLE;
  162. CommConfig.dcb.fDsrSensitivity = 0;
  163. CommConfig.dcb.fTXContinueOnXoff = 0;
  164. CommConfig.dcb.fOutX = 0;
  165. CommConfig.dcb.fInX = 0;
  166. CommConfig.dcb.fErrorChar = 1;
  167. CommConfig.dcb.fNull = 0;
  168. CommConfig.dcb.fRtsControl = RTS_CONTROL_ENABLE;
  169. CommConfig.dcb.fAbortOnError = 0;
  170. CommConfig.dcb.wReserved = 0;
  171. CommConfig.dcb.XonLim = 128;
  172. CommConfig.dcb.XoffLim = 512;
  173. CommConfig.dcb.ByteSize = 8;
  174. CommConfig.dcb.Parity = NOPARITY;
  175. CommConfig.dcb.StopBits = ONESTOPBIT;
  176. CommConfig.dcb.XonChar = 0;
  177. CommConfig.dcb.XoffChar = 0;
  178. CommConfig.dcb.ErrorChar = 0;
  179. CommConfig.dcb.EofChar = 127;
  180. CommConfig.dcb.EvtChar = 126;
  181. CommConfig.dcb.wReserved1 = 0;
  182. CommConfig.dwProviderSubType = PST_RS232;
  183. CommConfig.dwProviderOffset = 0;
  184. CommConfig.dwProviderSize = 0;
  185. bstatus = SetCommConfig (Port, &CommConfig, sizeof (CommConfig));
  186. if (!bstatus) {
  187. printf ("Failed to configure %s. GetLastError()=>%d\n", PortName, GetLastError());
  188. return;
  189. }
  190. bstatus = SetupComm (Port, 8, 8);
  191. if (!bstatus) {
  192. printf ("Failed to configure %s. GetLastError()=>%d\n", PortName, GetLastError());
  193. return;
  194. }
  195. //
  196. // Initialize perf logging.
  197. //
  198. g_perflogParams.Params.ControlGuid = GUID_DSHOW_CTL;
  199. g_perflogParams.Params.OnStateChanged = NULL;
  200. g_perflogParams.Params.NumberOfTraceGuids = 1;
  201. g_perflogParams.Params.TraceGuids[0].Guid = &GUID_USBAUDIOSTATE;
  202. PerflogInitialize (&g_perflogParams.Params);
  203. SetConsoleCtrlHandler (ConsoleCtrlHandler, TRUE);
  204. //
  205. // Receive data.
  206. //
  207. CurrentState = DISABLED;
  208. NumberOfFramesInCurrentState = 0;
  209. StreamEncountered = FALSE;
  210. bstatus = SetCommMask (Port, EV_RXCHAR);
  211. if (!bstatus) {
  212. printf ("Internal error (1). GetLastError()=>%d\n", GetLastError());
  213. return;
  214. }
  215. for (;;) {
  216. EventMask = 0;
  217. WaitCommEvent (Port, &EventMask, NULL);
  218. if (EventMask & EV_RXCHAR) {
  219. bstatus = ReadFile (Port, &Data, 1, &BytesRead, NULL);
  220. if (!bstatus || BytesRead != 1) {
  221. ClearCommError (Port, &BytesRead, NULL);
  222. continue;
  223. }
  224. ProcessEvent (Data);
  225. }
  226. }
  227. }
  228. /*
  229. John.keys@intel.com has provided the following information:
  230. Intel Hardware USB Audio Glitch Detector
  231. Theory of Operation
  232. -----------------------------------------
  233. Serial Port Configuration:
  234. 115,200 baud
  235. 8 bit words
  236. 1 stop bit
  237. no parity
  238. The Glitch detector's port (outside port, labeled UART) is configured as DTE,
  239. so only straight-through cables should be used. A pc-pc debug cable will not
  240. work.
  241. Because of special reset circuitry on the board, both DTR and RTS should be
  242. enabled. The detector is stuck in reset if all LEDs are lit.
  243. When plugged into the USB port and receiving SOFs (Start Of Frame packets, one
  244. received every millisecond), the HW glitch detector will output the following
  245. values once per millisecond:
  246. 0 - Device is disabled
  247. 1 - Device is enabled - SetInterface Request received
  248. 2 - Frame with Streaming data
  249. 3 - Frame with no streaming data
  250. 4 - Frame with Zero-stuffed data
  251. To determine which value to send, the device contains a small state machine.
  252. The states it moves through are DISABLED, ENABLED, STREAM, GLITCH, and ZERO.
  253. Note that these states duplicate the values returned on the serial port. In
  254. fact, the detector sends back it's state at every frame.
  255. DISABLED: device starts in this state, returns to this state when unplugged.
  256. This is a special case, and the device can return to this state from
  257. any other state. The device can only move to ENABLED from this state.
  258. ENABLED: Device goes to this state with every SetConfiguration or SetInterface
  259. request. Since SetInterface requests are made to open and close Audio
  260. pipes, this allows the device to detect the end of audio streams.
  261. The will stay in this state until it is disconnected or it receives
  262. Isochronous data. It can then go to either STREAM or ZERO,
  263. depending on the data payload received. This prevents false glitch
  264. detection while waiting for the stream to start.
  265. STREAM: Valid data was received. The device can move to this state from any
  266. other state, with the exception of DISABLED. It can move to any other
  267. state.
  268. GLITCH: No data received. The device can only move to this state from STREAM
  269. or ZERO. It can change from this state to any other state.
  270. ZERO: Data was received, but all samples had zero value. The device can move
  271. to this state from any other state except DISABLED. It can change to
  272. any other state from ZERO.
  273. ----------------------------------------------------------------------------
  274. Application Processing Considerations
  275. ----------------------------------------------------------------------------
  276. The difference between ZERO and GLITCH: Glitch indicates that no data was
  277. received by the board. This indicates low-level ISR, DPC, IRQL, or Critical
  278. Work Items. ZERO: indicates high-level thread latencies that result in
  279. KMIXER data starvation.
  280. Accurate glitch detection requires looking at the stream over time. The board
  281. can only report it's state at any given frame. Therefore, the application must
  282. perform some additional processing of state to eliminate false glitches.
  283. Specifically, it must look at the transitions between states.
  284. ZERO: Zero state should be ignored until the first STREAM state is encountered.
  285. This prevents false detection of rate-lock packets and of initial
  286. attenuated streams. After the first STREAM state is encountered, ZERO
  287. should only be reported when a ZERO->STREAM or a ZERO->GLITCH transition
  288. is seen. ZERO->ENABLED transitions should not be reported as they can
  289. occur normally when shutting down the stream. Also, ZERO->GLITCH->ENABLED
  290. transitions must be ignored for the same reason.
  291. GLITCH: Only GLITCH->ZERO and GLITCH->STREAM transitions should be reported as
  292. glitches. GLITCH->ENA transitions always occur at the end of a stream
  293. and are normal.
  294. When enabled, the device will send one state byte every 1 millisecond. This
  295. means that the stream can also be used as a clock source for time-stamping
  296. glitches.
  297. */