|
|
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: ¶mPath.Buffer[RegistryPath->Length / 2], SubKeyString, ! 97: sizeof(SubKeyString)); ! 98: ! 99: paramPath.Length = paramPath.MaximumLength - 2; ! 100: ! 101: RtlZeroMemory(¶mTable[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, ¶mTable[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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.