home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / SDKs / PCI Driver Development Kit / • Samples / Driver Samples / SCSI samples / SCSI 950629 / NCR_DriverProject / Src / DMATransfer.c next >
Encoding:
C/C++ Source or Header  |  1996-08-20  |  30.5 KB  |  985 lines  |  [TEXT/MPCC]

  1. /*                                    DMATransfer.c                                    */
  2. /*
  3.  * DMATransfer.c
  4.  * Copyright © 1995 Apple Computer Inc. All rights reserved.
  5.  */
  6. /*    .___________________________________________________________________________________.
  7.       | This library simplifies using PrepareMemoryForIO with DMA and non-DMA hardware    |
  8.     | devices. These functions can be called from any interrupt level.                    |
  9.     |                                                                                    |
  10.     | PrepareDMATransfer prepares the next segment (logical or physical) that can        |
  11.     | be computed from the current state of the I/O table. The caller must adapt the    |
  12.     | result if required maximum transfer length limitations.                            |
  13.     |                                                                                    |
  14.     | Usage:                                                                            |
  15.     |        status = PrepareMemoryForIO(&myIOTable);        // Do first prepare            |
  16.     |        if (status == noErr) {                            // Start dma preparation    |
  17.     |            status = InitializeDMATransfer(                                            |
  18.     |                        &myIOTable,                                                    |
  19.     |                        myLogicalAlignment,                                            |
  20.     |                        &myDMATable                                                    |
  21.     |                    );                                                                |
  22.     |            while (status == noErr) {                    // Start dma operation        |
  23.     |                status = PrepareDMATransfer(                                        |
  24.     |                            &myDMATable,                                            |
  25.     |                            &myNextTransfer,                                        |
  26.     |                            &nextIsLogical                                            |
  27.     |                        );                                                            |
  28.     |                if (status == noErr) {                                                |
  29.     |                    if (nextIsLogical)                                                |
  30.     |                        DoLogicalTransfer(&myNextTransfer);                            |
  31.     |                    else {                                                            |
  32.     |                        DoPhysicalTransfer(&myNextTransfer);                        |
  33.     |                    }                                                                |
  34.     |                } // For all DMA segments for this preparation.                        |
  35.     |            } // while there is data to transmit                                    |
  36.     |        } // if PrepareMemoryForIO succeeded                                        |
  37.     .___________________________________________________________________________________.
  38.  */
  39.  
  40. #include "DMATransfer.h"
  41. #include <DriverServices.h>
  42.  
  43. #ifndef FALSE
  44. #define FALSE    0
  45. #define TRUE    1
  46. #endif
  47. #define DMA        (*dmaTablePtr)
  48. #define IO        (*ioTablePtr)
  49. static UInt32        gPageSize;                    /* GetLogicalPageSize()                */
  50. static UInt32        gPageMask;                    /* pageSize - 1                        */
  51.  
  52. static void                    ComputeThisArea(
  53.         DMATransferInfoPtr        dmaTablePtr
  54.     );
  55. static OSStatus                GetNextSegment(
  56.         DMATransferInfoPtr        dmaTablePtr
  57.     );
  58. static Boolean                GetNextPhysicalTransfer(
  59.         DMATransferInfoPtr        dmaTablePtr
  60.     );
  61.  
  62. #ifndef TESTING
  63. #define TESTING    0
  64. #endif
  65. #if TESTING
  66. #include <stdio.h>
  67. #define LOG(what)    printf what
  68. #else
  69. #define LOG(what)    /* Nothing */
  70. #endif
  71.  
  72. /*    .___________________________________________________________________________________.
  73.       | InitializeDMATransfer                                                                |
  74.     |                                                                                    |
  75.     | Initialize the DMATransferInfo record.                                            |
  76.     | Input:                                                                            |
  77.     |    ioTable                The prepared I/O Preparation table. It is "ready to run"    |
  78.     |    logicalGranularity    This is a power of two that is used to group the transfer    |
  79.     |                        into logical and physical segments. If zero, only physical    |
  80.     |                        transfers will be reported. If one and a logical segment    |
  81.     |                        begins on an odd-byte boundary, PrepareDMATransfer will        |
  82.     |                        return a one-byte logical transfer, then one or more        |
  83.     |                        physical transfers then, if necessary, a one-byte logical    |
  84.     |                        transfer.                                                    |
  85.     |                                                                                    |
  86.     | Output:                                                                            |
  87.     |    dmaTablePtr            The DMATransferInfo record that will manage this transfer.    |
  88.     |                                                                                    |
  89.     | Result:                                                                            |
  90.     |    noErr                Normal.                                                        |
  91.     |    paramErr            Bad parameters (ioTable or dmaTablePtr are NULL or an error    |
  92.     |                        in the IOTable parameters).                                    |
  93.     |                                                                                    |
  94.     | Set the IOTable parameter block as follows:                                        |
  95.     |    logicalMapping        Required                                                    |
  96.     |    physicalMapping        Required.                                                    |
  97.     |    mappingEntryCount    > 0                                                            |
  98.     |    options:                                                                        |
  99.     |        kIOLogicalRanges            Required if non-zero logical granularity.        |
  100.     |        kIOMinimalLogicalMapping    Required if non-zero logical granularity.        |
  101.     |        kIOIsInput or kIOIsOutput    One is required                                    |
  102.     .___________________________________________________________________________________.
  103.  */
  104. OSStatus
  105. InitializeDMATransfer(
  106.         const IOPreparationTable *ioTablePtr,
  107.         UInt32                    logicalAlignment,
  108.         DMATransferInfoPtr        dmaTablePtr
  109.     )
  110. {
  111.         OSStatus                osStatus;
  112.         UInt32                    alignmentMask;
  113.  
  114.         if (gPageSize == 0) {
  115.             gPageSize = GetLogicalPageSize();
  116.             gPageMask = gPageSize - 1;
  117.         }
  118.         osStatus = noErr;
  119.         alignmentMask = logicalAlignment - 1;
  120.         if (ioTablePtr == NULL
  121.          || dmaTablePtr == NULL
  122.          || ioTablePtr->physicalMapping == NULL
  123.          || ioTablePtr->mappingEntryCount == 0
  124.          || ioTablePtr->lengthPrepared == 0) {
  125.             LOG(("InitialDMATransfer: missing parameter or IOPreparationTable error\n"));
  126.             osStatus = paramErr;
  127.         }
  128.         else if ((logicalAlignment & ~(-logicalAlignment)) != 0) {
  129.             LOG(("InitializeDMATransfer: logicalAligment %lu must be power of 2\n",
  130.                     logicalAlignment));
  131.             osStatus = paramErr;
  132.         }
  133.         else if (logicalAlignment >= gPageSize) {
  134.             LOG(("InitializeDMATransfer: logicalAligment %lu must be < page size %lu\n",
  135.                     logicalAlignment, gPageSize));
  136.             osStatus = paramErr;
  137.         }
  138.         else if ((ioTablePtr->options & kIOLogicalRanges) != 0
  139.               && (ioTablePtr->logicalMapping == NULL
  140.                || (ioTablePtr->options & kIOMinimalLogicalMapping) == 0)) {
  141.             LOG(("InitializeDMATransfer: logical transfer requires logical mapping\n"));
  142.             osStatus = paramErr;
  143.         }
  144.         else if ((ioTablePtr->options & kIOLogicalRanges) == 0
  145.               && logicalAlignment != 0
  146.               && ((((UInt32) ioTablePtr->physicalMapping[0]) & alignmentMask) != 0
  147.                 || (ioTablePtr->lengthPrepared & alignmentMask) != 0)) {
  148.             LOG(("InitializeDMATransfer: unaligned physical transfer\n"));
  149.             osStatus = paramErr;
  150.         }
  151.         else {
  152.             /*
  153.              * Setup our private globals and call GetNextSegment to compute the first
  154.              * (or only) transfer segment. We call it here as this function is probably
  155.              * being called at "task" context and, for simple transfers, we won't have
  156.              * to scan the physical table in a primary interrupt service routine.
  157.              *
  158.              * This library presumes that it is the only preparation. Some adjustments
  159.              * will be needed to support partial preparation.
  160.              */
  161.             DMA.ioTablePtr = ioTablePtr;
  162.             DMA.logicalAlignment = logicalAlignment;
  163.             if (IO.firstPrepared == 0) {
  164.                 /*
  165.                  * This is the first preparation: initialize the scatter-gather index.
  166.                  */
  167.                 DMA.scatterGatherIndex = 0;
  168.                 DMA.prepareCount = 0;
  169.                 DMA.rangeCount = 0;
  170.                 DMA.rangeLength = 0;
  171.             }
  172.             /*
  173.              * The preparation writes the physical map from index zero.
  174.              */
  175.             DMA.physicalMapIndex = 0;
  176.             DMA.prepareCount = 0;
  177.             osStatus = GetNextSegment(dmaTablePtr);
  178.         }
  179.         return (osStatus);
  180. }
  181.  
  182. /*    .___________________________________________________________________________________.
  183.       | PrepareDMATransfer                                                                |
  184.     |                                                                                    |
  185.     | Prepare the next DMA segment.                                                        |
  186.     | Input:                                                                            |
  187.     |    dmaTablePtr            The DMATransferInfo record that will manage this transfer.    |
  188.     |                                                                                    |
  189.     | Output:                                                                            |
  190.     |    nextTransferAddress    Gets the segment start address (required).                    |
  191.     |    nextTransferCount    Gets the segment transfer count (required).                    |
  192.     |    nextIsLogical        TRUE if this is a logical address.                            |
  193.     |                                                                                    |
  194.     | Result:                                                                            |
  195.     |    noErr                Normal                                                         |
  196.     |    paramErr            Programming bug.                                            |
  197.     |    eofErr                Nothing more to transfer.                                    |
  198.     |                                                                                    |
  199.     | Notes:                                                                            |
  200.     |                                                                                    |
  201.     |    eofErr is a normal status results. They should be replaced by                    |
  202.     |    by private error codes.                                                            |
  203.     |                                                                                    |
  204.     |    If logical addresses are needed, the PrepareMemoryForIO must provide a "minimal    |
  205.     |    logical mapping" table.                                                            |
  206.     .___________________________________________________________________________________.
  207.  */
  208. OSStatus
  209. PrepareDMATransfer(
  210.         DMATransferInfoPtr        dmaTablePtr,
  211.         AddressRange            *nextTransferRange,
  212.         Boolean                    *nextIsLogical
  213.     )
  214. {
  215.         OSStatus                osStatus;
  216.         const IOPreparationTable *ioTablePtr;
  217.  
  218.         ioTablePtr = DMA.ioTablePtr;
  219.         if (dmaTablePtr == NULL || nextTransferRange == NULL || nextIsLogical == NULL) {
  220.             LOG(("Bogus PrepareDMATransfer parameters\n"));
  221.             osStatus = paramErr;
  222.         }
  223.         else {
  224.             osStatus = noErr;
  225. computeNextTransfer:
  226.             if (DMA.logicalStart.length != 0) {
  227.                 *nextTransferRange = DMA.logicalStart;
  228.                 DMA.logicalStart.length = 0;
  229.                 *nextIsLogical = TRUE;
  230.             }
  231.             else if (GetNextPhysicalTransfer(dmaTablePtr)) {
  232.                 *nextTransferRange = DMA.physicalRange;
  233.                 *nextIsLogical = FALSE;
  234.             }
  235.             else if (DMA.logicalEnd.length != 0) {            
  236.                 *nextTransferRange = DMA.logicalEnd;
  237.                 DMA.logicalEnd.length = 0;
  238.                 *nextIsLogical = TRUE;
  239.             }
  240.             else {
  241.                 /*
  242.                  * Get here to compute the next scatter-gather segment. GetNextSegment
  243.                  * will return eofErr when we run off the end of the entire "prepared"
  244.                  * transfer.
  245.                  */
  246.                 ++DMA.scatterGatherIndex;
  247.                 osStatus = GetNextSegment(dmaTablePtr);
  248.                 if (osStatus == noErr)
  249.                     goto computeNextTransfer;
  250.             }
  251.         }
  252.         if (osStatus == noErr) {
  253.             /*
  254.              * We have some data to transfer: advance our indexes.
  255.              */
  256.             DMA.rangeCount += nextTransferRange->length;
  257.             DMA.prepareCount += nextTransferRange->length;
  258.         }
  259.         return (osStatus);
  260. }
  261.  
  262. /*    .___________________________________________________________________________________.
  263.       | GetNextSegment                                                                    |
  264.     |                                                                                    |
  265.     | Compute a logical segment (either the only segment or the current scatter-gather    |
  266.     | segment).                                                                            |
  267.     |                                                                                    |
  268.     | Input:                                                                            |
  269.     |    dmaTablePtr            The DMATransferInfo record that will manage this transfer.    |
  270.     |                                                                                    |
  271.     | Output:                                                                            |
  272.     |    The DMA global context is updated.                                                |
  273.     |                                                                                    |
  274.     | Result:                                                                            |
  275.     |    noErr                Normal                                                         |
  276.     |    paramErr            Programming bug.                                            |
  277.     |    eofErr                Nothing more to transfer.                                    |
  278.     |                                                                                    |
  279.     | Notes:                                                                            |
  280.     |    eofErr is an expected status result. It could be replaced by a private code.    |
  281.     .___________________________________________________________________________________.
  282.  */
  283. static OSStatus
  284. GetNextSegment(
  285.         DMATransferInfoPtr        dmaTablePtr
  286.     )
  287. {
  288.         OSStatus                osStatus;
  289.         const IOPreparationTable *ioTablePtr;
  290. #define RANGE        (IO.rangeInfo)
  291. #define RANGETABLE    (IO.rangeInfo.multipleRanges.rangeTable)
  292.  
  293.         ioTablePtr = DMA.ioTablePtr;
  294.         osStatus = noErr;
  295.         if (DMA.prepareCount >= IO.lengthPrepared)
  296.             osStatus = eofErr;
  297.         else if (DMA.rangeCount < DMA.rangeLength) {
  298.             /*
  299.              * We can get here if we need several calls to PrepareMemoryForIO to
  300.              * consume a single scatter-gather area.
  301.              */
  302.             ComputeThisArea(dmaTablePtr);
  303.         }
  304.         else if ((IO.options & kIOMultipleRanges) == 0) {
  305.             /*
  306.              * There is a single logical area (this is normal). If this function is
  307.              * re-called, DMA.scatterGatherIndex will be non-zero (it was incremented
  308.              * when we were previously called). Return eofErr to indicate a normal,
  309.              * successful, completion.
  310.              */
  311.             if (DMA.scatterGatherIndex > 0)
  312.                 osStatus = eofErr;
  313.             else {
  314.                 /*
  315.                  * This is the initial call for a single logical area. Compute the
  316.                  * logical and physical areas.
  317.                  */
  318.                 DMA.rangeLength = RANGE.range.length;
  319.                 ComputeThisArea(dmaTablePtr);
  320.             }
  321.         }
  322.         else if (DMA.scatterGatherIndex >= RANGE.multipleRanges.entryCount)
  323.                 osStatus = eofErr;
  324.         else {
  325.             /*
  326.              * We are processing a scatter-gather I/O table. Compute this segment.
  327.              */
  328.             DMA.rangeLength = RANGETABLE[DMA.scatterGatherIndex].length;
  329.             ComputeThisArea(dmaTablePtr);
  330.         }
  331.         return (osStatus);
  332. #undef RANGETABLE
  333. #undef RANGE
  334. }
  335.  
  336. /*    .___________________________________________________________________________________.
  337.       | ComputeThisArea                                                                    |
  338.     |                                                                                    |
  339.     | Compute the current logical segment. The caller has selected the segment.            |
  340.     | This function creates the initial and final logical segments and adjusts the        |
  341.     | physical transfer parameters if necessary.                                        |
  342.     |                                                                                    |
  343.     | Input:                                                                            |
  344.     |    dmaTablePtr            The DMATransferInfo record that will manage this transfer.    |
  345.     |    dmaTablePtr->scatterGatherIndex is the index into the logical mapping table.    |
  346.     |                                                                                    |
  347.     | Output:                                                                            |
  348.     |    The DMA global context is updated.                                                |
  349.     |                                                                                    |
  350.     | Result:                                                                            |
  351.     |    none                                                                            |
  352.     .___________________________________________________________________________________.
  353.  */
  354. static void
  355. ComputeThisArea(
  356.         DMATransferInfoPtr        dmaTablePtr
  357.     )
  358. {
  359.         const IOPreparationTable *ioTablePtr;
  360.         static const AddressRange gNullAddressRange;
  361.         ByteCount                lastPageLength;
  362.         ByteCount                segmentLength;
  363.         UInt32                    alignmentMask;
  364.         ByteCount                firstPageLength;        /* First physical chunk        */
  365.         LogicalAddress            *logicalMapPtr;
  366.         /*
  367.          * To keep the line lengths reasonable, logicalBase will refer to the base
  368.          * of the initial logical area represented as an integer. Don't make this a
  369.          * variable as the actual DMA.logicalStart.base must always be correct.
  370.          */
  371. #define logicalBase ((UInt32) DMA.logicalStart.base)
  372.  
  373.         ioTablePtr = DMA.ioTablePtr;
  374.         DMA.logicalStart = gNullAddressRange;
  375.         DMA.logicalEnd = gNullAddressRange;
  376.         DMA.firstPageOffset = firstPageLength = DMA.physicalStart = 0;
  377.         logicalMapPtr = &IO.logicalMapping[DMA.scatterGatherIndex * 2];
  378.         /*
  379.          * Get the actual transfer length; breaking it into initial, physical, and
  380.          * final segments.
  381.          */
  382.         segmentLength = DMA.rangeLength;
  383.         if ((segmentLength + DMA.prepareCount) > IO.lengthPrepared)
  384.             segmentLength = (IO.lengthPrepared - DMA.prepareCount);
  385.         DMA.physicalEnd = segmentLength;
  386.         if ((IO.options & kIOLogicalRanges) != 0    /* Is logical alignment possible    */
  387.          && DMA.logicalAlignment != 0) {            /* And logical alignment is needed    */
  388.             /*
  389.              * Compute the logical transfer parameters.
  390.              */
  391.             alignmentMask = DMA.logicalAlignment - 1;
  392.             DMA.logicalStart.base = logicalMapPtr[0];
  393.             if ((logicalBase & alignmentMask) != 0) {
  394.                 DMA.logicalStart.length =
  395.                     DMA.logicalAlignment - (logicalBase & alignmentMask);
  396.             }
  397.             if (DMA.logicalStart.length > segmentLength)
  398.                 DMA.logicalStart.length = segmentLength;
  399.             DMA.physicalStart += DMA.logicalStart.length;
  400.             DMA.logicalEnd.length =
  401.                 (segmentLength - DMA.logicalStart.length) & alignmentMask;
  402.             DMA.physicalEnd -= DMA.logicalEnd.length;
  403.         }
  404.         /*
  405.          * If there is an initial logical area length, compute the base of the initial
  406.          * logical area. The first physical transfer will be offset by the initial
  407.          * logical length.
  408.          */
  409.         if (DMA.logicalStart.length != 0) {
  410.             DMA.firstPageOffset = DMA.logicalStart.length;
  411.             if (PageOffset(logicalBase + DMA.logicalStart.length) == 0) {
  412.                 /*
  413.                  * Since the initial logical area consumed the remainder of a physical
  414.                  * page, we'll move to the start of the next page.
  415.                   */
  416.                 ++DMA.physicalMapIndex;
  417.                 DMA.firstPageOffset = 0;
  418.             }
  419.         }
  420.         /*
  421.          * If there is a final logical area, compute its starting address. This is
  422.          * also a good place to compute the length of the first physical page. (Note
  423.          * that the initial logical segment is included in firstPageLength).
  424.          */
  425.         firstPageLength = gPageSize - PageOffset(logicalBase);
  426.         if (firstPageLength > segmentLength)
  427.             firstPageLength = segmentLength;
  428.         if (DMA.logicalEnd.length != 0) {
  429.             if (PageOffset(logicalBase) + segmentLength <= gPageSize) {
  430.                 /*
  431.                  * Since the entire transfer is contained within a single page,
  432.                  * PrepareMemoryForIO will only compute a single result logical page.
  433.                  * If there is no physical transfer, combine the initial and final
  434.                  * logical transfers. (Hmm. can this cause the fifo to choke?)
  435.                  */
  436.                 if (DMA.physicalStart >= DMA.physicalEnd) {
  437.                     DMA.logicalStart.length += DMA.logicalEnd.length;
  438.                     DMA.logicalEnd.length = 0;
  439.                 }
  440.                 else {
  441.                     /*
  442.                      * The final segment starts at the end of the (only) logical page.
  443.                      */
  444.                     DMA.logicalEnd.base = (void *)
  445.                         (logicalBase + segmentLength - DMA.logicalEnd.length);
  446.                 }
  447.             }
  448.             else {
  449.                 /*
  450.                  * There are multiple pages. The final logical transfer starts at
  451.                  * the base of the last page, taken from the IOTable plus the
  452.                  * amount of physical transfer that lives in the last physical page.
  453.                  * First, compute the number of bytes that will be transferred from
  454.                  * the last physical (i.e., logical) page. This will be a combination
  455.                  * of physical and logical transfers, and includes the final logical
  456.                  * transfer. PageOffset removes any intervening full pages.
  457.                  */
  458.                 lastPageLength = PageOffset(segmentLength - firstPageLength);
  459.                 DMA.logicalEnd.base = (void *) (
  460.                         ((UInt32) logicalMapPtr[1])
  461.                         + lastPageLength
  462.                         - DMA.logicalEnd.length
  463.                     );
  464.             }
  465.         }
  466. #undef logicalBase
  467. }
  468.  
  469. /*    .___________________________________________________________________________________.
  470.       | GetNextPhysicalTransfer                                                            |
  471.     |                                                                                    |
  472.     | Compute the next physical segment. It begins from the current physical location    |
  473.     | (DMA.physicalFirstPrepared) and extends for as many pages as are physically        |
  474.     | contiguous.                                                                        |
  475.     |                                                                                    |
  476.     | Input:                                                                            |
  477.     |    dmaTablePtr            The DMATransferInfo record that will manage this transfer.    |
  478.     |    pageOffset            Offset into the physical page -- this will be non-zero if    |
  479.     |                        this is the first physical page and we had required an        |
  480.     |                        initial logical transfer to handle unaligned memory.        |
  481.     |                                                                                    |
  482.     | Output:                                                                            |
  483.     |    The DMA global context is updated.                                                |
  484.     |                                                                                    |
  485.     | Result:                                                                            |
  486.     |    TRUE if there is a physical transfer remaining.                                    |
  487.     .___________________________________________________________________________________.
  488.  */
  489. static Boolean
  490. GetNextPhysicalTransfer(
  491.         DMATransferInfoPtr        dmaTablePtr
  492.     )
  493. {
  494.         const IOPreparationTable *ioTablePtr;
  495.         ByteCount                newPosition;
  496.         Boolean                    result;
  497.  
  498.         ioTablePtr = DMA.ioTablePtr;
  499.         if (DMA.physicalStart >= DMA.physicalEnd) {
  500.             DMA.physicalRange.length = 0;
  501.             result = FALSE;
  502.         }
  503.         else {
  504.             DMA.physicalRange.base = (void *)
  505.                         (((UInt32) IO.physicalMapping[DMA.physicalMapIndex])
  506.                         + DMA.firstPageOffset
  507.                     );
  508.             DMA.firstPageOffset = 0;
  509.             /*
  510.              * The range length extends from the current page offset to the end of
  511.              * the page. If we start at the beginning of the page, PageOffset will
  512.              * be zero.
  513.              */
  514.             DMA.physicalRange.length =
  515.                         gPageSize - PageOffset((UInt32) DMA.physicalRange.base);
  516.             newPosition = DMA.physicalStart + DMA.physicalRange.length;
  517.             while (newPosition < DMA.physicalEnd
  518.                 && NextPageIsContiguous(IO.physicalMapping, DMA.physicalMapIndex)) {
  519.                 ++DMA.physicalMapIndex;
  520.                 DMA.physicalRange.length += gPageSize;
  521.                 newPosition += gPageSize;
  522.             }
  523.             /*
  524.              * We've reached the end of the physical sequence -- or as far as we can
  525.              * go this time. We'll always restart at the next sequence. Finally,
  526.              * ensure that we didn't fall off the end of the preparation.
  527.              */
  528.             ++DMA.physicalMapIndex;
  529.             if (newPosition > DMA.physicalEnd) {
  530.                 newPosition = DMA.physicalEnd;
  531.                 DMA.physicalRange.length = newPosition - DMA.physicalStart;
  532.             }
  533.             DMA.physicalStart = newPosition;
  534.             result = TRUE;
  535.         }
  536.         return (result);
  537. }
  538.  
  539. #if TESTING
  540. #include <stdlib.h>
  541. #include <console.h>
  542.  
  543. #undef DMA
  544. #undef IO
  545.  
  546. #define kWorkSize            32768
  547. #define kPageSize            4096
  548. #define kMaxScatterGather    16
  549. UInt8                        gWorkArea[kWorkSize + kPageSize];
  550. UInt8                        *gWorkAreaStart;
  551. UInt32                        gPageAlign;
  552. IOPreparationTable            gIOTable;
  553. AddressRange                gScatterGatherTable[kMaxScatterGather];
  554. LogicalAddress                gLogicalMapping[kMaxScatterGather * 2];
  555. PhysicalAddress                gPhysicalMapping[(kWorkSize / kPageSize) + 2];
  556. DMATransferInfo                gDMATable;
  557.  
  558. typedef struct SimpleArea {
  559.     UInt32                offset;
  560.     UInt32                byteCount;
  561. } SimpleArea, *SimpleAreaPtr;
  562.  
  563. SimpleArea            gSimpleTest[] = {
  564.     {        0,                16384        },
  565. #if 0
  566.     {        1,                4096        },
  567.     {        1,                16384        },
  568.     {        2,                4096        },
  569.     {        3,                4096        },
  570.     {        5,                4096        },
  571.     {        8,                4096        },
  572.     {        13,                4096        },
  573.     {        21,                4096        },
  574.     {        0,                1            },
  575.     {        0,                2            },
  576.     {        0,                14            },
  577.     {        0,                15            },
  578.     {        0,                16            },
  579.     {        0,                17            },
  580.     {        0,                18            },
  581.     {        4095,            1            },
  582.     {        4095,            2            },
  583.     {        4095,            3            },
  584.     {        4095,            4            },
  585.     {        4095,            4095        },
  586.     {        4095,            4096        },
  587.     {        4095,            4097        },
  588.     {        4095,            8195        },
  589.     {        8193,            517            },
  590. #endif
  591.     {        0,                0            }
  592. };
  593. SimpleArea            gSGTest1[] = {            /* Simple SG area                    */
  594.         {    0,                4096    },
  595.         {    0,                0        }
  596. };
  597. SimpleArea            gSGTest2[] = {            /* Two simple areas                    */
  598.         {    0,                4096    },
  599.         {    8192,            4096    },
  600.         {    0,                0        }
  601. };
  602. SimpleArea            gSGTest3[] = {            /* Three repeated logical transfers    */
  603.         {    0,                1        },
  604.         {    0,                1        },
  605.         {    0,                1        },
  606.         {    0,                0        }
  607. };
  608. SimpleArea            gSGTest4[] = {            /* Two adjacent areas in one page    */
  609.         {    0,                512        },
  610.         {    512,            512        },
  611.         {    0,                0        }
  612.     };
  613. SimpleArea            gSGTest5[] = {            /* Two identical areas                */
  614.         {    0,                512        },
  615.         {    0,                512        },
  616.         {    0,                0        }
  617. };
  618. SimpleArea            gSGTest6[] = {            /* Four randomly complex areas        */
  619.         {    0,                1        },
  620.         {    8193,            517        },
  621.         {    8193,            516        },
  622.         {    0,                1        },
  623.         {    0,                0        }
  624. };
  625. SimpleArea            gSGTest7[] = {
  626.         {    0,                16384    },
  627.         {    8192,            16384    },
  628.         {    0,                0        }
  629. };
  630. SimpleArea            gSGTest8[] = {
  631.         {    1,                1        },
  632.         {    2,                1        },
  633.         {    8193,            1        },
  634.         {    0,                0        }
  635. };
  636.  
  637. SimpleArea            *gSGTestVector[] = {
  638. //    gSGTest1, gSGTest2, gSGTest3, gSGTest4, gSGTest5, gSGTest6,
  639.     gSGTest7, gSGTest8,
  640.     NULL
  641. };
  642.  
  643. #define CLEAR(what)    BlockZero(&what, sizeof what)
  644.  
  645. void                        TestSimpleArea(
  646.         const SimpleAreaPtr        simpleAreaPtr,
  647.         ByteCount                granularity
  648.     );
  649. void                        TestScatterGatherArea(
  650.         const SimpleAreaPtr        sgAreaPtr,        /* Vector            */
  651.         ByteCount                granularity
  652.     );
  653.  
  654. #define ClearWorkArea()        CLEAR(gWorkArea)
  655. Boolean                        UpdateWorkArea(
  656.         UInt32                    offset,
  657.         ByteCount                byteCount,
  658.         AddressRange            *thisTransferPtr
  659.     );
  660. void                        CheckWorkArea(
  661.         UInt32                    offset,
  662.         ByteCount                byteCount
  663.     );
  664. void                        DoPreparationAndTest(void);
  665. void                        TestThisPreparation(void);
  666. void                        DumpPrepareIOTable(
  667.         IOPreparationTable        *ioTable
  668.     );
  669. void                        DumpDMATable(
  670.         DMATransferInfo            *dmaTable
  671.     );
  672. ItemCount                    GetMapEntryCount(
  673.         void                    *areaBaseAddress,
  674.         ByteCount                areaLength
  675.     );
  676.  
  677. void
  678. main(
  679.         int                        argc,
  680.         char                    **argv
  681.     )
  682. {
  683.         ItemCount                i;
  684.         ByteCount                granularity;
  685.  
  686.         if (gPageSize == 0) {
  687.             gPageSize = GetLogicalPageSize();
  688.             gPageMask = gPageSize - 1;
  689.         }
  690.         do { argc = argc; argv = argv; } while (0);
  691.         printf("Hello world!\n");
  692.         /*
  693.          * Compute a page-aligned base address for our work area.
  694.          */
  695.         for (gPageAlign = 0; gPageAlign < kPageSize; gPageAlign++) {
  696.             if ((((UInt32) &gWorkArea[gPageAlign]) & (kPageSize - 1)) == 0)
  697.                 break;
  698.         }
  699.         gWorkAreaStart = &gWorkArea[gPageAlign];
  700.         for (granularity = 0; granularity <= 8192; granularity += 4096) {
  701.             for (i = 0; gSimpleTest[i].byteCount != 0; i++) {
  702.                 printf("*\n*** Simple Area Test %ld\n*\n", i);
  703.                 TestSimpleArea(&gSimpleTest[i], granularity);
  704.             }
  705.             for (i = 0; gSGTestVector[i] != NULL; i++) {
  706.                 printf("*\n*** Scatter Gather Test %ld\n*\n", i);
  707.                 TestScatterGatherArea(gSGTestVector[i], granularity);
  708.             }
  709.         }
  710.         exit(EXIT_SUCCESS);
  711. }
  712.  
  713. void
  714. TestSimpleArea(
  715.         const SimpleAreaPtr        simpleAreaPtr,
  716.         ByteCount                granularity
  717.     )
  718. {
  719.         LogicalAddress            areaAddress;
  720.  
  721.         /*
  722.          * Initialize the ioTable.
  723.          */
  724.         areaAddress = &gWorkAreaStart[simpleAreaPtr->offset];
  725.         printf("%08lx, %lu offset, %lu byteCount\n",
  726.             areaAddress,
  727.             simpleAreaPtr->offset,
  728.             simpleAreaPtr->byteCount
  729.         );
  730.         CLEAR(gIOTable);
  731.         CLEAR(gLogicalMapping);
  732.         CLEAR(gPhysicalMapping);
  733.         gIOTable.options = kIOMinimalLogicalMapping | kIOLogicalRanges | kIOIsInput;
  734.         gIOTable.state = 0;
  735.         gIOTable.addressSpace = kCurrentAddressSpaceID;
  736.         gIOTable.granularity = granularity;
  737.         gIOTable.firstPrepared = 0;
  738.         gIOTable.lengthPrepared = 0;
  739.         if (gIOTable.granularity == 0)
  740.             gIOTable.mappingEntryCount = GetMapEntryCount(areaAddress, simpleAreaPtr->byteCount);
  741.         else {
  742.             gIOTable.mappingEntryCount = GetMapEntryCount(0, gIOTable.granularity);
  743.         }
  744.         gIOTable.logicalMapping = gLogicalMapping;
  745.         gIOTable.physicalMapping = gPhysicalMapping;
  746.         gIOTable.rangeInfo.range.base = areaAddress;
  747.         gIOTable.rangeInfo.range.length = simpleAreaPtr->byteCount;
  748.         DoPreparationAndTest();
  749. }
  750.  
  751. void
  752. TestScatterGatherArea(
  753.         const SimpleAreaPtr        sgAreaPtr,        /* Vector            */
  754.         ByteCount                granularity
  755.     )
  756. {
  757.         LogicalAddress            areaAddress;
  758.         ItemCount                totalMapAreaCount;
  759.         ItemCount                thisMapAreaCount;
  760.         UInt32                    i;
  761.  
  762.         /*
  763.          * Initialize the ioTable.
  764.          */
  765.         totalMapAreaCount = 0;
  766.         for (i = 0; sgAreaPtr[i].byteCount != 0; i++) {
  767.             areaAddress = &gWorkAreaStart[sgAreaPtr[i].offset];
  768.             thisMapAreaCount = GetMapEntryCount(areaAddress, sgAreaPtr[i].byteCount);
  769.             totalMapAreaCount += thisMapAreaCount;
  770.             printf("%2lu: %08lx, %6lu offset, %6lu byteCount, %2lu map count\n",
  771.                 i,
  772.                 areaAddress,
  773.                 sgAreaPtr[i].offset,
  774.                 sgAreaPtr[i].byteCount,
  775.                 thisMapAreaCount
  776.             );
  777.             gScatterGatherTable[i].base = areaAddress;
  778.             gScatterGatherTable[i].length = sgAreaPtr[i].byteCount;
  779.         }
  780.         printf("%lu total mapping entries\n", totalMapAreaCount);
  781.         CLEAR(gIOTable);
  782.         CLEAR(gLogicalMapping);
  783.         CLEAR(gPhysicalMapping);
  784.         gIOTable.options = kIOMinimalLogicalMapping | kIOLogicalRanges | kIOIsInput;
  785.         gIOTable.options |= kIOMultipleRanges;
  786.         gIOTable.state = 0;
  787.         gIOTable.addressSpace = kCurrentAddressSpaceID;
  788.         gIOTable.granularity = granularity;
  789.         gIOTable.firstPrepared = 0;
  790.         gIOTable.lengthPrepared = 0;
  791.         if (gIOTable.granularity == 0)
  792.             gIOTable.mappingEntryCount = totalMapAreaCount;
  793.         else {
  794.             gIOTable.mappingEntryCount = GetMapEntryCount(0, gIOTable.granularity);
  795.         }
  796.         gIOTable.mappingEntryCount = totalMapAreaCount;
  797.         gIOTable.logicalMapping = gLogicalMapping;
  798.         gIOTable.physicalMapping = gPhysicalMapping;
  799.         gIOTable.rangeInfo.multipleRanges.entryCount = i;
  800.         gIOTable.rangeInfo.multipleRanges.rangeTable = &gScatterGatherTable[0];
  801.         DoPreparationAndTest();
  802. }
  803.  
  804. void
  805. DoPreparationAndTest(void)
  806. {
  807.         OSStatus                osStatus;
  808.  
  809.         do {
  810.             printf("\n -- Preparation: first prepared = %ld\n", gIOTable.firstPrepared);
  811.             osStatus = PrepareMemoryForIO(&gIOTable);
  812.             if (osStatus != noErr) {
  813.                 printf("PrepareMemoryForIO error: %ld\n", (long) osStatus);
  814.                 exit(EXIT_FAILURE);
  815.             }
  816.             else {
  817.                 TestThisPreparation();
  818.             }
  819.             CheckpointIO(gIOTable.preparationID, kNilOptions);
  820.             gIOTable.firstPrepared += gIOTable.lengthPrepared;
  821.         } while (osStatus == noErr && (gIOTable.state & kIOStateDone) == 0);
  822. }
  823.  
  824. void
  825. TestThisPreparation(void)
  826. {
  827.         OSStatus                osStatus;
  828.         AddressRange            thisTransfer;
  829.         UInt32                    totalTransferCount;
  830.         Boolean                    isLogical;
  831.         ItemCount                pass;
  832.  
  833.         DumpPrepareIOTable(&gIOTable);
  834.         osStatus = InitializeDMATransfer(&gIOTable, 8, &gDMATable);
  835.         if (osStatus == eofErr) {
  836.             printf("EOF from InitializeDMATransfer\n");
  837.             return;
  838.         }
  839.         else if (osStatus != noErr) {
  840.             printf("InitializeDMATransfer error: %ld\n", (long) osStatus);
  841.             exit(EXIT_FAILURE);
  842.         }
  843.         pass = 0;
  844.         totalTransferCount = 0;
  845.         while (osStatus == noErr) {
  846.             osStatus = PrepareDMATransfer(&gDMATable, &thisTransfer, &isLogical);
  847.             if (0 && pass == 0)
  848.                 DumpDMATable(&gDMATable);
  849.             if (osStatus == eofErr) {
  850.                 printf("At normal end\n");
  851.                 break;
  852.             }
  853.             if (osStatus != noErr) {
  854.                 printf("Failure: %ld\n", (long) osStatus);
  855.                 exit(EXIT_FAILURE);
  856.             }
  857.             /* Got the data */
  858.             totalTransferCount += thisTransfer.length;
  859.             printf("%ld %ld: %8lx base, %6lu length, %s, map %2lu,"
  860.                     " first %6lu, length %6lu: %6lu\n",
  861.                 pass,
  862.                 gDMATable.scatterGatherIndex,
  863.                 thisTransfer.base, thisTransfer.length,
  864.                 (isLogical) ? " logical" : "physical",
  865.                 (UInt32) gDMATable.physicalMapIndex,
  866.                 (UInt32) gDMATable.physicalStart,
  867.                 (UInt32) gDMATable.physicalEnd,
  868.                 totalTransferCount
  869.             );
  870.             ++pass;
  871.         }
  872. }
  873.  
  874. void
  875. DumpPrepareIOTable(
  876.         IOPreparationTable        *ioTable
  877.     )
  878. {
  879.         UInt32                    i;
  880.         UInt32                    totalMapCount;
  881.         UInt32                    thisMapCount;
  882.         UInt32                    thisTransferCount;
  883.         UInt32                    totalTransferCount;
  884.  
  885.         totalMapCount = 0;
  886.         totalTransferCount = 0;
  887.         printf("%6ld granularity, %6ld first prepared, %6ld length prepared, %ld state\n",
  888.             ioTable->granularity,
  889.             ioTable->firstPrepared,
  890.             ioTable->lengthPrepared,
  891.             (unsigned long) ioTable->state
  892.         );
  893.         if ((ioTable->options & kIOMultipleRanges) != 0) {
  894.             /*
  895.              * Scatter-gather table
  896.              */
  897.             printf("%ld range%s\n",
  898.                 ioTable->rangeInfo.multipleRanges.entryCount,
  899.                 (ioTable->rangeInfo.multipleRanges.entryCount == 1) ? "" : "s"
  900.             );
  901.             for (i = 0; i < ioTable->rangeInfo.multipleRanges.entryCount; i++) {
  902.                 thisTransferCount = ioTable->rangeInfo.multipleRanges.rangeTable[i].length;
  903.                 thisMapCount = GetMapEntryCount(
  904.                             ioTable->rangeInfo.multipleRanges.rangeTable[i].base,
  905.                             thisTransferCount
  906.                         );
  907.                 totalMapCount += thisMapCount;
  908.                 totalTransferCount += thisTransferCount;
  909.                 printf("%2ld: %08lx %6ld, logicalMap %08lx %08lx, page %2ld\n",
  910.                     i,
  911.                     ioTable->rangeInfo.multipleRanges.rangeTable[i].base,
  912.                     thisTransferCount,
  913.                     ioTable->logicalMapping[i * 2],
  914.                     ioTable->logicalMapping[(i * 2) + 1],
  915.                     thisMapCount
  916.                 );
  917.             }
  918.         }
  919.         else {
  920.             /*
  921.              * Simple table.
  922.              */
  923.             thisMapCount = GetMapEntryCount(
  924.                         ioTable->rangeInfo.range.base,
  925.                         ioTable->rangeInfo.range.length
  926.             );
  927.             totalMapCount += thisMapCount;
  928.             thisTransferCount = ioTable->rangeInfo.range.length;
  929.             totalTransferCount += thisTransferCount;
  930.             printf("%08lx %6ld, logicalMap %08lx %08lx, page %2ld\n",
  931.                 ioTable->rangeInfo.range.base,
  932.                 thisTransferCount,
  933.                 ioTable->logicalMapping[0],
  934.                 ioTable->logicalMapping[1],
  935.                 thisMapCount
  936.             );
  937.         }
  938.         printf("%ld total transfer, physical map %ld allocated, %ld found\n",
  939.             totalTransferCount,
  940.             ioTable->mappingEntryCount,
  941.             totalMapCount
  942.         );
  943.         for (i = 0; i < ioTable->mappingEntryCount; i++)
  944.             printf("%2d: %08lx\n", (int) i, ioTable->physicalMapping[i]);
  945. }
  946.  
  947. void
  948. DumpDMATable(
  949.         DMATransferInfo            *dmaTable
  950.     )
  951. {
  952.         printf("%8lu logicalAlignment\n",         dmaTable->logicalAlignment);
  953.         printf("%8lu scatterGatherIndex\n",     dmaTable->scatterGatherIndex);
  954.         printf("%8lu physicalMapIndex\n",         dmaTable->physicalMapIndex);
  955.         printf("%8lu physicalStart\n",             dmaTable->physicalStart);
  956.         printf("%8lu physicalEnd\n",             dmaTable->physicalEnd);
  957.         printf("%08lx physicalRange.base\n",     dmaTable->physicalRange.base);
  958.         printf("%8lu physicalRange.length\n",     dmaTable->physicalRange.length);
  959.         printf("%08lx logicalStart.base\n",     dmaTable->logicalStart.base);
  960.         printf("%8lu logicalStart.length\n",     dmaTable->logicalStart.length);
  961.         printf("%08lx logicalEnd.base\n",         dmaTable->logicalEnd.base);
  962.         printf("%8lu logicalEnd.length\n",         dmaTable->logicalEnd.length);
  963. }
  964.  
  965. ItemCount
  966. GetMapEntryCount(
  967.         void                    *areaBaseAddress,
  968.         ByteCount                areaLength
  969.     )
  970. {
  971.         ItemCount                result;
  972.         ByteCount                normalizedLength;
  973.         UInt32                    areaAddress;
  974.         
  975.         areaAddress = (UInt32) areaBaseAddress;
  976.         normalizedLength = PageBaseAddress(areaAddress + areaLength - 1)
  977.                          - PageBaseAddress(areaAddress);
  978.         result = (ItemCount) (normalizedLength / gPageSize) + 1;
  979.         return (result);
  980. }
  981.  
  982. #endif
  983.  
  984.  
  985.