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.

910 lines
22 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. DEVICE.C
  5. Abstract:
  6. This module contains the code that implements various support functions
  7. related to device configuration.
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. Revision History:
  12. 10-29-95 : created
  13. --*/
  14. #include "wdm.h"
  15. #include "stdarg.h"
  16. #include "stdio.h"
  17. #include "usbdi.h" //public data structures
  18. #include "hcdi.h"
  19. #include "usbd.h" //private data strutures
  20. #ifdef USBD_DRIVER // USBPORT supercedes most of USBD, so we will remove
  21. // the obsolete code by compiling it only if
  22. // USBD_DRIVER is set.
  23. #define DEADMAN_TIMER
  24. #define DEADMAN_TIMEOUT 5000 //timeout in ms
  25. //use a 5 second timeout
  26. typedef struct _USBD_TIMEOUT_CONTEXT {
  27. PIRP Irp;
  28. KTIMER TimeoutTimer;
  29. KDPC TimeoutDpc;
  30. KSPIN_LOCK TimeoutSpin;
  31. KEVENT Event;
  32. BOOLEAN Complete;
  33. } USBD_TIMEOUT_CONTEXT, *PUSBD_TIMEOUT_CONTEXT;
  34. #ifdef PAGE_CODE
  35. #ifdef ALLOC_PRAGMA
  36. #pragma alloc_text(PAGE, USBD_SubmitSynchronousURB)
  37. #pragma alloc_text(PAGE, USBD_SendCommand)
  38. #pragma alloc_text(PAGE, USBD_OpenEndpoint)
  39. #pragma alloc_text(PAGE, USBD_CloseEndpoint)
  40. #pragma alloc_text(PAGE, USBD_FreeUsbAddress)
  41. #pragma alloc_text(PAGE, USBD_AllocateUsbAddress)
  42. #pragma alloc_text(PAGE, USBD_GetEndpointState)
  43. #endif
  44. #endif
  45. #ifdef DEADMAN_TIMER
  46. VOID
  47. USBD_SyncUrbTimeoutDPC(
  48. IN PKDPC Dpc,
  49. IN PVOID DeferredContext,
  50. IN PVOID SystemArgument1,
  51. IN PVOID SystemArgument2
  52. )
  53. /*++
  54. Routine Description:
  55. This routine runs at DISPATCH_LEVEL IRQL.
  56. Arguments:
  57. Dpc - Pointer to the DPC object.
  58. DeferredContext -
  59. SystemArgument1 - not used.
  60. SystemArgument2 - not used.
  61. Return Value:
  62. None.
  63. --*/
  64. {
  65. PUSBD_TIMEOUT_CONTEXT usbdTimeoutContext = DeferredContext;
  66. BOOLEAN complete;
  67. #if DBG
  68. BOOLEAN status;
  69. #endif
  70. KIRQL irql;
  71. KeAcquireSpinLock(&usbdTimeoutContext->TimeoutSpin, &irql);
  72. complete = usbdTimeoutContext->Complete;
  73. KeReleaseSpinLock(&usbdTimeoutContext->TimeoutSpin, irql);
  74. if (!complete) {
  75. #if DBG
  76. status =
  77. #endif
  78. IoCancelIrp(usbdTimeoutContext->Irp);
  79. #if DBG
  80. USBD_ASSERT(status == TRUE);
  81. #endif
  82. }
  83. //OK to free it
  84. KeSetEvent(&usbdTimeoutContext->Event, 1, FALSE);
  85. }
  86. NTSTATUS
  87. USBD_SyncIrp_Complete(
  88. IN PDEVICE_OBJECT DeviceObject,
  89. IN PIRP Irp,
  90. IN PVOID Context
  91. )
  92. /*++
  93. Routine Description:
  94. This routine is called when the port driver completes an IRP.
  95. Arguments:
  96. DeviceObject - Pointer to the device object for the class device.
  97. Irp - Irp completed.
  98. Context - Driver defined context.
  99. Return Value:
  100. The function value is the final status from the operation.
  101. --*/
  102. {
  103. PUSBD_TIMEOUT_CONTEXT usbdTimeoutContext = Context;
  104. KIRQL irql;
  105. BOOLEAN cancelled;
  106. NTSTATUS ntStatus;
  107. KeAcquireSpinLock(&usbdTimeoutContext->TimeoutSpin, &irql);
  108. usbdTimeoutContext->Complete = TRUE;
  109. cancelled = KeCancelTimer(&usbdTimeoutContext->TimeoutTimer);
  110. KeReleaseSpinLock(&usbdTimeoutContext->TimeoutSpin, irql);
  111. // see if the timer was in the queue, if it was then it is safe to free
  112. // it
  113. if (cancelled) {
  114. // safe to free it
  115. KeSetEvent(&usbdTimeoutContext->Event, 1, FALSE);
  116. }
  117. ntStatus = Irp->IoStatus.Status;
  118. return ntStatus;
  119. }
  120. #endif /* DEADMAN_TIMER */
  121. NTSTATUS
  122. USBD_SubmitSynchronousURB(
  123. IN PURB Urb,
  124. IN PDEVICE_OBJECT DeviceObject,
  125. IN PUSBD_DEVICE_DATA DeviceData
  126. )
  127. /*++
  128. Routine Description:
  129. Submit a Urb to HCD synchronously
  130. Arguments:
  131. Urb - Urb to submit
  132. DeviceObject USBD device object
  133. Return Value:
  134. STATUS_SUCCESS if successful,
  135. STATUS_UNSUCCESSFUL otherwise
  136. --*/
  137. {
  138. NTSTATUS ntStatus = STATUS_SUCCESS, status;
  139. PIRP irp;
  140. KEVENT event;
  141. IO_STATUS_BLOCK ioStatus;
  142. PIO_STACK_LOCATION nextStack;
  143. #ifdef DEADMAN_TIMER
  144. BOOLEAN haveTimer = FALSE;
  145. PUSBD_TIMEOUT_CONTEXT usbdTimeoutContext;
  146. #endif /* DEADMAN_TIMER */
  147. PAGED_CODE();
  148. USBD_KdPrint(3, ("'enter USBD_SubmitSynchronousURB\n"));
  149. ASSERT_DEVICE(DeviceData);
  150. irp = IoBuildDeviceIoControlRequest(
  151. IOCTL_INTERNAL_USB_SUBMIT_URB,
  152. HCD_DEVICE_OBJECT(DeviceObject),
  153. NULL,
  154. 0,
  155. NULL,
  156. 0,
  157. TRUE, /* INTERNAL */
  158. &event,
  159. &ioStatus);
  160. if (NULL == irp) {
  161. USBD_KdBreak(("USBD_SubmitSynchronousURB build Irp failed\n"));
  162. return STATUS_INSUFFICIENT_RESOURCES;
  163. }
  164. //
  165. // Call the hc driver to perform the operation. If the returned status
  166. // is PENDING, wait for the request to complete.
  167. //
  168. KeInitializeEvent(&event, NotificationEvent, FALSE);
  169. nextStack = IoGetNextIrpStackLocation(irp);
  170. ASSERT(nextStack != NULL);
  171. nextStack->Parameters.Others.Argument1 = Urb;
  172. #ifdef DEADMAN_TIMER
  173. usbdTimeoutContext = GETHEAP(NonPagedPool,
  174. sizeof(*usbdTimeoutContext));
  175. if (usbdTimeoutContext) {
  176. LARGE_INTEGER dueTime;
  177. usbdTimeoutContext->Irp = irp;
  178. usbdTimeoutContext->Complete = FALSE;
  179. KeInitializeEvent(&usbdTimeoutContext->Event, NotificationEvent, FALSE);
  180. KeInitializeSpinLock(&usbdTimeoutContext->TimeoutSpin);
  181. KeInitializeTimer(&usbdTimeoutContext->TimeoutTimer);
  182. KeInitializeDpc(&usbdTimeoutContext->TimeoutDpc,
  183. USBD_SyncUrbTimeoutDPC,
  184. usbdTimeoutContext);
  185. dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
  186. KeSetTimer(&usbdTimeoutContext->TimeoutTimer,
  187. dueTime,
  188. &usbdTimeoutContext->TimeoutDpc);
  189. haveTimer = TRUE;
  190. IoSetCompletionRoutine(irp,
  191. USBD_SyncIrp_Complete,
  192. // always pass FDO to completion routine
  193. usbdTimeoutContext,
  194. TRUE,
  195. TRUE,
  196. TRUE);
  197. }
  198. #endif
  199. //
  200. // initialize flags field
  201. // for internal request
  202. //
  203. Urb->UrbHeader.UsbdFlags = 0;
  204. //
  205. // Init the Irp field for transfers
  206. //
  207. switch(Urb->UrbHeader.Function) {
  208. case URB_FUNCTION_CONTROL_TRANSFER:
  209. case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
  210. HC_URB(Urb)->HcdUrbCommonTransfer.hca.HcdIrp = irp;
  211. if (HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferMDL == NULL &&
  212. HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferLength != 0) {
  213. if ((HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferMDL =
  214. IoAllocateMdl(HC_URB(Urb)->HcdUrbCommonTransfer.TransferBuffer,
  215. HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferLength,
  216. FALSE,
  217. FALSE,
  218. NULL)) == NULL)
  219. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  220. else {
  221. Urb->UrbHeader.UsbdFlags |= USBD_REQUEST_MDL_ALLOCATED;
  222. MmBuildMdlForNonPagedPool(HC_URB(Urb)->HcdUrbCommonTransfer.TransferBufferMDL);
  223. }
  224. }
  225. break;
  226. }
  227. USBD_KdPrint(3, ("'USBD_SubmitSynchronousURB: calling HCD with URB\n"));
  228. if (NT_SUCCESS(ntStatus)) {
  229. // set the renter bit on the URB function code
  230. Urb->UrbHeader.Function |= HCD_NO_USBD_CALL;
  231. ntStatus = IoCallDriver(HCD_DEVICE_OBJECT(DeviceObject),
  232. irp);
  233. }
  234. USBD_KdPrint(3, ("'ntStatus from IoCallDriver = 0x%x\n", ntStatus));
  235. status = STATUS_SUCCESS;
  236. if (ntStatus == STATUS_PENDING) {
  237. status = KeWaitForSingleObject(
  238. &event,
  239. Suspended,
  240. KernelMode,
  241. FALSE,
  242. NULL);
  243. ntStatus = ioStatus.Status;
  244. } else {
  245. ioStatus.Status = ntStatus;
  246. }
  247. #ifdef DEADMAN_TIMER
  248. // the completion routine should have canceled the timer
  249. // so we should never find it in the queue
  250. //
  251. // remove our timeoutDPC from the queue
  252. //
  253. if (haveTimer) {
  254. USBD_ASSERT(KeCancelTimer(&usbdTimeoutContext->TimeoutTimer) == FALSE);
  255. KeWaitForSingleObject(&usbdTimeoutContext->Event,
  256. Suspended,
  257. KernelMode,
  258. FALSE,
  259. NULL);
  260. RETHEAP(usbdTimeoutContext);
  261. }
  262. #endif
  263. // NOTE:
  264. // mapping is handled by completion routine
  265. // called by HCD
  266. USBD_KdPrint(3, ("'urb status = 0x%x ntStatus = 0x%x\n", Urb->UrbHeader.Status, ntStatus));
  267. return ntStatus;
  268. }
  269. NTSTATUS
  270. USBD_SendCommand(
  271. IN PUSBD_DEVICE_DATA DeviceData,
  272. IN PDEVICE_OBJECT DeviceObject,
  273. IN USHORT RequestCode,
  274. IN USHORT WValue,
  275. IN USHORT WIndex,
  276. IN USHORT WLength,
  277. IN PVOID Buffer,
  278. IN ULONG BufferLength,
  279. OUT PULONG BytesReturned,
  280. OUT USBD_STATUS *UsbStatus
  281. )
  282. /*++
  283. Routine Description:
  284. Send a standard USB command on the default pipe.
  285. Arguments:
  286. DeviceData - ptr to USBD device structure the command will be sent to
  287. DeviceObject -
  288. RequestCode -
  289. WValue - wValue for setup packet
  290. WIndex - wIndex for setup packet
  291. WLength - wLength for setup packet
  292. Buffer - Input/Output Buffer for command
  293. BufferLength - Length of Input/Output buffer.
  294. BytesReturned - pointer to ulong to copy number of bytes
  295. returned (optional)
  296. UsbStatus - USBD status code returned in the URB.
  297. Return Value:
  298. STATUS_SUCCESS if successful,
  299. STATUS_UNSUCCESSFUL otherwise
  300. --*/
  301. {
  302. NTSTATUS ntStatus;
  303. PHCD_URB urb = NULL;
  304. PUSBD_PIPE defaultPipe;
  305. PUSB_STANDARD_SETUP_PACKET setupPacket;
  306. PUSBD_EXTENSION deviceExtension;
  307. PAGED_CODE();
  308. USBD_KdPrint(3, ("'enter USBD_SendCommand\n"));
  309. ASSERT_DEVICE(DeviceData);
  310. if (!DeviceData || DeviceData->Sig != SIG_DEVICE) {
  311. USBD_Warning(NULL,
  312. "Bad DeviceData passed to USBD_SendCommand, fail!\n",
  313. FALSE);
  314. return STATUS_INVALID_PARAMETER;
  315. }
  316. defaultPipe = &(DeviceData->DefaultPipe);
  317. deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
  318. if (deviceExtension->DeviceHackFlags &
  319. USBD_DEVHACK_SLOW_ENUMERATION) {
  320. //
  321. // if noncomplience switch is on in the
  322. // registry we'll pause here to give the
  323. // device a chance to respond.
  324. //
  325. LARGE_INTEGER deltaTime;
  326. deltaTime.QuadPart = 100 * -10000;
  327. (VOID) KeDelayExecutionThread(KernelMode,
  328. FALSE,
  329. &deltaTime);
  330. }
  331. urb = GETHEAP(NonPagedPool,
  332. sizeof(struct _URB_CONTROL_TRANSFER));
  333. if (!urb) {
  334. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  335. } else {
  336. urb->UrbHeader.Length = sizeof(struct _URB_CONTROL_TRANSFER);
  337. urb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER;
  338. setupPacket = (PUSB_STANDARD_SETUP_PACKET)
  339. urb->HcdUrbCommonTransfer.Extension.u.SetupPacket;
  340. setupPacket->RequestCode = RequestCode;
  341. setupPacket->wValue = WValue;
  342. setupPacket->wIndex = WIndex;
  343. setupPacket->wLength = WLength;
  344. if (!USBD_ValidatePipe(defaultPipe) ||
  345. !defaultPipe->HcdEndpoint) {
  346. USBD_Warning(DeviceData,
  347. "Bad DefaultPipe or Endpoint in USBD_SendCommand, fail!\n",
  348. FALSE);
  349. ntStatus = STATUS_INVALID_PARAMETER;
  350. goto USBD_SendCommand_done;
  351. }
  352. urb->HcdUrbCommonTransfer.hca.HcdEndpoint = defaultPipe->HcdEndpoint;
  353. urb->HcdUrbCommonTransfer.TransferFlags = USBD_SHORT_TRANSFER_OK;
  354. // USBD is responsible for setting the transfer direction
  355. //
  356. // TRANSFER direction is implied in the command
  357. if (RequestCode & USB_DEVICE_TO_HOST)
  358. USBD_SET_TRANSFER_DIRECTION_IN(urb->HcdUrbCommonTransfer.TransferFlags);
  359. else
  360. USBD_SET_TRANSFER_DIRECTION_OUT(urb->HcdUrbCommonTransfer.TransferFlags);
  361. urb->HcdUrbCommonTransfer.TransferBufferLength = BufferLength;
  362. urb->HcdUrbCommonTransfer.TransferBuffer = Buffer;
  363. urb->HcdUrbCommonTransfer.TransferBufferMDL = NULL;
  364. urb->HcdUrbCommonTransfer.UrbLink = NULL;
  365. USBD_KdPrint(3, ("'SendCommand cmd = 0x%x buffer = 0x%x length = 0x%x direction = 0x%x\n",
  366. setupPacket->RequestCode,
  367. urb->HcdUrbCommonTransfer.TransferBuffer,
  368. urb->HcdUrbCommonTransfer.TransferBufferLength,
  369. urb->HcdUrbCommonTransfer.TransferFlags
  370. ));
  371. ntStatus = USBD_SubmitSynchronousURB((PURB)urb, DeviceObject, DeviceData);
  372. if (BytesReturned) {
  373. *BytesReturned = urb->HcdUrbCommonTransfer.TransferBufferLength;
  374. }
  375. if (UsbStatus) {
  376. *UsbStatus = urb->HcdUrbCommonTransfer.Status;
  377. }
  378. USBD_SendCommand_done:
  379. // free the transfer URB
  380. RETHEAP(urb);
  381. }
  382. USBD_KdPrint(3, ("'exit USBD_SendCommand 0x%x\n", ntStatus));
  383. return ntStatus;
  384. }
  385. NTSTATUS
  386. USBD_OpenEndpoint(
  387. IN PUSBD_DEVICE_DATA DeviceData,
  388. IN PDEVICE_OBJECT DeviceObject,
  389. IN OUT PUSBD_PIPE PipeHandle,
  390. OUT USBD_STATUS *UsbStatus,
  391. BOOLEAN IsDefaultPipe
  392. )
  393. /*++
  394. Routine Description:
  395. open an endpoint on a USB device.
  396. Arguments:
  397. DeviceData - data describes the device this endpoint is on.
  398. DeviceObject - USBD device object.
  399. PipeHandle - USBD PipeHandle to associate with the endpoint.
  400. on input MaxTransferSize initialize to the largest
  401. transfer that will be sent on this endpoint,
  402. Return Value:
  403. NT status code.
  404. --*/
  405. {
  406. NTSTATUS ntStatus;
  407. PHCD_URB urb;
  408. PUSBD_EXTENSION deviceExtension;
  409. extern UCHAR ForceDoubleBuffer;
  410. extern UCHAR ForceFastIso;
  411. PAGED_CODE();
  412. USBD_KdPrint(3, ("'enter USBD_OpenEndpoint\n"));
  413. deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
  414. ASSERT_DEVICE(DeviceData);
  415. USBD_ASSERT(PIPE_CLOSED(PipeHandle) == TRUE);
  416. urb = GETHEAP(NonPagedPool,
  417. sizeof(struct _URB_HCD_OPEN_ENDPOINT));
  418. if (!urb) {
  419. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  420. } else {
  421. urb->UrbHeader.Length = sizeof(struct _URB_HCD_OPEN_ENDPOINT);
  422. urb->UrbHeader.Function = URB_FUNCTION_HCD_OPEN_ENDPOINT;
  423. urb->HcdUrbOpenEndpoint.EndpointDescriptor = &PipeHandle->EndpointDescriptor;
  424. urb->HcdUrbOpenEndpoint.DeviceAddress = DeviceData->DeviceAddress;
  425. urb->HcdUrbOpenEndpoint.HcdEndpointFlags = 0;
  426. if (DeviceData->LowSpeed == TRUE) {
  427. urb->HcdUrbOpenEndpoint.HcdEndpointFlags |= USBD_EP_FLAG_LOWSPEED;
  428. }
  429. // default pipe and iso pipes never halt
  430. if (IsDefaultPipe ||
  431. (PipeHandle->EndpointDescriptor.bmAttributes &
  432. USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS) {
  433. urb->HcdUrbOpenEndpoint.HcdEndpointFlags |= USBD_EP_FLAG_NEVERHALT;
  434. }
  435. if (ForceDoubleBuffer &&
  436. ((PipeHandle->EndpointDescriptor.bmAttributes &
  437. USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK)) {
  438. PipeHandle->UsbdPipeFlags |= USBD_PF_DOUBLE_BUFFER;
  439. USBD_KdPrint(1, (">>Forcing Double Buffer -- Bulk <<\n"));
  440. }
  441. if (ForceFastIso &&
  442. ((PipeHandle->EndpointDescriptor.bmAttributes &
  443. USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_ISOCHRONOUS)) {
  444. PipeHandle->UsbdPipeFlags |= USBD_PF_ENABLE_RT_THREAD_ACCESS;
  445. USBD_KdPrint(1, (">>Forcing Fast Iso <<\n"));
  446. }
  447. urb->HcdUrbOpenEndpoint.MaxTransferSize =
  448. PipeHandle->MaxTransferSize;
  449. // check client option flags
  450. if (PipeHandle->UsbdPipeFlags & USBD_PF_DOUBLE_BUFFER) {
  451. USBD_KdPrint(1, (">>Setting Double Buffer Flag<<\n"));
  452. urb->HcdUrbOpenEndpoint.HcdEndpointFlags |=
  453. USBD_EP_FLAG_DOUBLE_BUFFER;
  454. }
  455. if (PipeHandle->UsbdPipeFlags & USBD_PF_ENABLE_RT_THREAD_ACCESS) {
  456. USBD_KdPrint(1, (">>Setting Fast ISO Flag<<\n"));
  457. urb->HcdUrbOpenEndpoint.HcdEndpointFlags |=
  458. USBD_EP_FLAG_FAST_ISO;
  459. }
  460. if (PipeHandle->UsbdPipeFlags & USBD_PF_MAP_ADD_TRANSFERS) {
  461. USBD_KdPrint(1, (">>Setting Map Add Flag<<\n"));
  462. urb->HcdUrbOpenEndpoint.HcdEndpointFlags |=
  463. USBD_EP_FLAG_MAP_ADD_IO;
  464. }
  465. //
  466. // Serialize Open Endpoint requests
  467. //
  468. ntStatus = USBD_SubmitSynchronousURB((PURB) urb, DeviceObject,
  469. DeviceData);
  470. if (NT_SUCCESS(ntStatus)) {
  471. PipeHandle->HcdEndpoint = urb->HcdUrbOpenEndpoint.HcdEndpoint;
  472. PipeHandle->ScheduleOffset = urb->HcdUrbOpenEndpoint.ScheduleOffset;
  473. PipeHandle->Sig = SIG_PIPE;
  474. }
  475. if (UsbStatus) {
  476. *UsbStatus = urb->UrbHeader.Status;
  477. }
  478. RETHEAP(urb);
  479. }
  480. USBD_KdPrint(3, ("'exit USBD_OpenEndpoint 0x%x\n", ntStatus));
  481. return ntStatus;
  482. }
  483. NTSTATUS
  484. USBD_CloseEndpoint(
  485. IN PUSBD_DEVICE_DATA DeviceData,
  486. IN PDEVICE_OBJECT DeviceObject,
  487. IN PUSBD_PIPE PipeHandle,
  488. IN OUT USBD_STATUS *UsbStatus
  489. )
  490. /*++
  491. Routine Description:
  492. Close an Endpoint
  493. Arguments:
  494. DeviceData - ptr to USBD device data structure.
  495. DeviceObject - USBD device object.
  496. PipeHandle - USBD pipe handle associated with the endpoint.
  497. Return Value:
  498. STATUS_SUCCESS if successful,
  499. STATUS_UNSUCCESSFUL otherwise
  500. --*/
  501. {
  502. NTSTATUS ntStatus;
  503. PHCD_URB urb;
  504. PUSBD_EXTENSION deviceExtension;
  505. PAGED_CODE();
  506. USBD_KdPrint(3, ("'enter USBD_CloseEndpoint\n"));
  507. ASSERT_DEVICE(DeviceData);
  508. deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
  509. urb = GETHEAP(NonPagedPool,
  510. sizeof(struct _URB_HCD_CLOSE_ENDPOINT));
  511. if (!urb) {
  512. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  513. } else {
  514. urb->UrbHeader.Length = sizeof(struct _URB_HCD_CLOSE_ENDPOINT);
  515. urb->UrbHeader.Function = URB_FUNCTION_HCD_CLOSE_ENDPOINT;
  516. urb->HcdUrbCloseEndpoint.HcdEndpoint = PipeHandle->HcdEndpoint;
  517. //
  518. // Serialize Close Endpoint requests
  519. //
  520. ntStatus = USBD_SubmitSynchronousURB((PURB) urb, DeviceObject,
  521. DeviceData);
  522. if (UsbStatus) {
  523. *UsbStatus = urb->UrbHeader.Status;
  524. }
  525. RETHEAP(urb);
  526. }
  527. USBD_KdPrint(3, ("'exit USBD_CloseEndpoint 0x%x\n", ntStatus));
  528. return ntStatus;
  529. }
  530. VOID
  531. USBD_FreeUsbAddress(
  532. IN PDEVICE_OBJECT DeviceObject,
  533. IN USHORT DeviceAddress
  534. )
  535. /*++
  536. Routine Description:
  537. Arguments:
  538. Return Value:
  539. Valid USB address (1..127) to use for this device,
  540. returns 0 if no device address available.
  541. --*/
  542. {
  543. PUSBD_EXTENSION deviceExtension;
  544. USHORT address = 0, i, j;
  545. ULONG bit;
  546. PAGED_CODE();
  547. // we should never see a free to device address 0
  548. USBD_ASSERT(DeviceAddress != 0);
  549. deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
  550. for (j=0; j<4; j++) {
  551. bit = 1;
  552. for (i=0; i<32; i++) {
  553. address = (USHORT)(j*32+i);
  554. if (address == DeviceAddress) {
  555. deviceExtension->AddressList[j] &= ~bit;
  556. goto USBD_FreeUsbAddress_Done;
  557. }
  558. bit = bit<<1;
  559. }
  560. }
  561. USBD_FreeUsbAddress_Done:
  562. USBD_KdPrint(3, ("'USBD free Address %d\n", address));
  563. }
  564. USHORT
  565. USBD_AllocateUsbAddress(
  566. IN PDEVICE_OBJECT DeviceObject
  567. )
  568. /*++
  569. Routine Description:
  570. Arguments:
  571. Return Value:
  572. Valid USB address (1..127) to use for this device,
  573. returns 0 if no device address available.
  574. --*/
  575. {
  576. PUSBD_EXTENSION deviceExtension;
  577. USHORT address = 0, i, j;
  578. ULONG bit;
  579. PAGED_CODE();
  580. deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
  581. for (j=0; j<4; j++) {
  582. bit = 1;
  583. for (i=0; i<32; i++) {
  584. if (!(deviceExtension->AddressList[j] & bit)) {
  585. deviceExtension->AddressList[j] |= bit;
  586. address = (USHORT)(j*32+i);
  587. goto USBD_AllocateUsbAddress_Done;
  588. }
  589. bit = bit<<1;
  590. }
  591. }
  592. USBD_AllocateUsbAddress_Done:
  593. USBD_KdPrint(3, ("'USBD assigning Address %d\n", address));
  594. return address;
  595. }
  596. NTSTATUS
  597. USBD_GetEndpointState(
  598. IN PUSBD_DEVICE_DATA DeviceData,
  599. IN PDEVICE_OBJECT DeviceObject,
  600. IN PUSBD_PIPE PipeHandle,
  601. OUT USBD_STATUS *UsbStatus,
  602. OUT PULONG EndpointState
  603. )
  604. /*++
  605. Routine Description:
  606. open an endpoint on a USB device.
  607. Arguments:
  608. DeviceData - data describes the device this endpoint is on.
  609. DeviceObject - USBD device object.
  610. PipeHandle - USBD PipeHandle to associate with the endpoint.
  611. Return Value:
  612. NT status code.
  613. --*/
  614. {
  615. NTSTATUS ntStatus;
  616. PHCD_URB urb;
  617. PUSBD_EXTENSION deviceExtension;
  618. PAGED_CODE();
  619. USBD_KdPrint(3, ("'enter USBD_GetEndpointState\n"));
  620. ASSERT_DEVICE(DeviceData);
  621. deviceExtension = GET_DEVICE_EXTENSION(DeviceObject);
  622. USBD_ASSERT(PIPE_CLOSED(PipeHandle) == FALSE);
  623. urb = GETHEAP(NonPagedPool,
  624. sizeof(struct _URB_HCD_OPEN_ENDPOINT));
  625. if (!urb) {
  626. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  627. } else {
  628. urb->UrbHeader.Length = sizeof(struct _URB_HCD_OPEN_ENDPOINT);
  629. urb->UrbHeader.Function = URB_FUNCTION_HCD_GET_ENDPOINT_STATE;
  630. urb->HcdUrbEndpointState.HcdEndpoint = PipeHandle->HcdEndpoint;
  631. urb->HcdUrbEndpointState.HcdEndpointState = 0;
  632. // Serialize Open Endpoint requests
  633. //
  634. ntStatus = USBD_SubmitSynchronousURB((PURB) urb,
  635. DeviceObject,
  636. DeviceData);
  637. if (UsbStatus) {
  638. *UsbStatus = urb->UrbHeader.Status;
  639. }
  640. *EndpointState = urb->HcdUrbEndpointState.HcdEndpointState;
  641. RETHEAP(urb);
  642. }
  643. USBD_KdPrint(3, ("'exit USBD_GetEndpointState 0x%x\n", ntStatus));
  644. return ntStatus;
  645. }
  646. #endif // USBD_DRIVER