Annotation of ntddk/src/scsi/scsiprnt/scsiprnt.c, revision 1.1

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: 

unix.superglobalmegacorp.com

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