Annotation of q_a/samples/ddk/portio/genport.c, revision 1.1

1.1     ! root        1: // Generic Port I/O driver for NT  VERSION 1.0
        !             2: //
        !             3: // Adapted from NT DDK ADLIB driver
        !             4: //
        !             5: // Robert R. Howell                 January 8, 1993
        !             6: //
        !             7: // Robert B. Nelson (Microsoft)     January 12, 1993
        !             8: //      Cleaned up comments
        !             9: //      Enabled and tested resource reporting
        !            10: //      Added code to retrieve I/O address and port count from the Registry.
        !            11: //
        !            12: // Robert B. Nelson (Microsoft)     March 1, 1993
        !            13: //      Added support for byte, word, and long I/O.
        !            14: //      Added support for MIPS.
        !            15: //      Fixed resource reporting.
        !            16: //
        !            17: // Robert B. Nelson (Microsoft)     May 1, 1993
        !            18: //      Fixed port number validation.
        !            19: //
        !            20: // Robert B. Nelson (Microsoft)     Oct 25, 1993
        !            21: //      Fixed MIPS support.
        !            22: //
        !            23: 
        !            24: #include "genport.h"
        !            25: #include "stdlib.h"
        !            26: 
        !            27: 
        !            28: NTSTATUS
        !            29: DriverEntry(
        !            30:     IN PDRIVER_OBJECT  DriverObject,
        !            31:     IN PUNICODE_STRING RegistryPath
        !            32:     )
        !            33: 
        !            34: /*++
        !            35: 
        !            36: Routine Description:
        !            37:     This routine is the entry point for the driver.  It is responsible
        !            38:     for setting the dispatch entry points in the driver object and creating
        !            39:     the device object.  Any resources such as ports, interrupts and DMA
        !            40:     channels used must be reported.  A symbolic link must be created between
        !            41:     the device name and an entry in \DosDevices in order to allow Win32
        !            42:     applications to open the device.
        !            43: 
        !            44: Arguments:
        !            45:     
        !            46:     DriverObject - Pointer to driver object created by the system.
        !            47: 
        !            48: Return Value:
        !            49: 
        !            50:     STATUS_SUCCESS if the driver initialized correctly, otherwise an error
        !            51:     indicating the reason for failure.
        !            52: 
        !            53: --*/
        !            54: 
        !            55: {
        !            56:     ULONG PortBase;                 // Port location, in NT's address form.
        !            57:     ULONG PortCount;                // Count of contiguous I/O ports
        !            58:     PHYSICAL_ADDRESS PortAddress;
        !            59: 
        !            60:     PLOCAL_DEVICE_INFO pLocalInfo;  // Device extension:
        !            61:                                     //      local information for each device.
        !            62:     NTSTATUS Status;
        !            63:     PDEVICE_OBJECT DeviceObject;
        !            64: 
        !            65:     CM_RESOURCE_LIST ResourceList;  // Resource usage list to report to system
        !            66:     BOOLEAN ResourceConflict;       // This is set true if our I/O ports
        !            67:                                     //      conflict with another driver
        !            68: 
        !            69:     // Try to retrieve base I/O port and range from the Parameters key of our
        !            70:     // entry in the Registry.
        !            71:     // If there isn't anything specified then use the values compiled into
        !            72:     // this driver.
        !            73:     {
        !            74:         static  WCHAR               SubKeyString[] = L"\\Parameters";
        !            75:         UNICODE_STRING              paramPath;
        !            76:         RTL_QUERY_REGISTRY_TABLE    paramTable[3];
        !            77:         ULONG                       DefaultBase = BASE_PORT;
        !            78:         ULONG                       DefaultCount = NUMBER_PORTS;
        !            79: 
        !            80:         //
        !            81:         // Since the registry path parameter is a "counted" UNICODE string, it
        !            82:         // might not be zero terminated.  For a very short time allocate memory
        !            83:         // to hold the registry path as well as the Parameters key name zero
        !            84:         // terminated so that we can use it to delve into the registry.
        !            85:         //
        !            86: 
        !            87:         paramPath.MaximumLength = RegistryPath->Length + sizeof(SubKeyString);
        !            88:         paramPath.Buffer = ExAllocatePool(PagedPool, paramPath.MaximumLength);
        !            89: 
        !            90:         if (paramPath.Buffer != NULL)
        !            91:         {
        !            92:             RtlMoveMemory(
        !            93:                 paramPath.Buffer, RegistryPath->Buffer, RegistryPath->Length);
        !            94: 
        !            95:             RtlMoveMemory(
        !            96:                 &paramPath.Buffer[RegistryPath->Length / 2], SubKeyString,
        !            97:                 sizeof(SubKeyString));
        !            98: 
        !            99:             paramPath.Length = paramPath.MaximumLength - 2;
        !           100: 
        !           101:             RtlZeroMemory(&paramTable[0], sizeof(paramTable));
        !           102: 
        !           103:             paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
        !           104:             paramTable[0].Name = L"IoPortAddress";
        !           105:             paramTable[0].EntryContext = &PortBase;
        !           106:             paramTable[0].DefaultType = REG_DWORD;
        !           107:             paramTable[0].DefaultData = &DefaultBase;
        !           108:             paramTable[0].DefaultLength = sizeof(ULONG);
        !           109: 
        !           110:             paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
        !           111:             paramTable[1].Name = L"IoPortCount";
        !           112:             paramTable[1].EntryContext = &PortCount;
        !           113:             paramTable[1].DefaultType = REG_DWORD;
        !           114:             paramTable[1].DefaultData = &DefaultCount;
        !           115:             paramTable[1].DefaultLength = sizeof(ULONG);
        !           116: 
        !           117:             if (!NT_SUCCESS(RtlQueryRegistryValues(
        !           118:                 RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
        !           119:                 paramPath.Buffer, &paramTable[0], NULL, NULL)))
        !           120:             {
        !           121:                 PortBase = DefaultBase;
        !           122:                 PortCount = DefaultCount;
        !           123:             }
        !           124:             ExFreePool(paramPath.Buffer);
        !           125:         }
        !           126:     }
        !           127: 
        !           128:     // Register resource usage (ports)
        !           129:     //
        !           130:     // This ensures that there isn't a conflict between this driver and
        !           131:     // a previously loaded one or a future loaded one.
        !           132: 
        !           133:     RtlZeroMemory((PVOID)&ResourceList, sizeof(ResourceList));
        !           134: 
        !           135:     ResourceList.Count = 1;
        !           136:     ResourceList.List[0].InterfaceType = Isa;
        !           137:     // ResourceList.List[0].Busnumber = 0;             Already 0
        !           138:     ResourceList.List[0].PartialResourceList.Count = 1;
        !           139:     ResourceList.List[0].PartialResourceList.PartialDescriptors[0].Type =
        !           140:                                                CmResourceTypePort;
        !           141:     ResourceList.List[0].PartialResourceList.PartialDescriptors[0].ShareDisposition =
        !           142:                                                CmResourceShareDriverExclusive;
        !           143:     ResourceList.List[0].PartialResourceList.PartialDescriptors[0].Flags =
        !           144:                                                CM_RESOURCE_PORT_IO;
        !           145:     ResourceList.List[0].PartialResourceList.PartialDescriptors[0].u.Port.Start =
        !           146:                                                PortAddress;
        !           147:     ResourceList.List[0].PartialResourceList.PartialDescriptors[0].u.Port.Length =
        !           148:                                                PortCount;
        !           149: 
        !           150:     // Report our resource usage and detect conflicts
        !           151:     Status = IoReportResourceUsage(
        !           152:                    NULL,
        !           153:                    DriverObject,
        !           154:                    &ResourceList,
        !           155:                    sizeof(ResourceList),
        !           156:                    NULL,
        !           157:                    NULL,
        !           158:                    0,
        !           159:                    FALSE,
        !           160:                    &ResourceConflict);
        !           161: 
        !           162:     if (ResourceConflict)
        !           163:         Status = STATUS_DEVICE_CONFIGURATION_ERROR;
        !           164: 
        !           165:     if (!NT_SUCCESS(Status))
        !           166:     {
        !           167:         KdPrint( ("Resource reporting problem %8X", Status) );
        !           168: 
        !           169:         return Status;
        !           170:     }
        !           171: 
        !           172:     // Initialize the driver object dispatch table.
        !           173:     // NT sends requests to these routines.
        !           174: 
        !           175:     DriverObject->MajorFunction[IRP_MJ_CREATE]          = GpdDispatch;
        !           176:     DriverObject->MajorFunction[IRP_MJ_CLOSE]           = GpdDispatch;
        !           177:     DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]  = GpdDispatch;
        !           178:     DriverObject->DriverUnload                          = GpdUnload;
        !           179: 
        !           180:     // Create our device.
        !           181:     Status = GpdCreateDevice(
        !           182:                     GPD_DEVICE_NAME,
        !           183:                     GPD_TYPE,
        !           184:                     DriverObject,
        !           185:                     &DeviceObject
        !           186:                     );
        !           187: 
        !           188:     if ( NT_SUCCESS(Status) )
        !           189:     {
        !           190:         PHYSICAL_ADDRESS MappedAddress;
        !           191:         ULONG MemType;
        !           192: 
        !           193:         // Convert the IO port address into a form NT likes.
        !           194:         MemType = 1;                        // located in IO space
        !           195:         PortAddress.LowPart  = PortBase;
        !           196:         PortAddress.HighPart = 0;
        !           197:         HalTranslateBusAddress( Isa,
        !           198:                                 0,
        !           199:                                 PortAddress,
        !           200:                                 &MemType,
        !           201:                                 &MappedAddress );
        !           202: 
        !           203: 
        !           204:         // Initialize the local driver info for each device object.
        !           205:         pLocalInfo = (PLOCAL_DEVICE_INFO)DeviceObject->DeviceExtension;
        !           206: 
        !           207:         if (MemType == 0)
        !           208:         {
        !           209:             // Port is accessed through memory space - so get a virtual address
        !           210: 
        !           211:             pLocalInfo->PortWasMapped = TRUE;            
        !           212: 
        !           213:             // BUGBUG
        !           214:             // MmMapIoSpace can fail if we run out of PTEs, we should be
        !           215:             // checking the return value here
        !           216: 
        !           217:             pLocalInfo->PortBase = MmMapIoSpace(MappedAddress, PortCount, FALSE);
        !           218:         }
        !           219:         else
        !           220:         {
        !           221:             pLocalInfo->PortWasMapped = FALSE;
        !           222:             pLocalInfo->PortBase = (PVOID)MappedAddress.LowPart;
        !           223:         }
        !           224: 
        !           225:         pLocalInfo->DeviceObject    = DeviceObject;
        !           226:         pLocalInfo->DeviceType      = GPD_TYPE;
        !           227:         pLocalInfo->PortCount       = PortCount;
        !           228:         pLocalInfo->PortMemoryType  = MemType;
        !           229:     }
        !           230:     else
        !           231:     {
        !           232:         //
        !           233:         // Error creating device - release resources
        !           234:         //
        !           235: 
        !           236:         RtlZeroMemory((PVOID)&ResourceList, sizeof(ResourceList));
        !           237:     
        !           238:         // Unreport our resource usage
        !           239:         Status = IoReportResourceUsage(
        !           240:                        NULL,
        !           241:                        DriverObject,
        !           242:                        &ResourceList,
        !           243:                        sizeof(ResourceList),
        !           244:                        NULL,
        !           245:                        NULL,
        !           246:                        0,
        !           247:                        FALSE,
        !           248:                        &ResourceConflict);
        !           249:     }
        !           250: 
        !           251:     return Status;
        !           252: }
        !           253: 
        !           254: NTSTATUS
        !           255: GpdCreateDevice(
        !           256:     IN   PWSTR              PrototypeName,
        !           257:     IN   DEVICE_TYPE        DeviceType,
        !           258:     IN   PDRIVER_OBJECT     DriverObject,
        !           259:     OUT  PDEVICE_OBJECT     *ppDevObj
        !           260:     )
        !           261: 
        !           262: /*++
        !           263: 
        !           264: Routine Description:
        !           265:     This routine creates the device object and the symbolic link in
        !           266:     \DosDevices.
        !           267:     
        !           268:     Ideally a name derived from a "Prototype", with a number appended at
        !           269:     the end should be used.  For simplicity, just use the fixed name defined
        !           270:     in the include file.  This means that only one device can be created.
        !           271:     
        !           272:     A symbolic link must be created between the device name and an entry
        !           273:     in \DosDevices in order to allow Win32 applications to open the device.
        !           274: 
        !           275: Arguments:
        !           276: 
        !           277:     PrototypeName - Name base, # WOULD be appended to this.
        !           278: 
        !           279:     DeviceType - Type of device to create
        !           280: 
        !           281:     DriverObject - Pointer to driver object created by the system.
        !           282: 
        !           283:     ppDevObj - Pointer to place to store pointer to created device object
        !           284: 
        !           285: Return Value:
        !           286: 
        !           287:     STATUS_SUCCESS if the device and link are created correctly, otherwise
        !           288:     an error indicating the reason for failure.
        !           289: 
        !           290: --*/
        !           291: 
        !           292: 
        !           293: {
        !           294:     NTSTATUS Status;                        // Status of utility calls
        !           295:     UNICODE_STRING NtDeviceName;
        !           296:     UNICODE_STRING Win32DeviceName;
        !           297: 
        !           298: 
        !           299:     // Get UNICODE name for device.
        !           300: 
        !           301:     RtlInitUnicodeString(&NtDeviceName, PrototypeName);
        !           302: 
        !           303:     Status = IoCreateDevice(                             // Create it.
        !           304:                     DriverObject,
        !           305:                     sizeof(LOCAL_DEVICE_INFO),
        !           306:                     &NtDeviceName,
        !           307:                     DeviceType,
        !           308:                     0,
        !           309:                     FALSE,                      // Not Exclusive
        !           310:                     ppDevObj
        !           311:                     );
        !           312: 
        !           313:     if (!NT_SUCCESS(Status))
        !           314:         return Status;             // Give up if create failed.
        !           315: 
        !           316:     // Clear local device info memory
        !           317:     RtlZeroMemory((*ppDevObj)->DeviceExtension, sizeof(LOCAL_DEVICE_INFO));
        !           318: 
        !           319:     //
        !           320:     // Set up the rest of the device info
        !           321:     //  These are used for IRP_MJ_READ and IRP_MJ_WRITE which we don't use
        !           322:     //    
        !           323:     //  (*ppDevObj)->Flags |= DO_BUFFERED_IO;
        !           324:     //  (*ppDevObj)->AlignmentRequirement = FILE_BYTE_ALIGNMENT;
        !           325:     //
        !           326: 
        !           327:     RtlInitUnicodeString(&Win32DeviceName, DOS_DEVICE_NAME);
        !           328: 
        !           329:     Status = IoCreateSymbolicLink( &Win32DeviceName, &NtDeviceName );
        !           330: 
        !           331:     if (!NT_SUCCESS(Status))    // If we we couldn't create the link then
        !           332:     {                           //  abort installation.
        !           333:         IoDeleteDevice(*ppDevObj);
        !           334:     }
        !           335: 
        !           336:     return Status;
        !           337: }
        !           338: 
        !           339:    
        !           340: NTSTATUS
        !           341: GpdDispatch(
        !           342:     IN    PDEVICE_OBJECT pDO,
        !           343:     IN    PIRP pIrp             
        !           344:     )
        !           345: 
        !           346: /*++
        !           347: 
        !           348: Routine Description:
        !           349:     This routine is the dispatch handler for the driver.  It is responsible
        !           350:     for processing the IRPs.
        !           351: 
        !           352: Arguments:
        !           353:     
        !           354:     pDO - Pointer to device object.
        !           355: 
        !           356:     pIrp - Pointer to the current IRP.
        !           357: 
        !           358: Return Value:
        !           359: 
        !           360:     STATUS_SUCCESS if the IRP was processed successfully, otherwise an error
        !           361:     indicating the reason for failure.
        !           362: 
        !           363: --*/
        !           364: 
        !           365: {
        !           366:     PLOCAL_DEVICE_INFO pLDI;
        !           367:     PIO_STACK_LOCATION pIrpStack;
        !           368:     NTSTATUS Status;
        !           369: 
        !           370:     //  Initialize the irp info field.
        !           371:     //      This is used to return the number of bytes transfered.
        !           372: 
        !           373:     pIrp->IoStatus.Information = 0;
        !           374:     pLDI = (PLOCAL_DEVICE_INFO)pDO->DeviceExtension;    // Get local info struct
        !           375: 
        !           376:     pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
        !           377: 
        !           378:     //  Set default return status
        !           379:     Status = STATUS_NOT_IMPLEMENTED;
        !           380: 
        !           381:     // Dispatch based on major fcn code.
        !           382: 
        !           383:     switch (pIrpStack->MajorFunction)
        !           384:     {
        !           385:         case IRP_MJ_CREATE:
        !           386:         case IRP_MJ_CLOSE:
        !           387:             // We don't need any special processing on open/close so we'll
        !           388:             // just return success.
        !           389:             Status = STATUS_SUCCESS;
        !           390:             break;
        !           391: 
        !           392:         case IRP_MJ_DEVICE_CONTROL:
        !           393:             //  Dispatch on IOCTL
        !           394:             switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode)
        !           395:             {
        !           396:             case IOCTL_GPD_READ_PORT_UCHAR:
        !           397:             case IOCTL_GPD_READ_PORT_USHORT:
        !           398:             case IOCTL_GPD_READ_PORT_ULONG:
        !           399:                 Status = GpdIoctlReadPort(
        !           400:                             pLDI,
        !           401:                             pIrp,
        !           402:                             pIrpStack,
        !           403:                             pIrpStack->Parameters.DeviceIoControl.IoControlCode
        !           404:                             );
        !           405:                 break;
        !           406: 
        !           407:             case IOCTL_GPD_WRITE_PORT_UCHAR:
        !           408:             case IOCTL_GPD_WRITE_PORT_USHORT:
        !           409:             case IOCTL_GPD_WRITE_PORT_ULONG:
        !           410:                 Status = GpdIoctlWritePort(
        !           411:                             pLDI, 
        !           412:                             pIrp,
        !           413:                             pIrpStack,
        !           414:                             pIrpStack->Parameters.DeviceIoControl.IoControlCode
        !           415:                             );
        !           416:                 break;
        !           417:             }
        !           418:             break;
        !           419:     }
        !           420: 
        !           421:     // We're done with I/O request.  Record the status of the I/O action.
        !           422:     pIrp->IoStatus.Status = Status;
        !           423: 
        !           424:     // Don't boost priority when returning since this took little time.
        !           425:     IoCompleteRequest(pIrp, IO_NO_INCREMENT );
        !           426: 
        !           427:     return Status;
        !           428: }
        !           429: 
        !           430: 
        !           431: NTSTATUS
        !           432: GpdIoctlReadPort(
        !           433:     IN PLOCAL_DEVICE_INFO pLDI,
        !           434:     IN PIRP pIrp,
        !           435:     IN PIO_STACK_LOCATION IrpStack,
        !           436:     IN ULONG IoctlCode  )
        !           437: 
        !           438: 
        !           439: /*++
        !           440: 
        !           441: Routine Description:
        !           442:     This routine processes the IOCTLs which read from the ports.
        !           443: 
        !           444: Arguments:
        !           445:     
        !           446:     pLDI        - our local device data
        !           447:     pIrp        - IO request packet
        !           448:     IrpStack    - The current stack location
        !           449:     IoctlCode   - The ioctl code from the IRP
        !           450: 
        !           451: Return Value:
        !           452:     STATUS_SUCCESS           -- OK
        !           453: 
        !           454:     STATUS_INVALID_PARAMETER -- The buffer sent to the driver
        !           455:                                 was too small to contain the
        !           456:                                 port, or the buffer which
        !           457:                                 would be sent back to the driver
        !           458:                                 was not a multiple of the data size.
        !           459: 
        !           460:     STATUS_ACCESS_VIOLATION  -- An illegal port number was given.
        !           461: 
        !           462: --*/
        !           463: 
        !           464: {
        !           465:                                 // NOTE:  Use METHOD_BUFFERED ioctls.
        !           466:     PULONG pIOBuffer;           // Pointer to transfer buffer
        !           467:                                 //      (treated as an array of longs).
        !           468:     ULONG InBufferSize;         // Amount of data avail. from caller.
        !           469:     ULONG OutBufferSize;        // Max data that caller can accept.
        !           470:     ULONG nPort;                // Port number to read
        !           471:     ULONG DataBufferSize;
        !           472: 
        !           473:     // Size of buffer containing data from application
        !           474:     InBufferSize  = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
        !           475: 
        !           476:     // Size of buffer for data to be sent to application
        !           477:     OutBufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
        !           478: 
        !           479:     // NT copies inbuf here before entry and copies this to outbuf after
        !           480:     // return, for METHOD_BUFFERED IOCTL's.
        !           481:     pIOBuffer     = (PULONG)pIrp->AssociatedIrp.SystemBuffer;
        !           482: 
        !           483:     // Check to ensure input buffer is big enough to hold a port number and
        !           484:     // the output buffer is at least as big as the port data width.
        !           485:     //
        !           486:     switch (IoctlCode)
        !           487:     {
        !           488:     case IOCTL_GPD_READ_PORT_UCHAR:
        !           489:         DataBufferSize = sizeof(UCHAR);
        !           490:         break;
        !           491:     case IOCTL_GPD_READ_PORT_USHORT:
        !           492:         DataBufferSize = sizeof(USHORT);
        !           493:         break;
        !           494:     case IOCTL_GPD_READ_PORT_ULONG:
        !           495:         DataBufferSize = sizeof(ULONG);
        !           496:         break;
        !           497:     }
        !           498: 
        !           499:     if ( InBufferSize != sizeof(ULONG) || OutBufferSize < DataBufferSize )
        !           500:     {
        !           501:         return STATUS_INVALID_PARAMETER;
        !           502:     }
        !           503: 
        !           504:     // Buffers are big enough.
        !           505: 
        !           506:     nPort = *pIOBuffer;             // Get the I/O port number from the buffer.
        !           507: 
        !           508:     if (nPort >= pLDI->PortCount ||
        !           509:         (nPort + DataBufferSize) > pLDI->PortCount ||
        !           510:         (((ULONG)pLDI->PortBase + nPort) & (DataBufferSize - 1)) != 0)
        !           511:     {
        !           512:         return STATUS_ACCESS_VIOLATION;   // It was not legal.
        !           513:     }
        !           514:     
        !           515:     if (pLDI->PortMemoryType == 1)
        !           516:     {
        !           517:         // Address is in I/O space
        !           518:         
        !           519:         switch (IoctlCode)
        !           520:         {
        !           521:         case IOCTL_GPD_READ_PORT_UCHAR:
        !           522:             *(PUCHAR)pIOBuffer = READ_PORT_UCHAR(
        !           523:                             (PUCHAR)((ULONG)pLDI->PortBase + nPort) );
        !           524:             break;
        !           525:         case IOCTL_GPD_READ_PORT_USHORT:
        !           526:             *(PUSHORT)pIOBuffer = READ_PORT_USHORT(
        !           527:                             (PUSHORT)((ULONG)pLDI->PortBase + nPort) );
        !           528:             break;
        !           529:         case IOCTL_GPD_READ_PORT_ULONG:
        !           530:             *(PULONG)pIOBuffer = READ_PORT_ULONG(
        !           531:                             (PULONG)((ULONG)pLDI->PortBase + nPort) );
        !           532:             break;
        !           533:         }
        !           534:     } else {
        !           535:         // Address is in Memory space
        !           536:         
        !           537:         switch (IoctlCode)
        !           538:         {
        !           539:         case IOCTL_GPD_READ_PORT_UCHAR:
        !           540:             *(PUCHAR)pIOBuffer = READ_REGISTER_UCHAR(
        !           541:                             (PUCHAR)((ULONG)pLDI->PortBase + nPort) );
        !           542:             break;
        !           543:         case IOCTL_GPD_READ_PORT_USHORT:
        !           544:             *(PUSHORT)pIOBuffer = READ_REGISTER_USHORT(
        !           545:                             (PUSHORT)((ULONG)pLDI->PortBase + nPort) );
        !           546:             break;
        !           547:         case IOCTL_GPD_READ_PORT_ULONG:
        !           548:             *(PULONG)pIOBuffer = READ_REGISTER_ULONG(
        !           549:                             (PULONG)((ULONG)pLDI->PortBase + nPort) );
        !           550:             break;
        !           551:         }
        !           552:     }
        !           553:     
        !           554:     // Indicate # of bytes read
        !           555:     //
        !           556:     
        !           557:     pIrp->IoStatus.Information = DataBufferSize;
        !           558: 
        !           559:     return STATUS_SUCCESS;
        !           560: }
        !           561: 
        !           562: 
        !           563: NTSTATUS
        !           564: GpdIoctlWritePort(
        !           565:     IN PLOCAL_DEVICE_INFO pLDI, 
        !           566:     IN PIRP pIrp, 
        !           567:     IN PIO_STACK_LOCATION IrpStack,
        !           568:     IN ULONG IoctlCode
        !           569:     )
        !           570: 
        !           571: /*++
        !           572: 
        !           573: Routine Description:
        !           574:     This routine processes the IOCTLs which write to the ports.
        !           575: 
        !           576: Arguments:
        !           577:     
        !           578:     pLDI        - our local device data
        !           579:     pIrp        - IO request packet
        !           580:     IrpStack    - The current stack location
        !           581:     IoctlCode   - The ioctl code from the IRP
        !           582: 
        !           583: Return Value:
        !           584:     STATUS_SUCCESS           -- OK
        !           585: 
        !           586:     STATUS_INVALID_PARAMETER -- The buffer sent to the driver
        !           587:                                 was too small to contain the
        !           588:                                 port, or the buffer which
        !           589:                                 would be sent back to the driver
        !           590:                                 was not a multiple of the data size.
        !           591: 
        !           592:     STATUS_ACCESS_VIOLATION  -- An illegal port number was given.
        !           593: 
        !           594: --*/
        !           595: 
        !           596: {
        !           597:                                 // NOTE:  Use METHOD_BUFFERED ioctls.
        !           598:     PULONG pIOBuffer;           // Pointer to transfer buffer
        !           599:                                 //      (treated as array of longs).
        !           600:     ULONG InBufferSize ;        // Amount of data avail. from caller.
        !           601:     ULONG OutBufferSize ;       // Max data that caller can accept.
        !           602:     ULONG nPort;                // Port number to read or write.
        !           603:     ULONG DataBufferSize;
        !           604: 
        !           605:     // Size of buffer containing data from application
        !           606:     InBufferSize  = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
        !           607: 
        !           608:     // Size of buffer for data to be sent to application
        !           609:     OutBufferSize = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
        !           610: 
        !           611:     // NT copies inbuf here before entry and copies this to outbuf after return,
        !           612:     // for METHOD_BUFFERED IOCTL's.
        !           613:     pIOBuffer     = (PULONG) pIrp->AssociatedIrp.SystemBuffer;
        !           614: 
        !           615:     // We don't return any data on a write port.
        !           616:     pIrp->IoStatus.Information = 0;
        !           617:     
        !           618:     // Check to ensure input buffer is big enough to hold a port number as well
        !           619:     // as the data to write.
        !           620:     //
        !           621:     // The relative port # is a ULONG, and the data is the type appropriate to
        !           622:     // the IOCTL.
        !           623:     //
        !           624: 
        !           625:     switch (IoctlCode)
        !           626:     {
        !           627:     case IOCTL_GPD_WRITE_PORT_UCHAR:
        !           628:         DataBufferSize = sizeof(UCHAR);
        !           629:         break;
        !           630:     case IOCTL_GPD_WRITE_PORT_USHORT:
        !           631:         DataBufferSize = sizeof(USHORT);
        !           632:         break;
        !           633:     case IOCTL_GPD_WRITE_PORT_ULONG:
        !           634:         DataBufferSize = sizeof(ULONG);
        !           635:         break;
        !           636:     }
        !           637: 
        !           638:     if ( InBufferSize < (sizeof(ULONG) + DataBufferSize) )
        !           639:     {
        !           640:         return STATUS_INVALID_PARAMETER;
        !           641:     }
        !           642: 
        !           643:     nPort = *pIOBuffer++;
        !           644: 
        !           645:     if (nPort >= pLDI->PortCount ||
        !           646:         (nPort + DataBufferSize) > pLDI->PortCount ||
        !           647:         (((ULONG)pLDI->PortBase + nPort) & (DataBufferSize - 1)) != 0)
        !           648:     {
        !           649:         return STATUS_ACCESS_VIOLATION;   // Illegal port number
        !           650:     }
        !           651: 
        !           652:     if (pLDI->PortMemoryType == 1)
        !           653:     {
        !           654:         // Address is in I/O space
        !           655:         
        !           656:         switch (IoctlCode)
        !           657:         {
        !           658:         case IOCTL_GPD_WRITE_PORT_UCHAR:
        !           659:             WRITE_PORT_UCHAR(
        !           660:                 (PUCHAR)((ULONG)pLDI->PortBase + nPort),
        !           661:                 *(PUCHAR)pIOBuffer );
        !           662:             break;
        !           663:         case IOCTL_GPD_WRITE_PORT_USHORT:
        !           664:             WRITE_PORT_USHORT(
        !           665:                 (PUSHORT)((ULONG)pLDI->PortBase + nPort),
        !           666:                 *(PUSHORT)pIOBuffer );
        !           667:             break;
        !           668:         case IOCTL_GPD_WRITE_PORT_ULONG:
        !           669:             WRITE_PORT_ULONG(
        !           670:                 (PULONG)((ULONG)pLDI->PortBase + nPort),
        !           671:                 *(PULONG)pIOBuffer );
        !           672:             break;
        !           673:         }
        !           674:     } else {
        !           675:         // Address is in Memory space
        !           676:         
        !           677:         switch (IoctlCode)
        !           678:         {
        !           679:         case IOCTL_GPD_WRITE_PORT_UCHAR:
        !           680:             WRITE_REGISTER_UCHAR( 
        !           681:                     (PUCHAR)((ULONG)pLDI->PortBase + nPort),
        !           682:                     *(PUCHAR)pIOBuffer );
        !           683:             break;
        !           684:         case IOCTL_GPD_WRITE_PORT_USHORT:
        !           685:             WRITE_REGISTER_USHORT(
        !           686:                     (PUSHORT)((ULONG)pLDI->PortBase + nPort),
        !           687:                     *(PUSHORT)pIOBuffer );
        !           688:             break;
        !           689:         case IOCTL_GPD_WRITE_PORT_ULONG:
        !           690:             WRITE_REGISTER_ULONG(
        !           691:                     (PULONG)((ULONG)pLDI->PortBase + nPort),
        !           692:                     *(PULONG)pIOBuffer );
        !           693:             break;
        !           694:         }
        !           695:     }
        !           696: 
        !           697:     return STATUS_SUCCESS;
        !           698: }
        !           699: 
        !           700: 
        !           701: VOID
        !           702: GpdUnload(
        !           703:     PDRIVER_OBJECT DriverObject
        !           704:     )
        !           705: 
        !           706: /*++
        !           707: 
        !           708: Routine Description:
        !           709:     This routine prepares our driver to be unloaded.  It is responsible
        !           710:     for freeing all resources allocated by DriverEntry as well as any 
        !           711:     allocated while the driver was running.  The symbolic link must be
        !           712:     deleted as well.
        !           713: 
        !           714: Arguments:
        !           715:     
        !           716:     DriverObject - Pointer to driver object created by the system.
        !           717: 
        !           718: Return Value:
        !           719: 
        !           720:     None
        !           721: 
        !           722: --*/
        !           723: 
        !           724: {
        !           725:     PLOCAL_DEVICE_INFO pLDI;
        !           726:     CM_RESOURCE_LIST NullResourceList;
        !           727:     BOOLEAN ResourceConflict;
        !           728:     UNICODE_STRING Win32DeviceName;
        !           729: 
        !           730:     // Find our global data
        !           731:     pLDI = (PLOCAL_DEVICE_INFO)DriverObject->DeviceObject->DeviceExtension;
        !           732: 
        !           733:     // Unmap the ports
        !           734: 
        !           735:     if (pLDI->PortWasMapped)
        !           736:     {
        !           737:         MmUnmapIoSpace(pLDI->PortBase, pLDI->PortCount);
        !           738:     }
        !           739: 
        !           740:     // Report we're not using any hardware.  If we don't do this
        !           741:     // then we'll conflict with ourselves (!) on the next load
        !           742: 
        !           743:     RtlZeroMemory((PVOID)&NullResourceList, sizeof(NullResourceList));
        !           744: 
        !           745:     IoReportResourceUsage(
        !           746:               NULL,
        !           747:               DriverObject,
        !           748:               &NullResourceList,
        !           749:               sizeof(ULONG),
        !           750:               NULL,
        !           751:               NULL,
        !           752:               0,
        !           753:               FALSE,
        !           754:               &ResourceConflict );
        !           755: 
        !           756:     // Assume all handles are closed down.
        !           757:     // Delete the things we allocated - devices, symbolic links
        !           758: 
        !           759:     RtlInitUnicodeString(&Win32DeviceName, DOS_DEVICE_NAME);
        !           760: 
        !           761:     IoDeleteSymbolicLink(&Win32DeviceName);
        !           762: 
        !           763:     IoDeleteDevice(pLDI->DeviceObject);
        !           764: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.