dma.c 21 KB

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