|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1990, 1991, 1992, 1993 Microsoft Corporation
4:
5: Module Name:
6:
7: pardrvr.c
8:
9: Abstract:
10:
11: This module contains the code that does the non-initialization work
12: of the parallel driver.
13:
14: Environment:
15:
16: Kernel mode
17:
18: Revision History :
19:
20: Complete rewrite to make it thread based and polled.
21:
22:
23: --*/
24:
25: //
26: // Note that we include ntddser that we can use the serials
27: // timeout structure and ioctl to set the timeout for a write.
28: //
29:
30: #include <stddef.h>
31: #include "ntddk.h"
32: #include "ntddpar.h"
33: #include "ntddser.h"
34: #include "par.h"
35: #include "parlog.h"
36:
37: #define VALID_FLAGS PARALLEL_INIT & ( PARALLEL_INIT | PARALLEL_AUTOFEED )
38:
39: //
40: // Busy, PE
41: //
42:
43: #define PAR_PAPER_EMPTY( Status ) ( \
44: (Status & PAR_STATUS_PE) )
45:
46: //
47: // Busy, not select, not error
48: //
49:
50: #define PAR_OFF_LINE( Status ) ( \
51: (Status & PAR_STATUS_NOT_ERROR) && \
52: ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
53: !(Status & PAR_STATUS_SLCT) )
54:
55: //
56: // error, ack, not busy
57: //
58:
59: #define PAR_POWERED_OFF( Status ) ( \
60: ((Status & PAR_STATUS_NOT_ERROR) ^ PAR_STATUS_NOT_ERROR) && \
61: ((Status & PAR_STATUS_NOT_ACK) ^ PAR_STATUS_NOT_ACK) && \
62: (Status & PAR_STATUS_NOT_BUSY))
63:
64: //
65: // not error, not busy, not select
66: //
67:
68: #define PAR_NOT_CONNECTED( Status ) ( \
69: (Status & PAR_STATUS_NOT_ERROR) && \
70: (Status & PAR_STATUS_NOT_BUSY) &&\
71: !(Status & PAR_STATUS_SLCT) )
72:
73: //
74: // not error, not busy
75: //
76:
77: #define PAR_OK(Status) ( \
78: (Status & PAR_STATUS_NOT_ERROR) && \
79: ((Status & PAR_STATUS_PE) ^ PAR_STATUS_PE) && \
80: (Status & PAR_STATUS_NOT_BUSY) )
81:
82: //
83: // not error, not busy, selected.
84: //
85: #define PAR_ONLINE(Status) ( \
86: (Status & PAR_STATUS_NOT_ERROR) && \
87: (Status & PAR_STATUS_NOT_BUSY) && \
88: ((Status & PAR_STATUS_PE) ^ PAR_STATUS_PE) && \
89: (Status & PAR_STATUS_SLCT) )
90:
91: //
92: // busy, select, not error
93: //
94:
95: #define PAR_POWERED_ON(Status) ( \
96: ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
97: (Status & PAR_STATUS_SLCT) && \
98: (Status & PAR_STATUS_NOT_ERROR))
99:
100: //
101: // busy, not error
102: //
103:
104: #define PAR_BUSY(Status) (\
105: (( Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
106: ( Status & PAR_STATUS_NOT_ERROR ) )
107:
108: //
109: // selected
110: //
111:
112: #define PAR_SELECTED(Status) ( \
113: ( Status & PAR_STATUS_SLCT ) )
114:
115: //
116: // No cable attached.
117: //
118: #define PAR_NO_CABLE(Status) ( \
119: ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
120: (Status & PAR_STATUS_NOT_ACK) && \
121: (Status & PAR_STATUS_PE) && \
122: (Status & PAR_STATUS_SLCT) && \
123: (Status & PAR_STATUS_NOT_ERROR))
124:
125: //
126: // autofeed
127: //
128:
129: #define PAR_AUTOFEED( Control ) (\
130: ( Control & PAR_CONTROL_AUTOFD ) )
131:
132: typedef struct _LOAD_PACKET {
133: NTSTATUS *Status;
134: PPAR_DEVICE_EXTENSION Extension;
135: WORK_QUEUE_ITEM WorkQueueItem;
136: KEVENT Event;
137: } LOAD_PACKET,*PLOAD_PACKET;
138:
139: VOID
140: ParallelThread(
141: IN PVOID Context
142: );
143:
144: VOID
145: ParWriteOutData(
146: PPAR_DEVICE_EXTENSION Extension
147: );
148:
149: VOID
150: ParCreateSystemThread(
151: PVOID Context
152: );
153:
154: VOID
155: ParNotInitError(
156: IN PPAR_DEVICE_EXTENSION Extension,
157: IN UCHAR deviceStatus
158: );
159:
160:
161: UCHAR
162: ParInitializeDevice(
163: IN PPAR_DEVICE_EXTENSION Extension
164: )
165:
166: /*++
167:
168: Routine Description:
169:
170: This routine is invoked to initialize the parallel port drive.
171: It performs the following actions:
172:
173: o Send INIT to the driver and if the device is online, it sends
174: SLIN
175:
176: Arguments:
177:
178: Context - Really the device extension.
179:
180: Return Value:
181:
182: The last value that we got from the status register.
183:
184: --*/
185:
186: {
187:
188: KIRQL oldIrql;
189: LONG countDown;
190: UCHAR deviceStatus;
191: LARGE_INTEGER startOfSpin;
192: LARGE_INTEGER nextQuery;
193: LARGE_INTEGER difference;
194: BOOLEAN doDelays;
195:
196: deviceStatus = GetStatus(Extension->Controller);
197: ParDump(
198: PARINITDEV,
199: ("PARALLEL: In ParInitializeDevice - device status is %x\n"
200: " Initialized: %x\n",
201: deviceStatus,
202: Extension->Initialized)
203: );
204:
205: if (!Extension->Initialized) {
206:
207: //
208: // Clear the register.
209: //
210:
211: if (GetControl(Extension->Controller) &
212: PAR_CONTROL_NOT_INIT) {
213:
214: //
215: // We should stall for at least 60 microseconds after
216: // the init.
217: //
218:
219: KeRaiseIrql(
220: DISPATCH_LEVEL,
221: &oldIrql
222: );
223: StoreControl(
224: Extension->Controller,
225: (UCHAR)(PAR_CONTROL_WR_CONTROL)
226: );
227: KeStallExecutionProcessor(60);
228: KeLowerIrql(oldIrql);
229:
230: }
231:
232: if (Extension->AutoFeed) {
233:
234: StoreControl(
235: Extension->Controller,
236: (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT |
237: PAR_CONTROL_AUTOFD)
238: );
239:
240: } else {
241:
242: StoreControl(
243: Extension->Controller,
244: (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT)
245: );
246:
247: }
248:
249: //
250: // Spin for up to 15 seconds waiting for the device
251: // to initialize.
252: //
253:
254: countDown = 15;
255: doDelays = FALSE;
256: KeQueryTickCount(&startOfSpin);
257: ParDump(
258: PARINITDEV,
259: ("PARALLEL: Starting init wait loop\n")
260: );
261: do {
262:
263: //
264: // After about a second of spinning, let the rest of
265: // the machine have time for one second.
266: //
267:
268: if (doDelays) {
269:
270: difference = RtlLargeIntegerNegate(Extension->AbsoluteOneSecond);
271: KeDelayExecutionThread(
272: KernelMode,
273: FALSE,
274: &difference
275: );
276: ParDump(
277: PARINITDEV,
278: ("PARALLEL: Did delay thread of one second\n")
279: );
280: countDown--;
281:
282: } else {
283:
284: KeQueryTickCount(&nextQuery);
285:
286: difference = RtlLargeIntegerSubtract(
287: nextQuery,
288: startOfSpin
289: );
290:
291: ASSERT(KeQueryTimeIncrement() <= MAXLONG);
292: if (RtlLargeIntegerGreaterThanOrEqualTo(
293: RtlExtendedIntegerMultiply(
294: difference,
295: (LONG)KeQueryTimeIncrement()
296: ),
297: Extension->AbsoluteOneSecond
298: )) {
299:
300: ParDump(
301: PARINITDEV,
302: ("PARALLEL: Did spin of one second\n"
303: " startOfSpin: %x nextQuery: %x\n",
304: startOfSpin.LowPart,nextQuery.LowPart)
305: );
306: ParDump(
307: PARINITDEV,
308: ("PARALLEL: parintialize 1 seconds wait\n")
309: );
310: countDown--;
311: doDelays = TRUE;
312:
313: }
314:
315: }
316:
317: if (countDown <= 0) {
318:
319: ParDump(
320: PARINITDEV,
321: ("PARALLEL: leaving with init timeout - status %x\n",
322: deviceStatus)
323: );
324: Extension->Initialized = FALSE;
325: return deviceStatus;
326:
327: }
328:
329: deviceStatus = GetStatus(Extension->Controller);
330:
331: } while (PAR_BUSY(deviceStatus) ||
332: ((!PAR_OK(deviceStatus)) &&
333: (!PAR_OFF_LINE(deviceStatus)) &&
334: (!PAR_POWERED_OFF(deviceStatus)) &&
335: (!PAR_NOT_CONNECTED(deviceStatus)) &&
336: (!PAR_NO_CABLE(deviceStatus))));
337:
338: if (PAR_OK(deviceStatus) || PAR_OFF_LINE(deviceStatus)) {
339:
340: ParDump(
341: PARINITDEV,
342: ("PARALLEL: device is set to initialized\n")
343: );
344: Extension->Initialized = TRUE;
345:
346: }
347:
348: }
349:
350: ParDump(
351: PARINITDEV,
352: ("PARALLEL: In ParInitializeDevice - leaving with device status is %x\n",
353: deviceStatus)
354: );
355: return deviceStatus;
356:
357: }
358:
359: NTSTATUS
360: ParCreateOpen(
361: IN PDEVICE_OBJECT DeviceObject,
362: IN PIRP Irp
363: )
364:
365: {
366:
367: NTSTATUS returnStatus;
368: PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
369: PLOAD_PACKET loadPacket;
370:
371: ParDump(
372: PARIRPPATH,
373: ("PARALLEL: In create/open with IRP: %x\n",
374: Irp)
375: );
376: Irp->IoStatus.Information = 0;
377:
378: if (!extension->Initialized) {
379:
380: UCHAR deviceStatus = ParInitializeDevice(extension);
381:
382: if (!extension->Initialized) {
383:
384: extension->CurrentOpIrp = Irp;
385:
386: ParNotInitError(
387: extension,
388: deviceStatus
389: );
390:
391: extension->CurrentOpIrp = NULL;
392: returnStatus = Irp->IoStatus.Status;
393: goto AllDone;
394:
395: }
396:
397: }
398:
399: extension->TimeToTerminateThread = FALSE;
400: extension->ThreadObjectPointer = NULL;
401: ParDump(
402: PARTHREAD,
403: ("PARALLEL: open initializing - state before init - %d\n",
404: extension->RequestSemaphore.Header.SignalState)
405: );
406: KeInitializeSemaphore(
407: &extension->RequestSemaphore,
408: 0L,
409: MAXLONG
410: );
411:
412: if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Create.Options
413: & FILE_DIRECTORY_FILE) {
414:
415: returnStatus = Irp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
416:
417: } else {
418:
419: loadPacket = ExAllocatePool(
420: PagedPool,
421: sizeof(LOAD_PACKET)
422: );
423:
424: if (!loadPacket) {
425:
426: returnStatus = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
427:
428: } else {
429:
430: loadPacket->Status = &Irp->IoStatus.Status;
431: loadPacket->Extension = extension;
432: KeInitializeEvent(
433: &loadPacket->Event,
434: NotificationEvent,
435: FALSE
436: );
437: ExInitializeWorkItem(
438: &loadPacket->WorkQueueItem,
439: ParCreateSystemThread,
440: loadPacket
441: );
442: ExQueueWorkItem(
443: &loadPacket->WorkQueueItem,
444: DelayedWorkQueue
445: );
446: KeWaitForSingleObject(
447: &loadPacket->Event,
448: UserRequest,
449: KernelMode,
450: FALSE,
451: NULL
452: );
453:
454: returnStatus = Irp->IoStatus.Status;
455:
456: }
457:
458: }
459:
460: AllDone:;
461:
462: ParDump(
463: PARIRPPATH,
464: ("PARALLEL: About to complete IRP in create/open\n"
465: "Irp: %x status: %x Information: %x\n",
466: Irp,
467: Irp->IoStatus.Status,
468: Irp->IoStatus.Information)
469: );
470: IoCompleteRequest(
471: Irp,
472: IO_NO_INCREMENT
473: );
474:
475: return returnStatus;
476:
477: }
478:
479: VOID
480: ParCreateSystemThread(
481: PVOID Context
482: )
483:
484: {
485:
486: HANDLE threadHandle;
487: //
488: // This function is executing in the context of a system
489: // worker thread. It is used so that we can create a
490: // thread in the context of the system process.
491: //
492:
493: PLOAD_PACKET lp = Context;
494:
495: //
496: // Start the thread and capture the thread handle into the extension
497: //
498:
499: *lp->Status = PsCreateSystemThread(
500: &threadHandle,
501: THREAD_ALL_ACCESS,
502: NULL,
503: NULL,
504: NULL,
505: ParallelThread,
506: lp->Extension
507: );
508:
509: if (!NT_ERROR(*lp->Status)) {
510:
511: //
512: // We've got the thread. Now get a pointer to it.
513: //
514:
515: *lp->Status = ObReferenceObjectByHandle(
516: threadHandle,
517: THREAD_ALL_ACCESS,
518: NULL,
519: KernelMode,
520: &lp->Extension->ThreadObjectPointer,
521: NULL
522: );
523:
524: if (NT_ERROR(*lp->Status)) {
525:
526: ParDump(
527: PARIRPPATH,
528: ("PARALLEL: Bad status on open from ref by handle: %x\n",
529: *lp->Status)
530: );
531:
532: lp->Extension->TimeToTerminateThread = TRUE;
533: KeReleaseSemaphore(
534: &lp->Extension->RequestSemaphore,
535: 0,
536: 1,
537: FALSE
538: );
539:
540: } else {
541:
542: //
543: // Now that we have a reference to the thread
544: // we can simply close the handle.
545: //
546:
547: ZwClose(threadHandle);
548:
549: }
550:
551: } else {
552:
553: ParDump(
554: PARIRPPATH,
555: ("PARALLEL: Bad status on open from ref by handle: %x\n",
556: *lp->Status)
557: );
558:
559: }
560:
561: //
562: // We're all done. Let the open code proceed.
563: //
564:
565: KeSetEvent(
566: &lp->Event,
567: 0,
568: FALSE
569: );
570:
571: }
572:
573: NTSTATUS
574: ParClose(
575: IN PDEVICE_OBJECT DeviceObject,
576: IN PIRP Irp
577: )
578:
579: {
580:
581: PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
582: NTSTATUS statusOfWait;
583:
584: ParDump(
585: PARIRPPATH,
586: ("PARALLEL: In close with IRP: %x\n",
587: Irp)
588: );
589:
590: //
591: // Set the semaphore that will wake up the thread, which
592: // will then notice that the thread is supposed to die.
593: //
594:
595: Irp->IoStatus.Status = STATUS_SUCCESS;
596: Irp->IoStatus.Information = 0;
597: extension->TimeToTerminateThread = TRUE;
598: ParDump(
599: PARTHREAD,
600: ("PARALLEL: close releasing - state before release - %d\n",
601: extension->RequestSemaphore.Header.SignalState)
602: );
603: KeReleaseSemaphore(
604: &extension->RequestSemaphore,
605: 0,
606: 1,
607: FALSE
608: );
609:
610: //
611: // Wait on the thread handle, when the wait is satisfied, the
612: // thread has gone away.
613: //
614:
615: statusOfWait = KeWaitForSingleObject(
616: extension->ThreadObjectPointer,
617: UserRequest,
618: KernelMode,
619: FALSE,
620: NULL
621: );
622:
623: ParDump(
624: PARTHREAD,
625: ("PARALLEL: return status of waiting for thread to die: %x\n",
626: statusOfWait)
627: );
628:
629: //
630: // Thread is gone. Status is successful for the close.
631: // Defreference the pointer to the thread object.
632: //
633:
634: ObDereferenceObject(extension->ThreadObjectPointer);
635: extension->ThreadObjectPointer = NULL;
636:
637: ParDump(
638: PARIRPPATH,
639: ("PARALLEL: About to complete IRP in close\n"
640: "Irp: %x status: %x Information: %x\n",
641: Irp,
642: Irp->IoStatus.Status,
643: Irp->IoStatus.Information)
644: );
645: IoCompleteRequest(
646: Irp,
647: IO_NO_INCREMENT
648: );
649:
650: return STATUS_SUCCESS;
651: }
652:
653: NTSTATUS
654: ParCleanup(
655: IN PDEVICE_OBJECT DeviceObject,
656: IN PIRP Irp
657: )
658:
659: {
660:
661: KIRQL cancelIrql;
662: PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
663:
664: ParDump(
665: PARIRPPATH,
666: ("PARALLEL: In cleanup with IRP: %x\n",
667: Irp)
668: );
669:
670: //
671: // While the list is not empty, go through and cancel each irp.
672: //
673:
674: IoAcquireCancelSpinLock(&cancelIrql);
675:
676:
677: //
678: // Clean the list from back to front.
679: //
680:
681: while (!IsListEmpty(&extension->WorkQueue)) {
682:
683: PDRIVER_CANCEL cancelRoutine;
684: PIRP currentLastIrp = CONTAINING_RECORD(
685: extension->WorkQueue.Blink,
686: IRP,
687: Tail.Overlay.ListEntry
688: );
689:
690: RemoveEntryList(extension->WorkQueue.Blink);
691:
692: cancelRoutine = currentLastIrp->CancelRoutine;
693: currentLastIrp->CancelIrql = cancelIrql;
694: currentLastIrp->CancelRoutine = NULL;
695: currentLastIrp->Cancel = TRUE;
696:
697: cancelRoutine(
698: DeviceObject,
699: currentLastIrp
700: );
701:
702: IoAcquireCancelSpinLock(&cancelIrql);
703:
704: }
705:
706: //
707: // If there is a current irp then mark it as cancelled.
708: //
709:
710: if (extension->CurrentOpIrp) {
711:
712: extension->CurrentOpIrp->Cancel = TRUE;
713:
714: }
715:
716: IoReleaseCancelSpinLock(cancelIrql);
717:
718: Irp->IoStatus.Status = STATUS_SUCCESS;
719: Irp->IoStatus.Information=0L;
720:
721: ParDump(
722: PARIRPPATH,
723: ("PARALLEL: About to complete IRP in cleanup\n"
724: "Irp: %x status: %x Information: %x\n",
725: Irp,
726: Irp->IoStatus.Status,
727: Irp->IoStatus.Information)
728: );
729: IoCompleteRequest(
730: Irp,
731: IO_NO_INCREMENT
732: );
733:
734: return STATUS_SUCCESS;
735: }
736:
737: NTSTATUS
738: ParDispatch(
739: IN PDEVICE_OBJECT DeviceObject,
740: IN PIRP Irp
741: )
742:
743: /*++
744:
745: Routine Description:
746:
747: This is the main dispatch routine for the parallel port driver.
748: It is given a pointer to the IRP for the current request and
749: it determines what to do with it. If the request is valid and doen't
750: have any parameter errors, then it is placed into the work queue.
751: Otherwise it is not completed and an appropriate error is returned.
752:
753: Arguments:
754:
755: DeviceObject - Pointer to the device object for this device
756:
757: Irp - Pointer to the IRP for the current request
758:
759: Return Value:
760:
761: The function value is the final status of call
762:
763: --*/
764:
765: {
766:
767: NTSTATUS status = STATUS_SUCCESS;
768: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
769: PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
770:
771: ParDump(
772: PARIRPPATH,
773: ("PARALLEL: In main dispatch with IRP: %x\n"
774: "MAIN: %d io control code: %d\n",
775: Irp,
776: irpSp->MajorFunction,
777: irpSp->Parameters.DeviceIoControl.IoControlCode)
778: );
779: Irp->IoStatus.Information=0L;
780: switch(irpSp->MajorFunction) {
781:
782: case IRP_MJ_WRITE:
783:
784: if ((irpSp->Parameters.Write.ByteOffset.HighPart != 0) ||
785: (irpSp->Parameters.Write.ByteOffset.LowPart != 0)) {
786:
787: status = STATUS_INVALID_PARAMETER;
788:
789: } else {
790:
791: if (irpSp->Parameters.Write.Length != 0) {
792:
793: status = STATUS_PENDING;
794: }
795:
796: }
797:
798: break;
799:
800: case IRP_MJ_DEVICE_CONTROL:
801:
802: switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
803:
804: case IOCTL_PAR_SET_INFORMATION :
805:
806: if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
807: 1) {
808:
809: status = STATUS_BUFFER_TOO_SMALL;
810:
811: } else {
812:
813: PPAR_SET_INFORMATION irpBuffer =
814: Irp->AssociatedIrp.SystemBuffer;
815:
816: //
817: // INIT is required, AUTOFEED is optional
818: //
819:
820: if (!(irpBuffer->Init & PARALLEL_INIT) ||
821: (irpBuffer->Init & ~VALID_FLAGS)) {
822:
823: status = STATUS_INVALID_PARAMETER;
824:
825: } else {
826:
827: status = STATUS_PENDING;
828: }
829:
830: }
831:
832: break;
833:
834: case IOCTL_PAR_QUERY_INFORMATION :
835:
836: if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
837: sizeof(PAR_QUERY_INFORMATION)) {
838:
839: status = STATUS_BUFFER_TOO_SMALL;
840:
841: } else {
842:
843: status = STATUS_PENDING;
844: }
845:
846: break;
847:
848: case IOCTL_SERIAL_SET_TIMEOUTS: {
849:
850: PSERIAL_TIMEOUTS NewTimeouts =
851: ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer));
852:
853: if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
854: sizeof(SERIAL_TIMEOUTS)) {
855:
856: status = STATUS_BUFFER_TOO_SMALL;
857: break;
858:
859: } else if (NewTimeouts->WriteTotalTimeoutConstant < 2000) {
860:
861: status = STATUS_INVALID_PARAMETER;
862: break;
863:
864: }
865:
866: status = STATUS_PENDING;
867:
868: break;
869:
870: }
871: case IOCTL_SERIAL_GET_TIMEOUTS:
872:
873: if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
874: sizeof(SERIAL_TIMEOUTS)) {
875:
876: status = STATUS_BUFFER_TOO_SMALL;
877: break;
878:
879: }
880:
881: //
882: // We don't need to synchronize the read.
883: //
884:
885: RtlZeroMemory(
886: Irp->AssociatedIrp.SystemBuffer,
887: sizeof(SERIAL_TIMEOUTS)
888: );
889: Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
890: ((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer)->
891: WriteTotalTimeoutConstant =
892: extension->TimerStart * 1000;
893:
894: break;
895:
896: default :
897:
898: status = STATUS_INVALID_PARAMETER;
899: break;
900:
901: }
902:
903: break;
904:
905: default:
906:
907: status = STATUS_INVALID_PARAMETER;
908: break;
909:
910: }
911:
912: Irp->IoStatus.Status = status;
913:
914: if (status == STATUS_PENDING) {
915:
916: KIRQL oldIrql;
917:
918: //
919: // Acquire the cancel spin lock and put it on the
920: // io queue. Then hit the semaphore and return.
921: //
922:
923: IoAcquireCancelSpinLock(&oldIrql);
924:
925: if (Irp->Cancel) {
926:
927: IoReleaseCancelSpinLock(oldIrql);
928:
929: status = STATUS_CANCELLED;
930: ParDump(
931: PARIRPPATH,
932: ("PARALLEL: About to CANCEL IRP in main dispatch\n"
933: "Irp: %x status: %x Information: %x\n",
934: Irp,
935: Irp->IoStatus.Status,
936: Irp->IoStatus.Information)
937: );
938: IoCompleteRequest(
939: Irp,
940: IO_NO_INCREMENT
941: );
942:
943: } else {
944:
945: ParDump(
946: PARIRPPATH,
947: ("PARALLEL: About to QUEUE IRP in main dispatch\n"
948: "Irp: %x status: %x Information: %x\n",
949: Irp,
950: Irp->IoStatus.Status,
951: Irp->IoStatus.Information)
952: );
953: Irp->IoStatus.Status = STATUS_PENDING;
954: IoMarkIrpPending(Irp);
955: IoSetCancelRoutine(
956: Irp,
957: ParCancelRequest
958: );
959:
960: InsertTailList(
961: &extension->WorkQueue,
962: &Irp->Tail.Overlay.ListEntry
963: );
964:
965: IoReleaseCancelSpinLock(oldIrql);
966:
967: ParDump(
968: PARTHREAD,
969: ("PARALLEL: dispatch releasing - state before release - %d\n",
970: extension->RequestSemaphore.Header.SignalState)
971: );
972: KeReleaseSemaphore(
973: &extension->RequestSemaphore,
974: (KPRIORITY)0,
975: 1,
976: FALSE
977: );
978:
979: }
980:
981: } else {
982:
983: ParDump(
984: PARIRPPATH,
985: ("PARALLEL: About to complete IRP in main dispatch\n"
986: "Irp: %x status: %x Information: %x\n",
987: Irp,
988: Irp->IoStatus.Status,
989: Irp->IoStatus.Information)
990: );
991: IoCompleteRequest(
992: Irp,
993: IO_NO_INCREMENT
994: );
995:
996: }
997:
998: return status;
999:
1000: }
1001:
1002: NTSTATUS
1003: ParQueryInformationFile(
1004: IN PDEVICE_OBJECT DeviceObject,
1005: IN PIRP Irp
1006: )
1007:
1008: /*++
1009:
1010: Routine Description:
1011:
1012: This routine is used to query the end of file information on
1013: the opened parallel port. Any other file information request
1014: is retured with an invalid parameter.
1015:
1016: This routine always returns an end of file of 0.
1017:
1018: Arguments:
1019:
1020: DeviceObject - Pointer to the device object for this device
1021:
1022: Irp - Pointer to the IRP for the current request
1023:
1024: Return Value:
1025:
1026: The function value is the final status of the call
1027:
1028: --*/
1029:
1030: {
1031: //
1032: // The status that gets returned to the caller and
1033: // set in the Irp.
1034: //
1035: NTSTATUS status = STATUS_SUCCESS;
1036:
1037: //
1038: // The current stack location. This contains all of the
1039: // information we need to process this particular request.
1040: //
1041: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
1042:
1043: UNREFERENCED_PARAMETER(DeviceObject);
1044:
1045: ParDump(
1046: PARIRPPATH,
1047: ("PARALLEL: In query information file with Irp: %x\n",
1048: Irp)
1049: );
1050: Irp->IoStatus.Information = 0L;
1051: if (irpSp->Parameters.QueryFile.FileInformationClass ==
1052: FileStandardInformation) {
1053:
1054: PFILE_STANDARD_INFORMATION buf = Irp->AssociatedIrp.SystemBuffer;
1055:
1056: buf->AllocationSize = RtlConvertUlongToLargeInteger(0ul);
1057: buf->EndOfFile = buf->AllocationSize;
1058: buf->NumberOfLinks = 0;
1059: buf->DeletePending = FALSE;
1060: buf->Directory = FALSE;
1061: Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
1062:
1063: } else if (irpSp->Parameters.QueryFile.FileInformationClass ==
1064: FilePositionInformation) {
1065:
1066: ((PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->
1067: CurrentByteOffset = RtlConvertUlongToLargeInteger(0ul);
1068: Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
1069:
1070: } else {
1071:
1072: status = STATUS_INVALID_PARAMETER;
1073:
1074: }
1075:
1076: Irp->IoStatus.Status = status;
1077: ParDump(
1078: PARIRPPATH,
1079: ("PARALLEL: About to complete IRP in query infomration\n"
1080: "Irp: %x status: %x Information: %x\n",
1081: Irp,
1082: Irp->IoStatus.Status,
1083: Irp->IoStatus.Information)
1084: );
1085: IoCompleteRequest(
1086: Irp,
1087: IO_NO_INCREMENT
1088: );
1089:
1090: return status;
1091:
1092: }
1093:
1094: NTSTATUS
1095: ParSetInformationFile(
1096: IN PDEVICE_OBJECT DeviceObject,
1097: IN PIRP Irp
1098: )
1099:
1100: /*++
1101:
1102: Routine Description:
1103:
1104: This routine is used to set the end of file information on
1105: the opened parallel port. Any other file information request
1106: is retured with an invalid parameter.
1107:
1108: This routine always ignores the actual end of file since
1109: the query information code always returns an end of file of 0.
1110:
1111: Arguments:
1112:
1113: DeviceObject - Pointer to the device object for this device
1114:
1115: Irp - Pointer to the IRP for the current request
1116:
1117: Return Value:
1118:
1119: The function value is the final status of the call
1120:
1121: --*/
1122:
1123: {
1124:
1125: NTSTATUS status = STATUS_SUCCESS;
1126:
1127: UNREFERENCED_PARAMETER(DeviceObject);
1128:
1129: ParDump(
1130: PARIRPPATH,
1131: ("PARALLEL: In set information with IRP: %x\n",
1132: Irp)
1133: );
1134: Irp->IoStatus.Information = 0L;
1135: if (IoGetCurrentIrpStackLocation(Irp)->
1136: Parameters.SetFile.FileInformationClass !=
1137: FileEndOfFileInformation) {
1138:
1139: status = STATUS_INVALID_PARAMETER;
1140:
1141: }
1142:
1143: Irp->IoStatus.Status = status;
1144: ParDump(
1145: PARIRPPATH,
1146: ("PARALLEL: About to complete IRP in set infomration\n"
1147: "Irp: %x status: %x Information: %x\n",
1148: Irp,
1149: Irp->IoStatus.Status,
1150: Irp->IoStatus.Information)
1151: );
1152: IoCompleteRequest(
1153: Irp,
1154: IO_NO_INCREMENT
1155: );
1156:
1157: return status;
1158:
1159: }
1160:
1161: UCHAR
1162: ParManageIoDevice(
1163: IN PPAR_DEVICE_EXTENSION Extension,
1164: OUT PUCHAR Status,
1165: OUT PUCHAR Control
1166: )
1167:
1168: /*++
1169:
1170: Routine Description :
1171:
1172: This routine does the IoControl commands.
1173:
1174: Arguments :
1175:
1176: Extension - The parallel device extension.
1177:
1178: Status - The pointer to the location to return the device status.
1179:
1180: Control - The pointer to the location to return the device control.
1181:
1182: Return Value :
1183:
1184: NONE.
1185:
1186: --*/
1187: {
1188: PIO_STACK_LOCATION irpSp =
1189: IoGetCurrentIrpStackLocation(Extension->CurrentOpIrp);
1190:
1191: if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
1192: IOCTL_PAR_SET_INFORMATION) {
1193:
1194: PPAR_SET_INFORMATION irpBuffer =
1195: Extension->CurrentOpIrp->AssociatedIrp.SystemBuffer;
1196:
1197: Extension->AutoFeed = (BOOLEAN)
1198: ((irpBuffer->Init & PARALLEL_AUTOFEED) != 0)?
1199: (TRUE):(FALSE);
1200:
1201: Extension->Initialized = FALSE;
1202: *Status = ParInitializeDevice(Extension);
1203:
1204: } else if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
1205: IOCTL_PAR_QUERY_INFORMATION) {
1206:
1207: *Status = GetStatus(Extension->Controller);
1208: *Control = GetControl(Extension->Controller);
1209:
1210: }
1211:
1212: return *Status;
1213:
1214: }
1215:
1216: VOID
1217: ParNotInitError(
1218: IN PPAR_DEVICE_EXTENSION Extension,
1219: IN UCHAR deviceStatus
1220: )
1221:
1222: {
1223:
1224: PIRP irp = Extension->CurrentOpIrp;
1225:
1226: if (PAR_OFF_LINE(deviceStatus)) {
1227:
1228: irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
1229: ParDump(
1230: PARSTARTER,
1231: ("PARALLEL: starter - off line\n"
1232: "-------- STATUS/INFORMATON: %x/%x\n",
1233: irp->IoStatus.Status,
1234: irp->IoStatus.Information)
1235: );
1236:
1237: } else if (PAR_NO_CABLE(deviceStatus)) {
1238:
1239: irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
1240: ParDump(
1241: PARSTARTER,
1242: ("PARALLEL: starter - no cable - not connect status\n"
1243: "-------- STATUS/INFORMATON: %x/%x\n",
1244: irp->IoStatus.Status,
1245: irp->IoStatus.Information)
1246: );
1247:
1248: } else if (PAR_PAPER_EMPTY(deviceStatus)) {
1249:
1250: irp->IoStatus.Status = STATUS_DEVICE_PAPER_EMPTY;
1251: ParDump(
1252: PARSTARTER,
1253: ("PARALLEL: starter - paper empty\n"
1254: "-------- STATUS/INFORMATON: %x/%x\n",
1255: irp->IoStatus.Status,
1256: irp->IoStatus.Information)
1257: );
1258:
1259: } else if (PAR_POWERED_OFF(deviceStatus)) {
1260:
1261: irp->IoStatus.Status = STATUS_DEVICE_POWERED_OFF;
1262: ParDump(
1263: PARSTARTER,
1264: ("PARALLEL: starter - power off\n"
1265: "-------- STATUS/INFORMATON: %x/%x\n",
1266: irp->IoStatus.Status,
1267: irp->IoStatus.Information)
1268: );
1269:
1270: } else {
1271:
1272: irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
1273: ParDump(
1274: PARSTARTER,
1275: ("PARALLEL: starter - not conn\n"
1276: "-------- STATUS/INFORMATON: %x/%x\n",
1277: irp->IoStatus.Status,
1278: irp->IoStatus.Information)
1279: );
1280:
1281: }
1282:
1283: }
1284:
1285: VOID
1286: ParStartIo(
1287: IN PPAR_DEVICE_EXTENSION Extension
1288: )
1289:
1290: /*++
1291:
1292: Routine Description:
1293:
1294: This routine starts an I/O operation for the driver and
1295: then returns
1296:
1297: Arguments:
1298:
1299: Extension - The parallel device extension
1300:
1301: Return Value:
1302:
1303: None
1304:
1305: --*/
1306:
1307: {
1308: PIRP irp = Extension->CurrentOpIrp;
1309: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
1310: KIRQL cancelIrql;
1311:
1312: ParDump(
1313: PARIRPPATH,
1314: ("PARALLEL: In startio with IRP: %x\n",
1315: irp)
1316: );
1317: if (irpSp->MajorFunction == IRP_MJ_WRITE) {
1318:
1319: UCHAR deviceStatus;
1320: if (!Extension->Initialized) {
1321:
1322: deviceStatus = ParInitializeDevice(Extension);
1323:
1324: }
1325:
1326: if (!Extension->Initialized) {
1327:
1328: ParNotInitError(
1329: Extension,
1330: deviceStatus
1331: );
1332:
1333: } else {
1334:
1335: ParWriteOutData(
1336: Extension
1337: );
1338: return;
1339:
1340: }
1341:
1342: } else if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
1343:
1344: UCHAR status;
1345: UCHAR control;
1346:
1347: ParManageIoDevice(
1348: Extension,
1349: &status,
1350: &control
1351: );
1352:
1353: if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
1354: IOCTL_PAR_SET_INFORMATION) {
1355:
1356: if (!Extension->Initialized) {
1357:
1358: ParNotInitError(
1359: Extension,
1360: status
1361: );
1362:
1363: } else {
1364:
1365: irp->IoStatus.Status = STATUS_SUCCESS;
1366:
1367: }
1368:
1369: } else if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
1370: IOCTL_PAR_QUERY_INFORMATION) {
1371:
1372: PPAR_QUERY_INFORMATION irpBuffer = irp->AssociatedIrp.SystemBuffer;
1373:
1374: irp->IoStatus.Status = STATUS_SUCCESS;
1375:
1376: //
1377: // Interpretating Status & Control
1378: //
1379:
1380: irpBuffer->Status = 0x0;
1381:
1382: if (PAR_POWERED_OFF(status) ||
1383: PAR_NO_CABLE(status)) {
1384:
1385: irpBuffer->Status =
1386: (UCHAR)(status | PARALLEL_POWER_OFF);
1387:
1388: } else if (PAR_PAPER_EMPTY(status)) {
1389:
1390: irpBuffer->Status =
1391: (UCHAR)(irpBuffer->Status | PARALLEL_PAPER_EMPTY);
1392:
1393: } else if (PAR_OFF_LINE(status)) {
1394:
1395: irpBuffer->Status =
1396: (UCHAR)(irpBuffer->Status | PARALLEL_OFF_LINE);
1397:
1398: } else if (PAR_NOT_CONNECTED(status)) {
1399:
1400: irpBuffer->Status =
1401: (UCHAR)(irpBuffer->Status | PARALLEL_NOT_CONNECTED);
1402:
1403: }
1404:
1405: if (PAR_BUSY(status)) {
1406:
1407: irpBuffer->Status =
1408: (UCHAR)(irpBuffer->Status | PARALLEL_BUSY);
1409:
1410: }
1411:
1412: if (PAR_SELECTED(status)) {
1413:
1414: irpBuffer->Status =
1415: (UCHAR)(irpBuffer->Status | PARALLEL_SELECTED);
1416:
1417: }
1418:
1419: if (PAR_AUTOFEED(control)) {
1420:
1421: irpBuffer->Status =
1422: (UCHAR)(irpBuffer->Status | PARALLEL_AUTOFEED);
1423:
1424: }
1425:
1426: irp->IoStatus.Information =
1427: sizeof( PAR_QUERY_INFORMATION );
1428:
1429: } else {
1430:
1431: PSERIAL_TIMEOUTS new = irp->AssociatedIrp.SystemBuffer;
1432:
1433: //
1434: // The only other thing let through is setting
1435: // the timer start.
1436: //
1437:
1438: Extension->TimerStart = new->WriteTotalTimeoutConstant / 1000;
1439: irp->IoStatus.Status = STATUS_SUCCESS;
1440:
1441: }
1442:
1443: }
1444:
1445: ParDump(
1446: PARIRPPATH,
1447: ("PARALLEL: About to complete IRP in startio\n"
1448: "Irp: %x status: %x Information: %x\n",
1449: irp,
1450: irp->IoStatus.Status,
1451: irp->IoStatus.Information)
1452: );
1453:
1454: IoAcquireCancelSpinLock(&cancelIrql);
1455: Extension->CurrentOpIrp = NULL;
1456: IoReleaseCancelSpinLock(cancelIrql);
1457:
1458: IoCompleteRequest(
1459: irp,
1460: IO_NO_INCREMENT
1461: );
1462:
1463: return;
1464:
1465: }
1466:
1467: VOID
1468: ParCancelRequest(
1469: PDEVICE_OBJECT DeviceObject,
1470: PIRP Irp
1471: )
1472:
1473: /*++
1474:
1475: Routine Description:
1476:
1477: This routine is used to cancel any request in the parallel driver.
1478:
1479: Arguments:
1480:
1481: DeviceObject - Pointer to the device object for this device
1482:
1483: Irp - Pointer to the IRP to be canceled.
1484:
1485: Return Value:
1486:
1487: None.
1488:
1489: --*/
1490:
1491: {
1492:
1493: //
1494: // The only reason that this irp can be on the queue is
1495: // if it's not the current irp. Pull it off the queue
1496: // and complete it as canceled.
1497: //
1498:
1499: ASSERT(!IsListEmpty(&Irp->Tail.Overlay.ListEntry));
1500:
1501: RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
1502: IoReleaseCancelSpinLock(Irp->CancelIrql);
1503: Irp->IoStatus.Status = STATUS_CANCELLED;
1504: Irp->IoStatus.Information = 0;
1505: ParDump(
1506: PARIRPPATH,
1507: ("PARALLEL: About to complete IRP in cancel routine\n"
1508: "Irp: %x status: %x Information: %x\n",
1509: Irp,
1510: Irp->IoStatus.Status,
1511: Irp->IoStatus.Information)
1512: );
1513: IoCompleteRequest(
1514: Irp,
1515: IO_NO_INCREMENT
1516: );
1517:
1518: }
1519:
1520: VOID
1521: ParallelThread(
1522: IN PVOID Context
1523: )
1524:
1525: {
1526:
1527: PPAR_DEVICE_EXTENSION extension = Context;
1528: KIRQL oldIrql;
1529:
1530: //
1531: // Lower ourselves down just at tad so that we compete a
1532: // little less.
1533: //
1534:
1535: KeSetBasePriorityThread(
1536: KeGetCurrentThread(),
1537: -1
1538: );
1539:
1540: do {
1541:
1542:
1543: //
1544: // Wait for a request from the dispatch routines.
1545: // KeWaitForSingleObject won't return error here - this thread
1546: // isn't alertable and won't take APCs, and we're not passing in
1547: // a timeout.
1548: //
1549:
1550: ParDump(
1551: PARTHREAD,
1552: ("PARALLEL: semaphore state before wait - %d\n",
1553: extension->RequestSemaphore.Header.SignalState)
1554: );
1555: KeWaitForSingleObject(
1556: &extension->RequestSemaphore,
1557: UserRequest,
1558: KernelMode,
1559: FALSE,
1560: NULL
1561: );
1562: ParDump(
1563: PARTHREAD,
1564: ("PARALLEL: semaphore state after wait - %d\n",
1565: extension->RequestSemaphore.Header.SignalState)
1566: );
1567:
1568: if ( extension->TimeToTerminateThread ) {
1569:
1570: ParDump(
1571: PARCONFIG,
1572: ("PARALLEL: Thread asked to kill itself\n")
1573: );
1574:
1575: PsTerminateSystemThread( STATUS_SUCCESS );
1576: }
1577:
1578: //
1579: // While we are manipulating the queue we capture the
1580: // cancel spin lock.
1581: //
1582:
1583: IoAcquireCancelSpinLock(&oldIrql);
1584:
1585: ASSERT(!extension->CurrentOpIrp);
1586: while (!IsListEmpty(&extension->WorkQueue)) {
1587:
1588: PLIST_ENTRY headOfList;
1589: PIRP currentIrp;
1590:
1591: headOfList = RemoveHeadList(&extension->WorkQueue);
1592: currentIrp = CONTAINING_RECORD(
1593: headOfList,
1594: IRP,
1595: Tail.Overlay.ListEntry
1596: );
1597:
1598: IoSetCancelRoutine(
1599: currentIrp,
1600: NULL
1601: );
1602:
1603: extension->CurrentOpIrp = currentIrp;
1604: IoReleaseCancelSpinLock(oldIrql);
1605:
1606: //
1607: // Do the Io.
1608: //
1609:
1610: ParStartIo(
1611: extension
1612: );
1613:
1614: IoAcquireCancelSpinLock(&oldIrql);
1615:
1616: }
1617:
1618: IoReleaseCancelSpinLock(oldIrql);
1619:
1620: } while (TRUE);
1621:
1622: }
1623: VOID
1624: ParWriteOutData(
1625: PPAR_DEVICE_EXTENSION Extension
1626: )
1627:
1628: {
1629:
1630: PIRP irp = Extension->CurrentOpIrp;
1631: KIRQL cancelIrql;
1632: UCHAR deviceStatus;
1633: LONG bytesAtATime;
1634: KIRQL oldIrql;
1635: ULONG timerStart = Extension->TimerStart;
1636: LONG countDown = (LONG)timerStart;
1637: UCHAR oldControl = GetControl(Extension->Controller);
1638: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
1639: ULONG bytesToWrite = irpSp->Parameters.Write.Length;
1640: PUCHAR irpBuffer = (PUCHAR)irp->AssociatedIrp.SystemBuffer;
1641: LARGE_INTEGER startOfSpin;
1642: LARGE_INTEGER nextQuery;
1643: LARGE_INTEGER difference;
1644: BOOLEAN doDelays;
1645:
1646: ParDump(
1647: PARTHREAD,
1648: ("PARALLEL: timerStart is: %d\n",
1649: timerStart)
1650: );
1651: PushSomeBytes:;
1652:
1653: //
1654: // While we are strobing data we don't want to get context
1655: // switched away. Raise up to dispatch level to prevent that.
1656: //
1657: // The reason we can't afford the context switch is that
1658: // the device can't have the data strobe line on for more
1659: // than 500 microseconds.
1660: //
1661: //
1662: // We never want to be at raised irql form more than
1663: // 200 microseconds, so we will do no more than 100
1664: // bytes at a time.
1665: //
1666:
1667: KeRaiseIrql(
1668: DISPATCH_LEVEL,
1669: &oldIrql
1670: );
1671: StoreControl(
1672: Extension->Controller,
1673: (UCHAR)(oldControl & ~(PAR_CONTROL_STROBE | PAR_CONTROL_DIR))
1674: );
1675:
1676: for (
1677: bytesAtATime = 100;
1678: bytesAtATime && bytesToWrite;
1679: bytesAtATime--
1680: ) {
1681:
1682: deviceStatus = GetStatus(Extension->Controller);
1683:
1684: if (PAR_ONLINE(deviceStatus)) {
1685:
1686: //
1687: // Anytime we write out a character we will restart
1688: // the count down timer.
1689: //
1690:
1691: countDown = timerStart;
1692: WRITE_PORT_UCHAR(
1693: Extension->Controller+PARALLEL_DATA_OFFSET,
1694: (UCHAR)*irpBuffer
1695: );
1696: KeStallExecutionProcessor((ULONG)1);
1697: StoreControl(
1698: Extension->Controller,
1699: (UCHAR)((oldControl | PAR_CONTROL_STROBE) & ~PAR_CONTROL_DIR)
1700: );
1701: KeStallExecutionProcessor((ULONG)1);
1702: StoreControl(
1703: Extension->Controller,
1704: (UCHAR)(oldControl & ~(PAR_CONTROL_STROBE | PAR_CONTROL_DIR))
1705: );
1706: KeStallExecutionProcessor((ULONG)1);
1707: irpBuffer++;
1708: bytesToWrite--;
1709:
1710: } else {
1711:
1712: ParDump(
1713: PARPUSHER,
1714: ("PARALLEL: Initiate IO - device is not on line, status: %x\n",
1715: deviceStatus)
1716: );
1717:
1718: break;
1719:
1720: }
1721:
1722: }
1723:
1724: //
1725: // Turn the line back to "input".
1726: //
1727: StoreControl(
1728: Extension->Controller,
1729: (UCHAR)(oldControl & ~(PAR_CONTROL_STROBE | PAR_CONTROL_DIR))
1730: );
1731: KeStallExecutionProcessor((ULONG)1);
1732:
1733: //
1734: // Restore to "original" value. We don't care what it was.
1735: //
1736:
1737: StoreControl(
1738: Extension->Controller,
1739: oldControl
1740: );
1741:
1742: KeLowerIrql(oldIrql);
1743:
1744: //
1745: // Check to see if the io is done. If it is then call the
1746: // code to complete the request.
1747: //
1748:
1749: if (!bytesToWrite) {
1750:
1751: irp->IoStatus.Status = STATUS_SUCCESS;
1752: irp->IoStatus.Information = irpSp->Parameters.Write.Length;
1753:
1754: ParDump(
1755: PARIRPPATH,
1756: ("PARALLEL: About to complete IRP in pusher - wrote ok\n"
1757: "irp: %x status: %x Information: %x\n",
1758: irp,
1759: irp->IoStatus.Status,
1760: irp->IoStatus.Information)
1761: );
1762: IoAcquireCancelSpinLock(&cancelIrql);
1763: Extension->CurrentOpIrp = NULL;
1764: IoReleaseCancelSpinLock(cancelIrql);
1765: IoCompleteRequest(
1766: irp,
1767: IO_PARALLEL_INCREMENT
1768: );
1769: return;
1770:
1771: //
1772: // See if the IO has been canceled. The cancel routine
1773: // has been removed already (when this became the
1774: // current irp). Simply check the bit. We don't even
1775: // need to capture the lock. If we miss a round
1776: // it won't be that bad.
1777: //
1778:
1779: } else if (irp->Cancel) {
1780:
1781: irp->IoStatus.Status = STATUS_CANCELLED;
1782: irp->IoStatus.Information = 0;
1783:
1784: ParDump(
1785: PARIRPPATH,
1786: ("PARALLEL: About to complete IRP in pusher - cancelled\n"
1787: "irp: %x status: %x Information: %x\n",
1788: irp,
1789: irp->IoStatus.Status,
1790: irp->IoStatus.Information)
1791: );
1792: IoAcquireCancelSpinLock(&cancelIrql);
1793: Extension->CurrentOpIrp = NULL;
1794: IoReleaseCancelSpinLock(cancelIrql);
1795: IoCompleteRequest(
1796: irp,
1797: IO_NO_INCREMENT
1798: );
1799:
1800: return;
1801:
1802:
1803: //
1804: // We've taken care of the reasons that the irp "itself"
1805: // might want to be completed.
1806: // printer to see if it is in a state that might
1807: // cause us to complete the irp.
1808: //
1809: } else {
1810:
1811: //
1812: // First let's check if the device status is
1813: // ok and online. If it is then simply go back
1814: // to the byte pusher.
1815: //
1816:
1817: if (PAR_OK(deviceStatus) && PAR_ONLINE(deviceStatus)) {
1818:
1819: goto PushSomeBytes;
1820:
1821: }
1822:
1823: //
1824: // Perhaps the operator took the device off line,
1825: // or forgot to put in enough paper. If so, then
1826: // let's hang out here for the until the timeout
1827: // period has expired waiting for them to make things
1828: // all better.
1829: //
1830:
1831: if (PAR_PAPER_EMPTY(deviceStatus) ||
1832: PAR_OFF_LINE(deviceStatus)) {
1833:
1834: if (countDown > 0) {
1835:
1836: //
1837: // We'll wait 1 second increments.
1838: //
1839:
1840: ParDump(
1841: PARTHREAD,
1842: ("PARALLEL: decrementing countdown for pe/ol\n"
1843: " countDown: %d status: %x\n",
1844: countDown,deviceStatus)
1845: );
1846: countDown--;
1847: KeDelayExecutionThread(
1848: KernelMode,
1849: FALSE,
1850: &Extension->OneSecond
1851: );
1852: goto PushSomeBytes;
1853:
1854: } else {
1855:
1856: //
1857: // Timer has expired. Complete the request.
1858: //
1859:
1860: irp->IoStatus.Information =
1861: irpSp->Parameters.Write.Length - bytesToWrite;
1862: if (PAR_OFF_LINE(deviceStatus)) {
1863:
1864: irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
1865: ParDump(
1866: PARIRPPATH,
1867: ("PARALLEL: About to complete IRP in pusher - offline\n"
1868: "irp: %x status: %x Information: %x\n",
1869: irp,
1870: irp->IoStatus.Status,
1871: irp->IoStatus.Information)
1872: );
1873:
1874: } else {
1875:
1876: irp->IoStatus.Status = STATUS_DEVICE_PAPER_EMPTY;
1877: ParDump(
1878: PARIRPPATH,
1879: ("PARALLEL: About to complete IRP in pusher - PE\n"
1880: "irp: %x status: %x Information: %x\n",
1881: irp,
1882: irp->IoStatus.Status,
1883: irp->IoStatus.Information)
1884: );
1885:
1886: }
1887:
1888: IoAcquireCancelSpinLock(&cancelIrql);
1889: Extension->CurrentOpIrp = NULL;
1890: IoReleaseCancelSpinLock(cancelIrql);
1891: IoCompleteRequest(
1892: irp,
1893: IO_PARALLEL_INCREMENT
1894: );
1895: return;
1896:
1897: }
1898:
1899:
1900: } else if (PAR_POWERED_OFF(deviceStatus) ||
1901: PAR_NOT_CONNECTED(deviceStatus) ||
1902: PAR_NO_CABLE(deviceStatus)) {
1903:
1904: //
1905: // Wimper, wimper, something "bad" happened. Is what
1906: // happened to the printer (power off, not connected, or
1907: // the cable being pulled) something that will require us
1908: // to reinitialize the printer? If we need to
1909: // reinitialize the printer then we should complete
1910: // this IO so that the driving application can
1911: // choose what is the best thing to do about it's
1912: // io.
1913: //
1914:
1915: irp->IoStatus.Information = 0;
1916: Extension->Initialized = FALSE;
1917:
1918: if (PAR_POWERED_OFF(deviceStatus)) {
1919:
1920: irp->IoStatus.Status = STATUS_DEVICE_POWERED_OFF;
1921: ParDump(
1922: PARIRPPATH,
1923: ("PARALLEL: About to complete IRP in pusher - OFF\n"
1924: "irp: %x status: %x Information: %x\n",
1925: irp,
1926: irp->IoStatus.Status,
1927: irp->IoStatus.Information)
1928: );
1929:
1930: } else if (PAR_NOT_CONNECTED(deviceStatus) ||
1931: PAR_NO_CABLE(deviceStatus)) {
1932:
1933: irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
1934: ParDump(
1935: PARIRPPATH,
1936: ("PARALLEL: About to complete IRP in pusher - NOT CONN\n"
1937: "irp: %x status: %x Information: %x\n",
1938: irp,
1939: irp->IoStatus.Status,
1940: irp->IoStatus.Information)
1941: );
1942:
1943: }
1944:
1945: IoAcquireCancelSpinLock(&cancelIrql);
1946: Extension->CurrentOpIrp = NULL;
1947: IoReleaseCancelSpinLock(cancelIrql);
1948: IoCompleteRequest(
1949: irp,
1950: IO_PARALLEL_INCREMENT
1951: );
1952: return;
1953:
1954: }
1955:
1956: //
1957: // The device could simply be busy at this point. Simply spin
1958: // here waiting for the device to be in a state that we
1959: // care about.
1960: //
1961: // As we spin, get the system ticks. Every time that it looks
1962: // like a second has passed, decrement the countdown. If
1963: // it ever goes to zero, then timeout the request.
1964: //
1965:
1966: KeQueryTickCount(&startOfSpin);
1967: doDelays = FALSE;
1968: do {
1969:
1970: //
1971: // After about a second of spinning, let the rest of the
1972: // machine have time for a second.
1973: //
1974:
1975: if (doDelays) {
1976:
1977: difference = RtlLargeIntegerNegate(Extension->AbsoluteOneSecond);
1978: KeDelayExecutionThread(
1979: KernelMode,
1980: FALSE,
1981: &difference
1982: );
1983: ParDump(
1984: PARINITDEV,
1985: ("PARALLEL: Did delay thread of one second\n")
1986: );
1987: countDown--;
1988:
1989: } else {
1990:
1991: KeQueryTickCount(&nextQuery);
1992:
1993: difference = RtlLargeIntegerSubtract(
1994: nextQuery,
1995: startOfSpin
1996: );
1997:
1998: if (RtlLargeIntegerGreaterThanOrEqualTo(
1999: RtlExtendedIntegerMultiply(
2000: difference,
2001: (LONG)KeQueryTimeIncrement()
2002: ),
2003: Extension->AbsoluteOneSecond
2004: )) {
2005:
2006: ParDump(
2007: PARTHREAD,
2008: ("PARALLEL: Countdown: %d - device Status: %x lowpart: %x highpart: %x\n",
2009: countDown,deviceStatus,difference.LowPart,difference.HighPart)
2010: );
2011: countDown--;
2012: doDelays = TRUE;
2013:
2014: }
2015:
2016: }
2017:
2018: if (countDown <= 0) {
2019: irp->IoStatus.Status = STATUS_DEVICE_BUSY;
2020: irp->IoStatus.Information =
2021: irpSp->Parameters.Write.Length - bytesToWrite;
2022:
2023: ParDump(
2024: PARIRPPATH,
2025: ("PARALLEL: About to complete IRP in pusher - T-OUT\n"
2026: "irp: %x status: %x Information: %x\n",
2027: irp,
2028: irp->IoStatus.Status,
2029: irp->IoStatus.Information)
2030: );
2031: IoAcquireCancelSpinLock(&cancelIrql);
2032: Extension->CurrentOpIrp = NULL;
2033: IoReleaseCancelSpinLock(cancelIrql);
2034: IoCompleteRequest(
2035: irp,
2036: IO_PARALLEL_INCREMENT
2037: );
2038:
2039: return;
2040:
2041: }
2042:
2043: deviceStatus = GetStatus(Extension->Controller);
2044:
2045: } while ((!PAR_ONLINE(deviceStatus)) &&
2046: (!PAR_PAPER_EMPTY(deviceStatus)) &&
2047: (!PAR_POWERED_OFF(deviceStatus)) &&
2048: (!PAR_NOT_CONNECTED(deviceStatus)) &&
2049: (!PAR_NO_CABLE(deviceStatus)) &&
2050: !irp->Cancel);
2051:
2052: if (countDown != (LONG)timerStart) {
2053:
2054: ParDump(
2055: PARTHREAD,
2056: ("PARALLEL: Leaving busy loop - countdown %d status %x\n",
2057: countDown,deviceStatus)
2058: );
2059:
2060: }
2061: goto PushSomeBytes;
2062:
2063: }
2064:
2065: return;
2066:
2067: }
2068:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.