Sample Code
windows driver samples/ AMCC5933 - PCI Device Driver Using WDF/ C++/ sys/ AMCC5933.c/
/*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: AMCC5933.c - Driver for the AMCC S5933 PCI chipset reference kit. Abstract: Environment: Kernel mode --*/ #include "AMCC5933.h" #include "AMCC5933.tmh" // auto-generated by WPP // // Make sure the initialization code is removed from memory after use. // #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, AmccPciAddDevice) #pragma alloc_text(PAGE, AmccPciEvtDevicePrepareHardware) #pragma alloc_text(PAGE, AmccPciEvtDeviceReleaseHardware) #pragma alloc_text(PAGE, AmccPciContextCleanup) #pragma alloc_text(PAGE, AmccPciEvtDeviceD0Exit) #endif NTSTATUS AmccPciAddDevice( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDeviceAdd is called by the framework in response to AddDevice call from the PnP manager. It is responsible for initializing and creating a WDFDEVICE object. Any work that should be done after the object is created should be deferred until EvtDeviceSoftwareInit, as that callback will be made with the device lock held (if there is one.) Arguments: Driver - Handle to a framework driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: NTSTATUS --*/ { NTSTATUS status = STATUS_SUCCESS; WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_OBJECT_ATTRIBUTES fdoAttributes; WDF_INTERRUPT_CONFIG interruptConfig; WDF_OBJECT_ATTRIBUTES interruptAttributes; WDF_IO_QUEUE_CONFIG ioQueueConfig; PAMCC_DEVICE_EXTENSION devExt; WDFQUEUE hQueue; WDFDEVICE device; PAGED_CODE(); TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_INIT, "AmccPciAddDevice: 0x%p", Driver); // // Zero out the PnpPowerCallbacks structure. // WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); // // Set Callbacks for any of the functions we are interested in. // If no callback is set, Framework will take the default action // by itself. // pnpPowerCallbacks.EvtDevicePrepareHardware = AmccPciEvtDevicePrepareHardware; pnpPowerCallbacks.EvtDeviceReleaseHardware = AmccPciEvtDeviceReleaseHardware; pnpPowerCallbacks.EvtDeviceD0Entry = AmccPciEvtDeviceD0Entry; pnpPowerCallbacks.EvtDeviceD0Exit = AmccPciEvtDeviceD0Exit; // // Register the PnP Callbacks.. // WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); // // Set various attributes for this device // WdfDeviceInitSetIoType( DeviceInit, WdfDeviceIoDirect ); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fdoAttributes, AMCC_DEVICE_EXTENSION); fdoAttributes.EvtCleanupCallback = AmccPciContextCleanup; // // We want all the queue callbacks, cancel routine, and DpcForIsr to be serialized // at the device level, so we don't have worry about any synchronization issues. // fdoAttributes.SynchronizationScope = WdfSynchronizationScopeDevice; status = WdfDeviceCreate( &DeviceInit, &fdoAttributes, &device ); if ( !NT_SUCCESS(status) ) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfDeviceInitialize failed 0x%X", status); return status; } // // Device Initialization is complete. // Get the Device Extension and initialize it. // devExt = AmccPciGetDevExt(device); devExt->Device = device; TraceEvents(TRACE_LEVEL_INFORMATION, AMCC_TRACE_INIT, "PDO 0x%p, FDO 0x%p, DevExt 0x%p", WdfDeviceWdmGetPhysicalDevice(device), WdfDeviceWdmGetDeviceObject( device ), devExt); // // This device generates an interrupt. So create an interrupt object which // will later be associated with the devices resources and connected // by the Framework. // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&interruptAttributes, INTERRUPT_DATA); // // Configure the Interrupt object // WDF_INTERRUPT_CONFIG_INIT(&interruptConfig, AmccPciEvtInterruptIsr, AmccPciEvtInterruptDpc); status = WdfInterruptCreate(device, &interruptConfig, &interruptAttributes, &devExt->WdfInterrupt); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfInterruptCreate failed: %!STATUS!\n", status); return status; } // // The S5933 requires DMA buffers be aligned on a 32-bit boundary // // NOTE: Read the existing alignment value. If it is greater than // or equal then keep it. If it is less then update the // alignment requirement field with this device's required // value. // // NOTE: See the MSDN section titled "Initializing a Device Object" // for details on how to specify this alignment value. // // NOTE: AMCC5933_ALIGNMENT__32BITS is equated to (4-1) for 32-bit // alignment. // { ULONG alignReq; alignReq = WdfDeviceGetAlignmentRequirement( device ); if (alignReq < AMCC5933_ALIGNMENT__32BITS) { // // Set the S5933 alignment requirement as new value. // WdfDeviceSetAlignmentRequirement( device, AMCC5933_ALIGNMENT__32BITS); } } // // Register I/O callbacks. // // Create a sequential IO Queue for serial operation. That means all the requests (Read/Write // & IOCTL) are serialized to the device. Until the driver completes the request presented to it, // the framework will not schedule another one. The requests held in the framework will be // cancelled automatically if the source of request (application) terminate or cancels it. // WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( &ioQueueConfig, WdfIoQueueDispatchSequential); ioQueueConfig.EvtIoDefault = AmccPciEvtIoDefault; // // By default, Static Driver Verifier (SDV) displays a warning if it // doesn't find the EvtIoStop callback on a power-managed queue. // The 'assume' below causes SDV to suppress this warning. If the driver // has not explicitly set PowerManaged to WdfFalse, the framework creates // power-managed queues when the device is not a filter driver. Normally // the EvtIoStop is required for power-managed queues, but for this driver // it is not needed b/c the driver doesn't hold on to the requests for // long time or forward them to other drivers. // If the EvtIoStop callback is not implemented, the framework waits for // all driver-owned requests to be done before moving in the Dx/sleep // states or before removing the device, which is the correct behavior // for this type of driver. If the requests were taking an indeterminate // amount of time to complete, or if the driver forwarded the requests // to a lower driver/another stack, the queue should have an // EvtIoStop/EvtIoResume. // __analysis_assume(ioQueueConfig.EvtIoStop != 0); status = WdfIoQueueCreate( device, &ioQueueConfig, WDF_NO_OBJECT_ATTRIBUTES, &hQueue ); __analysis_assume(ioQueueConfig.EvtIoStop == 0); if (!NT_SUCCESS (status)) { // // We don't have worry about deleting the device here because framework will automatically // cleanup that when the driver unloads. // TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfIoQueueCreate failed %!STATUS!", status); return status; } // // Register an interface so that application can find and talk to us. // NOTE: See the note in Public.h concerning this GUID value. // status = WdfDeviceCreateDeviceInterface( device, (LPGUID) &GUID_DEVINTERFACE_AMCC_PCI, NULL ); if (!NT_SUCCESS(status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "<-- AMCCAddDevice: WdfDeviceCreateDeviceInterface failed %!STATUS!", status); return status; } devExt->MaximumTransferLength = MAXIMUM_REQUEST_CONTEXT_LENGTH; // // Set the maximum physical pages for now, but this value may change if // there aren't enough map registers // devExt->MaximumPhysicalPages = MAXIMUM_PHYSICAL_PAGES; return status; } NTSTATUS AmccPciEvtDevicePrepareHardware( _In_ WDFDEVICE Device, _In_ WDFCMRESLIST Resources, _In_ WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: EvtDevicePrepareHardware event callback performs operations that are necessary to use the device's control registers. Arguments: Device - Handle to a framework device object. Resources - Handle to a collection of framework resource objects. This collection identifies the raw (bus-relative) hardware resources that have been assigned to the device. ResourcesTranslated - Handle to a collection of framework resource objects. This collection identifies the translated (system-physical) hardware resources that have been assigned to the device. The resources appear from the CPU's point of view. Use this list of resources to map I/O space and device-accessible memory into virtual address space Return Value: WDF status code. Let us not worry about cleaning up the resources here if we fail start, because the PNP manager will send a remove-request and we will free all the allocated resources in AmccPciEvtDeviceReleaseHardware. --*/ { ULONG i; NTSTATUS status = STATUS_SUCCESS; PAMCC_DEVICE_EXTENSION devExt = NULL; BOOLEAN foundPort = FALSE; PHYSICAL_ADDRESS portBasePA = {0}; ULONG portCount = 0; WDF_DMA_ENABLER_CONFIG dmaConfig; PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; PAGED_CODE(); // // The Resources collection is not used for PCI devices, since the PCI // bus driver manages the device's PCI Base Address Registers. // UNREFERENCED_PARAMETER( Resources ); devExt = AmccPciGetDevExt(Device); // // Parse the resource list and save the resource information. // for (i=0; i < WdfCmResourceListGetCount(ResourcesTranslated); i++) { desc = WdfCmResourceListGetDescriptor(ResourcesTranslated, i); if(!desc) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfResourceCmGetDescriptor failed"); return STATUS_DEVICE_CONFIGURATION_ERROR; } switch (desc->Type) { case CmResourceTypePort: portBasePA = desc->u.Port.Start; portCount = desc->u.Port.Length; devExt->PortMapped = (desc->Flags & CM_RESOURCE_PORT_IO) ? FALSE : TRUE; foundPort = TRUE; // // Map in the single IO Space resource. // if (devExt->PortMapped) { devExt->PortBase = (PUCHAR) MmMapIoSpace( portBasePA, portCount, MmNonCached ); if (!devExt->PortBase) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "Unable to map port range 0x%p, length %d", devExt->PortBase, devExt->PortCount); return STATUS_INSUFFICIENT_RESOURCES; } devExt->PortCount = portCount; } else { devExt->PortBase = (PUCHAR)(ULONG_PTR) portBasePA.QuadPart; devExt->PortCount = portCount; } devExt->Regs = (PREG5933) devExt->PortBase; break; default: TraceEvents(TRACE_LEVEL_WARNING, AMCC_TRACE_INIT, "Unknown resource type %d", desc->Type); break; } } if (!foundPort) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "Missing hardware resources"); return STATUS_DEVICE_CONFIGURATION_ERROR; } // // Configure the DMA object // WDF_DMA_ENABLER_CONFIG_INIT( &dmaConfig, WdfDmaProfilePacket, devExt->MaximumTransferLength ); status = WdfDmaEnablerCreate( devExt->Device, &dmaConfig, WDF_NO_OBJECT_ATTRIBUTES, &devExt->DmaEnabler ); if (!NT_SUCCESS (status)) { TraceEvents(TRACE_LEVEL_ERROR, AMCC_TRACE_INIT, "WdfDmaEnablerCreate failed %08X", status); return status; } return STATUS_SUCCESS; } NTSTATUS AmccPciEvtDeviceReleaseHardware ( _In_ WDFDEVICE hDevice, _In_ WDFCMRESLIST ResourcesTranslated ) /*++ Routine Description: EvtDeviceReleaseHardware is called by the framework whenever the PnP manager is revoking ownership of our resources. This may be in response to either IRP_MN_STOP_DEVICE or IRP_MN_REMOVE_DEVICE. The callback is made before passing down the IRP to the lower driver. In this callback, do anything necessary to free those resources. Arguments: Device - Handle to a framework device object. ResourcesTranslated - Handle to a collection of framework resource objects. This collection identifies the translated (system-physical) hardware resources that have been assigned to the device. The resources appear from the CPU's point of view. Use this list of resources to map I/O space and device-accessible memory into virtual address space Return Value: VOID --*/ { PAMCC_DEVICE_EXTENSION devExt = NULL; UNREFERENCED_PARAMETER(ResourcesTranslated); PAGED_CODE(); devExt = AmccPciGetDevExt(hDevice); // // Unmap the IO resource // if (devExt->PortBase) { if (devExt->PortMapped) { MmUnmapIoSpace( devExt->PortBase, devExt->PortCount ); } devExt->PortBase = NULL; } return STATUS_SUCCESS; } VOID AmccPciContextCleanup( _In_ WDFOBJECT Device ) /*++ Routine Description: EvtDeviceContextCleanup event callback must perform any operations that are necessary before the specified device is removed. The framework calls the driver's EvtDeviceRemove callback when the PnP manager sends an IRP_MN_REMOVE_DEVICE request to the driver stack. Function driver typically undo whatever they did in EvtDeviceSoftwareInit callback. Note: It's not necessary to delete the WDFINTERRUPT object created in EvtDeviceSoftwareInit, since the Framework will automatically clean that up. Arguments: Device - Handle to a framework device object. Return Value: VOID --*/ { PAGED_CODE(); UNREFERENCED_PARAMETER(Device); } BOOLEAN AmccPciInitializeHardware( IN PVOID Context ) /*++ Routine Description: Arguments: Context - Driver determined context information. For this driver, the context is a pointer to the device extension. Return Value: TRUE --*/ { PAMCC_DEVICE_EXTENSION devExt = Context; UNREFERENCED_PARAMETER( devExt ); return TRUE; } NTSTATUS AmccPciEvtDeviceD0Entry( _In_ IN WDFDEVICE Device, _In_ IN WDF_POWER_DEVICE_STATE PreviousState ) /*++ Routine Description: EvtDeviceD0Entry event callback must perform any operations that are necessary before the specified device is used. It will be called every time the hardware needs to be (re-)initialized. This includes after IRP_MN_START_DEVICE, IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE, IRP_MN_SET_POWER-D0. This function is not marked pageable because this function is in the device power up path. When a function is marked pagable and the code section is paged out, it will generate a page fault which could impact the fast resume behavior because the client driver will have to wait until the system drivers can service this page fault. Arguments: Device - Handle to a framework device object. PreviousState - Device power state which the device was in most recently. If the device is being newly started, this will be PowerDeviceUnspecified. Return Value: NTSTATUS --*/ { UNREFERENCED_PARAMETER(Device); UNREFERENCED_PARAMETER(PreviousState); return STATUS_SUCCESS; } NTSTATUS AmccPciEvtDeviceD0Exit( _In_ IN WDFDEVICE Device, _In_ IN WDF_POWER_DEVICE_STATE TargetState ) /*++ Routine Description: EvtDeviceD0Exit event callback must perform any operations that are necessary before the specified device is moved out of the D0 state. If the driver needs to save hardware state before the device is powered down, then that should be done here. Arguments: Device - Handle to a framework device object. TargetState - Device power state which the device will be put in once this callback is complete. Return Value: NTSTATUS --*/ { UNREFERENCED_PARAMETER(Device); UNREFERENCED_PARAMETER(TargetState); PAGED_CODE(); return STATUS_SUCCESS; }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials