www.pudn.com > PROFIBUS_DP_protocol_source.ZIP > driverwi.c, change:2004-03-17,size:14034b


//----------------------------------------------------------------------------- 
// $Id: driverwinnt.c,v 1.0.0                                       2004/01/13 
//----------------------------------------------------------------------------- 
// 
//      ProfiM - PROFIBUS MASTER DRIVER FOR WINDOWS NT/2000 
// 
// Author:   
//      Pavel Trnka, CTU FEE 
//      trnkap@seznam.cz 
// With help and advices from: 
//      Ing. Petr Smolik, CTU FEE 
//      Ing. Pavel Pisa, CTU FEE 
//      Ing. Pavel Burget, CTU FEE 
// 
//----------------------------------------------------------------------------- 
// 
// Popis: 
// ------ 
//   Cast ovladace, ktera je do projektu vkladana pokud ovladac neni prekladan 
// s podporou PnP - falesne makro PnP (vardef.h) neni nadefinovano. Prelozeny 
// ovladac je tak urcen do prostredi Windows NT. 
//   Zajistuje start ovladace vytvorenim vstupni bodu DriverEntry a ukoncovani 
// jeho cinnosti (UnloadDriver). 
// 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
 
 
 
 
 
 
//--------------------------------------------------------------------------- 
// DriverEntry 
// 
// Description: 
//  NT device Driver Entry point 
// 
// Arguments: 
//      DriverObject    - Pointer to this device's driver object 
//      RegistryPath    - Pointer to the Unicode regsitry path name 
// 
// Return Value: 
//      NTSTATUS 
// 
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, 
                      IN PUNICODE_STRING RegistryPath ) 
{ 
  PDEVICE_OBJECT            deviceObject  = NULL; 
  NTSTATUS                  status, ioConnectStatus; 
  UNICODE_STRING            uniNtNameString; 
  UNICODE_STRING            uniWin32NameString; 
  KIRQL                     irql          = DEF_IRQ_LINE; 
  KAFFINITY                 Affinity; 
  ULONG                     MappedVector, AddressSpace = 1; 
  PPROFIM_DEVICE_EXTENSION  extension; 
  BOOLEAN                   ResourceConflict; 
  PHYSICAL_ADDRESS          InPortAddr, OutPortAddr; 
 
 
  RS_DbgPrint( "ProfiM: Enter the driver!\n" ); 
  DbgPrint ("ProfiM: Version 0.025 (%s  %s)\n",__TIME__,__DATE__); 
 
  // 
  // Create counted string version of our device name. 
  // 
 
  RtlInitUnicodeString( &uniNtNameString, NT_DEVICE_NAME ); 
 
  // 
  // Create the device object, single-thread access (TRUE) 
  // 
 
  status = IoCreateDevice( DriverObject, 
                           sizeof( PROFIM_DEVICE_EXTENSION ), 
                           &uniNtNameString, 
                           FILE_DEVICE_UNKNOWN, 
                           0, 
                           TRUE, 
                           &deviceObject ); 
 
  if ( !NT_SUCCESS( status ) ) 
  { 
    RS_DbgPrint( "ProfiM: IoCreateDevice failed\n" ); 
    return status; 
  } 
 
  extension = ( PPROFIM_DEVICE_EXTENSION ) deviceObject->DeviceExtension; 
     
  // 
  // Initialize structure control identificator 
  // 
  extension->magic = PROFIM_MAGIC; 
  extension->PB.AllInitialized = FALSE; 
  extension->ContinueFrame = FALSE;   
     
  // 
  // Set the FLAGS field 
  // 
  deviceObject->Flags |= DO_BUFFERED_IO; 
 
  // 
  // Get the configuration information from the Registry 
  // 
 
  status = GetConfiguration( deviceObject->DeviceExtension, RegistryPath ); 
 
  if ( !NT_SUCCESS( status ) ) 
  { 
    RS_DbgPrint( "ProfiM: GetConfiguration failed\n" ); 
    return status; 
  } 
 
  // 
  // This call will map our IRQ to a system vector. It will also fill 
  // in the IRQL (the kernel-defined level at which our ISR will run), 
  // and affinity mask (which processors our ISR can run on). 
  // 
  // We need to do this so that when we connect to the interrupt, we 
  // can supply the kernel with this information. 
  // 
  MappedVector = HalGetInterruptVector( Isa,        // Interface type 
            0,          // Bus number 
            extension->IRQLine, extension->IRQLine, &irql,      // IRQ level 
 & Affinity   // Affinity mask 
  ); 
 
  // 
  // A little known Windows NT fact, 
  // If MappedVector==0, then HalGetInterruptVector failed. 
  // 
 
  if ( MappedVector == 0 ) 
  { 
    RS_DbgPrint( "ProfiM: HalGetInterruptVector failed\n" ); 
    return ( STATUS_INVALID_PARAMETER ); 
  } 
 
  // 
  // Save off the Irql 
  // 
 
  extension->Irql = irql; 
 
  // 
  // Translate the base port address to a system mapped address. 
  // This will be saved in the device extension after IoCreateDevice, 
  // because we use the translated port address to access the ports. 
  // 
 
  InPortAddr.LowPart = ( ULONG ) extension->PortAddress; 
  InPortAddr.HighPart = 0; 
  if ( !HalTranslateBusAddress( Isa, 
                                0, 
                                InPortAddr, 
                                &AddressSpace, 
                                &OutPortAddr ) ) 
  { 
    RS_DbgPrint( "ProfiM: HalTranslateBusAddress failed\n" ); 
    return STATUS_SOME_NOT_MAPPED; 
  } 
 
 
  if ( NT_SUCCESS( status ) ) 
  { 
    // 
    // Create dispatch points for create/open, close, unload, and ioctl 
    // 
 
    DriverObject->MajorFunction[IRP_MJ_CREATE] = DispatchRoutine; 
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchRoutine; 
    DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRoutine; 
    DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchRoutine; 
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchRoutine; 
    DriverObject->DriverUnload = UnloadDriver; 
 
    // 
    // check if resources (ports and interrupt) are available 
    // 
    ReportUsage( DriverObject, deviceObject, OutPortAddr, &ResourceConflict ); 
 
    if ( ResourceConflict ) 
    { 
      RS_DbgPrint( "ProfiM: Couldn't get resources\n" ); 
      IoDeleteDevice( deviceObject ); 
      return STATUS_INSUFFICIENT_RESOURCES; 
    } 
 
    // 
    // fill in the device extension 
    // 
    extension = ( PPROFIM_DEVICE_EXTENSION ) deviceObject->DeviceExtension; 
    extension->DeviceObject = deviceObject; 
    extension->PortAddress = ( PVOID ) OutPortAddr.LowPart; 
     
     
    KeInitializeDpc(&extension->CompleteDPC, ProfiM_CompleteDPC, extension); 
     
    KeInitializeSpinLock( &(extension->InterruptSpinLock) );     
     
 
    // 
    // connect the device driver to the IRQ 
    // 
    ioConnectStatus = IoConnectInterrupt( &extension->InterruptObject, 
                                          ProfiM_Isr, 
                                          extension->DeviceObject, 
                                          &(extension->InterruptSpinLock), 
                                          MappedVector, 
                                          irql, 
                                          irql, 
                                          Latched, 
                                          FALSE, 
                                          Affinity, 
                                          FALSE ); 
 
    if ( !NT_SUCCESS( ioConnectStatus ) ) 
    { 
      RS_DbgPrint( "ProfiM: Couldn't connect interrupt\n" ); 
      IoDeleteDevice( deviceObject ); 
      return ioConnectStatus; 
    } 
 
    RS_DbgPrint( "ProfiM: just about ready!\n" ); 
 
    // 
    // Create counted string version of our Win32 device name. 
    // 
 
    RtlInitUnicodeString( &uniWin32NameString, DOS_DEVICE_NAME ); 
 
    // 
    // Create a link from our device name to a name in the Win32 namespace. 
    // 
 
    status = IoCreateSymbolicLink( &uniWin32NameString, &uniNtNameString ); 
 
    if ( !NT_SUCCESS( status ) ) 
    { 
      RS_DbgPrint( "ProfiM: Couldn't create the symbolic link\n" ); 
      IoDeleteDevice( DriverObject->DeviceObject ); 
    } 
    else 
    { 
      // 
      // Setup the Dpc for ISR routine 
      // 
 
      IoInitializeDpcRequest( DriverObject->DeviceObject, ProfiM_Dpc_Routine ); 
             
 
      // 
      // Initialize the device (enable IRQ's, hit the hardware) 
      // 
 
      Initialize_ProfiM( extension, 0 ); 
 
      /// Nastaveni priznaku vysilani                         
      extension->Sending = FALSE;   
      // priznak k vymazani vsech casovacich znaku ze zacatku vysilaci fronty                    
      extension->FlushTCH = FALSE; 
       
      // umozni rozbeh ovladace nez se aktivuje hlidaci rutina watchdogu 
      extension->WatchDogTrigger = 0; 
       
 
      extension->HIDCounter = 1; 
 
#ifdef PISA_IO             
      extension->ModemInterruptState = MI_Disabled; 
#endif 
 
      RS_DbgPrint( "ProfiM: All initialized!\n" ); 
 
      PB_Init( &( extension->PB ), extension, RegistryPath ); 
    } 
  } 
  else 
  { 
    RS_DbgPrint( "ProfiM: Couldn't create the device\n" ); 
  } 
  return status; 
} 
 
 
 
 
//--------------------------------------------------------------------------- 
// UnloadDriver 
// 
// Description: 
//     Free all the allocated resources, etc. 
// 
// Arguments: 
//     DriverObject - pointer to a driver object 
//  
// Return Value: 
//      None 
//  
VOID UnloadDriver( IN PDRIVER_OBJECT DriverObject ) 
{ 
  WCHAR                     deviceLinkBuffer[]  = L"\\DosDevices\\ProfiM"; 
  UNICODE_STRING            deviceLinkUnicodeString; 
  PPROFIM_DEVICE_EXTENSION  extension; 
 
  extension = DriverObject->DeviceObject->DeviceExtension; 
 
  PB_Close( &( extension->PB ) ); 
 
  // 
  // Deactivate all of the MCR interrupt sources. 
  // 
 
  WRITE_PORT_UCHAR( extension->ComPort.MCR, MCR_DEACTIVATE_ALL ); 
 
  // 
  // Free any resources 
  // 
 
  IoDisconnectInterrupt( extension->InterruptObject ); 
 
  // 
  // Delete the symbolic link 
  // 
 
  RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer ); 
 
  IoDeleteSymbolicLink( &deviceLinkUnicodeString ); 
 
  // 
  // Delete the device object 
  // 
 
  IoDeleteDevice( DriverObject->DeviceObject ); 
 
  RS_DbgPrint( "ProfiM: Unloaded\n" ); 
  return; 
} 
 
 
 
 
//--------------------------------------------------------------------------- 
// ReportUsage 
// 
// Description: 
//  This routine registers (reports) the I/O and IRQ usage for this driver. 
// 
// Arguments: 
//      DriverObject    - Pointer to the driver object 
//      DeviceObject    - Pointer to the Device object 
//      PortAddress     - Address of I/O port used 
//      ConflictDetected - TRUE if a resource conflict was detected. 
// 
// Return Value: 
//      TRUE    - If a Resource conflict was detected 
//      FALSE   - If no conflict was detected 
// 
BOOLEAN ReportUsage( IN PDRIVER_OBJECT DriverObject, 
                     IN PDEVICE_OBJECT DeviceObject, 
                     IN PHYSICAL_ADDRESS PortAddress, 
                     IN BOOLEAN *ConflictDetected ) 
{ 
  PPROFIM_DEVICE_EXTENSION        extension; 
 
  ULONG                           sizeOfResourceList; 
  PCM_RESOURCE_LIST               resourceList; 
  PCM_FULL_RESOURCE_DESCRIPTOR    nextFrd; 
  PCM_PARTIAL_RESOURCE_DESCRIPTOR partial; 
 
  extension = ( PPROFIM_DEVICE_EXTENSION ) DeviceObject->DeviceExtension; 
 
  // 
  // The size of the resource list is going to be one full descriptor 
  // which already has one partial descriptor included, plus another 
  // partial descriptor. One partial descriptor will be for the 
  // interrupt, and the other for the port addresses. 
  // 
 
  sizeOfResourceList = sizeof( CM_FULL_RESOURCE_DESCRIPTOR ); 
 
  // 
  // The full resource descriptor already contains one 
  // partial. Make room for one more. 
  // 
  // It will hold the irq "prd", and the port "prd". 
  //    ("prd" = partial resource descriptor) 
  // 
 
  sizeOfResourceList += sizeof( CM_PARTIAL_RESOURCE_DESCRIPTOR ); 
 
  // 
  // Now we increment the length of the resource list by field offset 
  // of the first frd.   This will give us the length of what preceeds 
  // the first frd in the resource list. 
  //   (frd = full resource descriptor) 
  // 
 
  sizeOfResourceList += FIELD_OFFSET( CM_RESOURCE_LIST, List[0] ); 
 
  resourceList = ExAllocatePool( PagedPool, sizeOfResourceList ); 
 
  if ( !resourceList ) 
  { 
    return FALSE; 
  } 
 
  // 
  // Zero out the list 
  // 
 
  RtlZeroMemory( resourceList, sizeOfResourceList ); 
 
  resourceList->Count = 1; 
  nextFrd = &resourceList->List[0]; 
 
  nextFrd->InterfaceType = Isa; 
  nextFrd->BusNumber = 0; 
 
  // 
  // We are going to report port addresses and interrupt 
  // 
 
  nextFrd->PartialResourceList.Count = 2; 
 
  // 
  // Now fill in the port data.  We don't wish to share 
  // this port range with anyone. 
  // 
  // Note: the port address we pass in is the one we got 
  // back from HalTranslateBusAddress. 
  // 
 
  partial = &nextFrd->PartialResourceList.PartialDescriptors[0]; 
 
  partial->Type = CmResourceTypePort; 
  partial->ShareDisposition = CmResourceShareDriverExclusive; 
  partial->Flags = CM_RESOURCE_PORT_IO; 
  partial->u.Port.Start = PortAddress; 
  partial->u.Port.Length = DEF_PORT_RANGE; 
 
  partial++; 
 
  // 
  // Now fill in the irq stuff. 
  // 
  // Note: for IoReportResourceUsage, the Interrupt.Level and 
  // Interrupt.Vector are bus-specific level and vector, just 
  // as we passed in to HalGetInterruptVector, not the mapped 
  // system vector we got back from HalGetInterruptVector. 
  // 
 
  partial->Type = CmResourceTypeInterrupt; 
  partial->u.Interrupt.Level = extension->IRQLine; 
  partial->u.Interrupt.Vector = extension->IRQLine; 
  partial->ShareDisposition = CmResourceShareDriverExclusive; 
  partial->Flags = CM_RESOURCE_INTERRUPT_LATCHED; 
 
  IoReportResourceUsage( NULL, 
                         DriverObject, 
                         resourceList, 
                         sizeOfResourceList, 
                         NULL, 
                         NULL, 
                         0, 
                         FALSE, 
                         ConflictDetected ); 
 
  // 
  // The above routine sets the BOOLEAN parameter ConflictDetected 
  // to TRUE if a conflict was detected. 
  // 
 
  ExFreePool( resourceList ); 
 
  return ( *ConflictDetected ); 
}