www.pudn.com > PCIÇý¶¯ÊµÀý.zip > READ_WRITE.C


/////////////////////////////////////////////////////////////////////////////// 
// 
//    (C) Copyright 1995 - 1997 OSR Open Systems Resources, Inc. 
//    All Rights Reserved 
// 
//    This sofware is supplied for instructional purposes only. 
// 
//    OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty 
//    for this software.  THIS SOFTWARE IS PROVIDED  "AS IS" WITHOUT WARRANTY 
//    OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, 
//    THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR 
//    PURPOSE.  THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS 
//    WITH YOU.  OSR's entire liability and your exclusive remedy shall not 
//    exceed the price paid for this material.  In no event shall OSR or its 
//    suppliers be liable for any damages whatsoever (including, without 
//    limitation, damages for loss of business profit, business interruption, 
//    loss of business information, or any other pecuniary loss) arising out 
//    of the use or inability to use this software, even if OSR has been 
//    advised of the possibility of such damages.  Because some states/ 
//    jurisdictions do not allow the exclusion or limitation of liability for 
//    consequential or incidental damages, the above limitation may not apply 
//    to you. 
// 
//    OSR Open Systems Resources, Inc. 
//    105 Route 101A Suite 19 
//    Amherst, NH 03031  (603) 595-6500 FAX: (603) 595-6503 
//    email bugs to: bugs@osr.com 
// 
//                        
//    MODULE: 
// 
//        READ_WRITE.C 
// 
//    ABSTRACT: 
// 
//      This file contains read and write routines used by the 
//      PCI Busmaster DMA device driver for the AMCC 5933 chip. 
// 
//    AUTHOR(S): 
// 
//        OSR Open Systems Resources, Inc. 
//  
//    REVISION:    
// 
// 
/////////////////////////////////////////////////////////////////////////////// 
 
#include "osr-pci.h" 
 
// 
// forward declarations 
// 
BOOLEAN OsrStartReadOnDevice(IN PVOID SynchronizeContext); 
BOOLEAN OsrStartWriteOnDevice(IN PVOID SynchronizeContext); 
 
IO_ALLOCATION_ACTION  OsrAdapterControlRead(IN PDEVICE_OBJECT DeviceObject, 
                                IN PIRP NotUsed, IN PVOID MapRegisterBase, 
                                IN PVOID Context); 
IO_ALLOCATION_ACTION  OsrAdapterControlWrite(IN PDEVICE_OBJECT DeviceObject, 
                                IN PIRP NotUsed, IN PVOID MapRegisterBase, 
                                IN PVOID Context); 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  OsrWrite 
// 
//    This is the write dispatch entry point for the driver, called when the 
//    I/O Manager has an IRP_MJ_WRITE request for the driver to process. 
// 
//  INPUTS: 
// 
//      DeviceObject - Address of the DEVICE_OBJECT for our device. 
//   
//    Irp - Address of the IRP representing the IRP_MJ_WRITE call. 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//    STATUS_PENDING, since we are putting the IRP on our internal queue. 
// 
//  IRQL: 
// 
//    This routine is called at IRQL_PASSIVE_LEVEL. 
// 
//  NOTES: 
// 
//    Since we set the DO_DIRECT_IO bit in the Device Object, all buffers 
//    passed to us will have been probed and locked and described by an MDL. 
//    The I/O manager will provides us the MDL address in Irp->MdlAddress. 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS OsrWrite(PDEVICE_OBJECT DeviceObject, PIRP Irp) 
{ 
    POSR_DEVICE_EXT devExt = DeviceObject->DeviceExtension; 
    KIRQL oldIrql; 
    NTSTATUS code = STATUS_SUCCESS; 
    BOOLEAN listWasEmpty; 
    PIO_STACK_LOCATION ioStack; 
    ULONG temp; 
             
#if DBG 
    DbgPrint("OsrWrite: entered\n"); 
#endif 
 
    // 
    // Validate the IRP we've received 
    // 
    ioStack = IoGetCurrentIrpStackLocation(Irp); 
 
    // 
    // If the length of the requested transfer is either zero or too long, 
    // we immediately compelte the IRP with an error status. 
    // 
    if (ioStack->Parameters.Write.Length == 0 || 
        ioStack->Parameters.Write.Length > OSR_PCI_MAX_TXFER)  { 
             
        Irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER; 
        Irp->IoStatus.Information = 0; 
 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
 
        return(STATUS_INVALID_USER_BUFFER); 
 
    } 
     
    // Take out the Write list lock, since we'll insert this IRP 
    // onto the write queue 
    // 
    KeAcquireSpinLock(&devExt->WriteQueueLock, &oldIrql); 
 
    // 
    // Since we'll probably be queuing this request, set a routine  
    // to be called by the I/O Manager in case he needs to cancel 
    // this IRP. 
    // 
    IoSetCancelRoutine(Irp, OsrCancelFromWriteQueue); 
 
    // 
    // Before we queue this request, has it been cancelled?? 
    // 
    // What we're doing here is closing that tiny window between the time 
    // the Dispatch routine is called and when we acquired the queue spin 
    // lock.  Once the queue spin lock is held, and the IRP is queued, the 
    // cancellation routine will deal with any requests to cancel the IRP. 
    // 
    if (Irp->Cancel)  { 
         
        // 
        // Can't complete a request with a valid cancel routine! 
        // 
        // TECHNICAL ERRATA: Page 466, Example 17.5 has the following 
        // line, which is obviously in error: 
        // 
        // IoSetCancelRoutine(Irp, OsrCancelFromWriteQueue); 
        //  
        // This line SHOULD READ: 
        // 
        IoSetCancelRoutine(Irp, NULL); 
          
        KeReleaseSpinLock(&devExt->WriteQueueLock, oldIrql); 
 
        Irp->IoStatus.Status = STATUS_CANCELLED; 
        Irp->IoStatus.Information = 0; 
 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
 
        return(STATUS_CANCELLED); 
    } 
 
    // 
    // If we get this far, we will return with this request pending 
    // 
    IoMarkIrpPending(Irp); 
 
    // 
    // Do we need to start this request on the device? 
    // 
    // If there is no IRP currently in progress, we'll start the 
    // one we've just received. 
    // 
    if (devExt->CurrentWriteIrp == NULL)  { 
                 
        // 
        // No write presently active.  Start this request... 
        // (Note that we're still holding the queue lock here) 
        // 
        OsrStartWriteIrp(DeviceObject,Irp); 
 
    } else { 
 
        // 
        // Put this request on the end of the write queue 
        // 
        InsertTailList(&devExt->WriteQueue, &Irp->Tail.Overlay.ListEntry); 
 
    } 
 
    // 
    // We're done playing with the write queue now 
    // 
    KeReleaseSpinLock(&devExt->WriteQueueLock, oldIrql); 
     
#if DBG 
    DbgPrint("OsrWrite: exiting\n"); 
#endif 
 
    return(STATUS_PENDING); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  OsrRead 
// 
//    This is the read dispatch entry point for the driver, called when the 
//    I/O Manager has an IRP_MJ_READ request for the driver to process. 
// 
//  INPUTS: 
// 
//      DeviceObject - Address of the DEVICE_OBJECT for our device. 
//   
//    Irp - Address of the IRP representing the IRP_MJ_READ call. 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//    STATUS_PENDING, since we are putting the IRP on our internal queue. 
// 
//  IRQL: 
// 
//    This routine is called at IRQL_PASSIVE_LEVEL. 
// 
//  NOTES: 
// 
//    Since we set the DO_DIRECT_IO bit in the Device Object, all buffers 
//    passed to us will have been probed and locked and described by an MDL. 
//    The I/O manager will provides us the MDL address in Irp->MdlAddress. 
// 
/////////////////////////////////////////////////////////////////////////////// 
NTSTATUS OsrRead(PDEVICE_OBJECT DeviceObject, PIRP Irp) 
{ 
    POSR_DEVICE_EXT devExt = DeviceObject->DeviceExtension; 
    KIRQL oldIrql; 
    NTSTATUS code = STATUS_SUCCESS; 
    BOOLEAN listWasEmpty; 
    PIO_STACK_LOCATION ioStack; 
    ULONG temp; 
             
#if DBG 
    DbgPrint("OsrRead: entered\n"); 
#endif 
 
    // 
    // Validate the IRP we've received 
    // 
    ioStack = IoGetCurrentIrpStackLocation(Irp); 
 
    // 
    // If the length of the requested transfer is either zero or too long, 
    // we immediately compelte the IRP with an error status. 
    // 
    if (ioStack->Parameters.Read.Length == 0 || 
        ioStack->Parameters.Read.Length > OSR_PCI_MAX_TXFER)  { 
             
        Irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER; 
        Irp->IoStatus.Information = 0; 
 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
 
        return(STATUS_INVALID_USER_BUFFER); 
 
    } 
 
    // 
    // Get the Read Queue lock, so we can insert our IRP 
    // 
    KeAcquireSpinLock(&devExt->ReadQueueLock, &oldIrql); 
 
    // 
    // Since we'll probably be queuing this request, set a routine  
    // to be called by the I/O Manager in case he needs to cancel 
    // this IRP. 
    // 
    IoSetCancelRoutine(Irp, OsrCancelFromReadQueue); 
 
    // 
    // Do we need to cancel this IRP, instead of queue it? 
    // 
    if (Irp->Cancel)  { 
         
        // 
        // Can't complete a request with a valid cancel routine! 
        // 
        IoSetCancelRoutine(Irp, NULL); 
     
        KeReleaseSpinLock(&devExt->ReadQueueLock, oldIrql); 
 
        Irp->IoStatus.Status = STATUS_CANCELLED; 
        Irp->IoStatus.Information = 0; 
 
        IoCompleteRequest(Irp, IO_NO_INCREMENT); 
 
        return(STATUS_CANCELLED); 
    } 
 
    // 
    // We'll be returning with this request pending 
    // 
    IoMarkIrpPending(Irp); 
 
    // 
    // Do we need to start this request on the device? 
    // 
    // If there is no IRP currently in progress, we'll start the 
    // one we've just received. 
    // 
    if (devExt->CurrentReadIrp == NULL)  { 
                 
        // 
        // No read operation presently active.  Start this request... 
        // (Note that we're still holding the queue lock here) 
        // 
        OsrStartReadIrp(DeviceObject,Irp); 
 
    } else { 
 
        // 
        // Put this request on the end of the write queue 
        // 
        InsertTailList(&devExt->ReadQueue, &Irp->Tail.Overlay.ListEntry); 
 
    } 
 
    // 
    // We're done 
    // 
    KeReleaseSpinLock(&devExt->ReadQueueLock, oldIrql); 
     
#if DBG 
    DbgPrint("OsrRead: exiting\n"); 
#endif 
 
      return(STATUS_PENDING); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  OsrStartWriteIrp 
// 
//    This is routine is called by the OsrWrite and DpcForIsr routine to 
//    start a new Write operation.  The request started is the IRP located 
//    at the head of the write queue. 
// 
//  INPUTS: 
// 
//      DeviceObject - Address of the DEVICE_OBJECT for our device. 
//   
//      Irp - Address of the IRP representing the IRP_MJ_WRITE call. 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//      None. 
// 
//  IRQL: 
// 
//      This routine is called at IRQL_DISPATCH_LEVEL. 
// 
//  NOTES: 
//      *** Called (and returns) with the WriteQueueLock held. 
// 
/////////////////////////////////////////////////////////////////////////////// 
VOID 
OsrStartWriteIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp) 
{ 
    POSR_DEVICE_EXT devExt = DeviceObject->DeviceExtension; 
    PIO_STACK_LOCATION ioStack; 
    ULONG mapRegsNeeded; 
     
    ioStack = IoGetCurrentIrpStackLocation(Irp); 
 
    // 
    // In progress IRPs cannot be cancelled 
    // 
    IoSetCancelRoutine(Irp, NULL); 
 
#if DBG 
    DbgPrint("OsrWrite: Transfer length %d.\n", 
                                ioStack->Parameters.Write.Length); 
#endif 
 
    // 
    // There is no in-progress request.  Start this request on the 
    // device. 
    // 
    devExt->CurrentWriteIrp = Irp; 
 
    devExt->WriteTotalLength = ioStack->Parameters.Write.Length; 
 
    devExt->WriteSoFar = 0; 
 
    devExt->WriteStartingOffset = 0; 
 
    // 
    // Start the watchdog timer on this IRP 
    // 
    (ULONG)Irp->Tail.Overlay.DriverContext[0] = OSR_WATCHDOG_INTERVAL; 
 
    // 
    // Since we're about to initiate a DMA operation, ensure the user's data 
    // buffer is flushed from the cache back into memory, on processors that 
    // are non-DMA cache coherent. 
    // 
    KeFlushIoBuffers(Irp->MdlAddress, FALSE, TRUE); 
 
    // 
    // Determine the number of map registers we'll need for this transfer 
    // 
    mapRegsNeeded =  
        ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress), 
                                        ioStack->Parameters.Write.Length); 
         
#if DBG 
    DbgPrint("StartWrite: %d. map regs needed\n", mapRegsNeeded); 
#endif 
 
    // 
    // If the number of map registers required for this transfer exceeds the 
    // maximum we're allowed to use (as reported to us from HalGetAdapter() ), 
    // we'll need to limit ourselves to the maximum we're allowed. 
    // 
    devExt->MapRegsThisWrite = ((mapRegsNeeded > devExt->WriteMapRegsGot) ?  
                              devExt->WriteMapRegsGot : mapRegsNeeded); 
 
#if DBG 
    DbgPrint("StartWrite: %d. map regs this xfer\n", devExt->MapRegsThisWrite); 
#endif 
 
    // 
    // Ready to GO! Allocate the appropriate Adapter Object and map registers. 
    // 
    IoAllocateAdapterChannel(devExt->WriteAdapter, 
                             DeviceObject,  
                             devExt->MapRegsThisWrite, 
                             OsrAdapterControlWrite, 
                             Irp); 
} 
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  OsrStartReadIrp 
// 
//    This is routine is called by the OsrRead and Dpc routine in order to 
//    begin a new Read operation. 
// 
//  INPUTS: 
// 
//      DeviceObject - Address of the DEVICE_OBJECT for our device. 
//   
//      Irp - Address of the IRP representing the IRP_MJ_READ call. 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//      None. 
// 
//  IRQL: 
// 
//      This routine is called at IRQL_DISPATCH_LEVEL. 
// 
//  NOTES: 
//      *** Called (and returns) with the WriteQueueLock held. 
// 
/////////////////////////////////////////////////////////////////////////////// 
VOID 
OsrStartReadIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp) 
{ 
    POSR_DEVICE_EXT devExt = DeviceObject->DeviceExtension; 
    PIO_STACK_LOCATION ioStack; 
    ULONG mapRegsNeeded; 
 
    ioStack = IoGetCurrentIrpStackLocation(Irp); 
 
    // 
    // In progress IRPs cannot be cancelled 
    // 
    IoSetCancelRoutine(Irp, NULL); 
 
#if DBG 
    DbgPrint("OsrRead: Transfer length %d.\n", 
                                ioStack->Parameters.Read.Length); 
#endif 
 
    // 
    // There is no in-progress request.  Start this request on the 
    // device. 
    // 
    devExt->CurrentReadIrp = Irp; 
 
    devExt->ReadTotalLength = ioStack->Parameters.Read.Length; 
 
    devExt->ReadSoFar = 0; 
 
    devExt->ReadStartingOffset = 0; 
 
    // 
    // Start the watchdog timer on this IRP 
    // 
    (ULONG)Irp->Tail.Overlay.DriverContext[0] = OSR_WATCHDOG_INTERVAL; 
 
    // 
    // Flush the requestor's buffer back from cache on non-dma coherent 
    // machines. 
    // 
    KeFlushIoBuffers(Irp->MdlAddress, TRUE, TRUE); 
 
    // 
    // Determine number of map registers required by this read 
    // 
    mapRegsNeeded =  
        ADDRESS_AND_SIZE_TO_SPAN_PAGES(MmGetMdlVirtualAddress(Irp->MdlAddress), 
                                        ioStack->Parameters.Read.Length); 
         
#if DBG 
    DbgPrint("StartReadIrp: %d. map regs needed\n", mapRegsNeeded); 
#endif 
 
    // 
    // Limit the number of map registers used to the maximum allowed by the 
    // HAL.  We determined this max when we called HalGetAdapter() during 
    // our DriverEntry processing. 
    // 
    devExt->MapRegsThisRead = ((mapRegsNeeded > devExt->ReadMapRegsGot) ?  
                              devExt->ReadMapRegsGot : mapRegsNeeded); 
 
#if DBG 
    DbgPrint("StartReadIrp: %d. map regs this xfer\n", devExt->MapRegsThisRead); 
#endif 
 
    IoAllocateAdapterChannel(devExt->ReadAdapter, 
                             DeviceObject,  
                             devExt->MapRegsThisRead, 
                             OsrAdapterControlRead, 
                             Irp); 
} 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  OsrAdapterControlRead 
// 
//    This is routine is called by the I/O Manager when the Adapter resources 
//    (such as map registers) requested by the OsrStartReadIrp function are 
//    available for our use. 
// 
//  INPUTS: 
// 
//      DeviceObject - Address of the DEVICE_OBJECT for our device. 
//   
//      MapRegisterBase - Base address of the Map registers that have been 
//                        reserved for us use. 
// 
//       Context - address of the Read Irp for the operation to be started 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//    DeallocateObjectKeepRegisters - indicates that the Mapping Registers that 
//              were allocated to us should not be deallocated at this time.  We 
//              will deallocate them from the DpcForIsr when the Read completes. 
// 
//  IRQL: 
// 
//    This routine is called at IRQL_DISPATCH_LEVEL. 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
IO_ALLOCATION_ACTION  
OsrAdapterControlRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP NotUsed,  
                                  IN PVOID MapRegisterBase, IN PVOID Context) 
{ 
    PIRP irp = (PIRP) Context; 
    PIO_STACK_LOCATION ioStack; 
    POSR_DEVICE_EXT devExt; 
    PUCHAR baseVa; 
 
#if DBG 
    DbgPrint("AdapterControlRead: Irp = 0x%0x\n", irp); 
    DbgPrint("AdapterControlRead: Map Register Base = 0x%0x\n", MapRegisterBase); 
#endif 
 
    devExt = DeviceObject->DeviceExtension; 
     
    ioStack = IoGetCurrentIrpStackLocation(irp); 
 
    devExt->ReadLength = ioStack->Parameters.Read.Length - devExt->ReadSoFar; 
 
#if DBG 
    DbgPrint("AdapterControlRead: Length remaining = %d. \n", devExt->ReadLength); 
#endif 
 
    // 
    // Get set-up for the transfer 
    // 
    devExt->ReadMapRegBase = MapRegisterBase; 
 
    devExt->ReadStartingOffset =  devExt->ReadSoFar; 
 
    // 
    // Get requestor's virtual address of the buffer.  This is used by 
    // IoMapTransfer() as an index into the buffer to track the progress 
    // of the map operation. 
    // 
    baseVa = MmGetMdlVirtualAddress(irp->MdlAddress); 
 
    // 
    // Get the logical base address and length of a fragment of the  
    // requestor's buffer. 
    // 
    // Even though we are a Busmaster device, our device does not support 
    // scatter/gather.  Thus, we can only use a single base address and length 
    // at a time.  If the requestor's buffer has more fragments, we will 
    // do additional DMA operations (one for each fragment) until the entire 
    // transfer has been completed. 
    // 
    devExt->ReadPaToDevice = IoMapTransfer(NULL, 
                                   irp->MdlAddress, 
                                   MapRegisterBase, 
                                   baseVa+(devExt->ReadSoFar), 
                                   &devExt->ReadLength, 
                                   FALSE);  // FALSE = READ from device 
 
 
    // 
    // Track the length of the requestor's buffer we've read so far. 
    // 
    devExt->ReadSoFar += devExt->ReadLength; 
 
    // 
    // Start the request on the device -- Base Address and Length 
    // of this fragment are stored in the device extension 
    // 
    (VOID)KeSynchronizeExecution(devExt->InterruptObject, 
                            OsrStartReadOnDevice, 
                            DeviceObject); 
 
    return(DeallocateObjectKeepRegisters); 
}         
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  OsrAdapterControlWrite 
// 
//    This is routine is called by the I/O Manager when the Adapter resources 
//    (such as map registers) requested by the OsrStartWriteIrp function are 
//    available for our use. 
// 
//  INPUTS: 
// 
//      DeviceObject - Address of the DEVICE_OBJECT for our device. 
//   
//      MapRegisterBase - Base address of the Map registers that have been 
//                      reserved by the I/O Manager and HAL for our use. 
// 
//      Context - address of the Write Irp for the operation to be started on the  
//              device. 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//    DeallocateObjectKeepRegisters - indicates that the map registers that 
//            were allocated to us should not be deallocated at this time. 
//            We will deallocate them with the Read operation completes. 
// 
//  IRQL: 
// 
//    This routine is called at IRQL_DISPATCH_LEVEL. 
// 
//  NOTES: 
// 
/////////////////////////////////////////////////////////////////////////////// 
IO_ALLOCATION_ACTION  
OsrAdapterControlWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP NotUsed,  
                                  IN PVOID MapRegisterBase, IN PVOID Context) 
{ 
    PIRP irp = (PIRP) Context; 
    PIO_STACK_LOCATION ioStack; 
    POSR_DEVICE_EXT devExt; 
    PUCHAR baseVa; 
 
#if DBG 
    DbgPrint("AdapterControlWrite: Irp = 0x%0x\n", irp); 
#endif 
 
    devExt = DeviceObject->DeviceExtension; 
 
    ioStack = IoGetCurrentIrpStackLocation(irp); 
 
    devExt->WriteLength = ioStack->Parameters.Write.Length - devExt->WriteSoFar; 
 
#if DBG 
    DbgPrint("AdapterControlWrite: Length remaining = %d. \n", devExt->WriteLength); 
#endif 
 
    // 
    // Get set-up for the transfer 
    // 
    devExt->WriteMapRegBase = MapRegisterBase; 
 
    baseVa = MmGetMdlVirtualAddress(irp->MdlAddress); 
 
    devExt->WriteStartingOffset =  devExt->WriteSoFar; 
 
    // 
    // Get the base address and length of the segment to write. 
    // 
    devExt->WritePaToDevice = IoMapTransfer(NULL, 
                                   irp->MdlAddress, 
                                   MapRegisterBase, 
                                   baseVa+(devExt->WriteSoFar), 
                                   &devExt->WriteLength, 
                                   TRUE);      // WriteToDevice 
 
    // 
    // Update the length transfered so far 
    // 
    devExt->WriteSoFar += devExt->WriteLength; 
 
    // 
    // Put the request on the device 
    // 
    (VOID)KeSynchronizeExecution(devExt->InterruptObject, 
                            OsrStartWriteOnDevice, 
                            DeviceObject); 
 
    return(DeallocateObjectKeepRegisters); 
}         
 
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  OsrStartReadOnDevice 
// 
//      This function performs all the actual hardware manipulation to initiate 
//      a new read request on the AMCC device.  When called, all resources 
//      (mapping registers) have been allocated for the operation, and we have 
//      a base address and length of a buffer fragment to be DMA'ed. 
// 
//  INPUTS: 
// 
//      DeviceObject - Address of the DEVICE_OBJECT for our device. 
//   
//      BaseAddress  - Logical base address of the requestor's buffer fragment 
//                      to be used as the base address of the transfer 
// 
//      Length - Length in bytes of this fragment to be transfered. 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//      None. 
// 
//  IRQL: 
// 
//      This routine is called at IRQL_DISPATCH_LEVEL. 
// 
//  NOTES: 
// 
//      When this routine is called, no other Read operations are in progress on 
//      the device. 
// 
/////////////////////////////////////////////////////////////////////////////// 
BOOLEAN 
OsrStartReadOnDevice(IN PVOID SynchronizeContext) 
{ 
    ULONG temp; 
    PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT)SynchronizeContext; 
    PHYSICAL_ADDRESS baseAddress; 
    ULONG length; 
    POSR_DEVICE_EXT devExt = deviceObject->DeviceExtension; 
 
    baseAddress = devExt->ReadPaToDevice; 
    length = devExt->ReadLength; 
 
#if DBG 
    DbgPrint("StartReadOnDev: Reading BA = 0x%0x, Length = %d.\n", 
                        baseAddress.LowPart, length); 
#endif 
 
    // 
    // Pass the device the Physical Base Address of the buffer 
    // 
    ASSERT(!baseAddress.HighPart); 
 
    WRITE_PORT_ULONG(devExt->AmccBaseRegisterAddress+MWAR_OFF, 
                     baseAddress.LowPart); 
 
    // 
    // ...and the length of the read 
    // 
    WRITE_PORT_ULONG(devExt->AmccBaseRegisterAddress+MWTC_OFF, length); 
 
    // 
    // Tell the device to interrupt when the read is complete. 
    // 
    // NOTE: In this particular device, "read" operations from the 
    // device are called "WRITE" operations... since they write to 
    // MEMORY.  Thus, we set the INT_ON_WRITE bit in the Interrupt 
    // CSR. 
    // 
    temp = READ_PORT_ULONG(devExt->AmccBaseRegisterAddress+ICSR_OFF); 
 
#if DBG 
    DbgPrint("StartDmaRead: Current INTCSR State:\n"); 
    OsrPrintIntcsr(temp); 
#endif 
 
    temp &= ~AMCC_INT_ACK_BITS; 
    temp |= AMCC_INT_INT_ON_WRITE; 
     
    WRITE_PORT_ULONG(devExt->AmccBaseRegisterAddress+ICSR_OFF, temp); 
 
    // 
    // Yeeeeha!  Start the request by settting the "Write Enable" 
    // bit in the master CSR 
    // 
    temp = READ_PORT_ULONG(devExt->AmccBaseRegisterAddress+MCSR_OFF); 
    temp &= (AMCC_MCSR_READ_ENABLE        | 
                AMCC_MCSR_READ_FIFO_MGMT  | 
                AMCC_MCSR_READ_PRIORITY   | 
                AMCC_MCSR_WRITE_ENABLE    | 
                AMCC_MCSR_WRITE_FIFO_MGMT | 
                AMCC_MCSR_WRITE_PRIORITY); 
 
    temp |= AMCC_MCSR_WRITE_ENABLE; 
 
    WRITE_PORT_ULONG(devExt->AmccBaseRegisterAddress+MCSR_OFF, temp);  
 
    return(TRUE); 
}     
 
/////////////////////////////////////////////////////////////////////////////// 
// 
//  OsrStartWriteOnDevice 
// 
//      This function performs all the actual hardware manipulation to initiate 
//      a new read request on the AMCC device.  When called, all resources 
//      (mapping registers) have been allocated for the operation, and we have 
//      a base address and length of a buffer fragment to be DMA'ed. 
// 
//  INPUTS: 
// 
//      DeviceObject - Address of the DEVICE_OBJECT for our device. 
//   
//      BaseAddress  - Logical base address of the requestor's buffer fragment 
//                      to be used as the base address of the transfer 
// 
//      Length - Length in bytes of this fragment to be transfered. 
// 
//  OUTPUTS: 
// 
//      None. 
// 
//  RETURNS: 
// 
//    None. 
// 
//  IRQL: 
// 
//    This routine is called at IRQL_DISPATCH_LEVEL. 
// 
//  NOTES: 
// 
//    When this routine is called, no other Write operations are in progress on 
//    the device. 
// 
/////////////////////////////////////////////////////////////////////////////// 
BOOLEAN 
OsrStartWriteOnDevice(IN PVOID SynchronizeContext) 
{ 
    ULONG temp; 
    PDEVICE_OBJECT deviceObject = (PDEVICE_OBJECT)SynchronizeContext; 
    PHYSICAL_ADDRESS baseAddress; 
    ULONG length; 
    POSR_DEVICE_EXT devExt = deviceObject->DeviceExtension; 
 
    baseAddress = devExt->WritePaToDevice; 
    length = devExt->WriteLength; 
 
#if DBG 
    DbgPrint("StartWriteOnDev: Writing BA = 0x%0x, Length = %d.\n", 
                        baseAddress.LowPart, length); 
#endif 
 
    // 
    // Pass the device the Physical Base Address of the buffer... 
    // 
    ASSERT(!baseAddress.HighPart); 
 
    WRITE_PORT_ULONG(devExt->AmccBaseRegisterAddress+MRAR_OFF, 
                     baseAddress.LowPart); 
 
    // 
    // ...and the length of the write operation 
    // 
    WRITE_PORT_ULONG(devExt->AmccBaseRegisterAddress+MRTC_OFF, length); 
 
    // 
    // Request the device interrupt when the write operation is complete 
    // 
    temp = READ_PORT_ULONG(devExt->AmccBaseRegisterAddress+ICSR_OFF); 
 
#if DBG 
    DbgPrint("StartWriteOnDev: Current INTCSR State:\n"); 
    OsrPrintIntcsr(temp); 
#endif 
 
    temp &= ~AMCC_INT_ACK_BITS; 
    temp |= AMCC_INT_INT_ON_READ; 
    WRITE_PORT_ULONG(devExt->AmccBaseRegisterAddress+ICSR_OFF, temp); 
 
    // 
    // Yeeeeha!  Start the request by setting the appropriate enable bit. 
    // 
    temp = READ_PORT_ULONG(devExt->AmccBaseRegisterAddress+MCSR_OFF); 
    temp &= (AMCC_MCSR_READ_ENABLE| 
                AMCC_MCSR_READ_FIFO_MGMT| 
                AMCC_MCSR_READ_PRIORITY| 
                AMCC_MCSR_WRITE_ENABLE| 
                AMCC_MCSR_WRITE_FIFO_MGMT| 
                AMCC_MCSR_WRITE_PRIORITY); 
 
    temp |= AMCC_MCSR_READ_ENABLE; 
 
    WRITE_PORT_ULONG(devExt->AmccBaseRegisterAddress+MCSR_OFF, temp);  
 
    return(TRUE); 
}