spb.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. spb.c
  5. Abstract:
  6. This module implements support for the Simple Peripheral Bus support
  7. library driver.
  8. Author:
  9. Evan Green 14-Aug-2015
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include "spbp.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. #define SPB_CONTROLLER_INFORMATION_MAX_VERSION 0x1000
  22. //
  23. // ------------------------------------------------------ Data Type Definitions
  24. //
  25. //
  26. // ----------------------------------------------- Internal Function Prototypes
  27. //
  28. VOID
  29. SpbDriverUnload (
  30. PVOID Driver
  31. );
  32. KSTATUS
  33. SpbOpen (
  34. PSPB_INTERFACE Interface,
  35. PRESOURCE_SPB_DATA Configuration,
  36. PSPB_HANDLE Handle
  37. );
  38. VOID
  39. SpbClose (
  40. PSPB_INTERFACE Interface,
  41. SPB_HANDLE Handle
  42. );
  43. KSTATUS
  44. SpbSetConfiguration (
  45. SPB_HANDLE Handle,
  46. PRESOURCE_SPB_DATA Configuration
  47. );
  48. VOID
  49. SpbLockBus (
  50. SPB_HANDLE Handle
  51. );
  52. VOID
  53. SpbUnlockBus (
  54. SPB_HANDLE Handle
  55. );
  56. KSTATUS
  57. SpbSubmitTransferSet (
  58. SPB_HANDLE Handle,
  59. PSPB_TRANSFER_SET TransferSet
  60. );
  61. KSTATUS
  62. SpbExecuteTransferSet (
  63. SPB_HANDLE Handle,
  64. PSPB_TRANSFER_SET TransferSet
  65. );
  66. KSTATUS
  67. SpbpExecuteTransferSet (
  68. PSPB_CONTROLLER Controller,
  69. PSPB_TRANSFER_SET TransferSet
  70. );
  71. VOID
  72. SpbpCompleteTransferSet (
  73. PSPB_CONTROLLER Controller,
  74. PSPB_TRANSFER_SET TransferSet,
  75. KSTATUS Status
  76. );
  77. VOID
  78. SpbpSynchronousTransferCompletionCallback (
  79. PSPB_TRANSFER_SET TransferSet
  80. );
  81. //
  82. // -------------------------------------------------------------------- Globals
  83. //
  84. UUID SpbInterfaceUuid = UUID_SPB_INTERFACE;
  85. SPB_INTERFACE SpbInterfaceTemplate = {
  86. NULL,
  87. SpbOpen,
  88. SpbClose,
  89. SpbSetConfiguration,
  90. SpbLockBus,
  91. SpbUnlockBus,
  92. SpbSubmitTransferSet,
  93. SpbExecuteTransferSet
  94. };
  95. //
  96. // ------------------------------------------------------------------ Functions
  97. //
  98. KSTATUS
  99. DriverEntry (
  100. PDRIVER Driver
  101. )
  102. /*++
  103. Routine Description:
  104. This routine implements the initial entry point of the SPB core
  105. library, called when the library is first loaded.
  106. Arguments:
  107. Driver - Supplies a pointer to the driver object.
  108. Return Value:
  109. Status code.
  110. --*/
  111. {
  112. DRIVER_FUNCTION_TABLE FunctionTable;
  113. KSTATUS Status;
  114. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  115. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  116. FunctionTable.Unload = SpbDriverUnload;
  117. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  118. return Status;
  119. }
  120. SPB_API
  121. KSTATUS
  122. SpbCreateController (
  123. PSPB_CONTROLLER_INFORMATION Registration,
  124. PSPB_CONTROLLER *Controller
  125. )
  126. /*++
  127. Routine Description:
  128. This routine creates a new Simple Peripheral Bus controller.
  129. Arguments:
  130. Registration - Supplies a pointer to the host registration information.
  131. Controller - Supplies a pointer where a pointer to the new controller will
  132. be returned on success.
  133. Return Value:
  134. Status code.
  135. --*/
  136. {
  137. UINTN AllocationSize;
  138. PSPB_CONTROLLER NewController;
  139. KSTATUS Status;
  140. if ((Registration->Version < SPB_CONTROLLER_INFORMATION_VERSION) ||
  141. (Registration->Version > SPB_CONTROLLER_INFORMATION_MAX_VERSION) ||
  142. (Registration->BusType <= ResourceSpbBusInvalid) ||
  143. (Registration->BusType >= ResourceSpbBusTypeCount) ||
  144. (Registration->Device == NULL)) {
  145. return STATUS_INVALID_PARAMETER;
  146. }
  147. AllocationSize = sizeof(SPB_CONTROLLER);
  148. NewController = MmAllocatePagedPool(AllocationSize, SPB_ALLOCATION_TAG);
  149. if (NewController == NULL) {
  150. Status = STATUS_INSUFFICIENT_RESOURCES;
  151. goto CreateControllerEnd;
  152. }
  153. RtlZeroMemory(NewController, AllocationSize);
  154. RtlCopyMemory(&(NewController->Host),
  155. Registration,
  156. sizeof(SPB_CONTROLLER_INFORMATION));
  157. RtlCopyMemory(&(NewController->Interface),
  158. &SpbInterfaceTemplate,
  159. sizeof(SPB_INTERFACE));
  160. NewController->Magic = SPB_CONTROLLER_MAGIC;
  161. INITIALIZE_LIST_HEAD(&(NewController->HandleList));
  162. INITIALIZE_LIST_HEAD(&(NewController->TransferQueue));
  163. NewController->Lock = KeCreateQueuedLock();
  164. if (NewController->Lock == NULL) {
  165. Status = STATUS_INSUFFICIENT_RESOURCES;
  166. goto CreateControllerEnd;
  167. }
  168. NewController->BusLock = KeCreateQueuedLock();
  169. if (NewController->BusLock == NULL) {
  170. Status = STATUS_INSUFFICIENT_RESOURCES;
  171. goto CreateControllerEnd;
  172. }
  173. Status = STATUS_SUCCESS;
  174. CreateControllerEnd:
  175. if (!KSUCCESS(Status)) {
  176. if (NewController != NULL) {
  177. if (NewController->Lock != NULL) {
  178. KeDestroyQueuedLock(NewController->Lock);
  179. }
  180. if (NewController->BusLock != NULL) {
  181. KeDestroyQueuedLock(NewController->BusLock);
  182. }
  183. MmFreePagedPool(NewController);
  184. NewController = NULL;
  185. }
  186. }
  187. *Controller = NewController;
  188. return Status;
  189. }
  190. SPB_API
  191. VOID
  192. SpbDestroyController (
  193. PSPB_CONTROLLER Controller
  194. )
  195. /*++
  196. Routine Description:
  197. This routine destroys a Simple Peripheral Bus controller.
  198. Arguments:
  199. Controller - Supplies a pointer to the controller to tear down.
  200. Return Value:
  201. None.
  202. --*/
  203. {
  204. ASSERT(LIST_EMPTY(&(Controller->HandleList)));
  205. if (Controller->Lock != NULL) {
  206. KeDestroyQueuedLock(Controller->Lock);
  207. }
  208. if (Controller->BusLock != NULL) {
  209. KeDestroyQueuedLock(Controller->BusLock);
  210. }
  211. //
  212. // Ruin the magic (but in a way that's still identifiable to a human).
  213. //
  214. Controller->Magic += 1;
  215. MmFreePagedPool(Controller);
  216. return;
  217. }
  218. SPB_API
  219. KSTATUS
  220. SpbStartController (
  221. PSPB_CONTROLLER Controller
  222. )
  223. /*++
  224. Routine Description:
  225. This routine starts a Simple Peripheral Bus controller.
  226. Arguments:
  227. Controller - Supplies a pointer to the controller.
  228. Return Value:
  229. Status code.
  230. --*/
  231. {
  232. PSPB_CONTROLLER_INFORMATION Host;
  233. KSTATUS Status;
  234. ASSERT(Controller->Interface.Context == NULL);
  235. ASSERT(KeGetRunLevel() == RunLevelLow);
  236. KeAcquireQueuedLock(Controller->Lock);
  237. Host = &(Controller->Host);
  238. Controller->Interface.Context = &(Controller->Interface);
  239. Status = IoCreateInterface(&SpbInterfaceUuid,
  240. Host->Device,
  241. &(Controller->Interface),
  242. sizeof(SPB_INTERFACE));
  243. if (!KSUCCESS(Status)) {
  244. Controller->Interface.Context = NULL;
  245. goto StartControllerEnd;
  246. }
  247. //
  248. // Create a resource arbiter for these pins so that other devices can
  249. // allocate them as part of their official resource requirements.
  250. //
  251. if (Controller->ArbiterCreated == FALSE) {
  252. Status = IoCreateResourceArbiter(Host->Device, ResourceTypeSimpleBus);
  253. if ((!KSUCCESS(Status)) && (Status != STATUS_ALREADY_INITIALIZED)) {
  254. goto StartControllerEnd;
  255. }
  256. Status = IoAddFreeSpaceToArbiter(Host->Device,
  257. ResourceTypeSimpleBus,
  258. 0,
  259. -1ULL,
  260. 0,
  261. NULL,
  262. 0);
  263. if (!KSUCCESS(Status)) {
  264. goto StartControllerEnd;
  265. }
  266. Controller->ArbiterCreated = TRUE;
  267. }
  268. StartControllerEnd:
  269. KeReleaseQueuedLock(Controller->Lock);
  270. return Status;
  271. }
  272. SPB_API
  273. VOID
  274. SpbStopController (
  275. PSPB_CONTROLLER Controller
  276. )
  277. /*++
  278. Routine Description:
  279. This routine stops a Simple Peripheral Bus controller.
  280. Arguments:
  281. Controller - Supplies a pointer to the controller.
  282. Return Value:
  283. None.
  284. --*/
  285. {
  286. KSTATUS Status;
  287. ASSERT(Controller->Interface.Context == &(Controller->Interface));
  288. ASSERT(KeGetRunLevel() == RunLevelLow);
  289. KeAcquireQueuedLock(Controller->Lock);
  290. Status = IoDestroyInterface(&SpbInterfaceUuid,
  291. Controller->Host.Device,
  292. &(Controller->Interface));
  293. ASSERT(KSUCCESS(Status));
  294. Controller->Interface.Context = NULL;
  295. ASSERT(LIST_EMPTY(&(Controller->HandleList)));
  296. KeReleaseQueuedLock(Controller->Lock);
  297. return;
  298. }
  299. SPB_API
  300. PSPB_TRANSFER
  301. SpbTransferCompletion (
  302. PSPB_CONTROLLER Controller,
  303. PSPB_TRANSFER Transfer,
  304. KSTATUS Status
  305. )
  306. /*++
  307. Routine Description:
  308. This routine is called by an SPB host controller when a transfer has
  309. completed.
  310. Arguments:
  311. Controller - Supplies a pointer to the controller.
  312. Transfer - Supplies a pointer to the transfer that completed.
  313. Status - Supplies the status code the transfer completed with.
  314. Return Value:
  315. Returns a new transfer to begin executing if there are additional transfers
  316. in this set and the previous transfer completed successfully.
  317. NULL if no new transfers should be started at this time.
  318. --*/
  319. {
  320. PSPB_TRANSFER NextTransfer;
  321. ASSERT(Controller->CurrentSet != NULL);
  322. NextTransfer = NULL;
  323. Controller->CurrentSet->EntriesProcessed += 1;
  324. //
  325. // On failure or if this is the last transfer, complete the whole set.
  326. //
  327. if ((!KSUCCESS(Status)) ||
  328. (Transfer->ListEntry.Next == &(Controller->CurrentSet->TransferList))) {
  329. SpbpCompleteTransferSet(Controller, Controller->CurrentSet, Status);
  330. } else {
  331. NextTransfer = LIST_VALUE(Transfer->ListEntry.Next,
  332. SPB_TRANSFER,
  333. ListEntry);
  334. NextTransfer->Flags &= ~SPB_TRANSFER_FLAG_AUTO_MASK;
  335. if (NextTransfer->ListEntry.Next ==
  336. &(Controller->CurrentSet->TransferList)) {
  337. NextTransfer->Flags |= SPB_TRANSFER_FLAG_LAST;
  338. }
  339. }
  340. return NextTransfer;
  341. }
  342. //
  343. // --------------------------------------------------------- Internal Functions
  344. //
  345. VOID
  346. SpbDriverUnload (
  347. PVOID Driver
  348. )
  349. /*++
  350. Routine Description:
  351. This routine is called before a driver is about to be unloaded from memory.
  352. The driver should take this opportunity to free any resources it may have
  353. set up in the driver entry routine.
  354. Arguments:
  355. Driver - Supplies a pointer to the driver being torn down.
  356. Return Value:
  357. None.
  358. --*/
  359. {
  360. return;
  361. }
  362. KSTATUS
  363. SpbOpen (
  364. PSPB_INTERFACE Interface,
  365. PRESOURCE_SPB_DATA Configuration,
  366. PSPB_HANDLE Handle
  367. )
  368. /*++
  369. Routine Description:
  370. This routine opens a new connection to a Simple Peripheral Bus.
  371. Arguments:
  372. Interface - Supplies a pointer to the interface instance, used to identify
  373. which specific bus is being opened.
  374. Configuration - Supplies a pointer to the configuration data that specifies
  375. bus specific configuration parameters.
  376. Handle - Supplies a pointer where a handle will be returned on success
  377. representing the connection to the device.
  378. Return Value:
  379. Status code.
  380. --*/
  381. {
  382. PSPB_CONTROLLER Controller;
  383. PSPB_HANDLE_DATA HandleData;
  384. KSTATUS Status;
  385. Controller = PARENT_STRUCTURE(Interface->Context,
  386. SPB_CONTROLLER,
  387. Interface);
  388. ASSERT(Controller->Magic == SPB_CONTROLLER_MAGIC);
  389. HandleData = MmAllocatePagedPool(sizeof(SPB_HANDLE_DATA),
  390. SPB_ALLOCATION_TAG);
  391. if (HandleData == NULL) {
  392. Status = STATUS_INSUFFICIENT_RESOURCES;
  393. goto OpenEnd;
  394. }
  395. RtlZeroMemory(HandleData, sizeof(SPB_HANDLE_DATA));
  396. HandleData->Magic = SPB_HANDLE_MAGIC;
  397. HandleData->Controller = Controller;
  398. Status = SpbSetConfiguration(HandleData, Configuration);
  399. if (!KSUCCESS(Status)) {
  400. goto OpenEnd;
  401. }
  402. KeAcquireQueuedLock(Controller->Lock);
  403. INSERT_BEFORE(&(HandleData->ListEntry), &(Controller->HandleList));
  404. KeReleaseQueuedLock(Controller->Lock);
  405. OpenEnd:
  406. if (!KSUCCESS(Status)) {
  407. if (HandleData != NULL) {
  408. ASSERT(HandleData->Configuration == NULL);
  409. MmFreePagedPool(HandleData);
  410. HandleData = NULL;
  411. }
  412. }
  413. *Handle = HandleData;
  414. return Status;
  415. }
  416. VOID
  417. SpbClose (
  418. PSPB_INTERFACE Interface,
  419. SPB_HANDLE Handle
  420. )
  421. /*++
  422. Routine Description:
  423. This routine closes a previously opened to a Simple Peripheral Bus.
  424. Arguments:
  425. Interface - Supplies a pointer to the interface instance, used to identify
  426. which specific bus is being operated on.
  427. Handle - Supplies the open handle to close.
  428. Return Value:
  429. None.
  430. --*/
  431. {
  432. PSPB_CONTROLLER Controller;
  433. PSPB_HANDLE_DATA HandleData;
  434. HandleData = Handle;
  435. Controller = HandleData->Controller;
  436. ASSERT(HandleData->Magic == SPB_HANDLE_MAGIC);
  437. ASSERT(HandleData->BusReferenceCount == 0);
  438. ASSERT(Controller ==
  439. PARENT_STRUCTURE(Interface, SPB_CONTROLLER, Interface));
  440. if (HandleData->Event != NULL) {
  441. KeDestroyEvent(HandleData->Event);
  442. }
  443. KeAcquireQueuedLock(Controller->Lock);
  444. LIST_REMOVE(&(HandleData->ListEntry));
  445. if (Controller->CurrentConfiguration == HandleData->Configuration) {
  446. Controller->CurrentConfiguration = NULL;
  447. }
  448. KeReleaseQueuedLock(Controller->Lock);
  449. HandleData->ListEntry.Next = NULL;
  450. if (HandleData->Configuration != NULL) {
  451. MmFreePagedPool(HandleData->Configuration);
  452. }
  453. HandleData->Magic += 1;
  454. MmFreePagedPool(HandleData);
  455. return;
  456. }
  457. KSTATUS
  458. SpbSetConfiguration (
  459. SPB_HANDLE Handle,
  460. PRESOURCE_SPB_DATA Configuration
  461. )
  462. /*++
  463. Routine Description:
  464. This routine writes a new set of bus parameters to the bus.
  465. Arguments:
  466. Handle - Supplies the open handle to change configuration of.
  467. Configuration - Supplies the new configuration to set.
  468. Return Value:
  469. Status code.
  470. --*/
  471. {
  472. PSPB_CONTROLLER Controller;
  473. PSPB_HANDLE_DATA HandleData;
  474. PVOID NewData;
  475. PVOID OldData;
  476. HandleData = Handle;
  477. Controller = HandleData->Controller;
  478. ASSERT(HandleData->Magic == SPB_HANDLE_MAGIC);
  479. //
  480. // Perform some checks against accidental misconfiguration. This isn't
  481. // nearly a bulletproof set of checks.
  482. //
  483. if ((Configuration == NULL) ||
  484. (Configuration->Size < sizeof(RESOURCE_SPB_DATA)) ||
  485. (Configuration->VendorDataSize >
  486. Configuration->Size - sizeof(RESOURCE_SPB_DATA)) ||
  487. (Configuration->BusType != HandleData->Controller->Host.BusType)) {
  488. return STATUS_INVALID_PARAMETER;
  489. }
  490. NewData = MmAllocatePagedPool(Configuration->Size, SPB_ALLOCATION_TAG);
  491. if (NewData == NULL) {
  492. return STATUS_INSUFFICIENT_RESOURCES;
  493. }
  494. RtlCopyMemory(NewData, Configuration, Configuration->Size);
  495. KeAcquireQueuedLock(Controller->Lock);
  496. OldData = HandleData->Configuration;
  497. if (OldData != NULL) {
  498. if (Controller->CurrentConfiguration == OldData) {
  499. Controller->CurrentConfiguration = NULL;
  500. }
  501. }
  502. HandleData->Configuration = NewData;
  503. KeReleaseQueuedLock(Controller->Lock);
  504. if (OldData != NULL) {
  505. MmFreePagedPool(OldData);
  506. }
  507. return STATUS_SUCCESS;
  508. }
  509. VOID
  510. SpbLockBus (
  511. SPB_HANDLE Handle
  512. )
  513. /*++
  514. Routine Description:
  515. This routine locks the bus so that this handle may perform a sequence of
  516. accesses without being interrupted.
  517. Arguments:
  518. Handle - Supplies the open handle to the bus to lock.
  519. Return Value:
  520. None.
  521. --*/
  522. {
  523. PSPB_CONTROLLER Controller;
  524. PSPB_HANDLE_DATA HandleData;
  525. PSPB_CONTROLLER_INFORMATION Host;
  526. ULONG OldValue;
  527. HandleData = Handle;
  528. ASSERT(HandleData->Magic == SPB_HANDLE_MAGIC);
  529. OldValue = RtlAtomicAdd32(&(HandleData->BusReferenceCount), 1);
  530. ASSERT(OldValue < 0x1000);
  531. if (OldValue == 0) {
  532. KeAcquireQueuedLock(HandleData->Controller->BusLock);
  533. Controller = HandleData->Controller;
  534. Host = &(Controller->Host);
  535. if (Host->FunctionTable.LockBus != NULL) {
  536. Host->FunctionTable.LockBus(Host->Context,
  537. HandleData->Configuration);
  538. }
  539. }
  540. return;
  541. }
  542. VOID
  543. SpbUnlockBus (
  544. SPB_HANDLE Handle
  545. )
  546. /*++
  547. Routine Description:
  548. This routine unlocks a bus that was previously locked with the lock
  549. function.
  550. Arguments:
  551. Handle - Supplies the open handle to the bus to unlock. The caller must
  552. have previously locked the bus.
  553. Return Value:
  554. None.
  555. --*/
  556. {
  557. PSPB_CONTROLLER Controller;
  558. PSPB_HANDLE_DATA HandleData;
  559. PSPB_CONTROLLER_INFORMATION Host;
  560. PSPB_HANDLE_DATA NextHandleData;
  561. PSPB_TRANSFER_SET NextSet;
  562. ULONG OldValue;
  563. HandleData = Handle;
  564. Controller = HandleData->Controller;
  565. ASSERT(HandleData->Magic == SPB_HANDLE_MAGIC);
  566. OldValue = RtlAtomicAdd32(&(HandleData->BusReferenceCount), -1);
  567. ASSERT((OldValue != 0) && (OldValue < 0x1000));
  568. if (OldValue == 1) {
  569. Host = &(Controller->Host);
  570. //
  571. // Let the host know the bus is being unlocked.
  572. //
  573. if (Host->FunctionTable.UnlockBus != NULL) {
  574. Host->FunctionTable.UnlockBus(Host->Context);
  575. }
  576. //
  577. // If there are more items on the transfer queue and someone else
  578. // hasn't already started executing them, fire it off now. Do an
  579. // initial unsynchronized check to avoid acquiring the lock if possible.
  580. //
  581. NextSet = NULL;
  582. if ((Controller->CurrentSet == NULL) &&
  583. (!LIST_EMPTY(&(Controller->TransferQueue)))) {
  584. KeAcquireQueuedLock(Controller->Lock);
  585. if ((Controller->CurrentSet == NULL) &&
  586. (!LIST_EMPTY(&(Controller->TransferQueue)))) {
  587. NextSet = LIST_VALUE(Controller->TransferQueue.Next,
  588. SPB_TRANSFER_SET,
  589. ListEntry);
  590. Controller->CurrentSet = NextSet;
  591. //
  592. // Leave the actual lock acquired the whole time, and just
  593. // transfer the reference to the next handle.
  594. //
  595. HandleData = NextSet->Handle;
  596. RtlAtomicAdd32(&(HandleData->BusReferenceCount), 1);
  597. //
  598. // The host was told the bus was unlocked, so it needs to be
  599. // told its actually still locked.
  600. //
  601. if (Host->FunctionTable.LockBus != NULL) {
  602. NextHandleData = NextSet->Handle;
  603. Host->FunctionTable.LockBus(Host->Context,
  604. NextHandleData->Configuration);
  605. }
  606. KeReleaseQueuedLock(Controller->Lock);
  607. SpbpExecuteTransferSet(Controller, NextSet);
  608. } else {
  609. KeReleaseQueuedLock(Controller->Lock);
  610. }
  611. }
  612. //
  613. // If the bus lock wasn't transferred to another handle, then really
  614. // release the bus lock.
  615. //
  616. if (NextSet == NULL) {
  617. KeReleaseQueuedLock(Controller->BusLock);
  618. }
  619. }
  620. return;
  621. }
  622. KSTATUS
  623. SpbSubmitTransferSet (
  624. SPB_HANDLE Handle,
  625. PSPB_TRANSFER_SET TransferSet
  626. )
  627. /*++
  628. Routine Description:
  629. This routine submits a set of transfers to the bus for execution. This
  630. routine will ensure that other devices do not perform transfers while any
  631. transfer in this set is in progress. The submission is asynchronous, this
  632. routine will return immediately, and the callback function will be called
  633. when the transfer is complete.
  634. Arguments:
  635. Handle - Supplies the open handle to the bus to unlock.
  636. TransferSet - Supplies a pointer to the transfer set to execute.
  637. Return Value:
  638. Status code. This routine will return immediately, the transfer will not
  639. have been complete. The caller should utilize the callback function to get
  640. notified when a transfer has completed.
  641. --*/
  642. {
  643. PSPB_CONTROLLER Controller;
  644. BOOL ExecuteTransfer;
  645. PSPB_HANDLE_DATA HandleData;
  646. KSTATUS Status;
  647. HandleData = Handle;
  648. if (HandleData->Configuration == NULL) {
  649. return STATUS_NOT_CONFIGURED;
  650. }
  651. ASSERT(HandleData->Magic == SPB_HANDLE_MAGIC);
  652. ASSERT(TransferSet->ListEntry.Next == NULL);
  653. Controller = HandleData->Controller;
  654. TransferSet->Handle = Handle;
  655. TransferSet->EntriesProcessed = 0;
  656. TransferSet->Status = STATUS_NOT_HANDLED;
  657. ExecuteTransfer = FALSE;
  658. KeAcquireQueuedLock(Controller->Lock);
  659. if (Controller->CurrentSet == NULL) {
  660. ExecuteTransfer = TRUE;
  661. Controller->CurrentSet = TransferSet;
  662. }
  663. INSERT_BEFORE(&(TransferSet->ListEntry), &(Controller->TransferQueue));
  664. KeReleaseQueuedLock(Controller->Lock);
  665. //
  666. // If this was the first item on an empty list, then kick off the party.
  667. //
  668. Status = STATUS_SUCCESS;
  669. if (ExecuteTransfer != FALSE) {
  670. SpbLockBus(TransferSet->Handle);
  671. Status = SpbpExecuteTransferSet(Controller, TransferSet);
  672. }
  673. return Status;
  674. }
  675. KSTATUS
  676. SpbExecuteTransferSet (
  677. SPB_HANDLE Handle,
  678. PSPB_TRANSFER_SET TransferSet
  679. )
  680. /*++
  681. Routine Description:
  682. This routine submits a set of transfers to the bus for execution. This
  683. routine will ensure that other devices do not perform transfers while any
  684. transfer in this set is in progress. This routine is synchronous, it will
  685. not return until the transfer is complete.
  686. Arguments:
  687. Handle - Supplies the open handle to the bus to unlock.
  688. TransferSet - Supplies a pointer to the transfer set to execute.
  689. Return Value:
  690. Status code indicating completion status of the transfer. This routine will
  691. not return until the transfer is complete (or failed).
  692. --*/
  693. {
  694. PKEVENT Event;
  695. PSPB_HANDLE_DATA HandleData;
  696. KSTATUS Status;
  697. //
  698. // Create an event for the handle if there isn't one already. This is not
  699. // thread-safe, it is expected only one synchronous transfer will be
  700. // submitted at a time.
  701. //
  702. HandleData = Handle;
  703. if (HandleData->Event == NULL) {
  704. Event = KeCreateEvent(NULL);
  705. if (Event == NULL) {
  706. return STATUS_INSUFFICIENT_RESOURCES;
  707. }
  708. ASSERT(HandleData->Event == NULL);
  709. HandleData->Event = Event;
  710. }
  711. Event = HandleData->Event;
  712. ASSERT(Event != NULL);
  713. ASSERT((TransferSet->CompletionRoutine == NULL) &&
  714. (TransferSet->Context == NULL));
  715. KeSignalEvent(Event, SignalOptionUnsignal);
  716. TransferSet->CompletionRoutine = SpbpSynchronousTransferCompletionCallback;
  717. TransferSet->Context = Event;
  718. Status = SpbSubmitTransferSet(Handle, TransferSet);
  719. if (KSUCCESS(Status)) {
  720. KeWaitForEvent(Event, FALSE, WAIT_TIME_INDEFINITE);
  721. TransferSet->CompletionRoutine = NULL;
  722. TransferSet->Context = NULL;
  723. Status = TransferSet->Status;
  724. }
  725. return Status;
  726. }
  727. KSTATUS
  728. SpbpExecuteTransferSet (
  729. PSPB_CONTROLLER Controller,
  730. PSPB_TRANSFER_SET TransferSet
  731. )
  732. /*++
  733. Routine Description:
  734. This routine begins execution of a new transfer set. It is assumed that the
  735. bus lock is already held.
  736. Arguments:
  737. Controller - Supplies a pointer to the controller to execute on.
  738. TransferSet - Supplies a pointer to the transfer set to execute.
  739. Return Value:
  740. Status code. This routine will return immediately, the transfer will not
  741. have necessarily been completed. The caller should utilize the callback
  742. function to get notified when a transfer has completed.
  743. --*/
  744. {
  745. PSPB_HANDLE_DATA HandleData;
  746. KSTATUS Status;
  747. PSPB_TRANSFER Transfer;
  748. HandleData = TransferSet->Handle;
  749. ASSERT(HandleData->BusReferenceCount != 0);
  750. ASSERT(HandleData->Configuration != NULL);
  751. ASSERT(Controller->CurrentSet == TransferSet);
  752. //
  753. // Configure the bus if its configuration does not match what the handle
  754. // needs.
  755. //
  756. if (Controller->CurrentConfiguration != HandleData->Configuration) {
  757. Status = Controller->Host.FunctionTable.Configure(
  758. Controller->Host.Context,
  759. HandleData->Configuration);
  760. if (!KSUCCESS(Status)) {
  761. goto ExecuteTransferSetEnd;
  762. }
  763. Controller->CurrentConfiguration = HandleData->Configuration;
  764. }
  765. //
  766. // Execute the first transfer, or just complete the transfer if there are
  767. // none (bus configuration only).
  768. //
  769. if (LIST_EMPTY(&(TransferSet->TransferList))) {
  770. Status = STATUS_SUCCESS;
  771. SpbpCompleteTransferSet(Controller, TransferSet, Status);
  772. } else {
  773. Transfer = LIST_VALUE(TransferSet->TransferList.Next,
  774. SPB_TRANSFER,
  775. ListEntry);
  776. Transfer->Flags &= ~SPB_TRANSFER_FLAG_AUTO_MASK;
  777. Transfer->Flags |= SPB_TRANSFER_FLAG_FIRST;
  778. Status = Controller->Host.FunctionTable.SubmitTransfer(
  779. Controller->Host.Context,
  780. Transfer);
  781. if (!KSUCCESS(Status)) {
  782. goto ExecuteTransferSetEnd;
  783. }
  784. }
  785. ExecuteTransferSetEnd:
  786. if (!KSUCCESS(Status)) {
  787. SpbpCompleteTransferSet(Controller, TransferSet, Status);
  788. }
  789. return Status;
  790. }
  791. VOID
  792. SpbpCompleteTransferSet (
  793. PSPB_CONTROLLER Controller,
  794. PSPB_TRANSFER_SET TransferSet,
  795. KSTATUS Status
  796. )
  797. /*++
  798. Routine Description:
  799. This routine completes a transfer set. It is called with the bus lock held,
  800. and may release the bus lock.
  801. Arguments:
  802. Controller - Supplies a pointer to the controller that owns the transfer
  803. set.
  804. TransferSet - Supplies a pointer to the transfer set to complete.
  805. Status - Supplies the completion status code.
  806. Return Value:
  807. None.
  808. --*/
  809. {
  810. ASSERT(Controller->CurrentSet == TransferSet);
  811. Controller->CurrentSet = NULL;
  812. TransferSet->Status = Status;
  813. KeAcquireQueuedLock(Controller->Lock);
  814. LIST_REMOVE(&(TransferSet->ListEntry));
  815. TransferSet->ListEntry.Next = NULL;
  816. KeReleaseQueuedLock(Controller->Lock);
  817. //
  818. // Unlock the bus before calling the completion routine because the
  819. // transfer set can disappear as soon as the completion routine is called.
  820. //
  821. SpbUnlockBus(TransferSet->Handle);
  822. if (TransferSet->CompletionRoutine != NULL) {
  823. TransferSet->CompletionRoutine(TransferSet);
  824. }
  825. return;
  826. }
  827. VOID
  828. SpbpSynchronousTransferCompletionCallback (
  829. PSPB_TRANSFER_SET TransferSet
  830. )
  831. /*++
  832. Routine Description:
  833. This routine is called when a transfer set has completed or errored out.
  834. Arguments:
  835. TransferSet - Supplies a pointer to the transfer set that completed.
  836. Return Value:
  837. None.
  838. --*/
  839. {
  840. KeSignalEvent(TransferSet->Context, SignalOptionSignalAll);
  841. return;
  842. }