Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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