Leaked source code of windows server 2003
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.

1679 lines
46 KiB

  1. /**************************************************************************************************************************
  2. * DIAGS.C SigmaTel STIR4200 diagnostic module
  3. **************************************************************************************************************************
  4. * (C) Unpublished Copyright of Sigmatel, Inc. All Rights Reserved.
  5. *
  6. *
  7. * Created: 04/27/2000
  8. * Version 0.92
  9. * Edited: 05/12/2000
  10. * Version 0.94
  11. * Edited: 05/19/2000
  12. * Version 0.95
  13. * Edited: 05/24/2000
  14. * Version 0.96
  15. * Edited: 10/09/2000
  16. * Version 1.10
  17. *
  18. *
  19. **************************************************************************************************************************/
  20. #if defined(DIAGS)
  21. #define DOBREAKS // enable debug breaks
  22. #include <ndis.h>
  23. #include <ntddndis.h> // defines OID's
  24. #include <usbdi.h>
  25. #include <usbdlib.h>
  26. #include "debug.h"
  27. #include "ircommon.h"
  28. #include "irndis.h"
  29. #include "irusb.h"
  30. #include "stir4200.h"
  31. #include "diags.h"
  32. /*****************************************************************************
  33. *
  34. * Function: Diags_BufferToFirPacket
  35. *
  36. * Synopsis: convert a buffer to a Fir IR packet
  37. *
  38. * Write the IR packet into the provided buffer and report
  39. * its actual size.
  40. *
  41. * Arguments: pIrDev - pointer to device instance
  42. * pIrPacketBuf - output buffer
  43. * IrPacketBufLen - output buffer size
  44. * pContigPacketBuf - temporary staging buffer (input buffer)
  45. * ContigPacketLen - input buffer size
  46. * pIrPacketLen - lenght of the converted data
  47. *
  48. * MS Security bug #533243
  49. * Note: size of pContigPacketBuf staging buffer is:
  50. * MAX_TOTAL_SIZE_WITH_ALL_HEADERS + FAST_IR_FCS_SIZE
  51. *
  52. * Returns: TRUE - on success
  53. * FALSE - on failure
  54. *
  55. *
  56. *****************************************************************************/
  57. BOOLEAN
  58. Diags_BufferToFirPacket(
  59. IN PIR_DEVICE pIrDev,
  60. OUT PUCHAR pIrPacketBuf,
  61. ULONG IrPacketBufLen,
  62. IN PUCHAR pContigPacketBuf,
  63. ULONG ContigPacketLen,
  64. OUT PULONG pIrPacketLen
  65. )
  66. {
  67. ULONG I_fieldBytes;
  68. FAST_IR_FCS_TYPE fcs, *pfcs;
  69. ULONG i, TotalBytes, EscSize;
  70. PSTIR4200_FRAME_HEADER pFrameHeader = (PSTIR4200_FRAME_HEADER)pIrPacketBuf;
  71. PUCHAR pIrPacketBufFrame = pIrPacketBuf + sizeof(STIR4200_FRAME_HEADER);
  72. /***********************************************/
  73. /* Make sure that the packet is big enough */
  74. /* to be legal. It consists of an A, C, and */
  75. /* variable-length I field. */
  76. /***********************************************/
  77. if( ContigPacketLen < IRDA_A_C_TOTAL_SIZE )
  78. {
  79. DEBUGMSG(DBG_ERR, (" Diags_BufferToFirPacket(): Packet is too small\n"));
  80. return FALSE;
  81. }
  82. else
  83. {
  84. I_fieldBytes = ContigPacketLen - IRDA_A_C_TOTAL_SIZE;
  85. }
  86. /***********************************************/
  87. /* Make sure that we won't overwrite our */
  88. /* contiguous buffer */
  89. /***********************************************/
  90. if( (ContigPacketLen > MAX_TOTAL_SIZE_WITH_ALL_HEADERS) ||
  91. (MAX_POSSIBLE_IR_PACKET_SIZE_FOR_DATA(I_fieldBytes) > IrPacketBufLen) )
  92. {
  93. /***********************************************/
  94. /* The packet is too large. Tell the caller */
  95. /* to retry with a packet size large enough */
  96. /* to get past this stage next time. */
  97. /***********************************************/
  98. DEBUGMSG(DBG_ERR, (" Diags_BufferToFirPacket(): Packet is too big\n"));
  99. return FALSE;
  100. }
  101. /***********************************************/
  102. /* Compute the FCS on the packet BEFORE */
  103. /* applying transparency fixups. The FCS */
  104. /* also must be sent using ESC-char */
  105. /* transparency. */
  106. /***********************************************/
  107. fcs = ComputeFCS32( pContigPacketBuf, ContigPacketLen );
  108. /***********************************************/
  109. /* Add FCS to packet... */
  110. /***********************************************/
  111. pfcs = (FAST_IR_FCS_TYPE *)&pContigPacketBuf[ContigPacketLen];
  112. *pfcs = fcs;
  113. /***********************************************/
  114. /* Build the STIr4200 FIR frame. */
  115. /***********************************************/
  116. /***********************************************/
  117. /* Add preamble... */
  118. /***********************************************/
  119. memset( pIrPacketBufFrame, STIR4200_FIR_PREAMBLE, STIR4200_FIR_PREAMBLE_SIZ );
  120. /***********************************************/
  121. /* Add BOF's... */
  122. /***********************************************/
  123. memset( &pIrPacketBufFrame[STIR4200_FIR_PREAMBLE_SIZ], STIR4200_FIR_BOF, STIR4200_FIR_BOF_SIZ );
  124. /***********************************************/
  125. /* Escape A, C, I & CRC fields of packet... */
  126. /***********************************************/
  127. EscSize = ContigPacketLen + FAST_IR_FCS_SIZE;
  128. for( i = 0, TotalBytes = STIR4200_FIR_PREAMBLE_SIZ + STIR4200_FIR_BOF_SIZ; i < EscSize; i++ )
  129. {
  130. UCHAR c;
  131. switch( c = pContigPacketBuf[i] )
  132. {
  133. case STIR4200_FIR_ESC_CHAR:
  134. pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_CHAR;
  135. pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_DATA_7D;
  136. break;
  137. case STIR4200_FIR_BOF: // BOF = EOF too
  138. pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_CHAR;
  139. pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_DATA_7E;
  140. break;
  141. case STIR4200_FIR_PREAMBLE:
  142. pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_CHAR;
  143. pIrPacketBufFrame[TotalBytes++] = STIR4200_FIR_ESC_DATA_7F;
  144. break;
  145. default:
  146. pIrPacketBufFrame[TotalBytes++] = c;
  147. }
  148. }
  149. /***********************************************/
  150. /* Add EOF's... */
  151. /***********************************************/
  152. memset( &pIrPacketBufFrame[TotalBytes], STIR4200_FIR_EOF, STIR4200_FIR_EOF_SIZ );
  153. /***********************************************/
  154. /* Add in STIr4200 header... */
  155. /***********************************************/
  156. TotalBytes += STIR4200_FIR_EOF_SIZ;
  157. pFrameHeader->id1 = STIR4200_HEADERID_BYTE1;
  158. pFrameHeader->id2 = STIR4200_HEADERID_BYTE2;
  159. pFrameHeader->sizlsb = LOBYTE(TotalBytes);
  160. pFrameHeader->sizmsb = HIBYTE(TotalBytes);
  161. /***********************************************/
  162. /* Calc size packet w/escaped data... */
  163. /***********************************************/
  164. *pIrPacketLen = TotalBytes + sizeof(STIR4200_FRAME_HEADER);
  165. return TRUE;
  166. }
  167. /*****************************************************************************
  168. *
  169. * Function: Diags_BufferToSirPacket
  170. *
  171. * Synopsis: convert a buffer to a Sir IR packet
  172. *
  173. * Write the IR packet into the provided buffer and report
  174. * its actual size.
  175. *
  176. * Arguments: pIrDev - pointer to device instance
  177. * pPacket - NDIS packet to convert
  178. * pIrPacketBuf - output buffer
  179. * IrPacketBufLen - output buffer size
  180. * pContigPacketBuf - temporary staging buffer (input buffer)
  181. * ContigPacketLen - input buffer size
  182. * pIrPacketLen - lenght of the converted data
  183. *
  184. * MS Security bug #533243
  185. * Note: size of pContigPacketBuf staging buffer is:
  186. * MAX_TOTAL_SIZE_WITH_ALL_HEADERS + FAST_IR_FCS_SIZE
  187. *
  188. * Returns: TRUE - on success
  189. * FALSE - on failure
  190. *
  191. *
  192. *****************************************************************************/
  193. BOOLEAN
  194. Diags_BufferToSirPacket(
  195. IN PIR_DEVICE pIrDev,
  196. OUT PUCHAR pIrPacketBuf,
  197. ULONG IrPacketBufLen,
  198. IN PUCHAR pContigPacketBuf,
  199. ULONG ContigPacketLen,
  200. USHORT ExtraBOFs,
  201. OUT PULONG pIrPacketLen
  202. )
  203. {
  204. ULONG i;
  205. ULONG I_fieldBytes, totalBytes = 0;
  206. ULONG numExtraBOFs;
  207. SLOW_IR_FCS_TYPE fcs, tmpfcs;
  208. UCHAR fcsBuf[SLOW_IR_FCS_SIZE * 2];
  209. ULONG fcsLen = 0;
  210. UCHAR nextChar;
  211. PSTIR4200_FRAME_HEADER pFrameHeader = (PSTIR4200_FRAME_HEADER)pIrPacketBuf;
  212. PUCHAR pIrPacketBufFrame = pIrPacketBuf + sizeof(STIR4200_FRAME_HEADER);
  213. /***********************************************/
  214. /* Make sure that the packet is big enough */
  215. /* to be legal. It consists of an A, C, and */
  216. /* variable-length I field. */
  217. /***********************************************/
  218. if( ContigPacketLen < IRDA_A_C_TOTAL_SIZE )
  219. {
  220. DEBUGMSG(DBG_ERR, (" NdisToSirPacket(): Packet is too small\n"));
  221. return FALSE;
  222. }
  223. else
  224. {
  225. I_fieldBytes = ContigPacketLen - IRDA_A_C_TOTAL_SIZE;
  226. }
  227. /***********************************************/
  228. /* Make sure that we won't overwrite our */
  229. /* contiguous buffer. Make sure that the */
  230. /* passed-in buffer can accomodate this */
  231. /* packet's data no matter how much it */
  232. /* grows through adding ESC-sequences, etc. */
  233. /***********************************************/
  234. if( (ContigPacketLen > MAX_TOTAL_SIZE_WITH_ALL_HEADERS) ||
  235. (MAX_POSSIBLE_IR_PACKET_SIZE_FOR_DATA(I_fieldBytes) > IrPacketBufLen) )
  236. {
  237. //
  238. // Packet is too big
  239. //
  240. DEBUGMSG(DBG_ERR, (" NdisToSirPacket(): Packet is too big\n"));
  241. return FALSE;
  242. }
  243. /***********************************************/
  244. /* Compute the FCS on the packet BEFORE */
  245. /* applying transparency fixups. The FCS */
  246. /* also must be sent using ESC-char */
  247. /* transparency, so figure out how large */
  248. /* the fcs will really be. */
  249. /***********************************************/
  250. fcs = ComputeFCS16( pContigPacketBuf, ContigPacketLen );
  251. for( i = 0, tmpfcs = fcs, fcsLen = 0; i < SLOW_IR_FCS_SIZE; tmpfcs >>= 8, i++ )
  252. {
  253. UCHAR fcsbyte = tmpfcs & 0x00ff;
  254. switch( fcsbyte )
  255. {
  256. case SLOW_IR_BOF:
  257. case SLOW_IR_EOF:
  258. case SLOW_IR_ESC:
  259. fcsBuf[fcsLen++] = SLOW_IR_ESC;
  260. fcsBuf[fcsLen++] = fcsbyte ^ SLOW_IR_ESC_COMP;
  261. break;
  262. default:
  263. fcsBuf[fcsLen++] = fcsbyte;
  264. break;
  265. }
  266. }
  267. /***********************************************/
  268. /* Now begin building the IR frame. */
  269. /* */
  270. /* This is the final format: */
  271. /* */
  272. /* BOF (1) */
  273. /* extra BOFs ... */
  274. /* NdisMediumIrda packet (from NDIS): */
  275. /* Address (1) */
  276. /* Control (1) */
  277. /* FCS (2) */
  278. /* EOF (1) */
  279. /* */
  280. /* Prepend BOFs (extra BOFs + 1 actual BOF) */
  281. /***********************************************/
  282. numExtraBOFs = ExtraBOFs;
  283. if( numExtraBOFs > MAX_NUM_EXTRA_BOFS )
  284. {
  285. numExtraBOFs = MAX_NUM_EXTRA_BOFS;
  286. }
  287. for( i = totalBytes = 0; i < numExtraBOFs; i++ )
  288. {
  289. *(SLOW_IR_BOF_TYPE*)(pIrPacketBufFrame + totalBytes) = SLOW_IR_EXTRA_BOF;
  290. totalBytes += SLOW_IR_EXTRA_BOF_SIZE;
  291. }
  292. *(SLOW_IR_BOF_TYPE*)(pIrPacketBufFrame + totalBytes) = SLOW_IR_BOF;
  293. totalBytes += SLOW_IR_BOF_SIZE;
  294. /***********************************************/
  295. /* Copy the NDIS packet from our contiguous */
  296. /* buffer, applying escape-char */
  297. /* transparency. */
  298. /***********************************************/
  299. for( i = 0; i < ContigPacketLen; i++ )
  300. {
  301. nextChar = pContigPacketBuf[i];
  302. switch( nextChar )
  303. {
  304. case SLOW_IR_BOF:
  305. case SLOW_IR_EOF:
  306. case SLOW_IR_ESC:
  307. pIrPacketBufFrame[totalBytes++] = SLOW_IR_ESC;
  308. pIrPacketBufFrame[totalBytes++] = nextChar ^ SLOW_IR_ESC_COMP;
  309. break;
  310. default:
  311. pIrPacketBufFrame[totalBytes++] = nextChar;
  312. break;
  313. }
  314. }
  315. /***********************************************/
  316. /* Add FCS, EOF. */
  317. /***********************************************/
  318. NdisMoveMemory( (PVOID)(pIrPacketBufFrame + totalBytes), (PVOID)fcsBuf, fcsLen );
  319. totalBytes += fcsLen;
  320. *(SLOW_IR_EOF_TYPE*)(pIrPacketBufFrame + totalBytes) = (UCHAR)SLOW_IR_EOF;
  321. totalBytes += SLOW_IR_EOF_SIZE;
  322. /***********************************************/
  323. /* Add in STIr4200 header... */
  324. /***********************************************/
  325. pFrameHeader->id1 = STIR4200_HEADERID_BYTE1;
  326. pFrameHeader->id2 = STIR4200_HEADERID_BYTE2;
  327. pFrameHeader->sizlsb = LOBYTE(totalBytes);
  328. pFrameHeader->sizmsb = HIBYTE(totalBytes);
  329. *pIrPacketLen = totalBytes + sizeof(STIR4200_FRAME_HEADER);
  330. return TRUE;
  331. }
  332. /*****************************************************************************
  333. *
  334. * Function: Diags_Enable
  335. *
  336. * Synopsis: Switches the STIr4200 to diagnostic mode
  337. *
  338. * Arguments: pThisDev - pointer to IR device
  339. *
  340. * Returns: NT status code
  341. *
  342. * Notes:
  343. *
  344. *****************************************************************************/
  345. NTSTATUS
  346. Diags_Enable(
  347. IN OUT PIR_DEVICE pThisDev
  348. )
  349. {
  350. PIRUSB_CONTEXT pThisContext;
  351. PLIST_ENTRY pListEntry;
  352. //
  353. // Make sure diags aren't already active
  354. //
  355. if( pThisDev->DiagsActive )
  356. {
  357. DEBUGMSG(DBG_ERR, (" Diags_Enable diags already active\n"));
  358. return STATUS_UNSUCCESSFUL;
  359. }
  360. //
  361. // Get a context to switch to the new mode
  362. //
  363. pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
  364. if( NULL == pListEntry )
  365. {
  366. //
  367. // This must not happen
  368. //
  369. DEBUGMSG(DBG_ERR, (" Diags_Enable failed to find a free context struct\n"));
  370. IRUSB_ASSERT( 0 );
  371. return STATUS_UNSUCCESSFUL;
  372. }
  373. InterlockedDecrement( &pThisDev->SendAvailableCount );
  374. pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
  375. pThisContext->ContextType = CONTEXT_DIAGS_ENABLE;
  376. //
  377. // Disable further interaction with the stack
  378. //
  379. InterlockedExchange( &pThisDev->DiagsPendingActivation, TRUE );
  380. //
  381. // Queue the context and then wait
  382. //
  383. KeClearEvent( &pThisDev->EventDiags );
  384. ExInterlockedInsertTailList(
  385. &pThisDev->SendBuiltQueue,
  386. &pThisContext->ListEntry,
  387. &pThisDev->SendLock
  388. );
  389. InterlockedIncrement( &pThisDev->SendBuiltCount );
  390. MyKeWaitForSingleObject( pThisDev, &pThisDev->EventDiags, 0 );
  391. return pThisDev->IOCTLStatus;
  392. }
  393. /*****************************************************************************
  394. *
  395. * Function: Diags_Disable
  396. *
  397. * Synopsis: Switches the STIr4200 back to normal mode
  398. *
  399. * Arguments: pThisDev - pointer to IR device
  400. *
  401. * Returns: NT status code
  402. *
  403. * Notes:
  404. *
  405. *****************************************************************************/
  406. NTSTATUS
  407. Diags_Disable(
  408. IN OUT PIR_DEVICE pThisDev
  409. )
  410. {
  411. PRCV_BUFFER pRecBuf;
  412. PLIST_ENTRY pEntry;
  413. //
  414. // Make sure diags are active
  415. //
  416. if( !pThisDev->DiagsActive )
  417. {
  418. DEBUGMSG(DBG_ERR, (" Diags_Disable diags not active\n"));
  419. return STATUS_UNSUCCESSFUL;
  420. }
  421. //
  422. // Enable interaction with the stack and no queuing of contexts is required
  423. //
  424. InterlockedExchange( &pThisDev->DiagsActive, FALSE );
  425. InterlockedExchange( &pThisDev->DiagsPendingActivation, FALSE );
  426. //
  427. // Get rid of all the diagnostic buffers
  428. //
  429. while( pEntry=ExInterlockedRemoveHeadList(
  430. &pThisDev->DiagsReceiveQueue,
  431. &pThisDev->DiagsReceiveLock )
  432. )
  433. {
  434. pRecBuf = CONTAINING_RECORD( pEntry, RCV_BUFFER, ListEntry );
  435. InterlockedExchange( &pRecBuf->DataLen, 0 );
  436. InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
  437. }
  438. return STATUS_SUCCESS;
  439. }
  440. /*****************************************************************************
  441. *
  442. * Function: Diags_ReadRegisters
  443. *
  444. * Synopsis: Prepares a context to read the registers
  445. *
  446. * Arguments: pThisDev - pointer to IR device
  447. * pIOCTL - pointer to IOCTL descriptor
  448. * IOCTLSize - size of the IOCTL buffer
  449. *
  450. * Returns: NT status code
  451. *
  452. * Notes:
  453. *
  454. *****************************************************************************/
  455. NTSTATUS
  456. Diags_ReadRegisters(
  457. IN OUT PIR_DEVICE pThisDev,
  458. OUT PDIAGS_READ_REGISTERS_IOCTL pIOCTL,
  459. ULONG IOCTLSize
  460. )
  461. {
  462. PIRUSB_CONTEXT pThisContext;
  463. PLIST_ENTRY pListEntry;
  464. //
  465. // First basic validation
  466. //
  467. if( IOCTLSize < sizeof(DIAGS_READ_REGISTERS_IOCTL) )
  468. {
  469. DEBUGMSG(DBG_ERR, (" Diags_ReadRegisters invalid output buffer\n"));
  470. return STATUS_UNSUCCESSFUL;
  471. }
  472. //
  473. // Now we get a little more sofisticated
  474. //
  475. if( ((pIOCTL->FirstRegister+pIOCTL->NumberRegisters)>(STIR4200_MAX_REG+1)) ||
  476. ((IOCTLSize+1)<(sizeof(DIAGS_READ_REGISTERS_IOCTL)+pIOCTL->NumberRegisters)) )
  477. {
  478. DEBUGMSG(DBG_ERR, (" Diags_ReadRegisters invalid output buffer\n"));
  479. return STATUS_UNSUCCESSFUL;
  480. }
  481. pThisDev->pIOCTL = pIOCTL;
  482. pThisDev->IOCTLStatus = STATUS_UNSUCCESSFUL;
  483. //
  484. // Get a context to queue
  485. //
  486. pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
  487. if( NULL == pListEntry )
  488. {
  489. //
  490. // This must not happen
  491. //
  492. DEBUGMSG(DBG_ERR, (" Diags_ReadRegisters failed to find a free context struct\n"));
  493. IRUSB_ASSERT( 0 );
  494. return STATUS_UNSUCCESSFUL;
  495. }
  496. InterlockedDecrement( &pThisDev->SendAvailableCount );
  497. pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
  498. pThisContext->ContextType = CONTEXT_DIAGS_READ_REGISTERS;
  499. //
  500. // Queue the context and then wait
  501. //
  502. KeClearEvent( &pThisDev->EventDiags );
  503. ExInterlockedInsertTailList(
  504. &pThisDev->SendBuiltQueue,
  505. &pThisContext->ListEntry,
  506. &pThisDev->SendLock
  507. );
  508. InterlockedIncrement( &pThisDev->SendBuiltCount );
  509. MyKeWaitForSingleObject( pThisDev, &pThisDev->EventDiags, 0 );
  510. return pThisDev->IOCTLStatus;
  511. }
  512. /*****************************************************************************
  513. *
  514. * Function: Diags_WriteRegister
  515. *
  516. * Synopsis: Prepares a context to write the registers
  517. *
  518. * Arguments: pThisDev - pointer to IR device
  519. * pIOCTL - pointer to IOCTL descriptor
  520. * IOCTLSize - size of the IOCTL buffer
  521. *
  522. * Returns: NT status code
  523. *
  524. * Notes:
  525. *
  526. *****************************************************************************/
  527. NTSTATUS
  528. Diags_WriteRegister(
  529. IN OUT PIR_DEVICE pThisDev,
  530. OUT PDIAGS_READ_REGISTERS_IOCTL pIOCTL,
  531. ULONG IOCTLSize
  532. )
  533. {
  534. PIRUSB_CONTEXT pThisContext;
  535. PLIST_ENTRY pListEntry;
  536. //
  537. // Validation
  538. //
  539. if( (IOCTLSize < sizeof(DIAGS_READ_REGISTERS_IOCTL)) ||
  540. (pIOCTL->FirstRegister>STIR4200_MAX_REG) )
  541. {
  542. DEBUGMSG(DBG_ERR, (" Diags_WriteRegister invalid output buffer\n"));
  543. return STATUS_UNSUCCESSFUL;
  544. }
  545. pThisDev->pIOCTL = pIOCTL;
  546. pThisDev->IOCTLStatus = STATUS_UNSUCCESSFUL;
  547. //
  548. // Get a context to queue
  549. //
  550. pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
  551. if( NULL == pListEntry )
  552. {
  553. //
  554. // This must not happen
  555. //
  556. DEBUGMSG(DBG_ERR, (" Diags_ReadRegisters failed to find a free context struct\n"));
  557. IRUSB_ASSERT( 0 );
  558. return STATUS_UNSUCCESSFUL;
  559. }
  560. InterlockedDecrement( &pThisDev->SendAvailableCount );
  561. pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
  562. pThisContext->ContextType = CONTEXT_DIAGS_WRITE_REGISTER;
  563. //
  564. // Queue the context and the wait
  565. //
  566. KeClearEvent( &pThisDev->EventDiags );
  567. ExInterlockedInsertTailList(
  568. &pThisDev->SendBuiltQueue,
  569. &pThisContext->ListEntry,
  570. &pThisDev->SendLock
  571. );
  572. InterlockedIncrement( &pThisDev->SendBuiltCount );
  573. MyKeWaitForSingleObject( pThisDev, &pThisDev->EventDiags, 0 );
  574. return pThisDev->IOCTLStatus;
  575. }
  576. /*****************************************************************************
  577. *
  578. * Function: Diags_PrepareBulk
  579. *
  580. * Synopsis: Prepares a context to do a bulk transfer
  581. *
  582. * Arguments: pThisDev - pointer to IR device
  583. * pIOCTL - pointer to IOCTL descriptor
  584. * IOCTLSize - size of the IOCTL buffer
  585. * DirectionOut - TRUE if bulk-out, FALSE if bulk-in
  586. *
  587. * Returns: NT status code
  588. *
  589. * Notes:
  590. *
  591. *****************************************************************************/
  592. NTSTATUS
  593. Diags_PrepareBulk(
  594. IN OUT PIR_DEVICE pThisDev,
  595. OUT PDIAGS_BULK_IOCTL pIOCTL,
  596. ULONG IOCTLSize,
  597. BOOLEAN DirectionOut
  598. )
  599. {
  600. PIRUSB_CONTEXT pThisContext;
  601. PLIST_ENTRY pListEntry;
  602. //
  603. // First basic validation
  604. //
  605. if( IOCTLSize < sizeof(DIAGS_BULK_IOCTL) )
  606. {
  607. DEBUGMSG(DBG_ERR, (" Diags_PrepareBulk invalid input buffer\n"));
  608. return STATUS_UNSUCCESSFUL;
  609. }
  610. //
  611. // Now we get a little more sofisticated
  612. //
  613. if( IOCTLSize < (sizeof(DIAGS_BULK_IOCTL)+pIOCTL->DataSize-1) )
  614. {
  615. DEBUGMSG(DBG_ERR, (" Diags_PrepareBulk invalid output buffer\n"));
  616. return STATUS_UNSUCCESSFUL;
  617. }
  618. pThisDev->pIOCTL = pIOCTL;
  619. pThisDev->IOCTLStatus = STATUS_UNSUCCESSFUL;
  620. //
  621. // Get a context to queue
  622. //
  623. pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
  624. if( NULL == pListEntry )
  625. {
  626. //
  627. // This must not happen
  628. //
  629. DEBUGMSG(DBG_ERR, (" Diags_PrepareBulk failed to find a free context struct\n"));
  630. IRUSB_ASSERT( 0 );
  631. return STATUS_UNSUCCESSFUL;
  632. }
  633. InterlockedDecrement( &pThisDev->SendAvailableCount );
  634. pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
  635. if( DirectionOut )
  636. pThisContext->ContextType = CONTEXT_DIAGS_BULK_OUT;
  637. else
  638. pThisContext->ContextType = CONTEXT_DIAGS_BULK_IN;
  639. //
  640. // Queue the context and then wait
  641. //
  642. KeClearEvent( &pThisDev->EventDiags );
  643. ExInterlockedInsertTailList(
  644. &pThisDev->SendBuiltQueue,
  645. &pThisContext->ListEntry,
  646. &pThisDev->SendLock
  647. );
  648. InterlockedIncrement( &pThisDev->SendBuiltCount );
  649. MyKeWaitForSingleObject( pThisDev, &pThisDev->EventDiags, 0 );
  650. return pThisDev->IOCTLStatus;
  651. }
  652. /*****************************************************************************
  653. *
  654. * Function: Diags_PrepareSend
  655. *
  656. * Synopsis: Prepares a diagnostic send
  657. *
  658. * Arguments: pThisDev - pointer to IR device
  659. * pIOCTL - pointer to IOCTL descriptor
  660. * IOCTLSize - size of the IOCTL buffer
  661. *
  662. * Returns: None
  663. *
  664. * Notes:
  665. *
  666. *****************************************************************************/
  667. NTSTATUS
  668. Diags_PrepareSend(
  669. IN OUT PIR_DEVICE pThisDev,
  670. OUT PDIAGS_SEND_IOCTL pIOCTL,
  671. ULONG IOCTLSize
  672. )
  673. {
  674. PIRUSB_CONTEXT pThisContext;
  675. PLIST_ENTRY pListEntry;
  676. ULONG Size = sizeof(DIAGS_SEND_IOCTL)+pIOCTL->DataSize-1;
  677. //
  678. // First basic validation
  679. //
  680. if( IOCTLSize < sizeof(DIAGS_SEND_IOCTL) )
  681. {
  682. DEBUGMSG(DBG_ERR, (" Diags_PrepareBulk invalid input buffer\n"));
  683. return STATUS_UNSUCCESSFUL;
  684. }
  685. //
  686. // Now we get a little more sofisticated
  687. //
  688. if( IOCTLSize < (sizeof(DIAGS_SEND_IOCTL)+pIOCTL->DataSize-1) )
  689. {
  690. DEBUGMSG(DBG_ERR, (" Diags_PrepareSend invalid output buffer\n"));
  691. return STATUS_UNSUCCESSFUL;
  692. }
  693. pThisDev->pIOCTL = pIOCTL;
  694. pThisDev->IOCTLStatus = STATUS_UNSUCCESSFUL;
  695. //
  696. // Get a context to queue
  697. //
  698. pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
  699. if( NULL == pListEntry )
  700. {
  701. //
  702. // This must not happen
  703. //
  704. DEBUGMSG(DBG_ERR, (" Diags_PrepareSend failed to find a free context struct\n"));
  705. IRUSB_ASSERT( 0 );
  706. return STATUS_UNSUCCESSFUL;
  707. }
  708. InterlockedDecrement( &pThisDev->SendAvailableCount );
  709. pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
  710. pThisContext->ContextType = CONTEXT_DIAGS_SEND;
  711. //
  712. // Queue the context and then wait
  713. //
  714. KeClearEvent( &pThisDev->EventDiags );
  715. ExInterlockedInsertTailList(
  716. &pThisDev->SendBuiltQueue,
  717. &pThisContext->ListEntry,
  718. &pThisDev->SendLock
  719. );
  720. InterlockedIncrement( &pThisDev->SendBuiltCount );
  721. MyKeWaitForSingleObject( pThisDev, &pThisDev->EventDiags, 0 );
  722. return pThisDev->IOCTLStatus;
  723. }
  724. /*****************************************************************************
  725. *
  726. * Function: Diags_Receive
  727. *
  728. * Synopsis: Diagnostic receive
  729. *
  730. * Arguments: pThisDev - pointer to IR device
  731. * pIOCTL - pointer to IOCTL descriptor
  732. * IOCTLSize - size of the IOCTL buffer
  733. *
  734. * Returns: None
  735. *
  736. * Notes:
  737. *
  738. *****************************************************************************/
  739. NTSTATUS
  740. Diags_Receive(
  741. IN OUT PIR_DEVICE pThisDev,
  742. OUT PDIAGS_RECEIVE_IOCTL pIOCTL,
  743. ULONG IOCTLSize
  744. )
  745. {
  746. PLIST_ENTRY pListEntry;
  747. PRCV_BUFFER pRecBuf;
  748. //
  749. // First basic validation
  750. //
  751. if( IOCTLSize < sizeof(DIAGS_RECEIVE_IOCTL) )
  752. {
  753. DEBUGMSG(DBG_ERR, (" Diags_Receive invalid input buffer\n"));
  754. return STATUS_UNSUCCESSFUL;
  755. }
  756. //
  757. // Get a received packet
  758. //
  759. pListEntry = ExInterlockedRemoveHeadList( &pThisDev->DiagsReceiveQueue, &pThisDev->DiagsReceiveLock );
  760. if( NULL == pListEntry )
  761. {
  762. //
  763. // No packet available
  764. //
  765. return STATUS_UNSUCCESSFUL;
  766. }
  767. pRecBuf = CONTAINING_RECORD( pListEntry, RCV_BUFFER, ListEntry );
  768. //
  769. // Now we get a little more sofisticated
  770. //
  771. if( IOCTLSize < (sizeof(DIAGS_RECEIVE_IOCTL)+pIOCTL->DataSize-1) )
  772. {
  773. DEBUGMSG(DBG_ERR, (" Diags_Receive invalid output buffer\n"));
  774. return STATUS_UNSUCCESSFUL;
  775. }
  776. //
  777. // Fix MS Security bug #534771
  778. //
  779. if (pIOCTL->DataSize < pRecBuf->DataLen)
  780. {
  781. DEBUGMSG(DBG_ERR, (" Diags_Receive output buffer too small\n"));
  782. return STATUS_UNSUCCESSFUL;
  783. }
  784. //
  785. // Copy the data
  786. //
  787. NdisMoveMemory( pIOCTL->pData, pRecBuf->pDataBuf, pRecBuf->DataLen );
  788. pIOCTL->DataSize = (USHORT)pRecBuf->DataLen;
  789. pThisDev->pIOCTL = pIOCTL;
  790. InterlockedExchange( &pRecBuf->DataLen, 0 );
  791. InterlockedExchange( (PULONG)&pRecBuf->BufferState, RCV_STATE_FREE );
  792. return STATUS_SUCCESS;
  793. }
  794. /*****************************************************************************
  795. *
  796. * Function: Diags_GetSpeed
  797. *
  798. * Synopsis: Retrieves the current speed
  799. *
  800. * Arguments: pThisDev - pointer to IR device
  801. * pIOCTL - pointer to IOCTL descriptor
  802. * IOCTLSize - size of the IOCTL buffer
  803. *
  804. * Returns: None
  805. *
  806. * Notes:
  807. *
  808. *****************************************************************************/
  809. NTSTATUS
  810. Diags_GetSpeed(
  811. IN OUT PIR_DEVICE pThisDev,
  812. OUT PDIAGS_SPEED_IOCTL pIOCTL,
  813. ULONG IOCTLSize
  814. )
  815. {
  816. //
  817. // First basic validation
  818. //
  819. if( IOCTLSize < sizeof(DIAGS_SPEED_IOCTL) )
  820. {
  821. DEBUGMSG(DBG_ERR, (" Diags_GetSpeed invalid input buffer\n"));
  822. return STATUS_UNSUCCESSFUL;
  823. }
  824. pIOCTL->Speed = pThisDev->currentSpeed;
  825. return STATUS_SUCCESS;
  826. }
  827. /*****************************************************************************
  828. *
  829. * Function: Diags_SetSpeed
  830. *
  831. * Synopsis: Sets a new speed in diagnostic mode
  832. *
  833. * Arguments: pThisDev - pointer to IR device
  834. * pIOCTL - pointer to IOCTL descriptor
  835. * IOCTLSize - size of the IOCTL buffer
  836. *
  837. * Returns: None
  838. *
  839. * Notes:
  840. *
  841. *****************************************************************************/
  842. NTSTATUS
  843. Diags_SetSpeed(
  844. IN OUT PIR_DEVICE pThisDev,
  845. OUT PDIAGS_SPEED_IOCTL pIOCTL,
  846. ULONG IOCTLSize
  847. )
  848. {
  849. // MS Security fix bug #535716
  850. NDIS_STATUS status = STATUS_UNSUCCESSFUL;
  851. USHORT i;
  852. //
  853. // First basic validation
  854. //
  855. if( IOCTLSize < sizeof(DIAGS_SPEED_IOCTL) )
  856. {
  857. DEBUGMSG(DBG_ERR, (" Diags_SetSpeed invalid input buffer\n"));
  858. return STATUS_UNSUCCESSFUL;
  859. }
  860. if( pThisDev->currentSpeed == pIOCTL->Speed )
  861. {
  862. //
  863. // We are already set to the requested speed.
  864. //
  865. return STATUS_SUCCESS;
  866. }
  867. DEBUGMSG(DBG_ERR, (" Diags_SetSpeed(OID_IRDA_LINK_SPEED, 0x%x, decimal %d)\n",pIOCTL->Speed, pIOCTL->Speed));
  868. for( i = 0; i < NUM_BAUDRATES; i++ )
  869. {
  870. if( supportedBaudRateTable[i].BitsPerSec == pIOCTL->Speed )
  871. {
  872. //
  873. // Keep a pointer to the link speed which has
  874. // been requested.
  875. //
  876. pThisDev->linkSpeedInfo = &supportedBaudRateTable[i];
  877. status = NDIS_STATUS_PENDING;
  878. break; //for
  879. }
  880. }
  881. //
  882. // Don't set if there is an error
  883. //
  884. if( NDIS_STATUS_PENDING != status )
  885. {
  886. DEBUGMSG(DBG_ERR, (" Invalid link speed\n"));
  887. return STATUS_UNSUCCESSFUL;
  888. }
  889. //
  890. // Set the new speed
  891. //
  892. IrUsb_PrepareSetSpeed( pThisDev );
  893. while( pThisDev->linkSpeedInfo->BitsPerSec != pThisDev->currentSpeed )
  894. {
  895. NdisMSleep( 50000 );
  896. }
  897. return STATUS_SUCCESS;
  898. }
  899. /*****************************************************************************
  900. *
  901. * Function: Diags_CompleteEnable
  902. *
  903. * Synopsis: Completes the enabling of the diagnostic state
  904. *
  905. * Arguments: pThisDev - pointer to IR device
  906. * pContext - pinter to the operation context
  907. *
  908. * Returns: None
  909. *
  910. * Notes:
  911. *
  912. *****************************************************************************/
  913. VOID
  914. Diags_CompleteEnable(
  915. IN OUT PIR_DEVICE pThisDev,
  916. IN PVOID pContext
  917. )
  918. {
  919. PIRUSB_CONTEXT pThisContext = pContext;
  920. //
  921. // Really enable diags
  922. //
  923. InterlockedExchange( &pThisDev->DiagsActive, TRUE );
  924. //
  925. // Return the context
  926. //
  927. ExInterlockedInsertTailList(
  928. &pThisDev->SendAvailableQueue,
  929. &pThisContext->ListEntry,
  930. &pThisDev->SendLock
  931. );
  932. InterlockedIncrement( &pThisDev->SendAvailableCount );
  933. //
  934. // Signal
  935. //
  936. KeSetEvent( &pThisDev->EventDiags, 0, FALSE ); //signal we're done
  937. }
  938. /*****************************************************************************
  939. *
  940. * Function: Diags_CompleteReadRegisters
  941. *
  942. * Synopsis: Reads the registers and returns the value
  943. *
  944. * Arguments: pThisDev - pointer to IR device
  945. * pContext - pinter to the operation context
  946. *
  947. * Returns: NTSTATUS
  948. *
  949. * Notes:
  950. *
  951. *****************************************************************************/
  952. NTSTATUS
  953. Diags_CompleteReadRegisters(
  954. IN OUT PIR_DEVICE pThisDev,
  955. IN PVOID pContext
  956. )
  957. {
  958. PDIAGS_READ_REGISTERS_IOCTL pIOCTL = pThisDev->pIOCTL;
  959. PIRUSB_CONTEXT pThisContext = pContext;
  960. //
  961. // Read the data
  962. //
  963. pThisDev->IOCTLStatus = St4200ReadRegisters( pThisDev, pIOCTL->FirstRegister, pIOCTL->NumberRegisters );
  964. if( pThisDev->IOCTLStatus == STATUS_SUCCESS )
  965. {
  966. NdisMoveMemory(
  967. &pIOCTL->pRegisterBuffer,
  968. &pThisDev->StIrTranceiver.FifoDataReg+pIOCTL->FirstRegister,
  969. pIOCTL->NumberRegisters
  970. );
  971. }
  972. //
  973. // Return the context
  974. //
  975. ExInterlockedInsertTailList(
  976. &pThisDev->SendAvailableQueue,
  977. &pThisContext->ListEntry,
  978. &pThisDev->SendLock
  979. );
  980. InterlockedIncrement( &pThisDev->SendAvailableCount );
  981. //
  982. // Signal
  983. //
  984. KeSetEvent( &pThisDev->EventDiags, 0, FALSE ); //signal we're done
  985. return pThisDev->IOCTLStatus;
  986. }
  987. /*****************************************************************************
  988. *
  989. * Function: Diags_CompleteWriteRegister
  990. *
  991. * Synopsis: Reads the registers and returns the value
  992. *
  993. * Arguments: pThisDev - pointer to IR device
  994. * pContext - pinter to the operation context
  995. *
  996. * Returns: NTSTATUS
  997. *
  998. * Notes:
  999. *
  1000. *****************************************************************************/
  1001. NTSTATUS
  1002. Diags_CompleteWriteRegister(
  1003. IN OUT PIR_DEVICE pThisDev,
  1004. IN PVOID pContext
  1005. )
  1006. {
  1007. PDIAGS_READ_REGISTERS_IOCTL pIOCTL = pThisDev->pIOCTL;
  1008. PIRUSB_CONTEXT pThisContext = pContext;
  1009. //
  1010. // Copy the new register value
  1011. //
  1012. NdisMoveMemory(
  1013. &pThisDev->StIrTranceiver.FifoDataReg+pIOCTL->FirstRegister,
  1014. &pIOCTL->pRegisterBuffer,
  1015. 1
  1016. );
  1017. //
  1018. // Write to the device
  1019. //
  1020. pThisDev->IOCTLStatus = St4200WriteRegister( pThisDev, pIOCTL->FirstRegister );
  1021. //
  1022. // Return the context
  1023. //
  1024. ExInterlockedInsertTailList(
  1025. &pThisDev->SendAvailableQueue,
  1026. &pThisContext->ListEntry,
  1027. &pThisDev->SendLock
  1028. );
  1029. InterlockedIncrement( &pThisDev->SendAvailableCount );
  1030. //
  1031. // Signal
  1032. //
  1033. KeSetEvent( &pThisDev->EventDiags, 0, FALSE ); //signal we're done
  1034. return pThisDev->IOCTLStatus;
  1035. }
  1036. /*****************************************************************************
  1037. *
  1038. * Function: Diags_Bulk
  1039. *
  1040. * Synopsis: Executes a diagnostic bulk transfer
  1041. *
  1042. * Arguments: pThisDev - pointer to IR device
  1043. * pContext - pinter to the operation context
  1044. * DirectionOut - TRUE if bulk-out, FALSE if bulk-in
  1045. *
  1046. * Returns: NTSTATUS
  1047. *
  1048. * Notes:
  1049. *
  1050. *****************************************************************************/
  1051. NTSTATUS
  1052. Diags_Bulk(
  1053. IN OUT PIR_DEVICE pThisDev,
  1054. IN PVOID pContext,
  1055. BOOLEAN DirectionOut
  1056. )
  1057. {
  1058. PDIAGS_BULK_IOCTL pIOCTL = pThisDev->pIOCTL;
  1059. PIRUSB_CONTEXT pThisContext = pContext;
  1060. NTSTATUS status = STATUS_SUCCESS;
  1061. PIRP pIrp;
  1062. PURB pUrb = NULL;
  1063. PDEVICE_OBJECT pUrbTargetDev;
  1064. PIO_STACK_LOCATION pNextStack;
  1065. KIRQL OldIrql;
  1066. IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  1067. IRUSB_ASSERT( NULL != pThisContext );
  1068. //
  1069. // Stop if a halt/reset is going on
  1070. //
  1071. if( pThisDev->fPendingWriteClearStall || pThisDev->fPendingHalt ||
  1072. pThisDev->fPendingReset || pThisDev->fPendingClearTotalStall )
  1073. {
  1074. DEBUGMSG(DBG_ERR, (" Diags_Bulk abort due to pending reset or halt\n"));
  1075. goto done;
  1076. }
  1077. //
  1078. // MS Security recommendation - allocate a new urb.
  1079. //
  1080. pThisContext->UrbLen = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  1081. pThisContext->pUrb = MyUrbAlloc(pThisContext->UrbLen);
  1082. if (pThisContext->pUrb == NULL)
  1083. {
  1084. DEBUGMSG(DBG_ERR, (" Diags_Bulk abort due to urb alloc failure\n"));
  1085. goto done;
  1086. }
  1087. pUrb = pThisContext->pUrb;
  1088. //
  1089. // Save the effective length
  1090. //
  1091. pThisDev->BufLen = pIOCTL->DataSize;
  1092. //
  1093. // Now that we have created the urb, we will send a
  1094. // request to the USB device object.
  1095. //
  1096. pUrbTargetDev = pThisDev->pUsbDevObj;
  1097. //
  1098. // make an irp sending to usbhub
  1099. //
  1100. pIrp = IoAllocateIrp( (CCHAR)(pThisDev->pUsbDevObj->StackSize + 1), FALSE );
  1101. if( NULL == pIrp )
  1102. {
  1103. DEBUGMSG(DBG_ERR, (" Diags_Bulk failed to alloc IRP\n"));
  1104. MyUrbFree(pThisContext->pUrb, pThisContext->UrbLen);
  1105. goto done;
  1106. }
  1107. pIrp->IoStatus.Status = STATUS_PENDING;
  1108. pIrp->IoStatus.Information = 0;
  1109. pThisContext->pIrp = pIrp;
  1110. //
  1111. // Build our URB for USBD
  1112. //
  1113. pUrb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT)sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  1114. pUrb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  1115. if( DirectionOut )
  1116. {
  1117. pUrb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT ;
  1118. pUrb->UrbBulkOrInterruptTransfer.PipeHandle = pThisDev->BulkOutPipeHandle;
  1119. }
  1120. else
  1121. {
  1122. pUrb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN ;
  1123. pUrb->UrbBulkOrInterruptTransfer.PipeHandle = pThisDev->BulkInPipeHandle;
  1124. }
  1125. // short packet is not treated as an error.
  1126. pUrb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
  1127. pUrb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  1128. pUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
  1129. pUrb->UrbBulkOrInterruptTransfer.TransferBuffer = pIOCTL->pData;
  1130. pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = (int)pIOCTL->DataSize;
  1131. //
  1132. // Call the class driver to perform the operation.
  1133. //
  1134. pNextStack = IoGetNextIrpStackLocation( pIrp );
  1135. IRUSB_ASSERT( pNextStack != NULL );
  1136. //
  1137. // pass the URB to the USB driver stack
  1138. //
  1139. pNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1140. pNextStack->Parameters.Others.Argument1 = pUrb;
  1141. pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  1142. IoSetCompletionRoutine(
  1143. pIrp, // irp to use
  1144. Diags_CompleteIrp, // routine to call when irp is done
  1145. DEV_TO_CONTEXT(pThisContext), // context to pass routine
  1146. TRUE, // call on success
  1147. TRUE, // call on error
  1148. TRUE // call on cancel
  1149. );
  1150. #ifdef SERIALIZE
  1151. KeClearEvent( &pThisDev->EventSyncUrb );
  1152. #endif
  1153. //
  1154. // Call IoCallDriver to send the irp to the usb port.
  1155. //
  1156. ExInterlockedInsertTailList(
  1157. &pThisDev->SendPendingQueue,
  1158. &pThisContext->ListEntry,
  1159. &pThisDev->SendLock
  1160. );
  1161. InterlockedIncrement( &pThisDev->SendPendingCount );
  1162. status = MyIoCallDriver( pThisDev, pUrbTargetDev, pIrp );
  1163. //
  1164. // The USB driver should always return STATUS_PENDING when
  1165. // it receives a write irp
  1166. //
  1167. IRUSB_ASSERT( status == STATUS_PENDING );
  1168. status = MyKeWaitForSingleObject( pThisDev, &pThisDev->EventSyncUrb, 0 );
  1169. if( status == STATUS_TIMEOUT )
  1170. {
  1171. DEBUGMSG( DBG_ERR,(" Diags_Bulk() TIMED OUT! return from IoCallDriver USBD %x\n", status));
  1172. // MS Security recommendation - cannot cancel IRP.
  1173. IRUSB_ASSERT(0);
  1174. }
  1175. done:
  1176. //
  1177. // Return the context
  1178. //
  1179. KeAcquireSpinLock( &pThisDev->SendLock, &OldIrql );
  1180. RemoveEntryList( &pThisContext->ListEntry );
  1181. KeReleaseSpinLock( &pThisDev->SendLock, OldIrql );
  1182. InterlockedDecrement( &pThisDev->SendPendingCount );
  1183. ExInterlockedInsertTailList(
  1184. &pThisDev->SendAvailableQueue,
  1185. &pThisContext->ListEntry,
  1186. &pThisDev->SendLock
  1187. );
  1188. InterlockedIncrement( &pThisDev->SendAvailableCount );
  1189. //
  1190. // Signal
  1191. //
  1192. KeSetEvent( &pThisDev->EventDiags, 0, FALSE ); //signal we're done
  1193. return status;
  1194. }
  1195. /*****************************************************************************
  1196. *
  1197. * Function: Diags_Send
  1198. *
  1199. * Synopsis: Sends a packet through the diagnostic path
  1200. *
  1201. * Arguments: pThisDev - pointer to IR device
  1202. * pContext - pinter to the operation context
  1203. *
  1204. * Returns: NTSTATUS
  1205. *
  1206. * Notes:
  1207. *
  1208. *****************************************************************************/
  1209. NTSTATUS
  1210. Diags_Send(
  1211. IN OUT PIR_DEVICE pThisDev,
  1212. IN PVOID pContext
  1213. )
  1214. {
  1215. PDIAGS_SEND_IOCTL pIOCTL = pThisDev->pIOCTL;
  1216. PIRUSB_CONTEXT pThisContext = pContext;
  1217. NTSTATUS status = STATUS_SUCCESS;
  1218. PIRP pIrp;
  1219. PURB pUrb = NULL;
  1220. PDEVICE_OBJECT pUrbTargetDev;
  1221. PIO_STACK_LOCATION pNextStack;
  1222. BOOLEAN fConvertedPacket;
  1223. KIRQL OldIrql;
  1224. ULONG BytesToWrite;
  1225. IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  1226. IRUSB_ASSERT( NULL != pThisContext );
  1227. //
  1228. // Stop if a halt/reset is going on
  1229. //
  1230. if( pThisDev->fPendingWriteClearStall || pThisDev->fPendingHalt ||
  1231. pThisDev->fPendingReset || pThisDev->fPendingClearTotalStall )
  1232. {
  1233. DEBUGMSG(DBG_ERR, (" Diags_Send abort due to pending reset or halt\n"));
  1234. goto done;
  1235. }
  1236. DEBUGMSG(DBG_ERR, (" Diags_Send() packet size: %d\n", pIOCTL->DataSize));
  1237. //
  1238. // Convert the packet to an ir frame and copy into our buffer
  1239. // and send the irp.
  1240. //
  1241. if( pThisDev->currentSpeed<=MAX_SIR_SPEED )
  1242. {
  1243. fConvertedPacket = Diags_BufferToSirPacket(
  1244. pThisDev,
  1245. (PUCHAR)pThisDev->pBuffer,
  1246. MAX_IRDA_DATA_SIZE,
  1247. pIOCTL->pData,
  1248. pIOCTL->DataSize,
  1249. pIOCTL->ExtraBOFs,
  1250. &BytesToWrite
  1251. );
  1252. }
  1253. else if( pThisDev->currentSpeed<=MAX_MIR_SPEED )
  1254. {
  1255. fConvertedPacket = Diags_BufferToFirPacket(
  1256. pThisDev,
  1257. (PUCHAR)pThisDev->pBuffer,
  1258. MAX_IRDA_DATA_SIZE,
  1259. pIOCTL->pData,
  1260. pIOCTL->DataSize,
  1261. &BytesToWrite
  1262. );
  1263. }
  1264. else
  1265. {
  1266. fConvertedPacket = Diags_BufferToFirPacket(
  1267. pThisDev,
  1268. (PUCHAR)pThisDev->pBuffer,
  1269. MAX_IRDA_DATA_SIZE,
  1270. pIOCTL->pData,
  1271. pIOCTL->DataSize,
  1272. &BytesToWrite
  1273. );
  1274. }
  1275. if( fConvertedPacket == FALSE )
  1276. {
  1277. DEBUGMSG(DBG_ERR, (" Diags_Send() NdisToIrPacket failed. Couldn't convert packet!\n"));
  1278. goto done;
  1279. }
  1280. //
  1281. // Always force turnaround
  1282. //
  1283. NdisMSleep( pThisDev->dongleCaps.turnAroundTime_usec );
  1284. //
  1285. // MS Security recommendation - allocate a new urb.
  1286. //
  1287. pThisContext->UrbLen = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  1288. pThisContext->pUrb = MyUrbAlloc(pThisContext->UrbLen);
  1289. if (pThisContext->pUrb == NULL)
  1290. {
  1291. DEBUGMSG(DBG_ERR, (" Diags_Send abort due to urb alloc failure\n"));
  1292. goto done;
  1293. }
  1294. pUrb = pThisContext->pUrb;
  1295. //
  1296. // Now that we have created the urb, we will send a
  1297. // request to the USB device object.
  1298. //
  1299. pUrbTargetDev = pThisDev->pUsbDevObj;
  1300. //
  1301. // make an irp sending to usbhub
  1302. //
  1303. pIrp = IoAllocateIrp( (CCHAR)(pThisDev->pUsbDevObj->StackSize + 1), FALSE );
  1304. if( NULL == pIrp )
  1305. {
  1306. DEBUGMSG(DBG_ERR, (" Diags_Send failed to alloc IRP\n"));
  1307. MyUrbFree(pThisContext->pUrb, pThisContext->UrbLen);
  1308. goto done;
  1309. }
  1310. pIrp->IoStatus.Status = STATUS_PENDING;
  1311. pIrp->IoStatus.Information = 0;
  1312. pThisContext->pIrp = pIrp;
  1313. //
  1314. // Build our URB for USBD
  1315. //
  1316. pUrb->UrbBulkOrInterruptTransfer.Hdr.Length = (USHORT)sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  1317. pUrb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
  1318. pUrb->UrbBulkOrInterruptTransfer.PipeHandle = pThisDev->BulkOutPipeHandle;
  1319. pUrb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT ;
  1320. // short packet is not treated as an error.
  1321. pUrb->UrbBulkOrInterruptTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
  1322. pUrb->UrbBulkOrInterruptTransfer.UrbLink = NULL;
  1323. pUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL = NULL;
  1324. pUrb->UrbBulkOrInterruptTransfer.TransferBuffer = pThisDev->pBuffer;
  1325. pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = (int)BytesToWrite;
  1326. //
  1327. // Call the class driver to perform the operation.
  1328. //
  1329. pNextStack = IoGetNextIrpStackLocation( pIrp );
  1330. IRUSB_ASSERT( pNextStack != NULL );
  1331. //
  1332. // pass the URB to the USB driver stack
  1333. //
  1334. pNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1335. pNextStack->Parameters.Others.Argument1 = pUrb;
  1336. pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  1337. IoSetCompletionRoutine(
  1338. pIrp, // irp to use
  1339. Diags_CompleteIrp, // routine to call when irp is done
  1340. DEV_TO_CONTEXT(pThisContext), // context to pass routine
  1341. TRUE, // call on success
  1342. TRUE, // call on error
  1343. TRUE // call on cancel
  1344. );
  1345. #ifdef SERIALIZE
  1346. KeClearEvent( &pThisDev->EventSyncUrb );
  1347. #endif
  1348. //
  1349. // Call IoCallDriver to send the irp to the usb port.
  1350. //
  1351. ExInterlockedInsertTailList(
  1352. &pThisDev->SendPendingQueue,
  1353. &pThisContext->ListEntry,
  1354. &pThisDev->SendLock
  1355. );
  1356. InterlockedIncrement( &pThisDev->SendPendingCount );
  1357. status = MyIoCallDriver( pThisDev, pUrbTargetDev, pIrp );
  1358. //
  1359. // The USB driver should always return STATUS_PENDING when
  1360. // it receives a write irp
  1361. //
  1362. IRUSB_ASSERT( status == STATUS_PENDING );
  1363. status = MyKeWaitForSingleObject( pThisDev, &pThisDev->EventSyncUrb, 0 );
  1364. if( status == STATUS_TIMEOUT )
  1365. {
  1366. DEBUGMSG( DBG_ERR,(" Diags_Send() TIMED OUT! return from IoCallDriver USBD %x\n", status));
  1367. // MS Security recommendation - cannot cancel IRP.
  1368. IRUSB_ASSERT(0);
  1369. }
  1370. done:
  1371. //
  1372. // Return the context
  1373. //
  1374. KeAcquireSpinLock( &pThisDev->SendLock, &OldIrql );
  1375. RemoveEntryList( &pThisContext->ListEntry );
  1376. KeReleaseSpinLock( &pThisDev->SendLock, OldIrql );
  1377. InterlockedDecrement( &pThisDev->SendPendingCount );
  1378. ExInterlockedInsertTailList(
  1379. &pThisDev->SendAvailableQueue,
  1380. &pThisContext->ListEntry,
  1381. &pThisDev->SendLock
  1382. );
  1383. InterlockedIncrement( &pThisDev->SendAvailableCount );
  1384. //
  1385. // Signal
  1386. //
  1387. KeSetEvent( &pThisDev->EventDiags, 0, FALSE ); //signal we're done
  1388. return status;
  1389. }
  1390. /*****************************************************************************
  1391. *
  1392. * Function: Diags_CompleteIrp
  1393. *
  1394. * Synopsis: Completes a USB operation
  1395. *
  1396. * Arguments: pUsbDevObj - pointer to the USB device object which
  1397. * completed the irp
  1398. * pIrp - the irp which was completed by the
  1399. * device object
  1400. * Context - the context given to IoSetCompletionRoutine
  1401. * before calling IoCallDriver on the irp
  1402. * The Context is a pointer to the ir device object.
  1403. *
  1404. * Returns: STATUS_MORE_PROCESSING_REQUIRED - allows the completion routine
  1405. * (IofCompleteRequest) to stop working on the irp.
  1406. *
  1407. *****************************************************************************/
  1408. NTSTATUS
  1409. Diags_CompleteIrp(
  1410. IN PDEVICE_OBJECT pUsbDevObj,
  1411. IN PIRP pIrp,
  1412. IN PVOID Context
  1413. )
  1414. {
  1415. PIR_DEVICE pThisDev;
  1416. NTSTATUS status;
  1417. PIRUSB_CONTEXT pThisContext = (PIRUSB_CONTEXT)Context;
  1418. PIRP pContextIrp;
  1419. PURB pContextUrb;
  1420. PDIAGS_BULK_IOCTL pIOCTL;
  1421. //
  1422. // The context given to IoSetCompletionRoutine is an IRUSB_CONTEXT struct
  1423. //
  1424. IRUSB_ASSERT( NULL != pThisContext ); // we better have a non NULL buffer
  1425. pThisDev = pThisContext->pThisDev;
  1426. IRUSB_ASSERT( NULL != pThisDev );
  1427. pContextIrp = pThisContext->pIrp;
  1428. pContextUrb = pThisContext->pUrb;
  1429. pIOCTL = pThisDev->pIOCTL;
  1430. //
  1431. // Perform various IRP, URB, and buffer 'sanity checks'
  1432. //
  1433. IRUSB_ASSERT( pContextIrp == pIrp ); // check we're not a bogus IRP
  1434. IRUSB_ASSERT( pContextUrb != NULL );
  1435. status = pIrp->IoStatus.Status;
  1436. pThisDev->IOCTLStatus = status;
  1437. //
  1438. // we should have failed, succeeded, or cancelled, but NOT be pending
  1439. //
  1440. IRUSB_ASSERT( STATUS_PENDING != status );
  1441. //
  1442. // IoCallDriver has been called on this Irp;
  1443. // Set the length based on the TransferBufferLength
  1444. // value in the URB
  1445. //
  1446. pIrp->IoStatus.Information = pContextUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
  1447. pIOCTL->DataSize = (USHORT)pIrp->IoStatus.Information;
  1448. //
  1449. // Free the IRP.
  1450. //
  1451. IoFreeIrp( pIrp );
  1452. InterlockedIncrement( (PLONG)&pThisDev->NumWrites );
  1453. IrUsb_DecIoCount( pThisDev ); // we will track count of pending irps
  1454. // Free the URB.
  1455. MyUrbFree(pThisContext->pUrb, pThisContext->UrbLen);
  1456. pThisContext->pUrb = NULL;
  1457. #ifdef SERIALIZE
  1458. KeSetEvent( &pThisDev->EventSyncUrb, 0, FALSE ); //signal we're done
  1459. #endif
  1460. return STATUS_MORE_PROCESSING_REQUIRED;
  1461. }
  1462. #endif