dma.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. /*++
  2. Copyright (c) 2016 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. dma.c
  5. Abstract:
  6. This module implements common infrastructure support for DMA controller
  7. drivers.
  8. Author:
  9. Evan Green 1-Feb-2016
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include "dmap.h"
  18. //
  19. // ---------------------------------------------------------------- Definitions
  20. //
  21. //
  22. // ------------------------------------------------------ Data Type Definitions
  23. //
  24. //
  25. // ----------------------------------------------- Internal Function Prototypes
  26. //
  27. VOID
  28. DmaDriverUnload (
  29. PVOID Driver
  30. );
  31. KSTATUS
  32. DmaGetInformation (
  33. PDMA_INTERFACE Interface,
  34. PDMA_INFORMATION Information
  35. );
  36. KSTATUS
  37. DmaSubmit (
  38. PDMA_INTERFACE Interface,
  39. PDMA_TRANSFER Transfer
  40. );
  41. KSTATUS
  42. DmaCancel (
  43. PDMA_INTERFACE Interface,
  44. PDMA_TRANSFER Transfer
  45. );
  46. KSTATUS
  47. DmaControlRequest (
  48. PDMA_INTERFACE Interface,
  49. PDMA_TRANSFER Transfer,
  50. PVOID Request,
  51. UINTN RequestSize
  52. );
  53. KSTATUS
  54. DmaAllocateTransfer (
  55. PDMA_INTERFACE Interface,
  56. PDMA_TRANSFER *Transfer
  57. );
  58. VOID
  59. DmaFreeTransfer (
  60. PDMA_INTERFACE Interface,
  61. PDMA_TRANSFER Transfer
  62. );
  63. RUNLEVEL
  64. DmapAcquireChannelLock (
  65. PDMA_CONTROLLER Controller,
  66. PDMA_CHANNEL Channel
  67. );
  68. VOID
  69. DmapReleaseChannelLock (
  70. PDMA_CONTROLLER Controller,
  71. PDMA_CHANNEL Channel,
  72. RUNLEVEL OldRunLevel
  73. );
  74. //
  75. // -------------------------------------------------------------------- Globals
  76. //
  77. UUID DmaInterfaceUuid = UUID_DMA_INTERFACE;
  78. DMA_INTERFACE DmaInterfaceTemplate = {
  79. NULL,
  80. DmaGetInformation,
  81. DmaSubmit,
  82. DmaCancel,
  83. DmaControlRequest,
  84. DmaAllocateTransfer,
  85. DmaFreeTransfer
  86. };
  87. //
  88. // ------------------------------------------------------------------ Functions
  89. //
  90. KSTATUS
  91. DriverEntry (
  92. PDRIVER Driver
  93. )
  94. /*++
  95. Routine Description:
  96. This routine implements the initial entry point of the DMA core
  97. library, called when the library is first loaded.
  98. Arguments:
  99. Driver - Supplies a pointer to the driver object.
  100. Return Value:
  101. Status code.
  102. --*/
  103. {
  104. DRIVER_FUNCTION_TABLE FunctionTable;
  105. KSTATUS Status;
  106. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  107. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  108. FunctionTable.Unload = DmaDriverUnload;
  109. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  110. return Status;
  111. }
  112. DMA_API
  113. KSTATUS
  114. DmaCreateController (
  115. PDMA_CONTROLLER_INFORMATION Registration,
  116. PDMA_CONTROLLER *Controller
  117. )
  118. /*++
  119. Routine Description:
  120. This routine creates a new Direct Memory Access controller.
  121. Arguments:
  122. Registration - Supplies a pointer to the host registration information.
  123. Controller - Supplies a pointer where a pointer to the new controller will
  124. be returned on success.
  125. Return Value:
  126. Status code.
  127. --*/
  128. {
  129. UINTN AllocationSize;
  130. PDMA_CHANNEL Channel;
  131. ULONG ChannelCount;
  132. ULONG ChannelIndex;
  133. PDMA_CONTROLLER NewController;
  134. KSTATUS Status;
  135. if ((Registration->Version < DMA_CONTROLLER_INFORMATION_VERSION) ||
  136. (Registration->Version > DMA_CONTROLLER_INFORMATION_MAX_VERSION) ||
  137. (Registration->Device == NULL)) {
  138. return STATUS_INVALID_PARAMETER;
  139. }
  140. ChannelCount = Registration->Information.ChannelCount;
  141. AllocationSize = sizeof(DMA_CONTROLLER) +
  142. (ChannelCount * sizeof(DMA_CHANNEL));
  143. NewController = MmAllocateNonPagedPool(AllocationSize, DMA_ALLOCATION_TAG);
  144. if (NewController == NULL) {
  145. Status = STATUS_INSUFFICIENT_RESOURCES;
  146. goto CreateControllerEnd;
  147. }
  148. RtlZeroMemory(NewController, AllocationSize);
  149. RtlCopyMemory(&(NewController->Host),
  150. Registration,
  151. sizeof(DMA_CONTROLLER_INFORMATION));
  152. RtlCopyMemory(&(NewController->Interface),
  153. &DmaInterfaceTemplate,
  154. sizeof(DMA_INTERFACE));
  155. NewController->Magic = DMA_CONTROLLER_MAGIC;
  156. NewController->ChannelCount = ChannelCount;
  157. NewController->Channels = (PDMA_CHANNEL)(NewController + 1);
  158. for (ChannelIndex = 0; ChannelIndex < ChannelCount; ChannelIndex += 1) {
  159. Channel = &(NewController->Channels[ChannelIndex]);
  160. INITIALIZE_LIST_HEAD(&(Channel->Queue));
  161. KeInitializeSpinLock(&(Channel->Lock));
  162. }
  163. Status = STATUS_SUCCESS;
  164. CreateControllerEnd:
  165. if (!KSUCCESS(Status)) {
  166. if (NewController != NULL) {
  167. MmFreeNonPagedPool(NewController);
  168. NewController = NULL;
  169. }
  170. }
  171. *Controller = NewController;
  172. return Status;
  173. }
  174. DMA_API
  175. VOID
  176. DmaDestroyController (
  177. PDMA_CONTROLLER Controller
  178. )
  179. /*++
  180. Routine Description:
  181. This routine destroys a Direct Memory Access controller.
  182. Arguments:
  183. Controller - Supplies a pointer to the controller to tear down.
  184. Return Value:
  185. None.
  186. --*/
  187. {
  188. PDMA_CHANNEL Channel;
  189. ULONG ChannelIndex;
  190. for (ChannelIndex = 0;
  191. ChannelIndex < Controller->ChannelCount;
  192. ChannelIndex += 1) {
  193. Channel = &(Controller->Channels[ChannelIndex]);
  194. ASSERT((Channel->Transfer == NULL) &&
  195. ((Channel->Queue.Next == NULL) ||
  196. (LIST_EMPTY(&(Channel->Queue)))));
  197. }
  198. //
  199. // Ruin the magic (but in a way that's still identifiable to a human).
  200. //
  201. Controller->Magic += 1;
  202. MmFreeNonPagedPool(Controller);
  203. return;
  204. }
  205. DMA_API
  206. KSTATUS
  207. DmaStartController (
  208. PDMA_CONTROLLER Controller
  209. )
  210. /*++
  211. Routine Description:
  212. This routine starts a Direct Memory Access controller. This function is
  213. not thread safe, as it is meant to be called during the start IRP, which is
  214. always serialized.
  215. Arguments:
  216. Controller - Supplies a pointer to the controller.
  217. Return Value:
  218. Status code.
  219. --*/
  220. {
  221. PDMA_CONTROLLER_INFORMATION Host;
  222. KSTATUS Status;
  223. ASSERT(Controller->Interface.Context == NULL);
  224. ASSERT(KeGetRunLevel() == RunLevelLow);
  225. Host = &(Controller->Host);
  226. Controller->Interface.Context = Controller;
  227. Status = IoCreateInterface(&DmaInterfaceUuid,
  228. Host->Device,
  229. &(Controller->Interface),
  230. sizeof(DMA_INTERFACE));
  231. if (!KSUCCESS(Status)) {
  232. Controller->Interface.Context = NULL;
  233. goto StartControllerEnd;
  234. }
  235. //
  236. // Create a resource arbiter for these pins so that other devices can
  237. // allocate them as part of their official resource requirements.
  238. //
  239. if (Controller->ArbiterCreated == FALSE) {
  240. Status = IoCreateResourceArbiter(Host->Device, ResourceTypeDmaChannel);
  241. if ((!KSUCCESS(Status)) && (Status != STATUS_ALREADY_INITIALIZED)) {
  242. goto StartControllerEnd;
  243. }
  244. Status = IoAddFreeSpaceToArbiter(Host->Device,
  245. ResourceTypeDmaChannel,
  246. 0,
  247. Controller->ChannelCount,
  248. 0,
  249. NULL,
  250. 0);
  251. if (!KSUCCESS(Status)) {
  252. goto StartControllerEnd;
  253. }
  254. Controller->ArbiterCreated = TRUE;
  255. }
  256. StartControllerEnd:
  257. return Status;
  258. }
  259. DMA_API
  260. VOID
  261. DmaStopController (
  262. PDMA_CONTROLLER Controller
  263. )
  264. /*++
  265. Routine Description:
  266. This routine stops a Direct Memory Access controller. This function is not
  267. thread safe, as it is meant to be called during a state transition IRP,
  268. which is always serialized.
  269. Arguments:
  270. Controller - Supplies a pointer to the controller.
  271. Return Value:
  272. None.
  273. --*/
  274. {
  275. KSTATUS Status;
  276. ASSERT(Controller->Interface.Context == &(Controller->Interface));
  277. ASSERT(KeGetRunLevel() == RunLevelLow);
  278. Status = IoDestroyInterface(&DmaInterfaceUuid,
  279. Controller->Host.Device,
  280. &(Controller->Interface));
  281. ASSERT(KSUCCESS(Status));
  282. Controller->Interface.Context = NULL;
  283. return;
  284. }
  285. DMA_API
  286. PDMA_TRANSFER
  287. DmaTransferCompletion (
  288. PDMA_CONTROLLER Controller,
  289. PDMA_TRANSFER Transfer
  290. )
  291. /*++
  292. Routine Description:
  293. This routine is called by a DMA host controller when a transfer has
  294. completed. This function must be called at or below dispatch level. The
  295. host should have already filled in the number of bytes completed and the
  296. status.
  297. Arguments:
  298. Controller - Supplies a pointer to the controller.
  299. Transfer - Supplies a pointer to the transfer that completed.
  300. Return Value:
  301. Returns a pointer to the next transfer to start.
  302. NULL if no more transfers are queued.
  303. --*/
  304. {
  305. PDMA_CHANNEL Channel;
  306. PDMA_TRANSFER NextTransfer;
  307. RUNLEVEL OldRunLevel;
  308. ASSERT(Transfer->Allocation->Allocation < Controller->ChannelCount);
  309. ASSERT(Transfer->ListEntry.Next == NULL);
  310. NextTransfer = NULL;
  311. Channel = &(Controller->Channels[Transfer->Allocation->Allocation]);
  312. OldRunLevel = DmapAcquireChannelLock(Controller, Channel);
  313. ASSERT(Channel->Transfer == Transfer);
  314. Channel->Transfer = NULL;
  315. if (!LIST_EMPTY(&(Channel->Queue))) {
  316. NextTransfer = LIST_VALUE(Channel->Queue.Next, DMA_TRANSFER, ListEntry);
  317. LIST_REMOVE(&(NextTransfer->ListEntry));
  318. NextTransfer->ListEntry.Next = NULL;
  319. Channel->Transfer = NextTransfer;
  320. }
  321. DmapReleaseChannelLock(Controller, Channel, OldRunLevel);
  322. Transfer->CompletionCallback(Transfer);
  323. return NextTransfer;
  324. }
  325. //
  326. // --------------------------------------------------------- Internal Functions
  327. //
  328. VOID
  329. DmaDriverUnload (
  330. PVOID Driver
  331. )
  332. /*++
  333. Routine Description:
  334. This routine is called before a driver is about to be unloaded from memory.
  335. The driver should take this opportunity to free any resources it may have
  336. set up in the driver entry routine.
  337. Arguments:
  338. Driver - Supplies a pointer to the driver being torn down.
  339. Return Value:
  340. None.
  341. --*/
  342. {
  343. return;
  344. }
  345. KSTATUS
  346. DmaGetInformation (
  347. PDMA_INTERFACE Interface,
  348. PDMA_INFORMATION Information
  349. )
  350. /*++
  351. Routine Description:
  352. This routine returns information about a given DMA controller.
  353. Arguments:
  354. Interface - Supplies a pointer to the interface instance, used to identify
  355. which specific controller is being queried.
  356. Information - Supplies a pointer where the DMA controller information is
  357. returned on success. The caller should initialize the version number of
  358. this structure.
  359. Return Value:
  360. Status code.
  361. --*/
  362. {
  363. PDMA_CONTROLLER Controller;
  364. Controller = Interface->Context;
  365. if (Information == NULL) {
  366. return STATUS_INVALID_PARAMETER;
  367. }
  368. if ((Information->Version == 0) ||
  369. (Information->Version > DMA_INFORMATION_MAX_VERSION) ||
  370. (Information->Version < Controller->Host.Information.Version)) {
  371. Information->Version = Controller->Host.Information.Version;
  372. return STATUS_VERSION_MISMATCH;
  373. }
  374. if (Controller->Host.Information.Version == DMA_INFORMATION_VERSION) {
  375. RtlCopyMemory(Information,
  376. &(Controller->Host.Information),
  377. sizeof(DMA_INFORMATION));
  378. } else {
  379. return STATUS_VERSION_MISMATCH;
  380. }
  381. return STATUS_SUCCESS;
  382. }
  383. KSTATUS
  384. DmaSubmit (
  385. PDMA_INTERFACE Interface,
  386. PDMA_TRANSFER Transfer
  387. )
  388. /*++
  389. Routine Description:
  390. This routine submits a transfer to the DMA controller for execution. This
  391. routine will ensure that other devices do not perform transfers on the
  392. given channel while this transfer is in progress. The submission is
  393. asynchronous, this routine will return immediately, and the callback
  394. function will be called when the transfer is complete.
  395. Arguments:
  396. Interface - Supplies a pointer to the DMA controller interface.
  397. Transfer - Supplies a pointer to the transfer to execute.
  398. Return Value:
  399. Status code. This routine will return immediately, the transfer will not
  400. have been complete. The caller should utilize the callback function to get
  401. notified when a transfer has completed.
  402. --*/
  403. {
  404. PDMA_CHANNEL Channel;
  405. PDMA_CONTROLLER Controller;
  406. PRESOURCE_DMA_DATA DmaAllocation;
  407. ULONG Mask;
  408. RUNLEVEL OldRunLevel;
  409. KSTATUS Status;
  410. ULONG Width;
  411. Controller = Interface->Context;
  412. if ((Transfer->Allocation == NULL) ||
  413. (Transfer->Allocation->Allocation >= Controller->ChannelCount) ||
  414. (Transfer->Memory == NULL) ||
  415. (Transfer->CompletionCallback == NULL)) {
  416. return STATUS_INVALID_PARAMETER;
  417. }
  418. Transfer->Status = STATUS_NOT_STARTED;
  419. //
  420. // Try to figure out the width based on the resource allocation.
  421. //
  422. if (Transfer->Width == 0) {
  423. //
  424. // Grab the custom one if there is one.
  425. //
  426. if (((Transfer->Allocation->Characteristics &
  427. DMA_TRANSFER_SIZE_CUSTOM) != 0) &&
  428. (Transfer->Allocation->Data != NULL) &&
  429. (Transfer->Allocation->DataSize >= sizeof(RESOURCE_DMA_DATA))) {
  430. DmaAllocation = Transfer->Allocation->Data;
  431. Transfer->Width = DmaAllocation->Width;
  432. //
  433. // Try to find the width based on one of the characteristics flags.
  434. //
  435. } else {
  436. Mask = DMA_TRANSFER_SIZE_256;
  437. Width = 256;
  438. while (Mask >= DMA_TRANSFER_SIZE_8) {
  439. if ((Transfer->Allocation->Characteristics & Mask) != 0) {
  440. Transfer->Width = Width;
  441. break;
  442. }
  443. Width >>= 1;
  444. Mask >>= 1;
  445. }
  446. }
  447. }
  448. if (Transfer->Width == 0) {
  449. return STATUS_INVALID_CONFIGURATION;
  450. }
  451. ASSERT(Transfer->ListEntry.Next == NULL);
  452. Channel = &(Controller->Channels[Transfer->Allocation->Allocation]);
  453. OldRunLevel = DmapAcquireChannelLock(Controller, Channel);
  454. if (Channel->Transfer == NULL) {
  455. Channel->Transfer = Transfer;
  456. Transfer->ListEntry.Next = NULL;
  457. } else {
  458. INSERT_BEFORE(&(Transfer->ListEntry), &(Channel->Queue));
  459. Transfer = NULL;
  460. }
  461. DmapReleaseChannelLock(Controller, Channel, OldRunLevel);
  462. Status = STATUS_SUCCESS;
  463. //
  464. // If the transfer wasn't queued, kick it off now.
  465. //
  466. if (Transfer != NULL) {
  467. Status = Controller->Host.FunctionTable.SubmitTransfer(
  468. Controller->Host.Context,
  469. Transfer);
  470. }
  471. return Status;
  472. }
  473. KSTATUS
  474. DmaCancel (
  475. PDMA_INTERFACE Interface,
  476. PDMA_TRANSFER Transfer
  477. )
  478. /*++
  479. Routine Description:
  480. This routine attempts to cancel a transfer that is currently in flight.
  481. Arguments:
  482. Interface - Supplies a pointer to the DMA controller interface.
  483. Transfer - Supplies a pointer to the transfer to cancel.
  484. Return Value:
  485. STATUS_SUCCESS if the transfer was successfully canceled.
  486. STATUS_TOO_LATE if the transfer is already complete.
  487. Other status codes on other failures.
  488. --*/
  489. {
  490. PDMA_CHANNEL Channel;
  491. PDMA_CONTROLLER Controller;
  492. PDMA_TRANSFER NextTransfer;
  493. RUNLEVEL OldRunLevel;
  494. KSTATUS Status;
  495. KSTATUS SubmitStatus;
  496. Controller = Interface->Context;
  497. if ((Transfer->Allocation == NULL) ||
  498. (Transfer->Allocation->Allocation >= Controller->ChannelCount)) {
  499. return STATUS_INVALID_PARAMETER;
  500. }
  501. Channel = &(Controller->Channels[Transfer->Allocation->Allocation]);
  502. NextTransfer = NULL;
  503. OldRunLevel = DmapAcquireChannelLock(Controller, Channel);
  504. if (Channel->Transfer == Transfer) {
  505. Status = Controller->Host.FunctionTable.CancelTransfer(
  506. Controller->Host.Context,
  507. Transfer);
  508. if (KSUCCESS(Status)) {
  509. ASSERT(Channel->Transfer == Transfer);
  510. Channel->Transfer = NULL;
  511. //
  512. // Kick off the next transfer if this one was canceled and there is
  513. // more left to do.
  514. //
  515. if (!LIST_EMPTY(&(Channel->Queue))) {
  516. NextTransfer = LIST_VALUE(Channel->Queue.Next,
  517. DMA_TRANSFER,
  518. ListEntry);
  519. LIST_REMOVE(&(NextTransfer->ListEntry));
  520. NextTransfer->ListEntry.Next = NULL;
  521. Channel->Transfer = NextTransfer;
  522. }
  523. }
  524. } else if (Transfer->ListEntry.Next != NULL) {
  525. LIST_REMOVE(&(Transfer->ListEntry));
  526. Transfer->ListEntry.Next = NULL;
  527. Status = STATUS_SUCCESS;
  528. } else {
  529. Status = STATUS_TOO_LATE;
  530. }
  531. DmapReleaseChannelLock(Controller, Channel, OldRunLevel);
  532. //
  533. // If there's a next transfer, try to submit that. If that one fails,
  534. // process its completion and potentially submit the next one. Loop until
  535. // either a transfer is successfully submitted or there is nothing more
  536. // to do.
  537. //
  538. while (NextTransfer != NULL) {
  539. SubmitStatus = Controller->Host.FunctionTable.SubmitTransfer(
  540. Controller->Host.Context,
  541. Transfer);
  542. if (!KSUCCESS(SubmitStatus)) {
  543. Transfer->Status = SubmitStatus;
  544. NextTransfer = DmaTransferCompletion(Controller, NextTransfer);
  545. } else {
  546. break;
  547. }
  548. }
  549. return Status;
  550. }
  551. KSTATUS
  552. DmaControlRequest (
  553. PDMA_INTERFACE Interface,
  554. PDMA_TRANSFER Transfer,
  555. PVOID Request,
  556. UINTN RequestSize
  557. )
  558. /*++
  559. Routine Description:
  560. This routine is called to perform a DMA controller-specific operation. It
  561. provides a direct link between DMA controllers and users, for controller-
  562. specific functionality.
  563. Arguments:
  564. Interface - Supplies a pointer to the DMA controller interface.
  565. Transfer - Supplies an optional pointer to the transfer involved.
  566. Request - Supplies a pointer to the request/response data.
  567. RequestSize - Supplies the size of the request in bytes.
  568. Return Value:
  569. Status code.
  570. --*/
  571. {
  572. PDMA_CONTROLLER Controller;
  573. KSTATUS Status;
  574. Controller = Interface->Context;
  575. if (Controller->Host.FunctionTable.ControlRequest == NULL) {
  576. return STATUS_NOT_SUPPORTED;
  577. }
  578. //
  579. // The common DMA library doesn't know much of anything, just pass it on
  580. // down.
  581. //
  582. Status = Controller->Host.FunctionTable.ControlRequest(
  583. Controller->Host.Context,
  584. Transfer,
  585. Request,
  586. RequestSize);
  587. return Status;
  588. }
  589. KSTATUS
  590. DmaAllocateTransfer (
  591. PDMA_INTERFACE Interface,
  592. PDMA_TRANSFER *Transfer
  593. )
  594. /*++
  595. Routine Description:
  596. This routine creates a new DMA transfer structure.
  597. Arguments:
  598. Interface - Supplies a pointer to the DMA controller interface.
  599. Transfer - Supplies a pointer where a pointer to the newly allocated
  600. transfer is returned on success.
  601. Return Value:
  602. Status code.
  603. --*/
  604. {
  605. PDMA_TRANSFER DmaTransfer;
  606. *Transfer = NULL;
  607. DmaTransfer = MmAllocateNonPagedPool(sizeof(DMA_TRANSFER),
  608. DMA_ALLOCATION_TAG);
  609. if (DmaTransfer == NULL) {
  610. return STATUS_INSUFFICIENT_RESOURCES;
  611. }
  612. RtlZeroMemory(DmaTransfer, sizeof(DMA_TRANSFER));
  613. *Transfer = DmaTransfer;
  614. return STATUS_SUCCESS;
  615. }
  616. VOID
  617. DmaFreeTransfer (
  618. PDMA_INTERFACE Interface,
  619. PDMA_TRANSFER Transfer
  620. )
  621. /*++
  622. Routine Description:
  623. This routine destroys a previously created DMA transfer. This transfer
  624. must not be actively submitted to any controller.
  625. Arguments:
  626. Interface - Supplies a pointer to the DMA controller interface.
  627. Transfer - Supplies a pointer to the transfer to destroy.
  628. Return Value:
  629. None.
  630. --*/
  631. {
  632. MmFreeNonPagedPool(Transfer);
  633. return;
  634. }
  635. //
  636. // --------------------------------------------------------- Internal Functions
  637. //
  638. RUNLEVEL
  639. DmapAcquireChannelLock (
  640. PDMA_CONTROLLER Controller,
  641. PDMA_CHANNEL Channel
  642. )
  643. /*++
  644. Routine Description:
  645. This routine raises to dispatch and acquires the DMA controller's channel
  646. lock.
  647. Arguments:
  648. Controller - Supplies a pointer to the controller that owns the channel.
  649. Channel - Supplies a pointer to the channel to lock.
  650. Return Value:
  651. Returns the previous runlevel, which should be passed into the release
  652. function.
  653. --*/
  654. {
  655. RUNLEVEL OldRunLevel;
  656. OldRunLevel = KeRaiseRunLevel(RunLevelDispatch);
  657. KeAcquireSpinLock(&(Channel->Lock));
  658. return OldRunLevel;
  659. }
  660. VOID
  661. DmapReleaseChannelLock (
  662. PDMA_CONTROLLER Controller,
  663. PDMA_CHANNEL Channel,
  664. RUNLEVEL OldRunLevel
  665. )
  666. /*++
  667. Routine Description:
  668. This routine releases the DMA channel's lock and lowers to the runlevel
  669. the system was at before the acquire.
  670. Arguments:
  671. Controller - Supplies a pointer to the controller.
  672. Channel - Supplies a pointer to the channel to unlock.
  673. OldRunLevel - Supplies the runlevel returned by the acquire function.
  674. Return Value:
  675. None.
  676. --*/
  677. {
  678. KeReleaseSpinLock(&(Channel->Lock));
  679. KeLowerRunLevel(OldRunLevel);
  680. return;
  681. }