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.

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