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.

2422 lines
67 KiB

  1. /**************************************************************************************************************************
  2. * RWIR.C SigmaTel STIR4200 USB, but not NDIS, module
  3. **************************************************************************************************************************
  4. * (C) Unpublished Copyright of Sigmatel, Inc. All Rights Reserved.
  5. *
  6. *
  7. * Created: 04/06/2000
  8. * Version 0.9
  9. * Edited: 04/24/2000
  10. * Version 0.91
  11. * Edited: 04/27/2000
  12. * Version 0.92
  13. * Edited: 05/01/2000
  14. * Version 0.93
  15. * Edited: 05/12/2000
  16. * Version 0.94
  17. * Edited: 05/19/2000
  18. * Version 0.95
  19. * Edited: 05/24/2000
  20. * Version 0.96
  21. * Edited: 08/22/2000
  22. * Version 1.02
  23. * Edited: 09/25/2000
  24. * Version 1.10
  25. * Edited: 11/09/2000
  26. * Version 1.12
  27. *
  28. *
  29. **************************************************************************************************************************/
  30. #include <ndis.h>
  31. #include <ntdef.h>
  32. #include <windef.h>
  33. #include "usbdi.h"
  34. #include "usbdlib.h"
  35. #include "debug.h"
  36. #include "ircommon.h"
  37. #include "irusb.h"
  38. #include "diags.h"
  39. /*****************************************************************************
  40. *
  41. * Function: InitializeProcessing
  42. *
  43. * Synopsis: Initialize the driver processing (sending and receiving packets) functionality.
  44. *
  45. * Arguments: pThisDevice - pointer to current ir device object
  46. * InitPassiveThread - whether we must initialize the passive thread
  47. *
  48. * Returns: NDIS_STATUS_SUCCESS - if irp is successfully sent to USB
  49. * device object
  50. * NDIS_STATUS_RESOURCES - if mem can't be alloc'd
  51. * NDIS_STATUS_FAILURE - otherwise
  52. *
  53. * Notes:
  54. *
  55. * This routine must be called in IRQL PASSIVE_LEVEL.
  56. *
  57. *****************************************************************************/
  58. NTSTATUS
  59. InitializeProcessing(
  60. IN OUT PIR_DEVICE pThisDev,
  61. IN BOOLEAN InitPassiveThread
  62. )
  63. {
  64. NTSTATUS status = STATUS_SUCCESS;
  65. DEBUGMSG(DBG_FUNC, ("+InitializeProcessing\n"));
  66. if( InitPassiveThread )
  67. {
  68. //
  69. // Create a thread to run at IRQL PASSIVE_LEVEL.
  70. //
  71. status = PsCreateSystemThread(
  72. &pThisDev->hPassiveThread,
  73. (ACCESS_MASK)0L,
  74. NULL,
  75. NULL,
  76. NULL,
  77. PassiveLevelThread,
  78. pThisDev
  79. );
  80. if( status != STATUS_SUCCESS )
  81. {
  82. DEBUGMSG(DBG_ERROR, (" PsCreateSystemThread PassiveLevelThread failed. Returned 0x%.8x\n", status));
  83. status = STATUS_INSUFFICIENT_RESOURCES;
  84. goto done;
  85. }
  86. }
  87. //
  88. // Create a thread to run at IRQL PASSIVE_LEVEL to be always receiving.
  89. //
  90. status = PsCreateSystemThread(
  91. &pThisDev->hPollingThread,
  92. (ACCESS_MASK)0L,
  93. NULL,
  94. NULL,
  95. NULL,
  96. PollingThread,
  97. pThisDev
  98. );
  99. if( status != STATUS_SUCCESS )
  100. {
  101. DEBUGMSG(DBG_ERROR, (" PsCreateSystemThread PollingThread failed. Returned 0x%.8x\n", status));
  102. status = STATUS_INSUFFICIENT_RESOURCES;
  103. goto done;
  104. }
  105. pThisDev->fProcessing = TRUE;
  106. done:
  107. DEBUGMSG(DBG_FUNC, ("-InitializeProcessing\n"));
  108. return status;
  109. }
  110. /*****************************************************************************
  111. *
  112. * Function: ScheduleWorkItem
  113. *
  114. * Synopsis: Preapares a work item in such a way that the passive thread can process it
  115. *
  116. * Arguments: pThisDev - pointer to IR device
  117. * Callback - function to call
  118. * pInfoBuf - context for the call
  119. * InfoBufLen - length of the context
  120. *
  121. * Returns: TRUE if successful
  122. * FALSE otherwise
  123. *
  124. * Notes:
  125. *
  126. *****************************************************************************/
  127. BOOLEAN
  128. ScheduleWorkItem(
  129. IN OUT PIR_DEVICE pThisDev,
  130. WORK_PROC Callback,
  131. IN PVOID pInfoBuf,
  132. ULONG InfoBufLen
  133. )
  134. {
  135. int i;
  136. PIR_WORK_ITEM pWorkItem = NULL;
  137. BOOLEAN ItemScheduled = FALSE;
  138. DEBUGMSG(DBG_FUNC, ("+ScheduleWorkItem\n"));
  139. //
  140. // Find an item that is available
  141. //
  142. for( i = 0; i < NUM_WORK_ITEMS; i++ )
  143. {
  144. pWorkItem = &(pThisDev->WorkItems[i]);
  145. if( pWorkItem->fInUse == FALSE )
  146. {
  147. InterlockedExchange( (PLONG)&pWorkItem->fInUse, TRUE );
  148. ItemScheduled = TRUE;
  149. break;
  150. }
  151. }
  152. //
  153. // Can't fail because can only have one set and one query pending,
  154. // and no more than 8 packets to process
  155. //
  156. IRUSB_ASSERT( NULL != pWorkItem );
  157. IRUSB_ASSERT( i < NUM_WORK_ITEMS );
  158. InterlockedExchangePointer( &pWorkItem->pInfoBuf, pInfoBuf );
  159. InterlockedExchange( (PLONG)&pWorkItem->InfoBufLen, InfoBufLen );
  160. /*
  161. ** This interface was designed to use NdisScheduleWorkItem(), which
  162. ** would be good except that we're really only supposed to use that
  163. ** interface during startup and shutdown, due to the limited pool of
  164. ** threads available to service NdisScheduleWorkItem(). Therefore,
  165. ** instead of scheduling real work items, we simulate them, and use
  166. ** our own thread to process the calls. This also makes it easy to
  167. ** expand the size of our own thread pool, if we wish.
  168. **
  169. ** Our version is slightly different from actual NDIS_WORK_ITEMs,
  170. ** because that is an NDIS 5.0 structure, and we want people to
  171. ** (at least temporarily) build this with NDIS 4.0 headers.
  172. */
  173. InterlockedExchangePointer( (PVOID *)&pWorkItem->Callback, (PVOID)Callback );
  174. /*
  175. ** Our worker thread checks this list for new jobs, whenever its event
  176. ** is signalled.
  177. */
  178. // wake up worker thread
  179. KeSetEvent( &pThisDev->EventPassiveThread, 0, FALSE );
  180. DEBUGMSG(DBG_FUNC, ("-ScheduleWorkItem\n"));
  181. return ItemScheduled;
  182. }
  183. /*****************************************************************************
  184. *
  185. * Function: FreeWorkItem
  186. *
  187. * Synopsis: Sets the work item to the reusable state.
  188. *
  189. * Arguments: pItem - pointer to work item
  190. *
  191. * Returns: None
  192. *
  193. * Notes:
  194. *
  195. *****************************************************************************/
  196. VOID
  197. FreeWorkItem(
  198. IN OUT PIR_WORK_ITEM pItem
  199. )
  200. {
  201. InterlockedExchange( (PLONG)&pItem->fInUse, FALSE );
  202. }
  203. /*****************************************************************************
  204. *
  205. * Function: IrUsb_CancelPendingIo
  206. *
  207. * Synopsis: Cancels all the pending IO for the device
  208. *
  209. * Arguments: pThisDev - pointer to the IR device
  210. *
  211. * Returns: None
  212. *
  213. * Notes:
  214. *
  215. *****************************************************************************/
  216. VOID
  217. IrUsb_CancelPendingIo(
  218. IN OUT PIR_DEVICE pThisDev
  219. )
  220. {
  221. DEBUGMSG( DBG_FUNC, ("+IrUsb_CancelPendingIo(), fDeviceStarted =%d\n", pThisDev->fDeviceStarted)); // chag to FUNC later?
  222. IRUSB_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
  223. if( pThisDev->fDeviceStarted )
  224. {
  225. IrUsb_CancelPendingReadIo( pThisDev, TRUE );
  226. IrUsb_CancelPendingWriteIo( pThisDev );
  227. IrUsb_CancelPendingReadWriteIo( pThisDev );
  228. }
  229. DEBUGMSG( DBG_FUNC, ("-IrUsb_CancelPendingIo()\n")); // chag to FUNC later?
  230. }
  231. /*****************************************************************************
  232. *
  233. * Function: IrUsb_CancelPendingReadIo
  234. *
  235. * Synopsis: Cancels the pending read IRPs
  236. *
  237. * Arguments: pThisDev - pointer to the IR device
  238. * fWaitCancelComplete - pointer to the IRP to cancel
  239. *
  240. * Returns: TRUE if cancelled any
  241. * FALSE otherwise
  242. *
  243. * Notes:
  244. *
  245. *****************************************************************************/
  246. BOOLEAN
  247. IrUsb_CancelPendingReadIo(
  248. IN OUT PIR_DEVICE pThisDev,
  249. BOOLEAN fWaitCancelComplete
  250. )
  251. {
  252. BOOLEAN CancelResult = FALSE;
  253. int i;
  254. DEBUGMSG( DBG_FUNC, ("+IrUsb_CancelPendingReadIo()\n"));
  255. IRUSB_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
  256. if( ( RCV_STATE_PENDING == pThisDev->PreReadBuffer.BufferState ) &&
  257. ( NULL != pThisDev->PreReadBuffer.pIrp ) )
  258. {
  259. PIRP pIrp = (PIRP)pThisDev->PreReadBuffer.pIrp;
  260. //
  261. // Since IoCallDriver has been called on this request, we call IoCancelIrp
  262. // and let our completion routine handle it
  263. //
  264. DEBUGMSG( DBG_FUNC, (" IrUsb_CancelPendingReadIo() about to CANCEL a read IRP!\n"));
  265. KeClearEvent( &pThisDev->EventAsyncUrb );
  266. CancelResult = IoCancelIrp( (PIRP)pThisDev->PreReadBuffer.pIrp );
  267. DEBUGCOND( DBG_ERR, !CancelResult, (" IrUsb_CancelPendingReadIo() COULDN'T CANCEL IRP!\n"));
  268. DEBUGCOND( DBG_FUNC, CancelResult, (" IrUsb_CancelPendingReadIo() CANCELLED IRP SUCCESS!\n"));
  269. if( CancelResult && fWaitCancelComplete )
  270. {
  271. MyKeWaitForSingleObject(
  272. pThisDev,
  273. &pThisDev->EventAsyncUrb,
  274. NULL, // irp to cancel; we did it above already, so pass NULL
  275. 0
  276. );
  277. IRUSB_ASSERT( pThisDev->PreReadBuffer.pIrp == NULL );
  278. }
  279. }
  280. DEBUGMSG( DBG_FUNC, ("-IrUsb_CancelPendingReadIo()\n"));
  281. return CancelResult;
  282. }
  283. /*****************************************************************************
  284. *
  285. * Function: IrUsb_CancelPendingWriteIo
  286. *
  287. * Synopsis: Cancels the pending write IRPs
  288. *
  289. * Arguments: pThisDev - pointer to the IR device
  290. *
  291. * Returns: TRUE if cancelled any
  292. * FALSE otherwise
  293. *
  294. * Notes:
  295. *
  296. *****************************************************************************/
  297. BOOLEAN
  298. IrUsb_CancelPendingWriteIo(
  299. IN OUT PIR_DEVICE pThisDev
  300. )
  301. {
  302. BOOLEAN CancelResult = FALSE;
  303. PIRUSB_CONTEXT pThisContext;
  304. PLIST_ENTRY pListEntry;
  305. DEBUGMSG( DBG_FUNC, ("+IrUsb_CancelPendingWriteIo()\n"));
  306. IRUSB_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  307. //
  308. // Free all resources for the SEND buffer queue.
  309. //
  310. while( pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendPendingQueue, &pThisDev->SendLock ) )
  311. {
  312. InterlockedDecrement( &pThisDev->SendPendingCount );
  313. pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
  314. //
  315. // Get the IRUSB_CONTEXT and cancel its IRP; the completion routine will itself
  316. // remove it from the HeadPendingSendList and NULL out HeadPendingSendList
  317. // when the last IRP on the list has been cancelled; that's how we exit this loop
  318. //
  319. IRUSB_ASSERT( NULL != pThisContext->pIrp );
  320. DEBUGMSG( DBG_WARN, (" IrUsb_CancelPendingWriteIo() about to CANCEL a write IRP!\n"));
  321. //
  322. // Completion routine ( IrUsbCompleteWrite() )will free irps, mdls, buffers, etc as well
  323. //
  324. CancelResult = IoCancelIrp( pThisContext->pIrp );
  325. DEBUGCOND( DBG_ERR, !CancelResult,
  326. (" IrUsb_CancelPendingWriteIo() COULDN'T CANCEL IRP! 0x%x\n", pThisContext->pIrp ) );
  327. DEBUGCOND( DBG_FUNC, CancelResult,
  328. (" IrUsb_CancelPendingWriteIo() CANCELLED IRP SUCCESS! 0x%x\n\n", pThisContext->pIrp) );
  329. //
  330. // Sleep 200 microsecs to give cancellation time to work
  331. //
  332. NdisMSleep( 200 );
  333. }
  334. DEBUGMSG( DBG_FUNC, ("-IrUsb_CancelPendingWriteIo()\n"));
  335. return CancelResult;
  336. }
  337. /*****************************************************************************
  338. *
  339. * Function: IrUsb_CancelPendingReadWriteIo
  340. *
  341. * Synopsis: Cancels the pending register access IRPs
  342. *
  343. * Arguments: pThisDev - pointer to the IR device
  344. *
  345. * Returns: TRUE if cancelled any
  346. * FALSE otherwise
  347. *
  348. * Notes:
  349. *
  350. *****************************************************************************/
  351. BOOLEAN
  352. IrUsb_CancelPendingReadWriteIo(
  353. IN OUT PIR_DEVICE pThisDev
  354. )
  355. {
  356. BOOLEAN CancelResult = FALSE;
  357. PIRUSB_CONTEXT pThisContext;
  358. PLIST_ENTRY pListEntry;
  359. DEBUGMSG( DBG_FUNC, ("+IrUsb_CancelPendingReadWriteIo()\n"));
  360. IRUSB_ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL );
  361. //
  362. // Free all resources for the SEND buffer queue.
  363. //
  364. while( pListEntry = ExInterlockedRemoveHeadList( &pThisDev->ReadWritePendingQueue, &pThisDev->SendLock ) )
  365. {
  366. InterlockedDecrement( &pThisDev->ReadWritePendingCount );
  367. pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
  368. //
  369. // Get the IRUSB_CONTEXT and cancel its IRP; the completion routine will itself
  370. // remove it from the HeadPendingSendList and NULL out HeadPendingSendList
  371. // when the last IRP on the list has been cancelled; that's how we exit this loop
  372. //
  373. IRUSB_ASSERT( NULL != pThisContext->pIrp );
  374. DEBUGMSG( DBG_WARN, (" IrUsb_CancelPendingReadWriteIo() about to CANCEL a write IRP!\n"));
  375. //
  376. // Completion routine ( IrUsbCompleteWrite() )will free irps, mdls, buffers, etc as well
  377. //
  378. CancelResult = IoCancelIrp( pThisContext->pIrp );
  379. DEBUGCOND( DBG_ERR, !CancelResult,
  380. (" IrUsb_CancelPendingReadWriteIo() COULDN'T CANCEL IRP! 0x%x\n", pThisContext->pIrp ) );
  381. DEBUGCOND( DBG_WARN, CancelResult,
  382. (" IrUsb_CancelPendingReadWriteIo() CANCELLED IRP SUCCESS! 0x%x\n\n", pThisContext->pIrp) );
  383. //
  384. // Sleep 200 microsecs to give cancellation time to work
  385. //
  386. NdisMSleep( 200 );
  387. }
  388. DEBUGMSG( DBG_FUNC, ("-IrUsb_CancelPendingReadWriteIo()\n"));
  389. return CancelResult;
  390. }
  391. /*****************************************************************************
  392. *
  393. * Function: IrUsb_CancelIo
  394. *
  395. * Synopsis: Cancels a pending IRP
  396. *
  397. * Arguments: pThisDev - pointer to the IR device
  398. * pIrpToCancel - pointer to the IRP to cancel
  399. * pEventToClear - pointer to the event to wait on
  400. *
  401. * Returns: TRUE if cancelled,
  402. * FALSE otherwise
  403. *
  404. * Notes:
  405. *
  406. *****************************************************************************/
  407. BOOLEAN
  408. IrUsb_CancelIo(
  409. IN PIR_DEVICE pThisDev,
  410. IN PIRP pIrpToCancel,
  411. IN PKEVENT pEventToClear
  412. )
  413. {
  414. BOOLEAN CancelResult = FALSE;
  415. DEBUGMSG( DBG_FUNC, ("+IrUsb_CancelIo()\n"));
  416. IRUSB_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
  417. KeClearEvent( pEventToClear );
  418. CancelResult = IoCancelIrp( pIrpToCancel );
  419. DEBUGCOND( DBG_ERR, !CancelResult, (" IrUsb_CancelIo() COULDN'T CANCEL IRP!\n"));
  420. DEBUGCOND( DBG_FUNC, CancelResult, (" IrUsb_CancelIo() CANCELLED IRP SUCCESS!\n"));
  421. if( CancelResult )
  422. {
  423. MyKeWaitForSingleObject(
  424. pThisDev,
  425. pEventToClear,
  426. NULL, // irp to cancel; we did it above already, so pass NULL
  427. 0
  428. );
  429. }
  430. DEBUGMSG( DBG_FUNC, ("-IrUsb_CancelIo()\n"));
  431. return CancelResult;
  432. }
  433. /*****************************************************************************
  434. *
  435. * Function: MyIoCallDriver
  436. *
  437. * Synopsis: Calls a device driver and keeps track of the count
  438. *
  439. * Arguments: pThisDev - pointer to IR device
  440. * pDeviceObject - pointer to device driver to call
  441. * pIrp - pointer to Irp to submit
  442. *
  443. * Returns: NT status code
  444. *
  445. * Notes:
  446. *
  447. *****************************************************************************/
  448. NTSTATUS
  449. MyIoCallDriver(
  450. IN PIR_DEVICE pThisDev,
  451. IN PDEVICE_OBJECT pDeviceObject,
  452. IN OUT PIRP pIrp
  453. )
  454. {
  455. NTSTATUS ntStatus;
  456. DEBUGMSG( DBG_FUNC,("+MyIoCallDriver\n "));
  457. //
  458. // We will track count of pending irps;
  459. // We May later add logic to actually save array of pending irps
  460. //
  461. IrUsb_IncIoCount( pThisDev );
  462. ntStatus = IoCallDriver( pDeviceObject, pIrp );
  463. DEBUGMSG( DBG_FUNC,("+MyIoCallDriver\n "));
  464. return ntStatus;
  465. }
  466. /*****************************************************************************
  467. *
  468. * Function: IrUsb_CallUSBD
  469. *
  470. * Synopsis: Passes a URB to the USBD class driver
  471. * The client device driver passes USB request block (URB) structures
  472. * to the class driver as a parameter in an IRP with Irp->MajorFunction
  473. * set to IRP_MJ_INTERNAL_DEVICE_CONTROL and the next IRP stack location
  474. * Parameters.DeviceIoControl.IoControlCode field set to
  475. * IOCTL_INTERNAL_USB_SUBMIT_URB.
  476. *
  477. * Arguments: pThisDev - pointer to the IR device
  478. * pUrb - pointer to an already-formatted Urb request block
  479. *
  480. * Returns: STATUS_SUCCESS if successful,
  481. * STATUS_UNSUCCESSFUL otherwise
  482. *
  483. * Notes:
  484. *
  485. *****************************************************************************/
  486. NTSTATUS
  487. IrUsb_CallUSBD(
  488. IN PIR_DEVICE pThisDev,
  489. IN PURB pUrb
  490. )
  491. {
  492. NTSTATUS ntStatus;
  493. PDEVICE_OBJECT pUrbTargetDev;
  494. PIO_STACK_LOCATION pNextStack;
  495. DEBUGMSG( DBG_FUNC,("+IrUsb_CallUSBD\n"));
  496. IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  497. IRUSB_ASSERT( pThisDev );
  498. IRUSB_ASSERT( NULL == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb ); //shouldn't be multiple control calls pending
  499. //
  500. // issue a synchronous request (we'll wait )
  501. //
  502. pUrbTargetDev = pThisDev->pUsbDevObj;
  503. IRUSB_ASSERT( pUrbTargetDev );
  504. // make an irp sending to usbhub
  505. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb =
  506. IoAllocateIrp( (CCHAR)(pThisDev->pUsbDevObj->StackSize + 1), FALSE );
  507. if( NULL == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb )
  508. {
  509. DEBUGMSG(DBG_ERR, (" IrUsb_CallUsbd failed to alloc IRP\n"));
  510. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  511. goto done;
  512. }
  513. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb->IoStatus.Status = STATUS_PENDING;
  514. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb->IoStatus.Information = 0;
  515. //
  516. // Call the class driver to perform the operation. If the returned status
  517. // is PENDING, wait for the request to complete.
  518. //
  519. pNextStack = IoGetNextIrpStackLocation( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb );
  520. IRUSB_ASSERT( pNextStack != NULL );
  521. //
  522. // pass the URB to the USB driver stack
  523. //
  524. pNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  525. pNextStack->Parameters.Others.Argument1 = pUrb;
  526. pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  527. IoSetCompletionRoutine(
  528. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb, // irp to use
  529. UsbIoCompleteControl, // routine to call when irp is done
  530. DEV_TO_CONTEXT(pThisDev), // context to pass routine
  531. TRUE, // call on success
  532. TRUE, // call on error
  533. TRUE // call on cancel
  534. );
  535. KeClearEvent( &pThisDev->EventAsyncUrb );
  536. ntStatus = MyIoCallDriver(
  537. pThisDev,
  538. pUrbTargetDev,
  539. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb
  540. );
  541. DEBUGMSG( DBG_OUT,(" IrUsb_CallUSBD () return from IoCallDriver USBD %x\n", ntStatus));
  542. if( (ntStatus == STATUS_PENDING) || (ntStatus == STATUS_SUCCESS) )
  543. {
  544. //
  545. // wait, but dump out on timeout
  546. //
  547. if( ntStatus == STATUS_PENDING )
  548. {
  549. ntStatus = MyKeWaitForSingleObject( pThisDev, &pThisDev->EventAsyncUrb, NULL, 0 );
  550. if( ntStatus == STATUS_TIMEOUT )
  551. {
  552. DEBUGMSG( DBG_ERR,(" IrUsb_CallUSBD () TIMED OUT! return from IoCallDriver USBD %x\n", ntStatus));
  553. IrUsb_CancelIo(
  554. pThisDev,
  555. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb,
  556. &pThisDev->EventAsyncUrb
  557. );
  558. }
  559. else
  560. {
  561. //
  562. // Update the status to reflect the real return code
  563. //
  564. ntStatus = pThisDev->StatusControl;
  565. }
  566. }
  567. }
  568. else
  569. {
  570. DEBUGMSG( DBG_ERR, ("IrUsb_CallUSBD IoCallDriver FAILED(%x)\n",ntStatus));
  571. }
  572. DEBUGMSG( DBG_OUT,("IrUsb_CallUSBD () URB status = %x IRP status = %x\n", pUrb->UrbHeader.Status, ntStatus ));
  573. done:
  574. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb = NULL;
  575. DEBUGCOND( DBG_ERR, !NT_SUCCESS( ntStatus ), (" exit IrUsb_CallUSBD FAILED (%x)\n", ntStatus));
  576. DEBUGMSG( DBG_FUNC,("-IrUsb_CallUSBD\n"));
  577. return ntStatus;
  578. }
  579. /*****************************************************************************
  580. *
  581. * Function: IrUsb_ResetUSBD
  582. *
  583. * Synopsis: Passes a URB to the USBD class driver, forcing the latter to reset or part
  584. *
  585. * Arguments: pThisDev - pointer to the IR device
  586. * ForceUnload - flag to perform a reset or an unload
  587. *
  588. * Returns: STATUS_SUCCESS if successful,
  589. * STATUS_UNSUCCESSFUL otherwise
  590. *
  591. * Notes:
  592. *
  593. *****************************************************************************/
  594. NTSTATUS
  595. IrUsb_ResetUSBD(
  596. IN PIR_DEVICE pThisDev,
  597. BOOLEAN ForceUnload
  598. )
  599. {
  600. NTSTATUS ntStatus;
  601. PDEVICE_OBJECT pUrbTargetDev;
  602. PIO_STACK_LOCATION pNextStack;
  603. DEBUGMSG( DBG_FUNC,("+IrUsb_ResetUSBD\n"));
  604. IRUSB_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
  605. IRUSB_ASSERT( pThisDev );
  606. IRUSB_ASSERT( NULL == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb ); //shouldn't be multiple control calls pending
  607. //
  608. // issue a synchronous request (we'll wait )
  609. //
  610. pUrbTargetDev = pThisDev->pUsbDevObj;
  611. IRUSB_ASSERT( pUrbTargetDev );
  612. // make an irp sending to usbhub
  613. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb =
  614. IoAllocateIrp( (CCHAR)(pThisDev->pUsbDevObj->StackSize + 1), FALSE );
  615. if( NULL == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb )
  616. {
  617. DEBUGMSG(DBG_ERR, (" IrUsb_ResetUSBD failed to alloc IRP\n"));
  618. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  619. goto done;
  620. }
  621. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb->IoStatus.Status = STATUS_PENDING;
  622. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb->IoStatus.Information = 0;
  623. //
  624. // Call the class driver to perform the operation. If the returned status
  625. // is PENDING, wait for the request to complete.
  626. //
  627. pNextStack = IoGetNextIrpStackLocation( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb );
  628. IRUSB_ASSERT( pNextStack != NULL );
  629. //
  630. // pass the URB to the USB driver stack
  631. //
  632. pNextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  633. if( ForceUnload )
  634. pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_CYCLE_PORT;
  635. else
  636. pNextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_RESET_PORT;
  637. IoSetCompletionRoutine(
  638. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb, // irp to use
  639. UsbIoCompleteControl, // routine to call when irp is done
  640. DEV_TO_CONTEXT(pThisDev), // context to pass routine
  641. TRUE, // call on success
  642. TRUE, // call on error
  643. TRUE // call on cancel
  644. );
  645. KeClearEvent( &pThisDev->EventAsyncUrb );
  646. ntStatus = MyIoCallDriver(
  647. pThisDev,
  648. pUrbTargetDev,
  649. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb
  650. );
  651. DEBUGMSG( DBG_OUT,(" IrUsb_ResetUSBD () return from IoCallDriver USBD %x\n", ntStatus));
  652. if( (ntStatus == STATUS_PENDING) || (ntStatus == STATUS_SUCCESS) )
  653. {
  654. //
  655. // wait, but dump out on timeout
  656. //
  657. if( ntStatus == STATUS_PENDING )
  658. {
  659. ntStatus = MyKeWaitForSingleObject( pThisDev, &pThisDev->EventAsyncUrb, NULL, 0 );
  660. if( ntStatus == STATUS_TIMEOUT )
  661. {
  662. DEBUGMSG( DBG_ERR,(" IrUsb_ResetUSBD () TIMED OUT! return from IoCallDriver USBD %x\n", ntStatus));
  663. IrUsb_CancelIo(
  664. pThisDev,
  665. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb,
  666. &pThisDev->EventAsyncUrb
  667. );
  668. }
  669. else
  670. {
  671. //
  672. // Update the status to reflect the real return code
  673. //
  674. ntStatus = pThisDev->StatusControl;
  675. }
  676. }
  677. }
  678. else
  679. {
  680. DEBUGMSG( DBG_ERR, ("IrUsb_ResetUSBD IoCallDriver FAILED(%x)\n",ntStatus));
  681. }
  682. done:
  683. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->IrpSubmitUrb = NULL;
  684. DEBUGCOND( DBG_ERR, !NT_SUCCESS( ntStatus ), (" exit IrUsb_ResetUSBD FAILED (%x)\n", ntStatus));
  685. DEBUGMSG( DBG_FUNC,("-IrUsb_ResetUSBD\n"));
  686. return ntStatus;
  687. }
  688. /*****************************************************************************
  689. *
  690. * Function: UsbIoCompleteControl
  691. *
  692. * Synopsis: General completetion routine just to insure cancel-ability of control calls
  693. * and keep track of pending irp count
  694. *
  695. * Arguments: pUsbDevObj - pointer to the device object which
  696. * completed the irp
  697. * pIrp - the irp which was completed by the device
  698. * object
  699. * Context - dev ext
  700. *
  701. * Returns: STATUS_MORE_PROCESSING_REQUIRED - allows the completion routine
  702. * (IofCompleteRequest) to stop working on the irp.
  703. *
  704. *
  705. *****************************************************************************/
  706. NTSTATUS
  707. UsbIoCompleteControl(
  708. IN PDEVICE_OBJECT pUsbDevObj,
  709. IN PIRP pIrp,
  710. IN PVOID Context
  711. )
  712. {
  713. PIR_DEVICE pThisDev;
  714. NTSTATUS status;
  715. DEBUGMSG(DBG_FUNC, ("+UsbIoCompleteControl\n"));
  716. //
  717. // The context given to IoSetCompletionRoutine is simply the the ir
  718. // device object pointer.
  719. //
  720. pThisDev = CONTEXT_TO_DEV( Context );
  721. status = pIrp->IoStatus.Status;
  722. switch( status )
  723. {
  724. case STATUS_SUCCESS:
  725. DEBUGMSG(DBG_OUT, (" UsbIoCompleteControl STATUS_SUCCESS\n"));
  726. break; // STATUS_SUCCESS
  727. case STATUS_TIMEOUT:
  728. DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_TIMEOUT\n"));
  729. break;
  730. case STATUS_PENDING:
  731. DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_PENDING\n"));
  732. break;
  733. case STATUS_DEVICE_DATA_ERROR:
  734. // can get during shutdown
  735. DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_DEVICE_DATA_ERROR\n"));
  736. break;
  737. case STATUS_UNSUCCESSFUL:
  738. DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_UNSUCCESSFUL\n"));
  739. break;
  740. case STATUS_INSUFFICIENT_RESOURCES:
  741. DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_INSUFFICIENT_RESOURCES\n"));
  742. break;
  743. case STATUS_INVALID_PARAMETER:
  744. DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_INVALID_PARAMETER\n"));
  745. break;
  746. case STATUS_CANCELLED:
  747. DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_CANCELLED\n"));
  748. break;
  749. case STATUS_DEVICE_NOT_CONNECTED:
  750. // can get during shutdown
  751. DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_DEVICE_NOT_CONNECTED\n"));
  752. break;
  753. case STATUS_DEVICE_POWER_FAILURE:
  754. // can get during shutdown
  755. DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl STATUS_DEVICE_POWER_FAILURE\n"));
  756. break;
  757. default:
  758. DEBUGMSG(DBG_ERR, (" UsbIoCompleteControl UNKNOWN WEIRD STATUS = 0x%x, dec %d\n",status,status ));
  759. break;
  760. }
  761. IrUsb_DecIoCount( pThisDev ); //we track pending irp count
  762. if( pIrp == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb )
  763. {
  764. IRUSB_ASSERT( NULL != ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb );
  765. IoFreeIrp( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb );
  766. pThisDev->StatusControl = status; // save status because can't use irp after completion routine is hit!
  767. KeSetEvent( &pThisDev->EventAsyncUrb, 0, FALSE ); //signal we're done
  768. }
  769. else
  770. {
  771. DEBUGMSG( DBG_ERR, (" UsbIoCompleteControl UNKNOWN IRP\n"));
  772. IRUSB_ASSERT( 0 );
  773. }
  774. DEBUGCOND(DBG_ERR, !( NT_SUCCESS( status ) ), ("UsbIoCompleteControl BAD status = 0x%x\n", status));
  775. DEBUGMSG(DBG_FUNC, ("-UsbIoCompleteControl\n"));
  776. //
  777. // We return STATUS_MORE_PROCESSING_REQUIRED so that the completion
  778. // routine (IofCompleteRequest) will stop working on the irp.
  779. //
  780. return STATUS_MORE_PROCESSING_REQUIRED;
  781. }
  782. /*****************************************************************************
  783. *
  784. * Function: IrUsb_ConfigureDevice
  785. *
  786. * Synopsis: Initializes a given instance of the device on the USB and
  787. * selects and saves the configuration.
  788. *
  789. * Arguments: pThisDev - pointer to the IR device
  790. *
  791. * Returns: NT status code
  792. *
  793. * Notes:
  794. *
  795. *****************************************************************************/
  796. NTSTATUS
  797. IrUsb_ConfigureDevice(
  798. IN OUT PIR_DEVICE pThisDev
  799. )
  800. {
  801. NTSTATUS ntStatus;
  802. PURB pUrb;
  803. ULONG UrbSize;
  804. DEBUGMSG(DBG_FUNC,("+IrUsb_ConfigureDevice()\n"));
  805. IRUSB_ASSERT( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor == NULL );
  806. pUrb = (PURB)&((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->DescriptorUrb;
  807. //
  808. // When USB_CONFIGURATION_DESCRIPTOR_TYPE is specified for DescriptorType
  809. // in a call to UsbBuildGetDescriptorRequest(),
  810. // all interface, endpoint, class-specific, and vendor-specific descriptors
  811. // for the configuration also are retrieved.
  812. // The caller must allocate a buffer large enough to hold all of this
  813. // information or the data is truncated without error.
  814. // Therefore the 'siz' set below is just a 'good guess', and we may have to retry
  815. //
  816. UrbSize = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 512; // Store size, may need to free
  817. //
  818. // We will break out of this 'retry loop' when UsbBuildGetDescriptorRequest()
  819. // has a big enough pThisDev->UsbConfigurationDescriptor buffer not to truncate
  820. //
  821. while( TRUE )
  822. {
  823. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor = MyMemAlloc( UrbSize );
  824. if( !((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbConfigurationDescriptor )
  825. {
  826. MyMemFree( pUrb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST) );
  827. return STATUS_INSUFFICIENT_RESOURCES;
  828. }
  829. UsbBuildGetDescriptorRequest(
  830. pUrb,
  831. (USHORT) sizeof( struct _URB_CONTROL_DESCRIPTOR_REQUEST ),
  832. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  833. 0,
  834. 0,
  835. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor,
  836. NULL,
  837. UrbSize,
  838. NULL
  839. );
  840. ntStatus = IrUsb_CallUSBD( pThisDev, pUrb ); //Get Usb Config Descriptor; done in main thread
  841. DEBUGMSG(DBG_OUT,(" IrUsb_ConfigureDevice() Configuration Descriptor = %x, len %x\n",
  842. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbConfigurationDescriptor,
  843. pUrb->UrbControlDescriptorRequest.TransferBufferLength));
  844. //
  845. // if we got some data see if it was enough.
  846. // NOTE: we may get an error in URB because of buffer overrun
  847. if( (pUrb->UrbControlDescriptorRequest.TransferBufferLength > 0) &&
  848. (((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor->wTotalLength > UrbSize) &&
  849. NT_SUCCESS(ntStatus) )
  850. {
  851. MyMemFree( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor, UrbSize );
  852. UrbSize = ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor->wTotalLength;
  853. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor = NULL;
  854. }
  855. else
  856. {
  857. break; // we got it on the first try
  858. }
  859. } // end, while (retry loop )
  860. IRUSB_ASSERT( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbConfigurationDescriptor );
  861. if( !NT_SUCCESS(ntStatus) )
  862. {
  863. DEBUGMSG( DBG_ERR,(" IrUsb_ConfigureDevice() Get Config Descriptor FAILURE (%x)\n", ntStatus));
  864. goto done;
  865. }
  866. //
  867. // We have the configuration descriptor for the configuration we want.
  868. // Now we issue the select configuration command to get
  869. // the pipes associated with this configuration.
  870. //
  871. ntStatus = IrUsb_SelectInterface(
  872. pThisDev,
  873. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor
  874. );
  875. if( !NT_SUCCESS(ntStatus) )
  876. {
  877. DEBUGMSG( DBG_ERR,(" IrUsb_ConfigureDevice() IrUsb_SelectInterface() FAILURE (%x)\n", ntStatus));
  878. }
  879. done:
  880. DEBUGMSG(DBG_FUNC,("-IrUsb_ConfigureDevice (%x)\n", ntStatus));
  881. return ntStatus;
  882. }
  883. /*****************************************************************************
  884. *
  885. * Function: IrUsb_SelectInterface
  886. *
  887. * Synopsis: Initializes the ST4200 interfaces;
  888. * This minidriver only supports one interface (with multiple endpoints).
  889. *
  890. * Arguments: pThisDev - pointer to IR device
  891. * pConfigurationDescriptor - pointer to USB configuration descriptor
  892. *
  893. * Returns: NT status code
  894. *
  895. * Notes:
  896. *
  897. *****************************************************************************/
  898. NTSTATUS
  899. IrUsb_SelectInterface(
  900. IN OUT PIR_DEVICE pThisDev,
  901. IN PUSB_CONFIGURATION_DESCRIPTOR pConfigurationDescriptor
  902. )
  903. {
  904. NTSTATUS ntStatus;
  905. PURB pUrb = NULL;
  906. ULONG i;
  907. USHORT DescriptorSize;
  908. PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor = NULL;
  909. PUSBD_INTERFACE_INFORMATION pInterface = NULL;
  910. DEBUGMSG(DBG_FUNC,("+IrUsb_SelectInterface\n"));
  911. IRUSB_ASSERT( pConfigurationDescriptor != NULL );
  912. IRUSB_ASSERT( pThisDev != NULL );
  913. //
  914. // IrUsb driver only supports one interface, we must parse
  915. // the configuration descriptor for the interface
  916. // and remember the pipes. Needs to be aupdated
  917. //
  918. pUrb = USBD_CreateConfigurationRequest( pConfigurationDescriptor, &DescriptorSize );
  919. if( pUrb )
  920. {
  921. DEBUGMSG(DBG_OUT,(" USBD_CreateConfigurationRequest created the urb\n"));
  922. //
  923. // USBD_ParseConfigurationDescriptorEx searches a given configuration
  924. // descriptor and returns a pointer to an interface that matches the
  925. // given search criteria. We only support one interface on this device
  926. //
  927. pInterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
  928. pConfigurationDescriptor,
  929. pConfigurationDescriptor, // search from start of config descriptor
  930. -1, // interface number not a criteria; we only support one interface
  931. -1, // not interested in alternate setting here either
  932. -1, // interface class not a criteria
  933. -1, // interface subclass not a criteria
  934. -1 // interface protocol not a criteria
  935. );
  936. if( !pInterfaceDescriptor )
  937. {
  938. DEBUGMSG(DBG_ERR,("IrUsb_SelectInterface() ParseConfigurationDescriptorEx() failed\n returning STATUS_INSUFFICIENT_RESOURCES\n"));
  939. //
  940. // don't call the MyMemFree since the buffer was
  941. // alloced by USBD_CreateConfigurationRequest, not MyMemAlloc()
  942. //
  943. ExFreePool( pUrb );
  944. return STATUS_INSUFFICIENT_RESOURCES;
  945. }
  946. pInterface = &pUrb->UrbSelectConfiguration.Interface;
  947. DEBUGMSG(DBG_OUT,(" After USBD_CreateConfigurationRequest, before UsbBuildSelectConfigurationRequest\n" ));
  948. //
  949. // Now prepare the pipes
  950. //
  951. for( i=0; i<pInterface->NumberOfPipes; i++ )
  952. {
  953. //
  954. // perform any pipe initialization here; mainly set max xfer size
  955. // But Watch out! USB may change these when you select the interface;
  956. // In general USB doesn;t seem to like differing max transfer sizes on the pipes
  957. //
  958. pInterface->Pipes[i].MaximumTransferSize = STIR4200_FIFO_SIZE;
  959. }
  960. //
  961. // Initialize the device with the pipe structure found
  962. //
  963. UsbBuildSelectConfigurationRequest( pUrb, DescriptorSize, pConfigurationDescriptor );
  964. ntStatus = IrUsb_CallUSBD( pThisDev, pUrb ); //select config; done in main thread
  965. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationHandle =
  966. pUrb->UrbSelectConfiguration.ConfigurationHandle;
  967. }
  968. else
  969. {
  970. DEBUGMSG(DBG_ERR,(" IrUsb_SelectInterface() USBD_CreateConfigurationRequest() failed\n returning STATUS_INSUFFICIENT_RESOURCES\n"));
  971. return STATUS_INSUFFICIENT_RESOURCES;
  972. }
  973. if( NT_SUCCESS(ntStatus) )
  974. {
  975. //
  976. // Save the configuration handle for this device
  977. //
  978. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbConfigurationHandle =
  979. pUrb->UrbSelectConfiguration.ConfigurationHandle;
  980. if( NULL == ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface )
  981. {
  982. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface = MyMemAlloc( pInterface->Length );
  983. }
  984. if( NULL != ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface )
  985. {
  986. ULONG j;
  987. //
  988. // save a copy of the interface information returned
  989. //
  990. RtlCopyMemory( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface, pInterface, pInterface->Length );
  991. //
  992. // Dump the interface to the debugger
  993. //
  994. DEBUGMSG(DBG_FUNC,("---------After Select Config \n"));
  995. DEBUGMSG(DBG_FUNC,("NumberOfPipes 0x%x\n", ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->NumberOfPipes));
  996. DEBUGMSG(DBG_FUNC,("Length 0x%x\n", ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->Length));
  997. DEBUGMSG(DBG_FUNC,("Alt Setting 0x%x\n", ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->AlternateSetting));
  998. DEBUGMSG(DBG_FUNC,("Interface Number 0x%x\n", ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->InterfaceNumber));
  999. DEBUGMSG(DBG_FUNC,("Class, subclass, protocol 0x%x 0x%x 0x%x\n",
  1000. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->Class,
  1001. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->SubClass,
  1002. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->Protocol));
  1003. //
  1004. // Find our Bulk in and out pipes, save their handles, Dump the pipe info
  1005. //
  1006. for( j=0; j<pInterface->NumberOfPipes; j++ )
  1007. {
  1008. PUSBD_PIPE_INFORMATION pipeInformation;
  1009. pipeInformation = &((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbInterface->Pipes[j];
  1010. //
  1011. // Find the Bulk In and Out pipes ( these are probably the only two pipes )
  1012. //
  1013. if( UsbdPipeTypeBulk == pipeInformation->PipeType )
  1014. {
  1015. // endpoint address with bit 0x80 set are input pipes, else output
  1016. if( USB_ENDPOINT_DIRECTION_IN( pipeInformation->EndpointAddress ) )
  1017. {
  1018. pThisDev->BulkInPipeHandle = pipeInformation->PipeHandle;
  1019. }
  1020. if( USB_ENDPOINT_DIRECTION_OUT( pipeInformation->EndpointAddress ) )
  1021. {
  1022. pThisDev->BulkOutPipeHandle = pipeInformation->PipeHandle;
  1023. }
  1024. }
  1025. DEBUGMSG(DBG_FUNC,("---------\n"));
  1026. DEBUGMSG(DBG_FUNC,("PipeType 0x%x\n", pipeInformation->PipeType));
  1027. DEBUGMSG(DBG_FUNC,("EndpointAddress 0x%x\n", pipeInformation->EndpointAddress));
  1028. DEBUGMSG(DBG_FUNC,("MaxPacketSize 0x%x\n", pipeInformation->MaximumPacketSize));
  1029. DEBUGMSG(DBG_FUNC,("Interval 0x%x\n", pipeInformation->Interval));
  1030. DEBUGMSG(DBG_FUNC,("Handle 0x%x\n", pipeInformation->PipeHandle));
  1031. DEBUGMSG(DBG_FUNC,("MaximumTransferSize 0x%x\n", pipeInformation->MaximumTransferSize));
  1032. }
  1033. DEBUGMSG(DBG_FUNC,("---------\n"));
  1034. }
  1035. }
  1036. //
  1037. // we better have found input and output bulk pipes!
  1038. //
  1039. IRUSB_ASSERT( pThisDev->BulkInPipeHandle && pThisDev->BulkOutPipeHandle );
  1040. if( !pThisDev->BulkInPipeHandle || !pThisDev->BulkOutPipeHandle )
  1041. {
  1042. DEBUGMSG(DBG_ERR,("IrUsb_SelectInterface() failed to get pipes\n"));
  1043. ntStatus = STATUS_UNSUCCESSFUL;
  1044. }
  1045. if( pUrb )
  1046. {
  1047. //
  1048. // don't call the MyMemFree since the buffer was
  1049. // alloced by USBD_CreateConfigurationRequest, not MyMemAlloc()
  1050. //
  1051. ExFreePool( pUrb );
  1052. }
  1053. DEBUGMSG(DBG_FUNC,("-IrUsb_SelectInterface (%x)\n", ntStatus));
  1054. return ntStatus;
  1055. }
  1056. /*****************************************************************************
  1057. *
  1058. * Function: IrUsb_StartDevice
  1059. *
  1060. * Synopsis: Initializes a given instance of the device on the USB.
  1061. * USB client drivers such as us set up URBs (USB Request Packets) to send requests
  1062. * to the host controller driver (HCD). The URB structure defines a format for all
  1063. * possible commands that can be sent to a USB device.
  1064. * Here, we request the device descriptor and store it, and configure the device.
  1065. *
  1066. * Arguments: pThisDev - pointer to IR device
  1067. *
  1068. * Returns: NT status code
  1069. *
  1070. * Notes:
  1071. *
  1072. *****************************************************************************/
  1073. NTSTATUS
  1074. IrUsb_StartDevice(
  1075. IN PIR_DEVICE pThisDev
  1076. )
  1077. {
  1078. NTSTATUS ntStatus;
  1079. PUSB_DEVICE_DESCRIPTOR pDeviceDescriptor = NULL;
  1080. PURB pUrb;
  1081. ULONG DescriptorSize;
  1082. DEBUGMSG( DBG_FUNC, ("+IrUsb_StartDevice()\n"));
  1083. pUrb = MyMemAlloc( sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST));
  1084. DEBUGCOND( DBG_ERR,!pUrb, (" IrUsb_StartDevice() FAILED MyMemAlloc() for URB\n"));
  1085. if( pUrb )
  1086. {
  1087. DescriptorSize = sizeof( USB_DEVICE_DESCRIPTOR );
  1088. pDeviceDescriptor = MyMemAlloc( DescriptorSize );
  1089. DEBUGCOND( DBG_ERR, !pDeviceDescriptor, (" IrUsb_StartDevice() FAILED MyMemAlloc() for deviceDescriptor\n"));
  1090. if( pDeviceDescriptor )
  1091. {
  1092. //
  1093. // Get all the USB descriptor data
  1094. //
  1095. UsbBuildGetDescriptorRequest(
  1096. pUrb,
  1097. (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  1098. USB_DEVICE_DESCRIPTOR_TYPE,
  1099. 0,
  1100. 0,
  1101. pDeviceDescriptor,
  1102. NULL,
  1103. DescriptorSize,
  1104. NULL
  1105. );
  1106. ntStatus = IrUsb_CallUSBD( pThisDev, pUrb ); // build get descripttor req; main thread
  1107. DEBUGCOND( DBG_ERR, !NT_SUCCESS(ntStatus), (" IrUsb_StartDevice() FAILED IrUsb_CallUSBD (pThisDev, pUrb)\n"));
  1108. if( NT_SUCCESS(ntStatus) )
  1109. {
  1110. DEBUGMSG( DBG_FUNC,("Device Descriptor = %x, len %x\n",
  1111. pDeviceDescriptor,
  1112. pUrb->UrbControlDescriptorRequest.TransferBufferLength));
  1113. DEBUGMSG( DBG_FUNC,("IR Dongle Device Descriptor:\n"));
  1114. DEBUGMSG( DBG_FUNC,("-------------------------\n"));
  1115. DEBUGMSG( DBG_FUNC,("bLength %d\n", pDeviceDescriptor->bLength));
  1116. DEBUGMSG( DBG_FUNC,("bDescriptorType 0x%x\n", pDeviceDescriptor->bDescriptorType));
  1117. DEBUGMSG( DBG_FUNC,("bcdUSB 0x%x\n", pDeviceDescriptor->bcdUSB));
  1118. DEBUGMSG( DBG_FUNC,("bDeviceClass 0x%x\n", pDeviceDescriptor->bDeviceClass));
  1119. DEBUGMSG( DBG_FUNC,("bDeviceSubClass 0x%x\n", pDeviceDescriptor->bDeviceSubClass));
  1120. DEBUGMSG( DBG_FUNC,("bDeviceProtocol 0x%x\n", pDeviceDescriptor->bDeviceProtocol));
  1121. DEBUGMSG( DBG_FUNC,("bMaxPacketSize0 0x%x\n", pDeviceDescriptor->bMaxPacketSize0));
  1122. DEBUGMSG( DBG_FUNC,("idVendor 0x%x\n", pDeviceDescriptor->idVendor));
  1123. DEBUGMSG( DBG_FUNC,("idProduct 0x%x\n", pDeviceDescriptor->idProduct));
  1124. DEBUGMSG( DBG_FUNC,("bcdDevice 0x%x\n", pDeviceDescriptor->bcdDevice));
  1125. DEBUGMSG( DBG_FUNC,("iManufacturer 0x%x\n", pDeviceDescriptor->iManufacturer));
  1126. DEBUGMSG( DBG_FUNC,("iProduct 0x%x\n", pDeviceDescriptor->iProduct));
  1127. DEBUGMSG( DBG_FUNC,("iSerialNumber 0x%x\n", pDeviceDescriptor->iSerialNumber));
  1128. DEBUGMSG( DBG_FUNC,("bNumConfigurations 0x%x\n", pDeviceDescriptor->bNumConfigurations));
  1129. }
  1130. }
  1131. else
  1132. {
  1133. // if we got here we failed to allocate deviceDescriptor
  1134. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1135. }
  1136. if( NT_SUCCESS(ntStatus) )
  1137. {
  1138. ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbDeviceDescriptor = pDeviceDescriptor;
  1139. pThisDev->IdVendor = ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbDeviceDescriptor->idVendor;
  1140. }
  1141. MyMemFree( pUrb, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST) );
  1142. }
  1143. else
  1144. {
  1145. //
  1146. // if we got here we failed to allocate the urb
  1147. //
  1148. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1149. }
  1150. //
  1151. // Now that we have the descriptors, we can configure the device
  1152. //
  1153. if( NT_SUCCESS(ntStatus) )
  1154. {
  1155. ntStatus = IrUsb_ConfigureDevice( pThisDev );
  1156. DEBUGCOND( DBG_ERR,!NT_SUCCESS(ntStatus),(" IrUsb_StartDevice IrUsb_ConfigureDevice() FAILURE (%x)\n", ntStatus));
  1157. }
  1158. //
  1159. // Read all the initial registers
  1160. //
  1161. if( NT_SUCCESS(ntStatus) )
  1162. {
  1163. ntStatus = St4200ReadRegisters( pThisDev, 0, STIR4200_MAX_REG );
  1164. DEBUGCOND( DBG_ERR,!NT_SUCCESS(ntStatus),(" IrUsb_StartDevice St4200ReadRegisters() FAILURE (%x)\n", ntStatus));
  1165. }
  1166. //
  1167. // Get the current chip revision
  1168. //
  1169. if( NT_SUCCESS(ntStatus) )
  1170. {
  1171. pThisDev->ChipRevision = pThisDev->StIrTranceiver.SensitivityReg & STIR4200_SENS_IDMASK;
  1172. }
  1173. //
  1174. // Next we must get the Class-Specific Descriptor
  1175. // Get the IR USB dongle's Class-Specific descriptor; this has many
  1176. // characterisitics we must tell Ndis about, such as supported speeds,
  1177. // BOFS required, rate sniff-supported flag, turnaround time, window size,
  1178. // data size.
  1179. //
  1180. if( NT_SUCCESS(ntStatus) )
  1181. {
  1182. ntStatus = IrUsb_GetDongleCaps( pThisDev );
  1183. if( !NT_SUCCESS( ntStatus ) )
  1184. {
  1185. DEBUGMSG( DBG_ERR,(" IrUsb_ConfigureDevice() IrUsb_GetClassDescriptor() FAILURE (%x)\n", ntStatus));
  1186. }
  1187. else
  1188. {
  1189. // fill out dongleCaps struct from class-specific descriptor info
  1190. IrUsb_SetDongleCaps( pThisDev );
  1191. }
  1192. }
  1193. //
  1194. // Set the initial speed
  1195. //
  1196. if( NT_SUCCESS(ntStatus) )
  1197. {
  1198. ntStatus = St4200SetSpeed( pThisDev );
  1199. DEBUGCOND( DBG_ERR,!NT_SUCCESS(ntStatus),(" IrUsb_StartDevice St4200SetSpeed() FAILURE (%x)\n", ntStatus));
  1200. }
  1201. //
  1202. // All set and ready to roll
  1203. //
  1204. if( NT_SUCCESS(ntStatus) )
  1205. {
  1206. pThisDev->fDeviceStarted = TRUE;
  1207. }
  1208. DEBUGMSG( DBG_FUNC, ("-IrUsb_StartDevice (%x)\n", ntStatus));
  1209. return ntStatus;
  1210. }
  1211. /*****************************************************************************
  1212. *
  1213. * Function: IrUsb_StopDevice
  1214. *
  1215. * Synopsis: Stops a given instance of a ST4200 device on the USB.
  1216. * We basically just tell USB this device is now 'unconfigured'
  1217. *
  1218. * Arguments: pThisDev - pointer to IR device
  1219. *
  1220. * Returns: NT status code
  1221. *
  1222. * Notes:
  1223. *
  1224. *****************************************************************************/
  1225. NTSTATUS
  1226. IrUsb_StopDevice(
  1227. IN PIR_DEVICE pThisDev
  1228. )
  1229. {
  1230. NTSTATUS ntStatus = STATUS_SUCCESS;
  1231. PURB pUrb;
  1232. ULONG DescriptorSize;
  1233. DEBUGMSG( DBG_FUNC,("+IrUsb_StopDevice\n"));
  1234. //
  1235. // Send the select configuration urb with a NULL pointer for the configuration
  1236. // handle. This closes the configuration and puts the device in the 'unconfigured'
  1237. // state.
  1238. //
  1239. DescriptorSize = sizeof( struct _URB_SELECT_CONFIGURATION );
  1240. pUrb = MyMemAlloc( DescriptorSize );
  1241. if( pUrb )
  1242. {
  1243. UsbBuildSelectConfigurationRequest(
  1244. pUrb,
  1245. (USHORT)DescriptorSize,
  1246. NULL
  1247. );
  1248. ntStatus = IrUsb_CallUSBD( pThisDev, pUrb ); // build select config req; main thread
  1249. DEBUGCOND( DBG_ERR,
  1250. !NT_SUCCESS(ntStatus),(" IrUsb_StopDevice() FAILURE Configuration Closed status = %x usb status = %x.\n", ntStatus, pUrb->UrbHeader.Status));
  1251. DEBUGCOND( DBG_WARN,
  1252. NT_SUCCESS(ntStatus),(" IrUsb_StopDevice() SUCCESS Configuration Closed status = %x usb status = %x.\n", ntStatus, pUrb->UrbHeader.Status));
  1253. MyMemFree( pUrb, sizeof(struct _URB_SELECT_CONFIGURATION) );
  1254. }
  1255. else
  1256. {
  1257. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1258. }
  1259. DEBUGMSG( DBG_FUNC,("-IrUsb_StopDevice (%x) \n ", ntStatus));
  1260. return ntStatus;
  1261. }
  1262. /*****************************************************************************
  1263. *
  1264. * Function: ResetPipeCallback
  1265. *
  1266. * Synopsis: Callback for resetting a pipe
  1267. *
  1268. * Arguments: pWorkItem - pointer to the reset work item
  1269. *
  1270. * Returns: None
  1271. *
  1272. * Notes:
  1273. *
  1274. *****************************************************************************/
  1275. VOID
  1276. ResetPipeCallback (
  1277. IN PIR_WORK_ITEM pWorkItem
  1278. )
  1279. {
  1280. PIR_DEVICE pThisDev;
  1281. HANDLE Pipe;
  1282. NTSTATUS ntStatus;
  1283. pThisDev = (PIR_DEVICE)pWorkItem->pIrDevice;
  1284. Pipe = (HANDLE)pWorkItem->pInfoBuf;
  1285. if( Pipe == pThisDev->BulkInPipeHandle )
  1286. {
  1287. IRUSB_ASSERT( TRUE == pThisDev->fPendingReadClearStall );
  1288. IrUsb_CancelPendingReadIo( pThisDev, TRUE );
  1289. IrUsb_ResetPipe( pThisDev, Pipe );
  1290. InterlockedExchange( &pThisDev->fPendingReadClearStall, FALSE );
  1291. }
  1292. else if( Pipe == pThisDev->BulkOutPipeHandle )
  1293. {
  1294. IRUSB_ASSERT( TRUE == pThisDev->fPendingWriteClearStall );
  1295. IrUsb_CancelPendingWriteIo( pThisDev );
  1296. IrUsb_ResetPipe( pThisDev, Pipe );
  1297. InterlockedExchange( &pThisDev->fPendingWriteClearStall, FALSE );
  1298. }
  1299. #if DBG
  1300. else
  1301. {
  1302. IRUSB_ASSERT( 0 );
  1303. }
  1304. #endif
  1305. FreeWorkItem( pWorkItem );
  1306. }
  1307. /*****************************************************************************
  1308. *
  1309. * Function: IrUsb_ResetPipe
  1310. *
  1311. * Synopsis: This will reset the host pipe to Data0 and should also reset the device
  1312. * endpoint to Data0 for Bulk and Interrupt pipes by issuing a Clear_Feature
  1313. * Endpoint_Stall to the device endpoint.
  1314. *
  1315. * Arguments: pThisDev - pointer to IR device
  1316. * Pipe - handle to the pipe to reset
  1317. *
  1318. * Returns: NTSTATUS
  1319. *
  1320. * Notes: Must be called at IRQL PASSIVE_LEVEL
  1321. *
  1322. *****************************************************************************/
  1323. NTSTATUS
  1324. IrUsb_ResetPipe (
  1325. IN PIR_DEVICE pThisDev,
  1326. IN HANDLE Pipe
  1327. )
  1328. {
  1329. PURB pUrb;
  1330. NTSTATUS ntStatus;
  1331. DEBUGMSG(DBG_ERR, ("+IrUsb_ResetPipe()\n"));
  1332. //
  1333. // Allocate URB for RESET_PIPE request
  1334. //
  1335. pUrb = MyMemAlloc( sizeof(struct _URB_PIPE_REQUEST) );
  1336. if( pUrb != NULL )
  1337. {
  1338. #if 0
  1339. NdisZeroMemory( pUrb, sizeof (struct _URB_PIPE_REQUEST) );
  1340. DEBUGMSG(DBG_ERR, (" IrUsb_ResetPipe before ABORT PIPE \n"));
  1341. //
  1342. // Initialize ABORT_PIPE request URB
  1343. //
  1344. pUrb->UrbHeader.Length = sizeof (struct _URB_PIPE_REQUEST);
  1345. pUrb->UrbHeader.Function = URB_FUNCTION_ABORT_PIPE;
  1346. pUrb->UrbPipeRequest.PipeHandle = (USBD_PIPE_HANDLE)Pipe;
  1347. ntStatus = IrUsb_CallUSBD( pThisDev, pUrb );
  1348. DEBUGCOND(DBG_ERR, !NT_SUCCESS(ntStatus), (" IrUsb_ResetPipe ABORT PIPE FAILED \n"));
  1349. DEBUGMSG(DBG_ERR, (" IrUsb_ResetPipe before RESET_PIPE \n"));
  1350. #endif
  1351. NdisZeroMemory( pUrb, sizeof (struct _URB_PIPE_REQUEST) );
  1352. //
  1353. // Initialize RESET_PIPE request URB
  1354. //
  1355. pUrb->UrbHeader.Length = sizeof (struct _URB_PIPE_REQUEST);
  1356. pUrb->UrbHeader.Function = URB_FUNCTION_RESET_PIPE;
  1357. pUrb->UrbPipeRequest.PipeHandle = (USBD_PIPE_HANDLE)Pipe;
  1358. //
  1359. // Submit RESET_PIPE request URB
  1360. //
  1361. ntStatus = IrUsb_CallUSBD( pThisDev, pUrb );
  1362. DEBUGCOND(DBG_ERR, !NT_SUCCESS(ntStatus), (" IrUsb_ResetPipe RESET PIPE FAILED \n"));
  1363. DEBUGCOND(DBG_ERR, NT_SUCCESS(ntStatus), (" IrUsb_ResetPipe RESET PIPE SUCCEEDED \n"));
  1364. //
  1365. // Done with URB for RESET_PIPE request, free urb
  1366. //
  1367. MyMemFree( pUrb, sizeof(struct _URB_PIPE_REQUEST) );
  1368. }
  1369. else
  1370. {
  1371. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1372. }
  1373. DEBUGMSG(DBG_ERR, ("-IrUsb_ResetPipe %08X\n", ntStatus));
  1374. return ntStatus;
  1375. }
  1376. /*****************************************************************************
  1377. *
  1378. * Function: MyKeWaitForSingleObject
  1379. *
  1380. * Synopsis: Wait with a timeout in a loop
  1381. * so we will never hang if we are asked to halt/reset the driver while
  1382. * pollingthread is waiting for something.
  1383. * If input IRP is not null, also cancel it on timeout
  1384. *
  1385. * Arguments: pThisDev - pointer to IR device
  1386. * pEventWaitingFor - pointer to event to wait for
  1387. * pIrpWaitingFor - pointer to Irp to cancel if timing out
  1388. * timeout100ns - timeout
  1389. *
  1390. * Returns: NT status code
  1391. *
  1392. * Notes: THIS FUNCTION MUST BE RE-ENTERABLE!
  1393. *
  1394. *****************************************************************************/
  1395. NTSTATUS
  1396. MyKeWaitForSingleObject(
  1397. IN PIR_DEVICE pThisDev,
  1398. IN PVOID pEventWaitingFor,
  1399. IN OUT PIRP pIrpWaitingFor,
  1400. LONGLONG timeout100ns
  1401. )
  1402. {
  1403. NTSTATUS status = STATUS_SUCCESS;
  1404. LARGE_INTEGER Timeout;
  1405. DEBUGMSG( DBG_FUNC,("+MyKeWaitForSingleObject\n "));
  1406. if( timeout100ns )
  1407. {
  1408. //
  1409. //if a non-zero timeout was passed in, use it
  1410. //
  1411. Timeout.QuadPart = - ( timeout100ns );
  1412. }
  1413. else
  1414. {
  1415. //Timeout.QuadPart = -10000 * 1000 * 3; // default to 3 second relative delay
  1416. Timeout.QuadPart = -10000 * 1000; // default to 1 second relative delay
  1417. }
  1418. status = KeWaitForSingleObject( //keep this as standard wait
  1419. pEventWaitingFor,
  1420. Suspended,
  1421. KernelMode,
  1422. FALSE,
  1423. &Timeout
  1424. );
  1425. if( pIrpWaitingFor && (status != STATUS_SUCCESS) )
  1426. {
  1427. BOOLEAN CancelResult;
  1428. //
  1429. // if we get here we timed out and we were passed a PIRP to cancel
  1430. //
  1431. CancelResult = IoCancelIrp( pIrpWaitingFor );
  1432. DEBUGCOND( DBG_FUNC,
  1433. CancelResult,(" MyKeWaitForSingleObject successfully cancelled IRP (%x),CancelResult = %x\n",pIrpWaitingFor, CancelResult));
  1434. DEBUGCOND( DBG_ERR,
  1435. !CancelResult,(" MyKeWaitForSingleObject FAILED to cancel IRP (%x),CancelResult = %x\n",pIrpWaitingFor, CancelResult));
  1436. }
  1437. DEBUGCOND( DBG_OUT,( STATUS_TIMEOUT == status ),(" MyKeWaitForSingleObject TIMED OUT\n"));
  1438. DEBUGCOND( DBG_OUT,( STATUS_ALERTED == status ),(" MyKeWaitForSingleObject ALERTED\n"));
  1439. DEBUGCOND( DBG_OUT,( STATUS_USER_APC == status ),(" MyKeWaitForSingleObject USER APC\n"));
  1440. DEBUGMSG( DBG_FUNC,("-MyKeWaitForSingleObject (%x)\n", status));
  1441. return status;
  1442. }
  1443. /*****************************************************************************
  1444. *
  1445. * Function: PassiveLevelThread
  1446. *
  1447. * Synopsis: Thread running at IRQL PASSIVE_LEVEL.
  1448. *
  1449. * Arguments: Context - pointer to IR device
  1450. *
  1451. * Returns: None
  1452. *
  1453. * Notes:
  1454. *
  1455. * Any work item that can be called must be serialized.
  1456. * i.e. when IrUsbReset is called, NDIS will not make any other
  1457. * requests of the miniport until NdisMResetComplete is called.
  1458. *
  1459. *****************************************************************************/
  1460. VOID
  1461. PassiveLevelThread(
  1462. IN OUT PVOID Context
  1463. )
  1464. {
  1465. LARGE_INTEGER Timeout;
  1466. int i;
  1467. PIR_WORK_ITEM pWorkItem;
  1468. PIR_DEVICE pThisDev = (PIR_DEVICE)Context;
  1469. DEBUGMSG(DBG_WARN, ("+PassiveLevelThread\n")); // change to FUNC later?
  1470. DEBUGMSG(DBG_ERR, (" PassiveLevelThread: Starting\n"));
  1471. KeSetPriorityThread( KeGetCurrentThread(), LOW_REALTIME_PRIORITY+1 );
  1472. Timeout.QuadPart = -10000 * 1000 * 3; // 3 second relative delay
  1473. while ( !pThisDev->fKillPassiveLevelThread )
  1474. {
  1475. //
  1476. // The eventPassiveThread is an auto-clearing event, so
  1477. // we don't need to reset the event.
  1478. //
  1479. KeWaitForSingleObject( //keep this as standard wait
  1480. &pThisDev->EventPassiveThread,
  1481. Suspended,
  1482. KernelMode,
  1483. FALSE,
  1484. &Timeout
  1485. );
  1486. for( i = 0; i < NUM_WORK_ITEMS; i++ )
  1487. {
  1488. if( pThisDev->WorkItems[i].fInUse )
  1489. {
  1490. pThisDev->WorkItems[i].Callback( &(pThisDev->WorkItems[i]) );
  1491. }
  1492. }
  1493. } // while !fKill
  1494. DEBUGMSG(DBG_ERR, (" PassiveLevelThread: HALT\n"));
  1495. pThisDev->hPassiveThread = NULL;
  1496. DEBUGMSG(DBG_WARN, ("-PassiveLevelThread\n")); // change to FUNC later?
  1497. PsTerminateSystemThread( STATUS_SUCCESS );
  1498. }
  1499. /*****************************************************************************
  1500. *
  1501. * Function: PollingThread
  1502. *
  1503. * Synopsis: Thread running at IRQL PASSIVE_LEVEL.
  1504. *
  1505. * Arguments: Context - Pointer to IR device
  1506. *
  1507. * Returns: None
  1508. *
  1509. * Algorithm:
  1510. * 1) Call USBD for input data;
  1511. * 2) Call USBD for output data or sets a new speed;
  1512. *
  1513. * Notes:
  1514. *
  1515. *****************************************************************************/
  1516. VOID
  1517. PollingThread(
  1518. IN OUT PVOID Context
  1519. )
  1520. {
  1521. PIR_DEVICE pThisDev = (PIR_DEVICE)Context;
  1522. NTSTATUS Status;
  1523. PLIST_ENTRY pListEntry;
  1524. DEBUGMSG(DBG_WARN, ("+PollingThread\n")); // change to FUNC later?
  1525. DEBUGMSG(DBG_ERR, (" PollingThread: Starting\n"));
  1526. KeSetPriorityThread( KeGetCurrentThread(), LOW_REALTIME_PRIORITY );
  1527. while( !pThisDev->fKillPollingThread )
  1528. {
  1529. if( pThisDev->fProcessing )
  1530. {
  1531. ULONG FifoCount;
  1532. PIRUSB_CONTEXT pThisContext;
  1533. BOOLEAN SentPackets;
  1534. //
  1535. // First process the receive
  1536. //
  1537. if( ReceivePreprocessFifo( pThisDev, &FifoCount ) != STATUS_SUCCESS )
  1538. {
  1539. //
  1540. // There is a USB error, stop banging on the chip for a while
  1541. //
  1542. NdisMSleep( 1000 );
  1543. }
  1544. else if( FifoCount )
  1545. {
  1546. //
  1547. // Indicate that we are now receiving
  1548. //
  1549. InterlockedExchange( (PLONG)&pThisDev->fCurrentlyReceiving, TRUE );
  1550. //
  1551. // Tell the protocol that the media is now busy
  1552. //
  1553. if( pThisDev->fIndicatedMediaBusy == FALSE )
  1554. {
  1555. InterlockedExchange( &pThisDev->fMediaBusy, TRUE );
  1556. InterlockedExchange( &pThisDev->fIndicatedMediaBusy, TRUE );
  1557. IndicateMediaBusy( pThisDev );
  1558. }
  1559. ReceiveProcessFifoData( pThisDev );
  1560. }
  1561. else if( pThisDev->currentSpeed == SPEED_9600 )
  1562. {
  1563. NdisMSleep( 10*1000 );
  1564. }
  1565. //
  1566. // Then process the contexts that are ready
  1567. //
  1568. SentPackets = FALSE;
  1569. do
  1570. {
  1571. pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendBuiltQueue, &pThisDev->SendLock );
  1572. if( pListEntry )
  1573. {
  1574. InterlockedDecrement( &pThisDev->SendBuiltCount );
  1575. pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
  1576. switch( pThisContext->ContextType )
  1577. {
  1578. //
  1579. // Packet to send
  1580. //
  1581. case CONTEXT_NDIS_PACKET:
  1582. //
  1583. // make sure the receive is cleaned
  1584. //
  1585. ReceiveResetPointers( pThisDev );
  1586. //
  1587. // Send
  1588. //
  1589. SendPreprocessedPacketSend( pThisDev, pThisContext );
  1590. if( (pThisDev->ChipRevision >= CHIP_REVISION_7) &&
  1591. (pThisDev->currentSpeed > MAX_MIR_SPEED) )
  1592. {
  1593. SentPackets = TRUE;
  1594. SendCheckForOverflow( pThisDev );
  1595. }
  1596. else SendWaitCompletion( pThisDev );
  1597. break;
  1598. //
  1599. // Set the new speed
  1600. //
  1601. case CONTEXT_SET_SPEED:
  1602. //
  1603. // make sure the receive is cleaned
  1604. //
  1605. ReceiveResetPointers( pThisDev );
  1606. //
  1607. // Force completion and set
  1608. //
  1609. if( SentPackets )
  1610. {
  1611. SentPackets = TRUE;
  1612. SendWaitCompletion( pThisDev );
  1613. }
  1614. if( !pThisDev->fPendingHalt && !pThisDev->fPendingReset )
  1615. {
  1616. DEBUGMSG( DBG_ERR, (" Changing speed to: %d\n", pThisDev->linkSpeedInfo->BitsPerSec));
  1617. St4200SetSpeed( pThisDev );
  1618. InterlockedExchange( (PLONG)&pThisDev->currentSpeed, pThisDev->linkSpeedInfo->BitsPerSec );
  1619. #if defined(DIAGS)
  1620. if( !pThisDev->DiagsActive )
  1621. #endif
  1622. MyNdisMSetInformationComplete( pThisDev, STATUS_SUCCESS );
  1623. }
  1624. else
  1625. {
  1626. DEBUGMSG( DBG_ERR , (" St4200SetSpeed DUMPING OUT on TIMEOUT,HALT OR RESET\n"));
  1627. #if defined(DIAGS)
  1628. if( !pThisDev->DiagsActive )
  1629. #endif
  1630. MyNdisMSetInformationComplete( pThisDev, STATUS_UNSUCCESSFUL );
  1631. }
  1632. ExInterlockedInsertTailList(
  1633. &pThisDev->SendAvailableQueue,
  1634. &pThisContext->ListEntry,
  1635. &pThisDev->SendLock
  1636. );
  1637. InterlockedIncrement( &pThisDev->SendAvailableCount );
  1638. break;
  1639. #if defined(DIAGS)
  1640. //
  1641. // Diagnostic state is enabled
  1642. //
  1643. case CONTEXT_DIAGS_ENABLE:
  1644. Diags_CompleteEnable( pThisDev, pThisContext );
  1645. break;
  1646. //
  1647. // Diagnostic read of the registers
  1648. //
  1649. case CONTEXT_DIAGS_READ_REGISTERS:
  1650. Diags_CompleteReadRegisters( pThisDev, pThisContext );
  1651. break;
  1652. //
  1653. // Diagnostic write of the registers
  1654. //
  1655. case CONTEXT_DIAGS_WRITE_REGISTER:
  1656. Diags_CompleteWriteRegister( pThisDev, pThisContext );
  1657. break;
  1658. //
  1659. // Diagnostic bulk out
  1660. //
  1661. case CONTEXT_DIAGS_BULK_OUT:
  1662. Diags_Bulk( pThisDev, pThisContext, TRUE );
  1663. break;
  1664. //
  1665. // Diagnostic bulk in
  1666. //
  1667. case CONTEXT_DIAGS_BULK_IN:
  1668. Diags_Bulk( pThisDev, pThisContext, FALSE );
  1669. break;
  1670. //
  1671. // Diagnostic bulk out
  1672. //
  1673. case CONTEXT_DIAGS_SEND:
  1674. Diags_Send( pThisDev, pThisContext );
  1675. break;
  1676. #endif
  1677. }
  1678. }
  1679. } while( pListEntry );
  1680. //
  1681. // Force to wait
  1682. //
  1683. if( SentPackets )
  1684. SendWaitCompletion( pThisDev );
  1685. } // end if
  1686. else
  1687. {
  1688. NdisMSleep( 10*1000 );
  1689. }
  1690. } // end while
  1691. DEBUGMSG(DBG_ERR, (" PollingThread: HALT\n"));
  1692. pThisDev->hPollingThread = NULL;
  1693. //
  1694. // this thread will finish here
  1695. // if the terminate flag is TRUE
  1696. //
  1697. DEBUGMSG(DBG_WARN, ("-PollingThread\n")); // change to FUNC later?
  1698. PsTerminateSystemThread( STATUS_SUCCESS );
  1699. }
  1700. /*****************************************************************************
  1701. *
  1702. * Function: AllocUsbInfo
  1703. *
  1704. * Synopsis: Allocates the USB portion of the device context.
  1705. *
  1706. * Arguments: pThisDev - pointer to current ir device object
  1707. *
  1708. * Returns: TRUE - Success
  1709. * FALSE - Failure
  1710. *
  1711. * Notes:
  1712. *
  1713. *****************************************************************************/
  1714. BOOLEAN
  1715. AllocUsbInfo(
  1716. IN OUT PIR_DEVICE pThisDev
  1717. )
  1718. {
  1719. UINT Size = sizeof( IRUSB_USB_INFO );
  1720. pThisDev->pUsbInfo = MyMemAlloc( Size );
  1721. if( NULL == pThisDev->pUsbInfo )
  1722. {
  1723. return FALSE;
  1724. }
  1725. NdisZeroMemory( (PVOID)pThisDev->pUsbInfo, Size );
  1726. return TRUE;
  1727. }
  1728. /*****************************************************************************
  1729. *
  1730. * Function: AllocUsbInfo
  1731. *
  1732. * Synopsis: Deallocates the USB portion of the device context.
  1733. *
  1734. * Arguments: pThisDev - pointer to current ir device object
  1735. *
  1736. * Returns: None
  1737. *
  1738. * Notes:
  1739. *
  1740. *****************************************************************************/
  1741. VOID
  1742. FreeUsbInfo(
  1743. IN OUT PIR_DEVICE pThisDev
  1744. )
  1745. {
  1746. if( NULL != pThisDev->pUsbInfo )
  1747. {
  1748. //
  1749. // Free device descriptor structure
  1750. //
  1751. if ( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbDeviceDescriptor )
  1752. {
  1753. MyMemFree(
  1754. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbDeviceDescriptor,
  1755. sizeof(USB_DEVICE_DESCRIPTOR)
  1756. );
  1757. }
  1758. //
  1759. // Free up the Usb Interface structure
  1760. //
  1761. if( ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface )
  1762. {
  1763. MyMemFree(
  1764. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface,
  1765. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbInterface->Length
  1766. );
  1767. }
  1768. //
  1769. // free up the USB config discriptor
  1770. //
  1771. if( ((PIRUSB_USB_INFO) pThisDev->pUsbInfo)->UsbConfigurationDescriptor )
  1772. {
  1773. MyMemFree(
  1774. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->UsbConfigurationDescriptor,
  1775. sizeof(USB_CONFIGURATION_DESCRIPTOR) + 512
  1776. );
  1777. }
  1778. MyMemFree( (PVOID)pThisDev->pUsbInfo, sizeof(IRUSB_USB_INFO) );
  1779. }
  1780. }
  1781. /*****************************************************************************
  1782. *
  1783. * Function: IrUsb_InitSendStructures
  1784. *
  1785. * Synopsis: Allocates the send stuff
  1786. *
  1787. * Arguments: pThisDev - pointer to IR device
  1788. *
  1789. * Returns: TRUE if successful
  1790. * FALSE otherwise
  1791. *
  1792. * Notes:
  1793. *
  1794. *****************************************************************************/
  1795. BOOLEAN
  1796. IrUsb_InitSendStructures(
  1797. IN OUT PIR_DEVICE pThisDev
  1798. )
  1799. {
  1800. BOOLEAN InitResult = TRUE;
  1801. PUCHAR pThisContext;
  1802. PIRUSB_CONTEXT pCont;
  1803. int i;
  1804. DEBUGMSG(DBG_FUNC, ("+IrUsb_InitSendStructures\n"));
  1805. //
  1806. // Initialize a notification event for signalling PassiveLevelThread.
  1807. //
  1808. KeInitializeEvent(
  1809. &pThisDev->EventPassiveThread,
  1810. SynchronizationEvent, // auto-clearing event
  1811. FALSE // event initially non-signalled
  1812. );
  1813. #if defined(DIAGS)
  1814. KeInitializeEvent(
  1815. &pThisDev->EventDiags,
  1816. NotificationEvent, // non-auto-clearing event
  1817. FALSE // event initially non-signalled
  1818. );
  1819. #endif
  1820. ((PIRUSB_USB_INFO)pThisDev->pUsbInfo)->IrpSubmitUrb = NULL;
  1821. //
  1822. // set urblen to max possible urb size
  1823. //
  1824. pThisDev->UrbLen = sizeof( struct _URB_BULK_OR_INTERRUPT_TRANSFER );
  1825. pThisDev->UrbLen = MAX( pThisDev->UrbLen, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
  1826. pThisDev->UrbLen = MAX( pThisDev->UrbLen, sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST ));
  1827. pThisDev->UrbLen = MAX( pThisDev->UrbLen, sizeof(struct _URB_SELECT_CONFIGURATION));
  1828. //
  1829. // allocate our send context structs
  1830. //
  1831. pThisDev->pSendContexts = MyMemAlloc( NUM_SEND_CONTEXTS * sizeof(IRUSB_CONTEXT) );
  1832. if( NULL == pThisDev->pSendContexts )
  1833. {
  1834. InitResult = FALSE;
  1835. goto done;
  1836. }
  1837. NdisZeroMemory( pThisDev->pSendContexts, NUM_SEND_CONTEXTS * sizeof(IRUSB_CONTEXT) );
  1838. //
  1839. // Initialize list for holding pending read requests
  1840. //
  1841. InitializeListHead( &pThisDev->SendAvailableQueue );
  1842. InitializeListHead( &pThisDev->SendBuiltQueue );
  1843. InitializeListHead( &pThisDev->SendPendingQueue );
  1844. KeInitializeSpinLock( &pThisDev->SendLock );
  1845. //
  1846. // Prepare the read/write specific queue
  1847. //
  1848. InitializeListHead( &pThisDev->ReadWritePendingQueue );
  1849. pThisContext = pThisDev->pSendContexts;
  1850. for ( i= 0; i < NUM_SEND_CONTEXTS; i++ )
  1851. {
  1852. pCont = (PIRUSB_CONTEXT)pThisContext;
  1853. pCont->pThisDev = pThisDev;
  1854. // Also put in the available queue
  1855. ExInterlockedInsertTailList(
  1856. &pThisDev->SendAvailableQueue,
  1857. &pCont->ListEntry,
  1858. &pThisDev->SendLock
  1859. );
  1860. pThisContext += sizeof( IRUSB_CONTEXT );
  1861. } // for
  1862. //
  1863. // URB descriptor
  1864. //
  1865. pThisDev->pUrb = MyMemAlloc( pThisDev->UrbLen );
  1866. if( NULL == pThisDev->pUrb )
  1867. {
  1868. DEBUGMSG(DBG_ERR, (" IrUsb_InitSendStructures failed to alloc urb\n"));
  1869. InitResult = FALSE;
  1870. goto done;
  1871. }
  1872. NdisZeroMemory( pThisDev->pUrb, pThisDev->UrbLen );
  1873. //
  1874. // Send buffers
  1875. //
  1876. pThisDev->pBuffer = MyMemAlloc( MAX_IRDA_DATA_SIZE );
  1877. if( NULL == pThisDev->pBuffer )
  1878. {
  1879. DEBUGMSG(DBG_ERR, (" IrUsb_InitSendStructures failed to alloc info buf\n"));
  1880. InitResult = FALSE;
  1881. goto done;
  1882. }
  1883. pThisDev->pStagingBuffer = MyMemAlloc( MAX_TOTAL_SIZE_WITH_ALL_HEADERS + FAST_IR_FCS_SIZE );
  1884. if( NULL == pThisDev->pStagingBuffer )
  1885. {
  1886. DEBUGMSG(DBG_ERR, (" IrUsb_InitSendStructures failed to alloc staging buf\n"));
  1887. InitResult = FALSE;
  1888. goto done;
  1889. }
  1890. //
  1891. // and send counts
  1892. //
  1893. pThisDev->SendAvailableCount = NUM_SEND_CONTEXTS;
  1894. pThisDev->SendBuiltCount = 0;
  1895. pThisDev->SendPendingCount = 0;
  1896. pThisDev->ReadWritePendingCount = 0;
  1897. pThisDev->SendFifoCount = 0;
  1898. done:
  1899. DEBUGMSG(DBG_FUNC, ("-IrUsb_InitSendStructures\n"));
  1900. return InitResult;
  1901. }
  1902. /*****************************************************************************
  1903. *
  1904. * Function: IrUsb_FreeSendStructures
  1905. *
  1906. * Synopsis: Deallocates the send stuff
  1907. *
  1908. * Arguments: pThisDev - pointer to IR device
  1909. *
  1910. * Returns: None
  1911. *
  1912. * Notes:
  1913. *
  1914. *****************************************************************************/
  1915. VOID
  1916. IrUsb_FreeSendStructures(
  1917. IN OUT PIR_DEVICE pThisDev
  1918. )
  1919. {
  1920. DEBUGMSG(DBG_FUNC, ("+IrUsb_FreeSendStructures\n"));
  1921. if( NULL != pThisDev->pSendContexts )
  1922. {
  1923. MyMemFree( pThisDev->pSendContexts, NUM_SEND_CONTEXTS * sizeof(IRUSB_CONTEXT) );
  1924. pThisDev->pSendContexts = NULL;
  1925. }
  1926. if( NULL != pThisDev->pUrb )
  1927. {
  1928. MyMemFree( pThisDev->pUrb, pThisDev->UrbLen );
  1929. pThisDev->pUrb = NULL;
  1930. }
  1931. if( NULL != pThisDev->pBuffer )
  1932. {
  1933. MyMemFree( pThisDev->pBuffer, MAX_IRDA_DATA_SIZE );
  1934. pThisDev->pBuffer = NULL;
  1935. }
  1936. if( NULL != pThisDev->pStagingBuffer )
  1937. {
  1938. MyMemFree( pThisDev->pStagingBuffer, MAX_TOTAL_SIZE_WITH_ALL_HEADERS + FAST_IR_FCS_SIZE );
  1939. pThisDev->pStagingBuffer = NULL;
  1940. }
  1941. DEBUGMSG(DBG_FUNC, ("-IrUsb_FreeSendStructures\n"));
  1942. }
  1943. /*****************************************************************************
  1944. *
  1945. * Function: IrUsb_PrepareSetSpeed
  1946. *
  1947. * Synopsis: Prepares a context to set the new speed
  1948. *
  1949. * Arguments: pThisDev - pointer to IR device
  1950. *
  1951. * Returns: None
  1952. *
  1953. * Notes:
  1954. *
  1955. *****************************************************************************/
  1956. VOID
  1957. IrUsb_PrepareSetSpeed(
  1958. IN OUT PIR_DEVICE pThisDev
  1959. )
  1960. {
  1961. PIRUSB_CONTEXT pThisContext;
  1962. PLIST_ENTRY pListEntry;
  1963. DEBUGMSG( DBG_FUNC, ("+IrUsb_PrepareSetSpeed()\n"));
  1964. //
  1965. // Get a context to queue
  1966. //
  1967. pListEntry = ExInterlockedRemoveHeadList( &pThisDev->SendAvailableQueue, &pThisDev->SendLock );
  1968. if( NULL == pListEntry )
  1969. {
  1970. //
  1971. // This must not happen
  1972. //
  1973. DEBUGMSG(DBG_ERR, (" IrUsb_PrepareSetSpeed failed to find a free context struct\n"));
  1974. IRUSB_ASSERT( 0 );
  1975. goto done;
  1976. }
  1977. InterlockedDecrement( &pThisDev->SendAvailableCount );
  1978. pThisContext = CONTAINING_RECORD( pListEntry, IRUSB_CONTEXT, ListEntry );
  1979. pThisContext->ContextType = CONTEXT_SET_SPEED;
  1980. //
  1981. // Queue the context and nothing else has to be done
  1982. //
  1983. ExInterlockedInsertTailList(
  1984. &pThisDev->SendBuiltQueue,
  1985. &pThisContext->ListEntry,
  1986. &pThisDev->SendLock
  1987. );
  1988. InterlockedIncrement( &pThisDev->SendBuiltCount );
  1989. done:
  1990. DEBUGMSG( DBG_FUNC, ("-IrUsb_PrepareSetSpeed()\n"));
  1991. }
  1992. /*****************************************************************************
  1993. *
  1994. * Function: IrUsb_IncIoCount
  1995. *
  1996. * Synopsis: Tracks count of pending irps
  1997. *
  1998. * Arguments: pThisDev - pointer to IR device
  1999. *
  2000. * Returns: None
  2001. *
  2002. * Notes:
  2003. *
  2004. *****************************************************************************/
  2005. VOID
  2006. IrUsb_IncIoCount(
  2007. IN OUT PIR_DEVICE pThisDev
  2008. )
  2009. {
  2010. InterlockedIncrement( &pThisDev->PendingIrpCount );
  2011. }
  2012. /*****************************************************************************
  2013. *
  2014. * Function: IrUsb_DecIoCount
  2015. *
  2016. * Synopsis: Tracks count of pending irps
  2017. *
  2018. * Arguments: pThisDev - pointer to IR device
  2019. *
  2020. * Returns: None
  2021. *
  2022. * Notes:
  2023. *
  2024. *****************************************************************************/
  2025. VOID
  2026. IrUsb_DecIoCount(
  2027. IN OUT PIR_DEVICE pThisDev
  2028. )
  2029. {
  2030. InterlockedDecrement( &pThisDev->PendingIrpCount );
  2031. }
  2032. /*****************************************************************************
  2033. *
  2034. * Function: AllocXferUrb
  2035. *
  2036. * Synopsis: Allocates the transfer Urb for a USB transaction
  2037. *
  2038. * Arguments: None
  2039. *
  2040. * Returns: Pointer to Urb
  2041. *
  2042. * Notes:
  2043. *
  2044. *****************************************************************************/
  2045. PVOID
  2046. AllocXferUrb(
  2047. VOID
  2048. )
  2049. {
  2050. return MyMemAlloc( sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER) );
  2051. }
  2052. /*****************************************************************************
  2053. *
  2054. * Function: FreeXferUrb
  2055. *
  2056. * Synopsis: Deallocates the transfer Urb for a USB transaction
  2057. *
  2058. * Arguments: pUrb - pointer to Urb
  2059. *
  2060. * Returns: Pointer to Urb
  2061. *
  2062. * Notes:
  2063. *
  2064. *****************************************************************************/
  2065. VOID
  2066. FreeXferUrb(
  2067. IN OUT PVOID pUrb
  2068. )
  2069. {
  2070. MyMemFree( pUrb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER) );
  2071. }