|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1992 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: scisprnt.c ! 8: ! 9: Abstract: ! 10: ! 11: The printer class driver tranlates IRPs to SRBs with embedded CDBs ! 12: and sends them to its devices through the port driver. ! 13: ! 14: Author: ! 15: ! 16: Mike Glass (mglass) ! 17: ! 18: Environment: ! 19: ! 20: kernel mode only ! 21: ! 22: Notes: ! 23: ! 24: Revision History: ! 25: ! 26: --*/ ! 27: ! 28: #include "ntddk.h" ! 29: #include "ntddser.h" ! 30: #include "scsi.h" ! 31: #include "class.h" ! 32: ! 33: #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) ! 34: ! 35: ! 36: BOOLEAN ! 37: FindScsiPrinters( ! 38: IN PDRIVER_OBJECT DriveObject, ! 39: IN PDEVICE_OBJECT PortDeviceObject ! 40: ); ! 41: ! 42: NTSTATUS ! 43: CreatePrinterDeviceObject( ! 44: IN PDRIVER_OBJECT DriverObject, ! 45: IN PDEVICE_OBJECT PortDeviceObject, ! 46: IN PULONG DeviceCount, ! 47: IN PCHAR ArcName, ! 48: IN PIO_SCSI_CAPABILITIES PortCapabilities, ! 49: IN PSCSI_INQUIRY_DATA LunInfo ! 50: ); ! 51: ! 52: NTSTATUS ! 53: ScsiPrinterOpen( ! 54: IN PDEVICE_OBJECT DeviceObject, ! 55: IN PIRP Irp ! 56: ); ! 57: ! 58: NTSTATUS ! 59: ScsiPrinterWrite( ! 60: IN PDEVICE_OBJECT DeviceObject, ! 61: IN PIRP Irp ! 62: ); ! 63: ! 64: NTSTATUS ! 65: ScsiPrinterDeviceControl( ! 66: IN PDEVICE_OBJECT DeviceObject, ! 67: IN PIRP Irp ! 68: ); ! 69: ! 70: VOID ! 71: BuildPrintRequest( ! 72: PDEVICE_OBJECT DeviceObject, ! 73: PIRP Irp ! 74: ); ! 75: ! 76: VOID ! 77: SplitRequest( ! 78: IN PDEVICE_OBJECT DeviceObject, ! 79: IN PIRP Irp, ! 80: IN ULONG MaximumBytes ! 81: ); ! 82: ! 83: ! 84: NTSTATUS ! 85: DriverEntry( ! 86: IN PDRIVER_OBJECT DriverObject, ! 87: IN PUNICODE_STRING RegistryPath ! 88: ) ! 89: ! 90: /*++ ! 91: ! 92: Routine Description: ! 93: ! 94: This routine initializes the printer class driver. The driver ! 95: opens the port driver by name and then receives configuration ! 96: information used to attach to the Printer devices. ! 97: ! 98: Arguments: ! 99: ! 100: DriverObject ! 101: ! 102: Return Value: ! 103: ! 104: NT Status ! 105: ! 106: --*/ ! 107: ! 108: { ! 109: ULONG portNumber = 0; ! 110: NTSTATUS status; ! 111: PFILE_OBJECT fileObject; ! 112: PDEVICE_OBJECT portDeviceObject; ! 113: STRING deviceNameString; ! 114: CCHAR deviceNameBuffer[64]; ! 115: UNICODE_STRING unicodeDeviceName; ! 116: BOOLEAN foundOne = FALSE; ! 117: ! 118: DebugPrint((1,"\n\nSCSI Printer Class Driver\n")); ! 119: ! 120: // ! 121: // Set up the device driver entry points. ! 122: // ! 123: ! 124: DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiPrinterWrite; ! 125: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPrinterDeviceControl; ! 126: DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPrinterOpen; ! 127: ! 128: // ! 129: // Open port driver device objects by name. ! 130: // ! 131: ! 132: do { ! 133: ! 134: // ! 135: // Create port driver name. ! 136: // ! 137: ! 138: sprintf(deviceNameBuffer, ! 139: "\\Device\\ScsiPort%d", ! 140: portNumber++); ! 141: ! 142: DebugPrint((2,"ScsiPrinterInitialize: Open %s\n", ! 143: deviceNameBuffer)); ! 144: ! 145: RtlInitString(&deviceNameString, ! 146: deviceNameBuffer); ! 147: ! 148: status = RtlAnsiStringToUnicodeString(&unicodeDeviceName, ! 149: &deviceNameString, ! 150: TRUE); ! 151: ! 152: if (!NT_SUCCESS(status)) { ! 153: ! 154: DebugPrint((1, ! 155: "ScsiPrinterInitialize: Could not initalize unicode string %s\n", ! 156: deviceNameString)); ! 157: ! 158: break; ! 159: } ! 160: ! 161: status = IoGetDeviceObjectPointer(&unicodeDeviceName, ! 162: FILE_READ_ATTRIBUTES, ! 163: &fileObject, ! 164: &portDeviceObject); ! 165: ! 166: if (NT_SUCCESS(status)) { ! 167: ! 168: // ! 169: // SCSI port driver exists. ! 170: // ! 171: ! 172: if (FindScsiPrinters(DriverObject, ! 173: portDeviceObject)) { ! 174: ! 175: foundOne = TRUE; ! 176: } ! 177: ! 178: // ! 179: // Dereference the file object since the port device pointer is no ! 180: // longer needed. The claim device code refences the port driver ! 181: // pointer that is actually being used. ! 182: // ! 183: ! 184: ObDereferenceObject(fileObject); ! 185: } ! 186: ! 187: } while (NT_SUCCESS(status)); ! 188: ! 189: if (foundOne) { ! 190: return STATUS_SUCCESS; ! 191: } else { ! 192: return STATUS_NO_SUCH_DEVICE; ! 193: } ! 194: ! 195: } // end DriverEntry() ! 196: ! 197: ! 198: BOOLEAN ! 199: FindScsiPrinters( ! 200: IN PDRIVER_OBJECT DriverObject, ! 201: IN PDEVICE_OBJECT PortDeviceObject ! 202: ) ! 203: ! 204: /*++ ! 205: ! 206: Routine Description: ! 207: ! 208: Connect to SCSI port driver. Get adapter capabilities and ! 209: SCSI bus configuration information. Search inquiry data ! 210: for Printer devices to process. ! 211: ! 212: Arguments: ! 213: ! 214: Printer class driver object ! 215: SCSI port driver device object ! 216: ! 217: Return Value: ! 218: ! 219: NONE ! 220: ! 221: --*/ ! 222: ! 223: { ! 224: PIO_SCSI_CAPABILITIES portCapabilities; ! 225: PCHAR buffer; ! 226: PSCSI_INQUIRY_DATA lunInfo; ! 227: PSCSI_ADAPTER_BUS_INFO adapterInfo; ! 228: PINQUIRYDATA inquiryData; ! 229: ULONG scsiBus; ! 230: ULONG printerCount = 0; ! 231: NTSTATUS status; ! 232: ! 233: // ! 234: // Call port driver to get adapter capabilities. ! 235: // ! 236: ! 237: status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities); ! 238: ! 239: if (!NT_SUCCESS(status)) { ! 240: DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n")); ! 241: return FALSE; ! 242: } ! 243: ! 244: // ! 245: // Call port driver to get inquiry information to find Printers. ! 246: // ! 247: ! 248: status = ScsiClassGetInquiryData(PortDeviceObject, ! 249: (PSCSI_ADAPTER_BUS_INFO *)&buffer); ! 250: ! 251: if (!NT_SUCCESS(status)) { ! 252: DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n")); ! 253: return FALSE; ! 254: } ! 255: ! 256: adapterInfo = (PVOID)buffer; ! 257: ! 258: // ! 259: // For each SCSI bus this adapter supports ... ! 260: // ! 261: ! 262: for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) { ! 263: ! 264: // ! 265: // Get the SCSI bus scan data for this bus. ! 266: // ! 267: ! 268: lunInfo = (PVOID)(buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset); ! 269: ! 270: // ! 271: // Search list for unclaimed disk devices. ! 272: // ! 273: ! 274: while (adapterInfo->BusData[scsiBus].InquiryDataOffset) { ! 275: ! 276: inquiryData = (PVOID)lunInfo->InquiryData; ! 277: ! 278: DebugPrint((3,"FindScsiDevices: Inquiry data at %lx\n", ! 279: inquiryData)); ! 280: ! 281: if ((inquiryData->DeviceType == PRINTER_DEVICE) && ! 282: (!lunInfo->DeviceClaimed)) { ! 283: ! 284: DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n", ! 285: inquiryData->VendorId)); ! 286: ! 287: // ! 288: // Create device objects for Printer ! 289: // ! 290: ! 291: status = CreatePrinterDeviceObject(DriverObject, ! 292: PortDeviceObject, ! 293: &printerCount, ! 294: NULL, ! 295: portCapabilities, ! 296: lunInfo); ! 297: ! 298: if (NT_SUCCESS(status)) { ! 299: ! 300: // ! 301: // Increment printer count. ! 302: // ! 303: ! 304: printerCount++; ! 305: ! 306: } ! 307: } ! 308: ! 309: // ! 310: // Get next LunInfo. ! 311: // ! 312: ! 313: if (lunInfo->NextInquiryDataOffset == 0) { ! 314: break; ! 315: } ! 316: ! 317: lunInfo = (PVOID)(buffer + lunInfo->NextInquiryDataOffset); ! 318: } ! 319: } ! 320: ! 321: ExFreePool(buffer); ! 322: if (printerCount > 0) { ! 323: return TRUE; ! 324: } else { ! 325: return FALSE; ! 326: } ! 327: ! 328: } // end FindScsiPrinters() ! 329: ! 330: ! 331: NTSTATUS ! 332: CreatePrinterDeviceObject( ! 333: IN PDRIVER_OBJECT DriverObject, ! 334: IN PDEVICE_OBJECT PortDeviceObject, ! 335: IN PULONG DeviceCount, ! 336: IN PCHAR ArcName, ! 337: IN PIO_SCSI_CAPABILITIES PortCapabilities, ! 338: IN PSCSI_INQUIRY_DATA LunInfo ! 339: ) ! 340: ! 341: /*++ ! 342: ! 343: Routine Description: ! 344: ! 345: This routine creates an object for the device and then calls the ! 346: SCSI port driver for media capacity and sector size. ! 347: ! 348: Arguments: ! 349: ! 350: DriverObject - Pointer to driver object created by system. ! 351: PortDeviceObject - to connect to SCSI port driver. ! 352: DeviceCount - Number of previously installed Printers. ! 353: PortCapabilities - Pointer to structure returned by SCSI port ! 354: driver describing adapter capabilites (and limitations). ! 355: LunInfo - Pointer to configuration information for this device. ! 356: ! 357: Return Value: ! 358: ! 359: NTSTATUS ! 360: ! 361: --*/ ! 362: { ! 363: UCHAR ntNameBuffer[64]; ! 364: STRING ntNameString; ! 365: UNICODE_STRING ntUnicodeString; ! 366: CCHAR dosNameBuffer[64]; ! 367: STRING dosString; ! 368: UNICODE_STRING dosUnicodeString; ! 369: NTSTATUS status; ! 370: PDEVICE_OBJECT deviceObject = NULL; ! 371: PDEVICE_EXTENSION deviceExtension; ! 372: PVOID senseData = NULL; ! 373: ! 374: // ! 375: // Claim the device. ! 376: // ! 377: ! 378: status = ScsiClassClaimDevice(PortDeviceObject, ! 379: LunInfo, ! 380: FALSE, ! 381: &PortDeviceObject); ! 382: ! 383: if (!NT_SUCCESS(status)) { ! 384: return(status); ! 385: } ! 386: ! 387: // ! 388: // Create device object for this device. ! 389: // ! 390: ! 391: sprintf(ntNameBuffer, ! 392: "\\Device\\Printer%d", ! 393: *DeviceCount); ! 394: ! 395: RtlInitString(&ntNameString, ! 396: ntNameBuffer); ! 397: ! 398: DebugPrint((2,"CreatePrinterDeviceObjects: Create device object %s\n", ! 399: ntNameBuffer)); ! 400: ! 401: // ! 402: // Convert ANSI string to Unicode. ! 403: // ! 404: ! 405: status = RtlAnsiStringToUnicodeString(&ntUnicodeString, ! 406: &ntNameString, ! 407: TRUE); ! 408: ! 409: if (!NT_SUCCESS(status)) { ! 410: ! 411: DebugPrint((1, ! 412: "CreateDiskDeviceObjects: Cannot convert string %s\n", ! 413: ntNameBuffer)); ! 414: ! 415: // ! 416: // Release the device since an error occured. ! 417: // ! 418: ! 419: ScsiClassClaimDevice(PortDeviceObject, ! 420: LunInfo, ! 421: TRUE, ! 422: NULL); ! 423: ! 424: return(status); ! 425: } ! 426: ! 427: // ! 428: // Create device object for this Printer. ! 429: // ! 430: ! 431: status = IoCreateDevice(DriverObject, ! 432: DEVICE_EXTENSION_SIZE, ! 433: &ntUnicodeString, ! 434: FILE_DEVICE_PRINTER, ! 435: 0, ! 436: FALSE, ! 437: &deviceObject); ! 438: ! 439: if (!NT_SUCCESS(status)) { ! 440: DebugPrint((1,"CreatePrinterDeviceObjects: Can not create device %s\n", ! 441: ntNameBuffer)); ! 442: ! 443: RtlFreeUnicodeString(&ntUnicodeString); ! 444: deviceObject = NULL; ! 445: goto CreatePrinterDeviceObjectExit; ! 446: } ! 447: ! 448: // ! 449: // Create the DOS printer driver name. ! 450: // ! 451: ! 452: sprintf(dosNameBuffer, ! 453: "\\DosDevices\\LPT%d", ! 454: *DeviceCount + IoGetConfigurationInformation()->ParallelCount + 1); ! 455: ! 456: RtlInitString(&dosString, dosNameBuffer); ! 457: ! 458: status = RtlAnsiStringToUnicodeString(&dosUnicodeString, ! 459: &dosString, ! 460: TRUE); ! 461: ! 462: if(!NT_SUCCESS(status)) { ! 463: dosUnicodeString.Buffer = NULL; ! 464: } ! 465: ! 466: if (dosUnicodeString.Buffer != NULL && ntUnicodeString.Buffer != NULL) { ! 467: IoAssignArcName(&dosUnicodeString, &ntUnicodeString); ! 468: } ! 469: ! 470: if (dosUnicodeString.Buffer != NULL) { ! 471: RtlFreeUnicodeString(&dosUnicodeString); ! 472: } ! 473: ! 474: if (ntUnicodeString.Buffer != NULL ) { ! 475: RtlFreeUnicodeString(&ntUnicodeString); ! 476: } ! 477: ! 478: // ! 479: // Indicate that IRPs should include MDLs. ! 480: // ! 481: ! 482: deviceObject->Flags |= DO_DIRECT_IO; ! 483: ! 484: // ! 485: // Set up required stack size in device object. ! 486: // ! 487: ! 488: deviceObject->StackSize = PortDeviceObject->StackSize + 1; ! 489: ! 490: deviceExtension = deviceObject->DeviceExtension; ! 491: ! 492: // ! 493: // Allocate spinlock for split request completion. ! 494: // ! 495: ! 496: KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); ! 497: ! 498: // ! 499: // This is the physical device. ! 500: // ! 501: ! 502: deviceExtension->PhysicalDevice = deviceObject; ! 503: ! 504: // ! 505: // Copy port device object to device extension. ! 506: // ! 507: ! 508: deviceExtension->PortDeviceObject = PortDeviceObject; ! 509: ! 510: // ! 511: // Save address of port driver capabilities. ! 512: // ! 513: ! 514: deviceExtension->PortCapabilities = PortCapabilities; ! 515: ! 516: // ! 517: // Disable synchronous transfer for Printer requests. ! 518: // ! 519: ! 520: deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER; ! 521: ! 522: // ! 523: // Allocate request sense buffer. ! 524: // ! 525: ! 526: senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); ! 527: ! 528: if (senseData == NULL) { ! 529: ! 530: // ! 531: // The buffer cannot be allocated. ! 532: // ! 533: ! 534: status = STATUS_INSUFFICIENT_RESOURCES; ! 535: goto CreatePrinterDeviceObjectExit; ! 536: } ! 537: ! 538: // ! 539: // Set the sense data pointer in the device extension. ! 540: // ! 541: ! 542: deviceExtension->SenseData = senseData; ! 543: ! 544: // ! 545: // Printers are not partitionable so starting offset is 0. ! 546: // ! 547: ! 548: deviceExtension->StartingOffset.LowPart = 0; ! 549: deviceExtension->StartingOffset.HighPart = 0; ! 550: ! 551: // ! 552: // Path/TargetId/LUN describes a device location on the SCSI bus. ! 553: // This information comes from the LunInfo buffer. ! 554: // ! 555: ! 556: deviceExtension->PathId = LunInfo->PathId; ! 557: deviceExtension->TargetId = LunInfo->TargetId; ! 558: deviceExtension->Lun = LunInfo->Lun; ! 559: ! 560: // ! 561: // Set timeout value in seconds. ! 562: // ! 563: ! 564: deviceExtension->TimeOutValue = 360; ! 565: ! 566: // ! 567: // Back pointer to device object. ! 568: // ! 569: ! 570: deviceExtension->DeviceObject = deviceObject; ! 571: ! 572: return(STATUS_SUCCESS); ! 573: ! 574: CreatePrinterDeviceObjectExit: ! 575: ! 576: // ! 577: // Release the device since an error occured. ! 578: // ! 579: ! 580: ScsiClassClaimDevice(PortDeviceObject, ! 581: LunInfo, ! 582: TRUE, ! 583: NULL); ! 584: ! 585: if (senseData != NULL) { ! 586: ExFreePool(senseData); ! 587: } ! 588: ! 589: if (deviceObject != NULL) { ! 590: IoDeleteDevice(deviceObject); ! 591: } ! 592: ! 593: return status; ! 594: ! 595: } // end CreatePrinterDeviceObject() ! 596: ! 597: ! 598: NTSTATUS ! 599: ScsiPrinterOpen( ! 600: IN PDEVICE_OBJECT DeviceObject, ! 601: IN PIRP Irp ! 602: ) ! 603: ! 604: /*++ ! 605: ! 606: Routine Description: ! 607: ! 608: This routine is called to establish a connection to the printer ! 609: class driver. It does no more than return STATUS_SUCCESS. ! 610: ! 611: Arguments: ! 612: ! 613: DeviceObject - Device object for a printer. ! 614: Irp - Open request packet ! 615: ! 616: Return Value: ! 617: ! 618: NT Status - STATUS_SUCCESS ! 619: ! 620: --*/ ! 621: ! 622: { ! 623: // ! 624: // Set status in Irp. ! 625: // ! 626: ! 627: Irp->IoStatus.Status = STATUS_SUCCESS; ! 628: ! 629: // ! 630: // Complete request at raised IRQ. ! 631: // ! 632: ! 633: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 634: return STATUS_SUCCESS; ! 635: ! 636: } // end ScsiPrinterOpen() ! 637: ! 638: ! 639: NTSTATUS ! 640: ScsiPrinterWrite( ! 641: IN PDEVICE_OBJECT DeviceObject, ! 642: IN PIRP Irp ! 643: ) ! 644: ! 645: /*++ ! 646: ! 647: Routine Description: ! 648: ! 649: This is the entry called by the I/O system for print requests. ! 650: ! 651: Arguments: ! 652: ! 653: DeviceObject - the system object for the device. ! 654: Irp - IRP involved. ! 655: ! 656: Return Value: ! 657: ! 658: NT Status ! 659: ! 660: --*/ ! 661: ! 662: { ! 663: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 664: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ! 665: ULONG transferByteCount = currentIrpStack->Parameters.Write.Length; ! 666: LARGE_INTEGER startingOffset = ! 667: currentIrpStack->Parameters.Write.ByteOffset; ! 668: ULONG maximumTransferLength = ! 669: deviceExtension->PortCapabilities->MaximumTransferLength; ! 670: ULONG transferPages; ! 671: ! 672: DebugPrint((3,"ScsiPrinterWrite: Enter routine\n")); ! 673: ! 674: // ! 675: // Mark IRP with status pending. ! 676: // ! 677: ! 678: IoMarkIrpPending(Irp); ! 679: ! 680: // ! 681: // Check if request length is greater than the maximum number of ! 682: // bytes that the hardware can transfer. ! 683: // ! 684: ! 685: if (currentIrpStack->Parameters.Write.Length > maximumTransferLength) { ! 686: ! 687: DebugPrint((2,"ScsiPrinterWrite: Request greater than maximum\n")); ! 688: DebugPrint((2,"ScsiPrinterWrite: Maximum is %lx\n", ! 689: maximumTransferLength)); ! 690: DebugPrint((2,"ScsiPrinterWrite: Byte count is %lx\n", ! 691: currentIrpStack->Parameters.Write.Length)); ! 692: ! 693: ASSERT(0); ! 694: ! 695: // ! 696: // Request greater than port driver maximum. ! 697: // Break up into smaller routines. ! 698: // ! 699: ! 700: ScsiClassSplitRequest(DeviceObject, Irp, maximumTransferLength); ! 701: ! 702: return STATUS_PENDING; ! 703: } ! 704: ! 705: // ! 706: // Calculate number of pages in this transfer. ! 707: // ! 708: ! 709: transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( ! 710: MmGetMdlVirtualAddress(Irp->MdlAddress), ! 711: currentIrpStack->Parameters.Write.Length); ! 712: ! 713: // ! 714: // Check if number of pages is greater than adapter's maximum ! 715: // number of physical breaks. ! 716: // ! 717: ! 718: if (transferPages > ! 719: deviceExtension->PortCapabilities->MaximumPhysicalPages) { ! 720: ! 721: DebugPrint((1,"ScsiPrinterWrite: Request greater than maximum\n")); ! 722: DebugPrint((1,"ScsiPrinterWrite: Maximum pages is %lx\n", ! 723: deviceExtension->PortCapabilities->MaximumPhysicalPages)); ! 724: DebugPrint((1,"ScsiPrinterWrite: Number of pages is %lx\n", ! 725: transferPages)); ! 726: ! 727: ASSERT(0); ! 728: ! 729: // ! 730: // Calculate maximum bytes to transfer that gaurantees ! 731: // not exceeding the maximum number of page breaks, ! 732: // assuming that the transfer may not be page alligned. ! 733: // ! 734: ! 735: maximumTransferLength = (transferPages - 1) * PAGE_SIZE; ! 736: ! 737: // ! 738: // Request greater than port driver maximum. ! 739: // Break up into smaller routines. ! 740: // ! 741: ! 742: SplitRequest(DeviceObject, Irp, maximumTransferLength); ! 743: ! 744: return STATUS_PENDING; ! 745: } ! 746: ! 747: // ! 748: // Build SRB and CDB for this IRP. ! 749: // ! 750: ! 751: BuildPrintRequest(DeviceObject, Irp); ! 752: ! 753: // ! 754: // Return the results of the call to the port driver. ! 755: // ! 756: ! 757: return IoCallDriver(deviceExtension->PortDeviceObject, Irp); ! 758: ! 759: } // end ScsiPrinterWrite() ! 760: ! 761: ! 762: NTSTATUS ! 763: ScsiPrinterDeviceControl( ! 764: IN PDEVICE_OBJECT DeviceObject, ! 765: IN PIRP Irp ! 766: ) ! 767: ! 768: /*++ ! 769: ! 770: Routine Description: ! 771: ! 772: This is the NT device control handler for Printers. ! 773: ! 774: Arguments: ! 775: ! 776: DeviceObject - for this Printer ! 777: ! 778: Irp - IO Request packet ! 779: ! 780: Return Value: ! 781: ! 782: NTSTATUS ! 783: ! 784: --*/ ! 785: ! 786: { ! 787: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); ! 788: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 789: SCSI_REQUEST_BLOCK srb; ! 790: PCDB cdb = (PCDB)srb.Cdb; ! 791: PVOID outputBuffer = Irp->AssociatedIrp.SystemBuffer; ! 792: ULONG bytesTransferred = 0; ! 793: NTSTATUS status; ! 794: ! 795: DebugPrint((3,"ScsiPrinterDeviceControl: Enter routine\n")); ! 796: ! 797: // ! 798: // Zero CDB in SRB on stack. ! 799: // ! 800: ! 801: RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE); ! 802: ! 803: switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { ! 804: ! 805: case IOCTL_SERIAL_SET_TIMEOUTS: { ! 806: ! 807: PSERIAL_TIMEOUTS newTimeouts = ! 808: ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer)); ! 809: ! 810: if (irpStack->Parameters.DeviceIoControl.InputBufferLength < ! 811: sizeof(SERIAL_TIMEOUTS)) { ! 812: ! 813: status = STATUS_BUFFER_TOO_SMALL; ! 814: } else if (newTimeouts->WriteTotalTimeoutConstant < 2000) { ! 815: ! 816: status = STATUS_INVALID_PARAMETER; ! 817: } else { ! 818: deviceExtension->TimeOutValue = ! 819: newTimeouts->WriteTotalTimeoutConstant / 1000; ! 820: status = STATUS_SUCCESS; ! 821: } ! 822: ! 823: break; ! 824: } ! 825: ! 826: case IOCTL_SERIAL_GET_TIMEOUTS: ! 827: ! 828: if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < ! 829: sizeof(SERIAL_TIMEOUTS)) { ! 830: ! 831: status = STATUS_BUFFER_TOO_SMALL; ! 832: } else { ! 833: ! 834: RtlZeroMemory( ! 835: Irp->AssociatedIrp.SystemBuffer, ! 836: sizeof(SERIAL_TIMEOUTS) ! 837: ); ! 838: ! 839: Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS); ! 840: ((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer)-> ! 841: WriteTotalTimeoutConstant = ! 842: deviceExtension->TimeOutValue * 1000; ! 843: ! 844: status = STATUS_SUCCESS; ! 845: } ! 846: ! 847: break; ! 848: ! 849: default: ! 850: ! 851: // ! 852: // Pass the request to the common device control routine. ! 853: // ! 854: ! 855: return(ScsiClassDeviceControl(DeviceObject, Irp)); ! 856: ! 857: break; ! 858: ! 859: } // end switch() ! 860: ! 861: // ! 862: // Update IRP with completion status. ! 863: // ! 864: ! 865: Irp->IoStatus.Status = status; ! 866: ! 867: // ! 868: // Complete the request. ! 869: // ! 870: ! 871: IoCompleteRequest(Irp, IO_DISK_INCREMENT); ! 872: DebugPrint((2, "ScsiPrinterDeviceControl: Status is %lx\n", status)); ! 873: return status; ! 874: ! 875: } // end ScsiPrinterDeviceControl() ! 876: ! 877: VOID ! 878: BuildPrintRequest( ! 879: PDEVICE_OBJECT DeviceObject, ! 880: PIRP Irp ! 881: ) ! 882: ! 883: /*++ ! 884: ! 885: Routine Description: ! 886: ! 887: Build SRB and CDB requests to scsi printer. ! 888: ! 889: Arguments: ! 890: ! 891: DeviceObject - Device object representing this printer device. ! 892: Irp - System IO request packet. ! 893: ! 894: Return Value: ! 895: ! 896: None. ! 897: ! 898: --*/ ! 899: ! 900: { ! 901: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 902: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ! 903: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); ! 904: PSCSI_REQUEST_BLOCK srb; ! 905: PCDB cdb; ! 906: ULONG transferLength; ! 907: ! 908: // ! 909: // Allocate an Srb. ! 910: // ! 911: ! 912: if (deviceExtension->SrbZone != NULL && ! 913: (srb = ExInterlockedAllocateFromZone( ! 914: deviceExtension->SrbZone, ! 915: deviceExtension->SrbZoneSpinLock)) != NULL) { ! 916: ! 917: srb->SrbFlags = SRB_FLAGS_ALLOCATED_FROM_ZONE; ! 918: ! 919: } else { ! 920: ! 921: // ! 922: // Allocate Srb from non-paged pool. ! 923: // This call must succeed. ! 924: // ! 925: ! 926: srb = ExAllocatePool(NonPagedPoolMustSucceed, SCSI_REQUEST_BLOCK_SIZE); ! 927: ! 928: srb->SrbFlags = 0; ! 929: } ! 930: ! 931: // ! 932: // Write length to SRB. ! 933: // ! 934: ! 935: srb->Length = SCSI_REQUEST_BLOCK_SIZE; ! 936: ! 937: // ! 938: // Set up IRP Address. ! 939: // ! 940: ! 941: srb->OriginalRequest = Irp; ! 942: ! 943: // ! 944: // Set up target id and logical unit number. ! 945: // ! 946: ! 947: srb->PathId = deviceExtension->PathId; ! 948: srb->TargetId = deviceExtension->TargetId; ! 949: srb->Lun = deviceExtension->Lun; ! 950: ! 951: srb->Function = SRB_FUNCTION_EXECUTE_SCSI; ! 952: ! 953: srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); ! 954: ! 955: // ! 956: // Save byte count of transfer in SRB Extension. ! 957: // ! 958: ! 959: srb->DataTransferLength = currentIrpStack->Parameters.Write.Length; ! 960: ! 961: // ! 962: // Initialize the queue actions field. ! 963: // ! 964: ! 965: srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; ! 966: ! 967: // ! 968: // Queue sort key is not used. ! 969: // ! 970: ! 971: srb->QueueSortKey = 0; ! 972: ! 973: // ! 974: // Indicate auto request sense by specifying buffer and size. ! 975: // ! 976: ! 977: srb->SenseInfoBuffer = deviceExtension->SenseData; ! 978: ! 979: srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; ! 980: ! 981: // ! 982: // Set timeout value in seconds. ! 983: // ! 984: ! 985: srb->TimeOutValue = deviceExtension->TimeOutValue; ! 986: ! 987: // ! 988: // Zero statuses. ! 989: // ! 990: ! 991: srb->SrbStatus = srb->ScsiStatus = 0; ! 992: ! 993: srb->NextSrb = 0; ! 994: ! 995: // ! 996: // Calculate number of blocks to transfer. ! 997: // ! 998: ! 999: transferLength = currentIrpStack->Parameters.Write.Length; ! 1000: ! 1001: // ! 1002: // Get pointer to CDB in SRB. ! 1003: // ! 1004: ! 1005: cdb = (PCDB)srb->Cdb; ! 1006: ! 1007: // ! 1008: // Indicate that 6-byte CDB's will be used. ! 1009: // ! 1010: ! 1011: srb->CdbLength = 6; ! 1012: ! 1013: cdb->PRINT.LogicalUnitNumber = deviceExtension->Lun; ! 1014: ! 1015: // ! 1016: // Zero out reserved field. ! 1017: // ! 1018: ! 1019: cdb->PRINT.Reserved = 0; ! 1020: ! 1021: // ! 1022: // Move little endian values into CDB in big endian format. ! 1023: // ! 1024: ! 1025: cdb->PRINT.TransferLength[2] = ((PFOUR_BYTE)&transferLength)->Byte0; ! 1026: cdb->PRINT.TransferLength[1] = ((PFOUR_BYTE)&transferLength)->Byte1; ! 1027: cdb->PRINT.TransferLength[0] = ((PFOUR_BYTE)&transferLength)->Byte2; ! 1028: ! 1029: cdb->PRINT.Control = 0; ! 1030: ! 1031: // ! 1032: // Set transfer direction flag and Cdb command. ! 1033: // The operation field is at the same location ! 1034: // for 6- and 10-byte CDBs. ! 1035: // ! 1036: ! 1037: srb->SrbFlags |= SRB_FLAGS_DATA_OUT; ! 1038: cdb->PRINT.OperationCode = SCSIOP_PRINT; ! 1039: ! 1040: // ! 1041: // Or in the default flags from the device object. ! 1042: // ! 1043: ! 1044: srb->SrbFlags |= deviceExtension->SrbFlags; ! 1045: ! 1046: // ! 1047: // Set up major SCSI function. ! 1048: // ! 1049: ! 1050: nextIrpStack->MajorFunction = IRP_MJ_SCSI; ! 1051: ! 1052: // ! 1053: // Save SRB address in next stack for port driver. ! 1054: // ! 1055: ! 1056: nextIrpStack->Parameters.Scsi.Srb = srb; ! 1057: ! 1058: // ! 1059: // Save retry count in current IRP stack. ! 1060: // ! 1061: ! 1062: currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; ! 1063: ! 1064: // ! 1065: // Set up IoCompletion routine address. ! 1066: // ! 1067: ! 1068: IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, FALSE); ! 1069: ! 1070: return; ! 1071: ! 1072: } // end BuildPrintRequest() ! 1073: ! 1074: ! 1075: VOID ! 1076: SplitRequest( ! 1077: IN PDEVICE_OBJECT DeviceObject, ! 1078: IN PIRP Irp, ! 1079: IN ULONG MaximumBytes ! 1080: ) ! 1081: ! 1082: /*++ ! 1083: ! 1084: Routine Description: ! 1085: ! 1086: Break request into smaller requests. Each new request will be the ! 1087: maximum transfer size that the port driver can handle or if it ! 1088: is the final request, it may be the residual size. ! 1089: ! 1090: The number of IRPs required to process this request is written in the ! 1091: current stack of the original IRP. Then as each new IRP completes ! 1092: the count in the original IRP is decremented. When the count goes to ! 1093: zero, the original IRP is completed. ! 1094: ! 1095: Arguments: ! 1096: ! 1097: DeviceObject - Pointer to the class device object to be addressed. ! 1098: ! 1099: Irp - Pointer to Irp the orginal request. ! 1100: ! 1101: Return Value: ! 1102: ! 1103: None. ! 1104: ! 1105: --*/ ! 1106: ! 1107: { ! 1108: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 1109: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ! 1110: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); ! 1111: ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; ! 1112: LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset; ! 1113: PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); ! 1114: ULONG dataLength = MaximumBytes; ! 1115: ULONG irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes; ! 1116: PSCSI_REQUEST_BLOCK srb; ! 1117: ULONG i; ! 1118: ! 1119: DebugPrint((1, "SplitRequest: Requires %d IRPs\n", irpCount)); ! 1120: DebugPrint((1, "SplitRequest: Original IRP %lx\n", Irp)); ! 1121: ! 1122: // ! 1123: // If all partial transfers complete successfully then the status and ! 1124: // bytes transferred are already set up. Failing a partial-transfer IRP ! 1125: // will set status to error and bytes transferred to 0 during ! 1126: // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows ! 1127: // asynchronous partial transfers. This is an optimization for the ! 1128: // successful case. ! 1129: // ! 1130: ! 1131: Irp->IoStatus.Status = STATUS_SUCCESS; ! 1132: Irp->IoStatus.Information = transferByteCount; ! 1133: ! 1134: // ! 1135: // Save number of IRPs to complete count on current stack ! 1136: // of original IRP. ! 1137: // ! 1138: ! 1139: nextIrpStack->Parameters.Others.Argument1 = (PVOID) irpCount; ! 1140: ! 1141: for (i = 0; i < irpCount; i++) { ! 1142: ! 1143: PIRP newIrp; ! 1144: PIO_STACK_LOCATION newIrpStack; ! 1145: ! 1146: // ! 1147: // Allocate new IRP. ! 1148: // ! 1149: ! 1150: newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE); ! 1151: ! 1152: if (newIrp == NULL) { ! 1153: ! 1154: DebugPrint((1,"SplitRequest: Can't allocate Irp\n")); ! 1155: ! 1156: // ! 1157: // If an Irp can't be allocated then the orginal request cannot ! 1158: // be executed. If this is the first request then just fail the ! 1159: // orginal request; otherwise just return. When the pending ! 1160: // requests complete, they will complete the original request. ! 1161: // In either case set the IRP status to failure. ! 1162: // ! 1163: ! 1164: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; ! 1165: Irp->IoStatus.Information = 0; ! 1166: ! 1167: if (i == 0) { ! 1168: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 1169: } ! 1170: ! 1171: return; ! 1172: } ! 1173: ! 1174: DebugPrint((2, "SplitRequest: New IRP %lx\n", newIrp)); ! 1175: ! 1176: // ! 1177: // Write MDL address to new IRP. In the port driver the SRB data ! 1178: // buffer field is used as an offset into the MDL, so the same MDL ! 1179: // can be used for each partial transfer. This saves having to build ! 1180: // a new MDL for each partial transfer. ! 1181: // ! 1182: ! 1183: newIrp->MdlAddress = Irp->MdlAddress; ! 1184: ! 1185: // ! 1186: // At this point there is no current stack. IoSetNextIrpStackLocation ! 1187: // will make the first stack location the current stack so that the ! 1188: // SRB address can be written there. ! 1189: // ! 1190: ! 1191: IoSetNextIrpStackLocation(newIrp); ! 1192: newIrpStack = IoGetCurrentIrpStackLocation(newIrp); ! 1193: ! 1194: newIrpStack->MajorFunction = currentIrpStack->MajorFunction; ! 1195: newIrpStack->Parameters.Read.Length = dataLength; ! 1196: newIrpStack->Parameters.Read.ByteOffset = startingOffset; ! 1197: newIrpStack->DeviceObject = DeviceObject; ! 1198: ! 1199: // ! 1200: // Build SRB and CDB. ! 1201: // ! 1202: ! 1203: BuildPrintRequest(DeviceObject, newIrp); ! 1204: ! 1205: // ! 1206: // Adjust SRB for this partial transfer. ! 1207: // ! 1208: ! 1209: newIrpStack = IoGetNextIrpStackLocation(newIrp); ! 1210: ! 1211: srb = newIrpStack->Parameters.Others.Argument1; ! 1212: srb->DataBuffer = dataBuffer; ! 1213: ! 1214: // ! 1215: // Write original IRP address to new IRP. ! 1216: // ! 1217: ! 1218: newIrp->AssociatedIrp.MasterIrp = Irp; ! 1219: ! 1220: // ! 1221: // Set the completion routine to ScsiClassIoCompleteAssociated. ! 1222: // ! 1223: ! 1224: IoSetCompletionRoutine(newIrp, ! 1225: ScsiClassIoCompleteAssociated, ! 1226: srb, ! 1227: TRUE, ! 1228: TRUE, ! 1229: TRUE); ! 1230: ! 1231: // ! 1232: // Call port driver with new request. ! 1233: // ! 1234: ! 1235: IoCallDriver(deviceExtension->PortDeviceObject, newIrp); ! 1236: ! 1237: // ! 1238: // Set up for next request. ! 1239: // ! 1240: ! 1241: dataBuffer = (PCHAR)dataBuffer + MaximumBytes; ! 1242: ! 1243: transferByteCount -= MaximumBytes; ! 1244: ! 1245: if (transferByteCount > MaximumBytes) { ! 1246: ! 1247: dataLength = MaximumBytes; ! 1248: ! 1249: } else { ! 1250: ! 1251: dataLength = transferByteCount; ! 1252: } ! 1253: ! 1254: // ! 1255: // Adjust disk byte offset. ! 1256: // ! 1257: ! 1258: startingOffset = LiAdd(startingOffset, LiFromUlong(MaximumBytes)); ! 1259: } ! 1260: ! 1261: return; ! 1262: ! 1263: } // end SplitRequest() ! 1264:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.