|
|
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.