usbhost.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. usbhost.c
  9. Abstract:
  10. This module implements USB host controller support routines.
  11. Author:
  12. Evan Green 16-Jan-2013
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/driver.h>
  20. #include "usbcore.h"
  21. //
  22. // ---------------------------------------------------------------- Definitions
  23. //
  24. //
  25. // ------------------------------------------------------ Data Type Definitions
  26. //
  27. //
  28. // ----------------------------------------------- Internal Function Prototypes
  29. //
  30. VOID
  31. UsbpDestroyEndpoint (
  32. PUSB_DEVICE Device,
  33. PUSB_ENDPOINT Endpoint
  34. );
  35. VOID
  36. UsbpPortStatusChangeWorker (
  37. PVOID Parameter
  38. );
  39. //
  40. // -------------------------------------------------------------------- Globals
  41. //
  42. //
  43. // ------------------------------------------------------------------ Functions
  44. //
  45. USB_API
  46. KSTATUS
  47. UsbHostRegisterController (
  48. PUSB_HOST_CONTROLLER_INTERFACE ControllerInterface,
  49. PHANDLE ControllerHandle
  50. )
  51. /*++
  52. Routine Description:
  53. This routine registers a new host controller instance with the USB core.
  54. This routine must be called at low level.
  55. Arguments:
  56. ControllerInterface - Supplies a pointer to the interface that the USB
  57. core will use to call back into the host controller. This contents of
  58. this memory will be copied during this call, so the caller can pass
  59. a pointer to a stack-allocated buffer here.
  60. ControllerHandle - Supplies a pointer where a handle will be returned
  61. representing this controller instance. When calls are made to the USB
  62. core regarding a specific controller, pass this handle.
  63. Return Value:
  64. STATUS_SUCCESS on success. A handle will also be returned on success.
  65. STATUS_NOT_SUPPORTED if an unsupported version was supplied with the
  66. controller interface.
  67. Other error codes on other failures.
  68. --*/
  69. {
  70. UCHAR Address;
  71. PUSB_TRANSFER_COMPLETION_QUEUE CompletionQueue;
  72. PUSB_HOST_CONTROLLER Controller;
  73. KSTATUS Status;
  74. //
  75. // Surely DriverEntry must have been called to initialize this list head.
  76. //
  77. ASSERT(UsbHostControllerList.Next != NULL);
  78. Controller = NULL;
  79. if (UsbHostControllerListLock == NULL) {
  80. Status = STATUS_NOT_READY;
  81. goto HostRegisterControllerEnd;
  82. }
  83. //
  84. // Validate parameters.
  85. //
  86. if ((ControllerInterface == NULL) || (ControllerHandle == NULL)) {
  87. Status = STATUS_INVALID_PARAMETER;
  88. goto HostRegisterControllerEnd;
  89. }
  90. if (ControllerInterface->Version < USB_HOST_CONTROLLER_INTERFACE_VERSION) {
  91. Status = STATUS_NOT_SUPPORTED;
  92. goto HostRegisterControllerEnd;
  93. }
  94. if ((ControllerInterface->DriverObject == NULL) ||
  95. (ControllerInterface->DeviceObject == NULL) ||
  96. (ControllerInterface->CreateEndpoint == NULL) ||
  97. (ControllerInterface->DestroyEndpoint == NULL) ||
  98. (ControllerInterface->CreateTransfer == NULL) ||
  99. (ControllerInterface->DestroyTransfer == NULL) ||
  100. (ControllerInterface->SubmitTransfer == NULL) ||
  101. (ControllerInterface->CancelTransfer == NULL) ||
  102. (ControllerInterface->GetRootHubStatus == NULL) ||
  103. (ControllerInterface->SetRootHubStatus == NULL) ||
  104. (ControllerInterface->Speed == UsbDeviceSpeedInvalid) ||
  105. (ControllerInterface->RootHubPortCount == 0)) {
  106. Status = STATUS_INVALID_PARAMETER;
  107. goto HostRegisterControllerEnd;
  108. }
  109. //
  110. // The endpoint flush routine is required if polled I/O is supported.
  111. //
  112. if ((ControllerInterface->SubmitPolledTransfer != NULL) &&
  113. (ControllerInterface->FlushEndpoint == NULL)) {
  114. Status = STATUS_INVALID_PARAMETER;
  115. goto HostRegisterControllerEnd;
  116. }
  117. //
  118. // Create a controller structure.
  119. //
  120. Controller = MmAllocateNonPagedPool(sizeof(USB_HOST_CONTROLLER),
  121. USB_CORE_ALLOCATION_TAG);
  122. if (Controller == NULL) {
  123. Status = STATUS_INSUFFICIENT_RESOURCES;
  124. goto HostRegisterControllerEnd;
  125. }
  126. RtlZeroMemory(Controller, sizeof(USB_HOST_CONTROLLER));
  127. RtlCopyMemory(&(Controller->Device),
  128. ControllerInterface,
  129. sizeof(USB_HOST_CONTROLLER_INTERFACE));
  130. Controller->Lock = KeCreateQueuedLock();
  131. if (Controller->Lock == NULL) {
  132. Status = STATUS_INSUFFICIENT_RESOURCES;
  133. goto HostRegisterControllerEnd;
  134. }
  135. Controller->AddressLock = KeCreateQueuedLock();
  136. if (Controller->AddressLock == NULL) {
  137. Status = STATUS_INSUFFICIENT_RESOURCES;
  138. goto HostRegisterControllerEnd;
  139. }
  140. //
  141. // Initialize the completed transfers queue. It uses the USB core's work
  142. // queue.
  143. //
  144. CompletionQueue = &(Controller->TransferCompletionQueue);
  145. Status = UsbpInitializeTransferCompletionQueue(CompletionQueue, FALSE);
  146. if (!KSUCCESS(Status)) {
  147. goto HostRegisterControllerEnd;
  148. }
  149. //
  150. // Allocate a work item for handling root hub port change notifications.
  151. //
  152. Controller->PortStatusWorkItem = KeCreateWorkItem(
  153. UsbCoreWorkQueue,
  154. WorkPriorityNormal,
  155. UsbpPortStatusChangeWorker,
  156. Controller,
  157. USB_CORE_ALLOCATION_TAG);
  158. if (Controller->PortStatusWorkItem == NULL) {
  159. Status = STATUS_INSUFFICIENT_RESOURCES;
  160. goto HostRegisterControllerEnd;
  161. }
  162. ASSERT(Controller->PortStatusWorkItemQueued == FALSE);
  163. //
  164. // If the debugger handoff data refers to this controller, set it in the
  165. // host controller.
  166. //
  167. if ((UsbDebugHandoffData != NULL) &&
  168. (ControllerInterface->DebugPortSubType ==
  169. UsbDebugHandoffData->PortSubType) &&
  170. (ControllerInterface->Identifier == UsbDebugHandoffData->Identifier)) {
  171. if ((UsbDebugFlags & USB_DEBUG_DEBUGGER_HANDOFF) != 0) {
  172. RtlDebugPrint("USB: Handoff data matches host 0x%x\n", Controller);
  173. }
  174. Controller->HandoffData = UsbDebugHandoffData;
  175. //
  176. // Reserve the debugger device and hub address if they're valid.
  177. //
  178. Address = Controller->HandoffData->U.Usb.DeviceAddress;
  179. if (Address != 0) {
  180. Status = UsbpReserveDeviceAddress(Controller, NULL, Address);
  181. if (!KSUCCESS(Status)) {
  182. goto HostRegisterControllerEnd;
  183. }
  184. }
  185. Address = Controller->HandoffData->U.Usb.HubAddress;
  186. if (Address != 0) {
  187. Status = UsbpReserveDeviceAddress(Controller, NULL, Address);
  188. if (!KSUCCESS(Status)) {
  189. goto HostRegisterControllerEnd;
  190. }
  191. }
  192. }
  193. //
  194. // Add the controller to the master list and return successfully.
  195. //
  196. ASSERT(KeGetRunLevel() == RunLevelLow);
  197. KeAcquireQueuedLock(UsbHostControllerListLock);
  198. INSERT_BEFORE(&(Controller->ListEntry), &UsbHostControllerList);
  199. KeReleaseQueuedLock(UsbHostControllerListLock);
  200. Status = STATUS_SUCCESS;
  201. HostRegisterControllerEnd:
  202. if (!KSUCCESS(Status)) {
  203. if (Controller != NULL) {
  204. UsbHostDestroyControllerState((HANDLE)Controller);
  205. Controller = NULL;
  206. }
  207. *ControllerHandle = INVALID_HANDLE;
  208. } else {
  209. *ControllerHandle = (HANDLE)Controller;
  210. }
  211. return Status;
  212. }
  213. USB_API
  214. VOID
  215. UsbHostDestroyControllerState (
  216. HANDLE ControllerHandle
  217. )
  218. /*++
  219. Routine Description:
  220. This routine destroys the state of a USB host controller that was created
  221. during registration.
  222. Arguments:
  223. ControllerHandle - Supplies a handle to a controller instance.
  224. Return Value:
  225. None.
  226. --*/
  227. {
  228. PUSB_HOST_CONTROLLER Controller;
  229. ASSERT(ControllerHandle != INVALID_HANDLE);
  230. Controller = (PUSB_HOST_CONTROLLER)ControllerHandle;
  231. if (Controller->PortStatusWorkItem != NULL) {
  232. KeDestroyWorkItem(Controller->PortStatusWorkItem);
  233. }
  234. UsbpDestroyTransferCompletionQueue(&(Controller->TransferCompletionQueue));
  235. if (Controller->AddressLock != NULL) {
  236. KeDestroyQueuedLock(Controller->AddressLock);
  237. }
  238. if (Controller->Lock != NULL) {
  239. KeDestroyQueuedLock(Controller->Lock);
  240. }
  241. MmFreeNonPagedPool(Controller);
  242. return;
  243. }
  244. USB_API
  245. VOID
  246. UsbHostProcessCompletedTransfer (
  247. PUSB_TRANSFER_INTERNAL Transfer
  248. )
  249. /*++
  250. Routine Description:
  251. This routine is called by the USB host controller when the host controller
  252. is done with a transfer. This routine must be called if the transfer is
  253. completed successfully, failed, or was cancelled.
  254. This routine must be called while the host controller holds its controller
  255. lock. This is expected to be done at dispatch level.
  256. Arguments:
  257. Transfer - Supplies a pointer to the transfer that has completed.
  258. Return Value:
  259. None.
  260. --*/
  261. {
  262. ASSERT(KeGetRunLevel() == RunLevelDispatch);
  263. ASSERT(Transfer->Public.LengthTransferred <= Transfer->Public.Length);
  264. if (((UsbDebugFlags & USB_DEBUG_TRANSFER_COMPLETION) != 0) ||
  265. ((!KSUCCESS(Transfer->Public.Status)) &&
  266. ((UsbDebugFlags & USB_DEBUG_ERRORS) != 0))) {
  267. if ((UsbDebugDeviceAddress == 0) ||
  268. (UsbDebugDeviceAddress == Transfer->DeviceAddress)) {
  269. ASSERT(Transfer->Public.Error < UsbErrorCount);
  270. RtlDebugPrint(
  271. "USB: Transfer (0x%08x) %s dev %d EP%x status %d (%s), "
  272. "len 0x%x of 0x%x\n",
  273. Transfer,
  274. UsbTransferDirectionStrings[Transfer->Public.Direction],
  275. Transfer->DeviceAddress,
  276. Transfer->EndpointNumber,
  277. Transfer->Public.Status,
  278. UsbErrorStrings[Transfer->Public.Error],
  279. Transfer->Public.LengthTransferred,
  280. Transfer->Public.Length);
  281. }
  282. }
  283. //
  284. // Forward this on for the transfer code to handle.
  285. //
  286. UsbpProcessCompletedTransfer(Transfer);
  287. return;
  288. }
  289. USB_API
  290. VOID
  291. UsbHostNotifyPortChange (
  292. HANDLE ControllerHandle
  293. )
  294. /*++
  295. Routine Description:
  296. This routine notifies the USB core that the USB host controller detected a
  297. port change.
  298. Arguments:
  299. ControllerHandle - Supplies a handle to the USB core instance that needs to
  300. be notified that a host port changed status.
  301. Return Value:
  302. None.
  303. --*/
  304. {
  305. PUSB_HOST_CONTROLLER Controller;
  306. BOOL OldValue;
  307. KSTATUS Status;
  308. ASSERT(KeGetRunLevel() == RunLevelDispatch);
  309. ASSERT(ControllerHandle != INVALID_HANDLE);
  310. //
  311. // Do nothing if the root hub is not yet initialized.
  312. //
  313. Controller = (PUSB_HOST_CONTROLLER)ControllerHandle;
  314. if (Controller->RootHub == NULL) {
  315. goto HostNotifyPortChangeEnd;
  316. }
  317. //
  318. // Queue a work item to handle the actual processing since this is running
  319. // at dispatch. But be sure not to queue the work item if it is already
  320. // on the queue.
  321. //
  322. OldValue = RtlAtomicCompareExchange32(
  323. &(Controller->PortStatusWorkItemQueued),
  324. TRUE,
  325. FALSE);
  326. if (OldValue != FALSE) {
  327. goto HostNotifyPortChangeEnd;
  328. }
  329. Status = KeQueueWorkItem(Controller->PortStatusWorkItem);
  330. ASSERT(KSUCCESS(Status));
  331. HostNotifyPortChangeEnd:
  332. return;
  333. }
  334. KSTATUS
  335. UsbpCreateEndpoint (
  336. PUSB_DEVICE Device,
  337. UCHAR Number,
  338. USB_TRANSFER_DIRECTION Direction,
  339. USB_TRANSFER_TYPE Type,
  340. ULONG MaxPacketSize,
  341. ULONG PollRate,
  342. PUSB_ENDPOINT *CreatedEndpoint
  343. )
  344. /*++
  345. Routine Description:
  346. This routine creates the accounting structures associated with a new USB
  347. endpoint.
  348. Arguments:
  349. Device - Supplies a pointer to the device that will own the endpoint.
  350. Number - Supplies the endpoint number of the new endpoint.
  351. Direction - Supplies the direction of the endpoint.
  352. Type - Supplies the type of the endpoint.
  353. MaxPacketSize - Supplies the maximum packet size for the endpoint, in bytes.
  354. PollRate - Supplies the polling rate of the endpoint.
  355. CreatedEndpoint - Supplies a pointer where the newly minted endpoint will
  356. be returned.
  357. Return Value:
  358. Status code.
  359. --*/
  360. {
  361. PVOID Context;
  362. PUSB_HOST_CREATE_ENDPOINT CreateEndpoint;
  363. PUSB_ENDPOINT Endpoint;
  364. USB_HOST_ENDPOINT_CREATION_REQUEST Request;
  365. KSTATUS Status;
  366. //
  367. // Convert the supplied poll rate into (micro)frames. For isochronous high
  368. // and full speed endpoints and high speed interrupt endpoints, the
  369. // supplied poll rate value is (x), between 1 and 16, where the
  370. // (micro)frame period is calculated by the forumla 2^(x-1).
  371. //
  372. // For all other combinations, the poll rate is a value between 1 and 255.
  373. // For full and low-speed interrupts this indicates the frame rate. For
  374. // high-speed control and bulk transfers, this indicates the maximum NAK
  375. // rate.
  376. //
  377. if ((PollRate != 0) &&
  378. (((Type == UsbTransferTypeInterrupt) &&
  379. (Device->Speed == UsbDeviceSpeedHigh)) ||
  380. ((Type == UsbTransferTypeIsochronous) &&
  381. ((Device->Speed == UsbDeviceSpeedFull) ||
  382. (Device->Speed == UsbDeviceSpeedHigh))))) {
  383. PollRate = 1 << (PollRate - 1);
  384. }
  385. //
  386. // Allocate and initialize the endpoint structures.
  387. //
  388. Endpoint = MmAllocateNonPagedPool(sizeof(USB_ENDPOINT),
  389. USB_CORE_ALLOCATION_TAG);
  390. if (Endpoint == NULL) {
  391. Status = STATUS_INSUFFICIENT_RESOURCES;
  392. goto CreateEndpointEnd;
  393. }
  394. RtlZeroMemory(Endpoint, sizeof(USB_ENDPOINT));
  395. Endpoint->Type = Type;
  396. Endpoint->Direction = Direction;
  397. Endpoint->MaxPacketSize = MaxPacketSize;
  398. Endpoint->PollRate = PollRate;
  399. Endpoint->Number = Number;
  400. Endpoint->ReferenceCount = 1;
  401. //
  402. // Fill out the endpoint creation request.
  403. //
  404. RtlZeroMemory(&Request, sizeof(USB_HOST_ENDPOINT_CREATION_REQUEST));
  405. Request.Version = USB_HOST_ENDPOINT_CREATION_REQUEST_VERSION;
  406. Request.Type = Type;
  407. Request.Direction = Direction;
  408. Request.Speed = Device->Speed;
  409. Request.MaxPacketSize = Endpoint->MaxPacketSize;
  410. Request.PollRate = Endpoint->PollRate;
  411. Request.EndpointNumber = Endpoint->Number;
  412. Request.HubPortNumber = Device->PortNumber;
  413. if (Device->Parent != NULL) {
  414. Request.HubAddress = Device->Parent->BusAddress;
  415. }
  416. //
  417. // Call the host controller to create any needed endpoint structures on its
  418. // end, and save the context pointer it returns.
  419. //
  420. CreateEndpoint = Device->Controller->Device.CreateEndpoint;
  421. Context = Device->Controller->Device.HostControllerContext;
  422. Status = CreateEndpoint(Context,
  423. &Request,
  424. &(Endpoint->HostControllerContext));
  425. if (!KSUCCESS(Status)) {
  426. goto CreateEndpointEnd;
  427. }
  428. CreateEndpointEnd:
  429. if (!KSUCCESS(Status)) {
  430. if (Endpoint != NULL) {
  431. MmFreeNonPagedPool(Endpoint);
  432. Endpoint = NULL;
  433. }
  434. }
  435. *CreatedEndpoint = Endpoint;
  436. return Status;
  437. }
  438. VOID
  439. UsbpResetEndpoint (
  440. PUSB_DEVICE Device,
  441. PUSB_ENDPOINT Endpoint
  442. )
  443. /*++
  444. Routine Description:
  445. This routine resets a USB endpoint.
  446. Arguments:
  447. Device - Supplies a pointer to the device to which the endpoint belongs.
  448. Endpoint - Supplies a pointer to the USB endpoint.
  449. Return Value:
  450. None.
  451. --*/
  452. {
  453. PVOID Context;
  454. PUSB_HOST_RESET_ENDPOINT ResetEndpoint;
  455. ResetEndpoint = Device->Controller->Device.ResetEndpoint;
  456. Context = Device->Controller->Device.HostControllerContext;
  457. ResetEndpoint(Context,
  458. Endpoint->HostControllerContext,
  459. Endpoint->MaxPacketSize);
  460. return;
  461. }
  462. KSTATUS
  463. UsbpFlushEndpoint (
  464. PUSB_DEVICE Device,
  465. PUSB_ENDPOINT Endpoint,
  466. PULONG TransferCount
  467. )
  468. /*++
  469. Routine Description:
  470. This routine flushes the given endpoint for the given USB device. This
  471. includes busily waiting for all active transfers to complete. This is only
  472. meant to be used at high run level when preparing to write a crash dump
  473. file using USB Mass Storage.
  474. Arguments:
  475. Device - Supplies a pointer to the device to which the endpoint belongs.
  476. Endpoint - Supplies a pointer to the USB endpoint.
  477. TransferCount - Supplies a pointer that receives the total number of
  478. transfers that were flushed.
  479. Return Value:
  480. Status code.
  481. --*/
  482. {
  483. PVOID Context;
  484. PUSB_HOST_FLUSH_ENDPOINT FlushEndpoint;
  485. KSTATUS Status;
  486. FlushEndpoint = Device->Controller->Device.FlushEndpoint;
  487. if (FlushEndpoint == NULL) {
  488. return STATUS_NOT_SUPPORTED;
  489. }
  490. Context = Device->Controller->Device.HostControllerContext;
  491. Status = FlushEndpoint(Context,
  492. Endpoint->HostControllerContext,
  493. TransferCount);
  494. return Status;
  495. }
  496. VOID
  497. UsbpEndpointAddReference (
  498. PUSB_ENDPOINT Endpoint
  499. )
  500. /*++
  501. Routine Description:
  502. This routine increments the reference count on the given endpoint.
  503. Arguments:
  504. Endpoint - Supplies a pointer to the endpoint whose reference count should
  505. be incremented.
  506. Return Value:
  507. None.
  508. --*/
  509. {
  510. ULONG OldReferenceCount;
  511. OldReferenceCount = RtlAtomicAdd32(&(Endpoint->ReferenceCount), 1);
  512. ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x1000));
  513. return;
  514. }
  515. VOID
  516. UsbpEndpointReleaseReference (
  517. PUSB_DEVICE Device,
  518. PUSB_ENDPOINT Endpoint
  519. )
  520. /*++
  521. Routine Description:
  522. This routine decrements the reference count on the given endpoint, and
  523. destroys it if it hits zero.
  524. Arguments:
  525. Device - Supplies a pointer to the device that owns the endpoint.
  526. Endpoint - Supplies a pointer to the endpoint whose reference count should
  527. be decremented.
  528. Return Value:
  529. None.
  530. --*/
  531. {
  532. ULONG OldReferenceCount;
  533. OldReferenceCount = RtlAtomicAdd32(&(Endpoint->ReferenceCount), -1);
  534. ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x1000));
  535. if (OldReferenceCount == 1) {
  536. UsbpDestroyEndpoint(Device, Endpoint);
  537. }
  538. return;
  539. }
  540. //
  541. // --------------------------------------------------------- Internal Functions
  542. //
  543. VOID
  544. UsbpDestroyEndpoint (
  545. PUSB_DEVICE Device,
  546. PUSB_ENDPOINT Endpoint
  547. )
  548. /*++
  549. Routine Description:
  550. This routine destroys a created USB endpoint.
  551. Arguments:
  552. Device - Supplies a pointer to the device that owns the endpoint.
  553. Endpoint - Supplies a pointer to the endpoint.
  554. Return Value:
  555. None.
  556. --*/
  557. {
  558. PVOID ControllerContext;
  559. PUSB_HOST_DESTROY_ENDPOINT DestroyEndpoint;
  560. if (Endpoint->ListEntry.Next != NULL) {
  561. LIST_REMOVE(&(Endpoint->ListEntry));
  562. }
  563. DestroyEndpoint = Device->Controller->Device.DestroyEndpoint;
  564. ControllerContext = Device->Controller->Device.HostControllerContext;
  565. DestroyEndpoint(ControllerContext, Endpoint->HostControllerContext);
  566. MmFreeNonPagedPool(Endpoint);
  567. return;
  568. }
  569. VOID
  570. UsbpPortStatusChangeWorker (
  571. PVOID Parameter
  572. )
  573. /*++
  574. Routine Description:
  575. This routine processes a port status change notification for the host
  576. controller.
  577. Arguments:
  578. Parameter - Supplies a pointer to the USB host controller.
  579. Return Value:
  580. None.
  581. --*/
  582. {
  583. PUSB_HOST_CONTROLLER Controller;
  584. BOOL OldValue;
  585. Controller = (PUSB_HOST_CONTROLLER)Parameter;
  586. //
  587. // Only the hub module can accurately handle this.
  588. //
  589. ASSERT(Controller->RootHub != NULL);
  590. UsbpNotifyRootHubStatusChange(Controller->RootHub);
  591. //
  592. // The above call collected the port status and cleared the hardware change
  593. // bits. Now allow another item to queue. This is done after the hub
  594. // notification to prevent the host controller from queuing a second work
  595. // item based on the same change information.
  596. //
  597. ASSERT(Controller->PortStatusWorkItemQueued != FALSE);
  598. OldValue = RtlAtomicCompareExchange32(
  599. &(Controller->PortStatusWorkItemQueued),
  600. FALSE,
  601. TRUE);
  602. ASSERT(OldValue != FALSE);
  603. return;
  604. }