Annotation of q_a/samples/ddk/portio/genport.c, revision 1.1.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.