|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1990 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: The code is set up to be mostly interrupt driven. Some printers
21: won't interrupt when initialized, so the is structured so that
22: when it starts a request, it will determine if a previous initialize
23: was done - and if so did it complete correctly.
24:
25: In addition, code has been adjusted so that an interrupt can't be
26: aquired for port, then we will drive the port using a timer dpc
27: that will attempt to push X characters out while polling the port.
28: If a port isn't ready after Y microseconds then the timer will be
29: resubmitted to try again later.
30:
31: Access to device extension variables
32:
33: The access on these variables may be serialized :
34: TimerCount, Initialized, Initializing, CountBuffer, Command,
35: CompletingIoControl.
36:
37: TimerCount is useful for the management of timeout; when the driver
38: makes an operation on the controller, it sets a timeout, if the interrupt
39: genrated by ACK doesn't arrive the timer routine complete the
40: operation with a failure result.
41: TimerCount is modified by : InitializeDevice, ManageTimeOut,
42: InitiateIo, ISR.
43:
44: Initialized is true when the device is initialized.
45: Initialized is modified by : InitializeDevice, ISR, InitiateIo.
46:
47: Initializing is TRUE when an initialization of the device is going on.
48: Initializing is modified by : InitializeDevice, ISR,
49: ManageTimeOut.
50:
51: CountBuffer is != 0 when a writing is going on, it is the number of
52: characters the driver has still to send to the controller to end the
53: operation.
54: CountBuffer is modified by : Initialize, ManageTimeOut, ISR,
55: StartCriticalFunctions.
56:
57: Command is the command the driver is servicing.
58: Command is modified by : StartCriticalFunctions, ManageIoDevice.
59:
60: CompletingIoControl it is useful to synchronize Dpc and TimerRoutine
61: when IoControl is completing.
62:
63: --*/
64:
65: //
66: // Note that we include ntddser that we can use the serials
67: // timeout structure and ioctl to set the timeout for a write.
68: //
69:
70: #include <stddef.h>
71: #include "ntddk.h"
72: #include "ntddpar.h"
73: #include "ntddser.h"
74: #include "par.h"
75: #include "parlog.h"
76:
77: static const PHYSICAL_ADDRESS ParPhysicalZero = {0};
78:
79: #define PAR_INIT_TIMEOUT_VALUE 2
80:
81: #define VALID_FLAGS PARALLEL_INIT & ( PARALLEL_INIT | PARALLEL_AUTOFEED )
82:
83: typedef enum _PAR_DPC_ACTION {
84: ParCompleteWrite,
85: ParCompleteSetIoctl,
86: ParUnknownError,
87: ParPoweredOff,
88: ParNotConnected,
89: ParOffline,
90: ParPaperEmpty,
91: ParBusy,
92: ParDebug,
93: ParCancel
94: } PAR_DPC_ACTION, *PPAR_ACTION;
95:
96: typedef struct _CONTROL_AREA {
97: PPAR_DEVICE_EXTENSION Extension;
98: UCHAR Status;
99: UCHAR Control;
100: PIRP Irp;
101: } CONTROL_AREA, *PCONTROL_AREA;
102:
103: typedef struct _PAR_SYNCH_COUNT {
104: PPAR_DEVICE_EXTENSION Extension;
105: ULONG OldCount;
106: } PAR_SYNCH_COUNT,*PPAR_SYNCH_COUNT;
107:
108:
109: //
110: // Declarations for all internal and external routines used by this module
111: //
112:
113:
114:
115: //
116: //Macros definitions
117: //
118:
119: //
120: // Busy, PE
121: //
122:
123: #define PAR_PAPER_EMPTY( Status ) ( \
124: (Status & PAR_STATUS_PE) )
125:
126: //
127: // Busy, not select, not error
128: //
129:
130: #define PAR_OFF_LINE( Status ) ( \
131: (Status & PAR_STATUS_NOT_ERROR) && \
132: ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
133: !(Status & PAR_STATUS_SLCT) )
134:
135: //
136: // error, ack, not busy
137: //
138:
139: #define PAR_POWERED_OFF( Status ) ( \
140: ((Status & PAR_STATUS_NOT_ERROR) ^ PAR_STATUS_NOT_ERROR) && \
141: ((Status & PAR_STATUS_NOT_ACK) ^ PAR_STATUS_NOT_ACK) && \
142: (Status & PAR_STATUS_NOT_BUSY))
143:
144: //
145: // not error, not busy, not select
146: //
147:
148: #define PAR_NOT_CONNECTED( Status ) ( \
149: (Status & PAR_STATUS_NOT_ERROR) && \
150: (Status & PAR_STATUS_NOT_BUSY) &&\
151: !(Status & PAR_STATUS_SLCT) )
152:
153: //
154: // not error, not busy
155: //
156:
157: #define PAR_OK(Status) ( \
158: (Status & PAR_STATUS_NOT_ERROR) && \
159: ((Status & PAR_STATUS_PE) ^ PAR_STATUS_PE) && \
160: (Status & PAR_STATUS_NOT_BUSY) )
161:
162: //
163: // not error, not busy, selected.
164: //
165: #define PAR_ONLINE(Status) ( \
166: (Status & PAR_STATUS_NOT_ERROR) && \
167: (Status & PAR_STATUS_NOT_BUSY) && \
168: ((Status & PAR_STATUS_PE) ^ PAR_STATUS_PE) && \
169: (Status & PAR_STATUS_SLCT) )
170:
171: //
172: // busy, select, not error
173: //
174:
175: #define PAR_POWERED_ON(Status) ( \
176: ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
177: (Status & PAR_STATUS_SLCT) && \
178: (Status & PAR_STATUS_NOT_ERROR))
179:
180: //
181: // busy, not error
182: //
183:
184: #define PAR_BUSY(Status) (\
185: (( Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
186: ( Status & PAR_STATUS_NOT_ERROR ) )
187:
188: //
189: // selected
190: //
191:
192: #define PAR_SELECTED(Status) ( \
193: ( Status & PAR_STATUS_SLCT ) )
194:
195: //
196: // No cable attached.
197: //
198: #define PAR_NO_CABLE(Status) ( \
199: ((Status & PAR_STATUS_NOT_BUSY) ^ PAR_STATUS_NOT_BUSY) && \
200: (Status & PAR_STATUS_NOT_ACK) && \
201: (Status & PAR_STATUS_PE) && \
202: (Status & PAR_STATUS_SLCT) && \
203: (Status & PAR_STATUS_NOT_ERROR))
204:
205: //
206: // autofeed
207: //
208:
209: #define PAR_AUTOFEED( Control ) (\
210: ( Control & PAR_CONTROL_AUTOFD ) )
211:
212:
213: BOOLEAN
214: ParInitializeDevice(
215: IN PVOID Context
216: )
217:
218: /*++
219:
220: Routine Description:
221:
222: This routine is invoked to initialize the parallel port drive.
223: It performs the following actions:
224:
225: o Sets the timer, because an interrupt is expected on the last
226: StoreControl
227:
228: o Send INIT to the driver and if the device is online, it sends
229: SLIN
230:
231: This routine is invoked by ParInitialize and InterruptServiceRoutine, and
232: its execution is synchronized with ISR execution.
233:
234: Arguments:
235:
236: Context - Really the device extension.
237:
238: Return Value:
239:
240: Always FALSE.
241:
242: --*/
243:
244: {
245:
246: PPAR_DEVICE_EXTENSION extension = Context;
247:
248: ParDump(
249: PARINITDEV,
250: ("PARALLEL: In ParInitializeDevice - device status is %x\n",
251: GetStatus(extension->Controller))
252: );
253:
254: if ((!extension->Initialized) ||
255: ((extension->Command == ParSetInformation) &&
256: !extension->CompletingIoControl)) {
257:
258: UCHAR irqValue = ((extension->UsingATimer)?(0):
259: (PAR_CONTROL_IRQ_ENB));
260:
261: extension->Initializing = TRUE;
262:
263: //
264: // Clear the register.
265: //
266:
267: if (GetControl(extension->Controller) &
268: PAR_CONTROL_NOT_INIT) {
269:
270: StoreControl(
271: extension->Controller,
272: (UCHAR)(PAR_CONTROL_WR_CONTROL | irqValue)
273: );
274: KeStallExecutionProcessor(60);
275:
276: }
277:
278: if (extension->AutoFeed) {
279:
280: StoreControl(
281: extension->Controller,
282: (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT |
283: PAR_CONTROL_AUTOFD | irqValue)
284: );
285:
286: } else {
287:
288: StoreControl(
289: extension->Controller,
290: (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT |
291: irqValue)
292: );
293:
294: }
295:
296: extension->TimerCount = PAR_INIT_TIMEOUT_VALUE;
297:
298: }
299:
300: return FALSE;
301:
302: }
303:
304: VOID
305: ParTimerRoutine(
306: IN PDEVICE_OBJECT DeviceObject,
307: IN PVOID Context
308: )
309:
310: /*++
311:
312: Routine Description:
313:
314: This is the driver's timer routine. It is invoked once every second.
315: The value of the timeout counter is set in the Interrupt Service Routine
316: (ISR) and decremented by the ParManageTimeOut function, invoked by this
317: routine. If the current operation has timed out, then it is the function
318: of this routine to complete the current packet with an error status and
319: get the next operation started.
320:
321: A timeout may occur under any of the following conditions:
322:
323: o The device is powered off.
324:
325: o The device is disconnected.
326:
327: o The device is off-line.
328:
329: o PE?
330:
331: Arguments:
332:
333: DeviceObject - Pointer to the device object associated with this device.
334:
335: Context - Unused context parameter.
336:
337: Return value:
338:
339: None.
340:
341: --*/
342:
343: {
344:
345: PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
346:
347: UNREFERENCED_PARAMETER(Context);
348:
349: //
350: // the test isn't in a critical region, because it can loose a round
351: // It is useful to avoid the useless ParSynchronizeExecution call.
352: //
353:
354: if (extension->TimerCount != -1) {
355:
356: KIRQL cancelIrql;
357:
358: ParDump(
359: PARTIMEOUT,
360: ("PARALLEL: In ParTimerRoutine - about to sync with ISR\n")
361: );
362: IoAcquireCancelSpinLock(&cancelIrql);
363: ParSynchronizeExecution(
364: extension,
365: ParManageTimeOut,
366: DeviceObject
367: );
368: IoReleaseCancelSpinLock(cancelIrql);
369:
370:
371: }
372:
373: if (extension->StormKnocksOutInterrupts) {
374:
375: extension->StormKnocksOutInterrupts = FALSE;
376:
377: ParLogError(
378: DeviceObject->DriverObject,
379: DeviceObject,
380: extension->OriginalController,
381: ParPhysicalZero,
382: 0,
383: 0,
384: 0,
385: 41,
386: STATUS_SUCCESS,
387: PAR_INTERRUPT_STORM
388: );
389:
390: }
391:
392: }
393:
394: BOOLEAN
395: ParManageTimeOut(
396: IN PVOID Context
397: )
398:
399: /*++
400:
401: Routine Description:
402:
403: This routine sets the status of the device in the extension when
404: an interrupt was expected didn't arrive and timeout was reached.
405:
406: This function is synchronized with the ISR.
407:
408: Arguments:
409:
410: Context - Really a pointer to the device object.
411:
412: Return value:
413:
414: Always FALSE.
415:
416: --*/
417:
418: {
419:
420: PDEVICE_OBJECT deviceObject = Context;
421: PPAR_DEVICE_EXTENSION extension = deviceObject->DeviceExtension;
422:
423: ParDump(
424: PARTIMEOUT,
425: ("PARALLEL: In ParManageTimeout\n")
426: );
427:
428: //
429: // Reset the storm interrupt count back to zero on each timer tick.
430: //
431:
432: extension->UnexpectedCount = 0;
433:
434: if (extension->TimerCount < 0) {
435:
436: //
437: // Nothing to do.
438: //
439: return FALSE;
440:
441: } else {
442:
443: //
444: // We can assume that we are called with the cancel spinlock
445: // held. Check to see if we have a current irp, and if so
446: // was it canceled.
447: //
448:
449: if (deviceObject->CurrentIrp) {
450:
451: if (deviceObject->CurrentIrp->Cancel) {
452:
453: ParDump(
454: PARTIMEOUT,
455: ("PARALLEL: In ParManageTimeout - irp %x has been cancelled\n",
456: deviceObject->CurrentIrp)
457: );
458: extension->TimerCount = -1;
459: IoRequestDpc(
460: deviceObject,
461: deviceObject->CurrentIrp,
462: (PVOID)ParCancel
463: );
464: return FALSE;
465:
466: }
467:
468: }
469:
470: if (extension->TimerCount > 0) {
471:
472: //
473: // We are going to call the isr routine. We do this
474: // so that if the device went on/off line during IO
475: // we can start up the IO again. The driver will NOT
476: // put a character out to the device if it is off line.
477: //
478:
479: ParInterruptServiceRoutine(
480: extension->Interrupt,
481: extension->DeviceObject
482: );
483: if (extension->TimerCount != -1) {
484:
485: ASSERT(extension->TimerCount);
486: extension->TimerCount--;
487:
488: }
489: return FALSE;
490:
491: } else {
492:
493: UCHAR deviceStatus = GetStatus(extension->Controller);
494: PAR_DPC_ACTION action;
495:
496: extension->TimerCount = -1;
497:
498: ParDump(
499: PARTIMEOUT,
500: ("PARALLEL: In timeout status of device is %x\n",
501: deviceStatus)
502: );
503:
504: //
505: // CountBuffer is = 0 if no packet is being writtten or a Dpc
506: // is completing a request
507: //
508:
509: if (extension->Initializing) {
510:
511: extension->Initializing = FALSE;
512:
513: //
514: // This is a patch for the Centronic Interface for the
515: // laser printer that hasn't INIT pin, so it doesn't
516: // generate an interrupt when it is initialized.
517: //
518:
519: if (PAR_OK(deviceStatus)) {
520:
521: ParDump(
522: PARTIMEOUT,
523: ("PARALLEL - ParManageTimeout: In centronics patch\n")
524: );
525: extension->Initialized = TRUE;
526:
527: if ((extension->Command == ParSetInformation) &&
528: !extension->CompletingIoControl ) {
529:
530: extension->CompletingIoControl = TRUE;
531: IoRequestDpc(
532: deviceObject,
533: deviceObject->CurrentIrp,
534: (PVOID)ParCompleteSetIoctl
535: );
536:
537: }
538:
539: return FALSE;
540:
541: }
542:
543: }
544:
545: if ((extension->CountBuffer != 0) ||
546: ((extension->Command == ParSetInformation ) &&
547: !extension->CompletingIoControl)) {
548:
549: extension->CompletingIoControl = TRUE;
550:
551: if (PAR_POWERED_OFF(deviceStatus) ||
552: PAR_NO_CABLE(deviceStatus)) {
553:
554: ParDump(
555: PARTIMEOUT,
556: ("PARALLEL - ParManageTimeout: powered off\n")
557: );
558: extension->Initialized = FALSE;
559: action = ParPoweredOff;
560:
561: } else if (PAR_NOT_CONNECTED(deviceStatus)) {
562:
563: ParDump(
564: PARTIMEOUT,
565: ("PARALLEL - ParManageTimeout: not connected\n")
566: );
567: extension->Initialized = FALSE;
568: action = ParNotConnected;
569:
570: } else if (PAR_OFF_LINE(deviceStatus)) {
571:
572: ParDump(
573: PARTIMEOUT,
574: ("PARALLEL - ParManageTimeout: off line\n")
575: );
576: action = ParOffline;
577:
578: } else if (PAR_PAPER_EMPTY(deviceStatus)) {
579:
580: ParDump(
581: PARTIMEOUT,
582: ("PARALLEL - ParManageTimeout: paper empty\n")
583: );
584: action = ParPaperEmpty;
585:
586: } else if (PAR_BUSY(deviceStatus)) {
587:
588: ParDump(
589: PARTIMEOUT,
590: ("PARALLEL - ParManageTimeout: busy\n")
591: );
592: action = ParBusy;
593:
594: } else {
595:
596: //
597: // This code should never be executed.
598: //
599:
600: ParDump(
601: PARTIMEOUT,
602: ("PARALLEL - ParManageTimeout: shouldn't be here\n")
603: );
604: extension->Initialized = FALSE;
605: action = ParUnknownError;
606:
607: }
608:
609: IoRequestDpc(
610: deviceObject,
611: deviceObject->CurrentIrp,
612: (PVOID)action
613: );
614:
615: }
616:
617: }
618:
619: }
620:
621: return FALSE;
622: }
623:
624: BOOLEAN
625: ParSetTimerStart(
626: IN PVOID Context
627: )
628:
629: /*++
630:
631: Routine Description:
632:
633: This routine is invoked via KeSynchronize. It is used to
634: set the value that we should start counting down with
635: after every successful IO operation.
636:
637: Arguments:
638:
639: Context - Really a pointer to the irp.
640:
641: Return Value:
642:
643: Always False.
644:
645: --*/
646:
647: {
648:
649: PPAR_DEVICE_EXTENSION extension =
650: IoGetCurrentIrpStackLocation((PIRP)Context)
651: ->DeviceObject->DeviceExtension;
652:
653: PSERIAL_TIMEOUTS New =
654: ((PSERIAL_TIMEOUTS)(((PIRP)Context)->AssociatedIrp.SystemBuffer));
655:
656: ParDump(
657: PARDISPATCH,
658: ("Parallel: SET TIME OUT to %d seconds\n",
659: extension->TimerStart)
660: );
661: extension->TimerStart = New->WriteTotalTimeoutConstant / 1000;
662:
663: return FALSE;
664: }
665:
666: NTSTATUS
667: ParDispatch(
668: IN PDEVICE_OBJECT DeviceObject,
669: IN PIRP Irp
670: )
671:
672: /*++
673:
674: Routine Description:
675:
676: This is the main dispatch routine for the parallel port driver.
677: It is given a pointer to the IRP for the current request and
678: it determines what to do with it. If the request is valid and doen't
679: have any parameter errors, then it is placed into the work queue.
680: Otherwise it is not completed and an appropriate error is returned.
681:
682: Arguments:
683:
684: DeviceObject - Pointer to the device object for this device
685:
686: Irp - Pointer to the IRP for the current request
687:
688: Return Value:
689:
690: The function value is the final status of the call
691:
692: --*/
693:
694: {
695:
696: NTSTATUS status = STATUS_SUCCESS;
697: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
698: PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
699:
700: ParDump(
701: PARDISPATCH,
702: ("PARALLEL: In main dispatch with IRP: %x\n",
703: Irp)
704: );
705: Irp->IoStatus.Information=0L;
706: switch(irpSp->MajorFunction) {
707:
708: case IRP_MJ_CLOSE: {
709:
710: ParDump(
711: PARDISPATCH,
712: ("PARALLEL: About to close the port for extension: %x\n",
713: extension)
714: );
715: //
716: // Before we close we want to wait until the busy
717: // path is false. We don't want any paths of
718: // execution running around while we're closed.
719: //
720:
721: while (extension->BusyPath) {
722:
723: KeDelayExecutionThread(
724: KernelMode,
725: FALSE,
726: &extension->BusyDelayAmount
727: );
728:
729: }
730: break;
731:
732:
733: }
734: case IRP_MJ_CREATE:
735:
736: ParDump(
737: PARDISPATCH,
738: ("PARALLEL: About to open the port for extension: %x\n",
739: extension)
740: );
741: //
742: // Let's make sure they aren't trying to create a directory.
743: // This is a silly, but what's a driver to do!?
744: //
745:
746: if (irpSp->Parameters.Create.Options & FILE_DIRECTORY_FILE) {
747:
748: status = STATUS_NOT_A_DIRECTORY;
749:
750: }
751:
752: break;
753:
754: case IRP_MJ_WRITE:
755:
756: ParDump(
757: PARDISPATCH,
758: ("PARALLEL: Starting write IRP: %x for extension: %x\n",
759: Irp,
760: extension)
761: );
762: if ((irpSp->Parameters.Write.ByteOffset.HighPart != 0) ||
763: (irpSp->Parameters.Write.ByteOffset.LowPart != 0)) {
764:
765: status = STATUS_INVALID_PARAMETER;
766:
767: } else {
768:
769: if (irpSp->Parameters.Write.Length != 0) {
770:
771: status = STATUS_PENDING;
772: }
773:
774: }
775:
776: break;
777:
778: case IRP_MJ_DEVICE_CONTROL:
779:
780: ParDump(
781: PARDISPATCH,
782: ("PARALLEL: Starting device controlIRP: %x for extension: %x\n",
783: Irp,
784: extension)
785: );
786: switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
787:
788: case IOCTL_PAR_SET_INFORMATION :
789:
790: if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
791: 1) {
792:
793: status = STATUS_BUFFER_TOO_SMALL;
794:
795: } else {
796:
797: PPAR_SET_INFORMATION irpBuffer =
798: Irp->AssociatedIrp.SystemBuffer;
799:
800: //
801: // INIT is required, AUTOFEED is optional
802: //
803:
804: if (!(irpBuffer->Init & PARALLEL_INIT) ||
805: (irpBuffer->Init & ~VALID_FLAGS)) {
806:
807: status = STATUS_INVALID_PARAMETER;
808:
809: } else {
810:
811: status = STATUS_PENDING;
812: }
813:
814: }
815:
816: break;
817:
818: case IOCTL_PAR_QUERY_INFORMATION :
819:
820: if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
821: sizeof(PAR_QUERY_INFORMATION)) {
822:
823: status = STATUS_BUFFER_TOO_SMALL;
824:
825: } else {
826:
827: status = STATUS_PENDING;
828: }
829:
830: break;
831:
832: case IOCTL_SERIAL_SET_TIMEOUTS: {
833:
834: PSERIAL_TIMEOUTS NewTimeouts =
835: ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer));
836:
837: ParDump(
838: PARDISPATCH,
839: ("PARALLEL: Got a set timeouts irp: %x for extension: %x\n",
840: Irp,
841: extension)
842: );
843:
844: if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
845: sizeof(SERIAL_TIMEOUTS)) {
846:
847: status = STATUS_BUFFER_TOO_SMALL;
848: break;
849:
850: } else if (NewTimeouts->WriteTotalTimeoutConstant < 2000) {
851:
852: status = STATUS_INVALID_PARAMETER;
853: break;
854:
855: }
856:
857: ParSynchronizeExecution(
858: extension,
859: ParSetTimerStart,
860: Irp
861: );
862:
863: break;
864:
865: }
866: case IOCTL_SERIAL_GET_TIMEOUTS:
867:
868: if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
869: sizeof(SERIAL_TIMEOUTS)) {
870:
871: status = STATUS_BUFFER_TOO_SMALL;
872: break;
873:
874: }
875:
876: //
877: // We don't need to synchronize the read.
878: //
879:
880: RtlZeroMemory(
881: Irp->AssociatedIrp.SystemBuffer,
882: sizeof(SERIAL_TIMEOUTS)
883: );
884: Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
885: ((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer)->
886: WriteTotalTimeoutConstant =
887: extension->TimerStart * 1000;
888:
889: break;
890:
891: default :
892:
893: status = STATUS_INVALID_PARAMETER;
894: break;
895:
896: }
897:
898: break;
899:
900: }
901:
902: Irp->IoStatus.Status = status;
903:
904: if (status == STATUS_PENDING) {
905:
906: IoMarkIrpPending(Irp);
907: IoStartPacket(
908: DeviceObject,
909: Irp,
910: (PULONG)NULL,
911: ParCancelRequest
912: );
913:
914: } else {
915:
916: ParDump(
917: PARIRPCOMPLETE,
918: ("PARALLEL: About to complete IRP in dispatch: %x\n",Irp)
919: );
920: IoCompleteRequest(
921: Irp,
922: IO_NO_INCREMENT
923: );
924:
925: }
926:
927: return status;
928:
929: }
930:
931: NTSTATUS
932: ParQueryInformationFile(
933: IN PDEVICE_OBJECT DeviceObject,
934: IN PIRP Irp
935: )
936:
937: /*++
938:
939: Routine Description:
940:
941: This routine is used to query the end of file information on
942: the opened parallel port. Any other file information request
943: is retured with an invalid parameter.
944:
945: This routine always returns an end of file of 0.
946:
947: Arguments:
948:
949: DeviceObject - Pointer to the device object for this device
950:
951: Irp - Pointer to the IRP for the current request
952:
953: Return Value:
954:
955: The function value is the final status of the call
956:
957: --*/
958:
959: {
960: //
961: // The status that gets returned to the caller and
962: // set in the Irp.
963: //
964: NTSTATUS status = STATUS_SUCCESS;
965:
966: //
967: // The current stack location. This contains all of the
968: // information we need to process this particular request.
969: //
970: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
971:
972: UNREFERENCED_PARAMETER(DeviceObject);
973:
974: ParDump(
975: PARDISPATCH,
976: ("PARALLEL: In query information file with Irp: %x\n",
977: Irp)
978: );
979: Irp->IoStatus.Information = 0L;
980: if (irpSp->Parameters.QueryFile.FileInformationClass ==
981: FileStandardInformation) {
982:
983: PFILE_STANDARD_INFORMATION buf = Irp->AssociatedIrp.SystemBuffer;
984:
985: buf->AllocationSize = RtlConvertUlongToLargeInteger(0ul);
986: buf->EndOfFile = buf->AllocationSize;
987: buf->NumberOfLinks = 0;
988: buf->DeletePending = FALSE;
989: buf->Directory = FALSE;
990: Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
991:
992: } else if (irpSp->Parameters.QueryFile.FileInformationClass ==
993: FilePositionInformation) {
994:
995: ((PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer)->
996: CurrentByteOffset = RtlConvertUlongToLargeInteger(0ul);
997: Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
998:
999: } else {
1000:
1001: status = STATUS_INVALID_PARAMETER;
1002:
1003: }
1004:
1005: Irp->IoStatus.Status = status;
1006: ParDump(
1007: PARIRPCOMPLETE,
1008: ("PARALLEL: About to complete IRP: %x\n",Irp)
1009: );
1010: IoCompleteRequest(
1011: Irp,
1012: IO_NO_INCREMENT
1013: );
1014:
1015: return status;
1016:
1017: }
1018:
1019: NTSTATUS
1020: ParSetInformationFile(
1021: IN PDEVICE_OBJECT DeviceObject,
1022: IN PIRP Irp
1023: )
1024:
1025: /*++
1026:
1027: Routine Description:
1028:
1029: This routine is used to set the end of file information on
1030: the opened parallel port. Any other file information request
1031: is retured with an invalid parameter.
1032:
1033: This routine always ignores the actual end of file since
1034: the query information code always returns an end of file of 0.
1035:
1036: Arguments:
1037:
1038: DeviceObject - Pointer to the device object for this device
1039:
1040: Irp - Pointer to the IRP for the current request
1041:
1042: Return Value:
1043:
1044: The function value is the final status of the call
1045:
1046: --*/
1047:
1048: {
1049:
1050: NTSTATUS status = STATUS_SUCCESS;
1051:
1052: UNREFERENCED_PARAMETER(DeviceObject);
1053:
1054: ParDump(
1055: PARDISPATCH,
1056: ("PARALLEL: In set information with IRP: %x\n",
1057: Irp)
1058: );
1059: Irp->IoStatus.Information = 0L;
1060: if (IoGetCurrentIrpStackLocation(Irp)->
1061: Parameters.SetFile.FileInformationClass !=
1062: FileEndOfFileInformation) {
1063:
1064: status = STATUS_INVALID_PARAMETER;
1065:
1066: }
1067:
1068: Irp->IoStatus.Status = status;
1069: ParDump(
1070: PARIRPCOMPLETE,
1071: ("PARALLEL: About to complete IRP: %x\n",Irp)
1072: );
1073: IoCompleteRequest(
1074: Irp,
1075: IO_NO_INCREMENT
1076: );
1077:
1078: return status;
1079:
1080: }
1081:
1082: VOID
1083: ParCheckTheWeather(
1084: IN PPAR_DEVICE_EXTENSION Extension
1085: )
1086:
1087: /*++
1088:
1089: Routine Description:
1090:
1091: This routine checks to see if we've gotten too many interrupts
1092: within a certain amount of time. If so we turn the device into
1093: a polling device. This is to deal with interrupt storms.
1094:
1095: Arguments:
1096:
1097: Extension - Pointer to the device extension.
1098:
1099: Return Value:
1100:
1101: None.
1102:
1103: --*/
1104:
1105: {
1106:
1107: //
1108: // We've sometimes seen interrupt storms. If had no work to do
1109: // and we are on an EISA or an ISA bus and we've exceeded the
1110: // threshold for interrupts that weren't ours, then turn off
1111: // interrupts, turn on the using a timer flag, and set a variable
1112: // that our one second timer routine will note to cause it to
1113: // put an event in the event log that this occured.
1114:
1115: if ((Extension->UnexpectedCount > PARALLEL_STORM_WATCH) &&
1116: (!Extension->UsingATimer) &&
1117: ((Extension->InterfaceType == Eisa) ||
1118: (Extension->InterfaceType == Isa))) {
1119:
1120: if (Extension->AutoFeed) {
1121:
1122: StoreControl(
1123: Extension->Controller,
1124: (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT |
1125: PAR_CONTROL_AUTOFD)
1126: );
1127:
1128: } else {
1129:
1130: StoreControl(
1131: Extension->Controller,
1132: (UCHAR)(PAR_CONTROL_WR_CONTROL | PAR_CONTROL_NOT_INIT)
1133: );
1134:
1135: }
1136:
1137: Extension->StormKnocksOutInterrupts = TRUE;
1138: Extension->UsingATimer = TRUE;
1139:
1140: }
1141:
1142: }
1143:
1144: BOOLEAN
1145: ParInterruptServiceRoutine(
1146: IN PKINTERRUPT InterruptObject,
1147: IN PVOID Context
1148: )
1149:
1150: /*++
1151:
1152: Routine Description:
1153:
1154: This is the interrupt service routine for the parallel port driver.
1155: An interrupt will occur under any of the following conditions:
1156:
1157: o A character was received by the device
1158:
1159: o The device's power was switched off
1160:
1161: o In some printers PAPER_EMPTY and OFF_LINE don't generate
1162: interrupts, but they are read on the status when a character
1163: is received ( because the printer accepts one more character )
1164:
1165: Arguments:
1166:
1167: InterruptObject - Pointer to the interrupt object used to connect
1168: to the interrupt vector for the parallel port
1169:
1170: Context - Really a Pointer to the device object for the parallel
1171: port device that is interrupting
1172:
1173: Return Value:
1174:
1175: Returns TRUE if an interrupt was expected from the device;
1176: otherwise FALSE
1177:
1178: --*/
1179:
1180: {
1181:
1182: LONG saveTimer;
1183: PDEVICE_OBJECT deviceObject = Context;
1184: PPAR_DEVICE_EXTENSION extension = deviceObject->DeviceExtension;
1185: UCHAR deviceStatus;
1186: PAR_DPC_ACTION action;
1187:
1188: UNREFERENCED_PARAMETER(InterruptObject);
1189:
1190: deviceStatus = GetStatus(extension->Controller);
1191:
1192: ParDump(
1193: PARISR,
1194: ("PARALLEL: ISR - device status is %x\n",deviceStatus)
1195: );
1196: //
1197: // saveTimer == -1 implies that there is no current operation
1198: // in progress.
1199: //
1200:
1201: saveTimer = extension->TimerCount;
1202: action = ParUnknownError;
1203: extension->TimerCount = -1;
1204:
1205: if (extension->Initializing) {
1206:
1207: ParDump(
1208: PARISR,
1209: ("PARALLEL: ISR - In initializing code path\n")
1210: );
1211: extension->Initializing = FALSE;
1212:
1213: if (PAR_OK(deviceStatus)) {
1214:
1215: extension->Initialized = TRUE;
1216: if ((extension->Command == ParSetInformation) &&
1217: !extension->CompletingIoControl) {
1218:
1219: ParDump(
1220: PARISR,
1221: ("PARALLEL: ISR - Completing IO control\n")
1222: );
1223: extension->CompletingIoControl = TRUE;
1224: IoRequestDpc(
1225: deviceObject,
1226: deviceObject->CurrentIrp,
1227: (PVOID)ParCompleteWrite
1228: );
1229:
1230: } else if ((extension->CountBuffer != 0) &&
1231: (saveTimer != -1)) {
1232:
1233: ParDump(
1234: PARISR,
1235: ("PARALLEL: ISR Doing More writes - count:%d\n",
1236: extension->CountBuffer)
1237: );
1238: ParInitiateIo(deviceObject);
1239:
1240: }
1241:
1242: return TRUE;
1243:
1244: } else if ((extension->CountBuffer != 0 ) ||
1245: (extension->Command == ParSetInformation) &&
1246: !extension->CompletingIoControl) {
1247:
1248: if (PAR_POWERED_OFF(deviceStatus)) {
1249:
1250: //
1251: // For the real powered off case make sure we aren't
1252: // getting an interrupt storm from turning an HPxp
1253: // off on an MIO-X00 adapter.
1254: //
1255: // If it is just an simple turning off then bumping
1256: // the unexpected count up won't hurt.
1257: //
1258:
1259: extension->UnexpectedCount++;
1260: action = ParPoweredOff;
1261: ParCheckTheWeather(extension);
1262:
1263: } else if (PAR_NO_CABLE(deviceStatus)) {
1264:
1265: action = ParPoweredOff;
1266:
1267: } else if (PAR_OFF_LINE(deviceStatus) ||
1268: PAR_PAPER_EMPTY(deviceStatus)) {
1269:
1270: //
1271: // Paper empty or device off line should let
1272: // the normal time out code handle the problem
1273: //
1274:
1275: extension->TimerCount = saveTimer;
1276: return TRUE;
1277:
1278: } else if (PAR_PAPER_EMPTY(deviceStatus)) {
1279:
1280: action = ParPaperEmpty;
1281:
1282: } else if (PAR_NOT_CONNECTED(deviceStatus)) {
1283:
1284: action = ParNotConnected;
1285:
1286: } else if (PAR_BUSY(deviceStatus)) {
1287:
1288: //
1289: // For the busy state we will just let the regular timeout code
1290: // handle it.
1291: //
1292: extension->TimerCount = saveTimer;
1293: return TRUE;
1294:
1295: }
1296:
1297: ParDump(
1298: PARISR | PARISRACTION,
1299: ("PARALLEL: ISR Completing request with bad status - ACTION: %d\n",
1300: action)
1301: );
1302: IoRequestDpc(
1303: deviceObject,
1304: deviceObject->CurrentIrp,
1305: (PVOID)action
1306: );
1307:
1308: return TRUE;
1309:
1310: }
1311:
1312: } else {
1313:
1314: //
1315: // The port is not being initialized at this point. Check to see
1316: // whether or not it has been initialized at all and drive the
1317: // remainder of the ISR based on the result.
1318: //
1319:
1320: if (extension->Initialized) {
1321:
1322: ParDump(
1323: PARISR,
1324: ("PARALLEL - ISR Inited path\n")
1325: );
1326:
1327:
1328: if (PAR_OK(deviceStatus) && PAR_ONLINE(deviceStatus) &&
1329: (saveTimer != -1)) {
1330:
1331: if (extension->CountBuffer > 0) {
1332:
1333: ParDump(
1334: PARISR,
1335: ("PARALLEL - ISR Inited - more io - count:%d\n",
1336: extension->CountBuffer)
1337: );
1338: ParInitiateIo(deviceObject);
1339:
1340: } else {
1341:
1342: ParDump(
1343: PARISR,
1344: ("PARALLEL - ISR Inited - good io all done:\n")
1345: );
1346: IoRequestDpc(
1347: deviceObject,
1348: deviceObject->CurrentIrp,
1349: (PVOID)ParCompleteWrite
1350: );
1351:
1352: }
1353:
1354: return TRUE;
1355:
1356: } else if ((PAR_OK(deviceStatus)) && (saveTimer != -1) &&
1357: (extension->CountBuffer == 0)) {
1358:
1359: //
1360: // The odd case of the device going off line just after
1361: // we give the hardware the very last byte.
1362: //
1363:
1364: ParDump(
1365: PARISR,
1366: ("PARALLEL - ISR Inited - good io all done:\n")
1367: );
1368: IoRequestDpc(
1369: deviceObject,
1370: deviceObject->CurrentIrp,
1371: (PVOID)ParCompleteWrite
1372: );
1373:
1374: return TRUE;
1375:
1376: } else {
1377:
1378: if ((saveTimer != -1) &&
1379: (PAR_PAPER_EMPTY(deviceStatus) ||
1380: PAR_OFF_LINE(deviceStatus))) {
1381:
1382: //
1383: // Paper empty or device off line should let
1384: // the normal time out code handle the problem
1385: //
1386:
1387: ParDump(
1388: PARISRACTION,
1389: ("PARALLEL: Isr found device to be off line or empty\n")
1390: );
1391: extension->TimerCount = saveTimer;
1392: return TRUE;
1393:
1394: } else if (PAR_POWERED_OFF(deviceStatus) ||
1395: PAR_NOT_CONNECTED(deviceStatus) ||
1396: PAR_NO_CABLE(deviceStatus)) {
1397:
1398: extension->Initialized = FALSE;
1399:
1400: if (saveTimer != -1) {
1401:
1402: if (PAR_POWERED_OFF(deviceStatus)) {
1403:
1404: //
1405: // For the real powered off case make sure we aren't
1406: // getting an interrupt storm from turning an HPxp
1407: // off on an MIO-X00 adapter.
1408: //
1409: // If it is just an simple turning off then bumping
1410: // the unexpected count up won't hurt.
1411: //
1412:
1413: extension->UnexpectedCount++;
1414: action = ParPoweredOff;
1415: ParCheckTheWeather(extension);
1416:
1417: } else if (PAR_NO_CABLE(deviceStatus)) {
1418:
1419: action = ParPoweredOff;
1420:
1421: }
1422:
1423: if (PAR_NOT_CONNECTED(deviceStatus)) {
1424:
1425: action = ParNotConnected;
1426:
1427: }
1428:
1429: ParDump(
1430: PARISR,
1431: ("PARALLEL - ISR Inited off/connected complete "
1432: "irp - action %d\n",action)
1433: );
1434: IoRequestDpc(
1435: deviceObject,
1436: deviceObject->CurrentIrp,
1437: (PVOID)action
1438: );
1439:
1440: return TRUE;
1441:
1442: } else {
1443:
1444: //
1445: // Well we weren't doing an operation, but
1446: // the device has changed state since we
1447: // last looked. So this interrupt might
1448: // as well have been for us.
1449: //
1450:
1451: return TRUE;
1452:
1453: }
1454:
1455: } else if ((PAR_BUSY(deviceStatus)) &&
1456: (saveTimer != -1)) {
1457:
1458: ParDump(
1459: PARISR | PARBUSYPATH,
1460: ("PARALLEL - ISR inited - busy interrupt?\n")
1461: );
1462:
1463: //
1464: // Well we think that we have work to do, but for
1465: // some reason we got an interrupt, yet the device
1466: // thinks it's busy.
1467: //
1468: // Three things could have happened.
1469: //
1470: // 1) We are running this device off a timer
1471: // (NO interrupts are ever being used).
1472: // The driver is just calling the ISR to
1473: // force the work to be done.
1474: //
1475: // 2) We are on some kind of Jazz machine. We
1476: // *THINK* that the part on the machine is
1477: // signaling an interrupt on just the device
1478: // going BUSY, which is bizarre.
1479: //
1480: // 3) Some printers (whose name shall go unmentioned
1481: // except that their initials are HP),
1482: // seem to give an interrupt to acknowledge
1483: // the character, *THEN* decide that they want
1484: // to go busy (I think this is bizarre too).
1485: //
1486: //
1487: // For 1 we could just return, since the run off
1488: // the timer code will calm down and try to run later
1489: // if it gets too many "busys".
1490: //
1491: // For 2 we could also just return, because we
1492: // get another acknowledge interrupt later.
1493: //
1494: // 3 is quite painful because WE ARE NOT GOING
1495: // TO GET ANOTHER INTERRUPT FROM THE DEVICE.
1496: //
1497: // What we do to solve 3 is to queue off a dpc
1498: // that will start a timer that when the timer
1499: // fires will cause a dpc to synchrnoize with the
1500: // isr and then call this isr. If the busy bit
1501: // has gone away then we will just act as if we
1502: // got interrupted. If the busy bit hasn't gone
1503: // away, we just start off the dpc again.
1504: //
1505:
1506: extension->TimerCount = saveTimer;
1507:
1508: //
1509: // If this driver is using a timer to drive the
1510: // writes then we should return that we haven't
1511: // done anything yet with the io.
1512: //
1513:
1514: if (extension->UsingATimer) {
1515:
1516: return FALSE;
1517:
1518: } else {
1519:
1520: if (!extension->BusyPath) {
1521:
1522: extension->BusyPath = TRUE;
1523:
1524: ParDump(
1525: PARBUSYPATH,
1526: ("Parallel: About to queue the start busy"
1527: "timer\n")
1528: );
1529: KeInsertQueueDpc(
1530: &extension->StartBusyTimerDpc,
1531: NULL,
1532: NULL
1533: );
1534:
1535: }
1536:
1537: }
1538:
1539: }
1540:
1541: }
1542:
1543: extension->TimerCount = saveTimer;
1544: return TRUE;
1545:
1546: } else {
1547:
1548: // not initialized
1549:
1550: if (PAR_POWERED_ON(deviceStatus)) {
1551:
1552: ParDump(
1553: PARISR | PARBUSYPATH,
1554: ("PARALLEL: ISR - not initialized / not on\n")
1555: );
1556: extension->AutoFeed = FALSE;
1557: ParInitializeDevice(extension);
1558: return TRUE;
1559:
1560: }
1561:
1562: }
1563:
1564: }
1565:
1566: //
1567: // Well we couldn't find anything to do. Restore the
1568: // timer value and return FALSE.
1569: //
1570:
1571: ParDump(
1572: PARISR,
1573: ("PARALLEL: ISR returning FALSE with a timer count of %d\n",
1574: extension->TimerCount)
1575: );
1576: extension->TimerCount = saveTimer;
1577: extension->UnexpectedCount++;
1578:
1579: ParCheckTheWeather(extension);
1580: return FALSE;
1581:
1582: }
1583:
1584: BOOLEAN
1585: ParSynchCount(
1586: IN PVOID Context
1587: )
1588:
1589: /*++
1590:
1591: Routine Description:
1592:
1593: This routine is synchronized to work at device level (e.g. the
1594: ISR can't be running). It is used to clear the count buffer.
1595: We do this so that when we completing a request prematurely, we
1596: don't have to refer to a variable that the ISR used to determine
1597: if it is doing work. We clear that variable here.
1598:
1599: Arguments:
1600:
1601: Context - Pointer to a struct that contains the extension and.
1602: a ulong to hold the old count.
1603:
1604: Return Value:
1605:
1606: Always False.
1607:
1608: --*/
1609:
1610: {
1611:
1612: PPAR_SYNCH_COUNT synchCount = Context;
1613:
1614: synchCount->OldCount = synchCount->Extension->CountBuffer;
1615: synchCount->Extension->CountBuffer = 0;
1616:
1617: return FALSE;
1618:
1619: }
1620:
1621: VOID
1622: ParDpcRoutine(
1623: IN PKDPC Dpc,
1624: IN PDEVICE_OBJECT DeviceObject,
1625: IN PIRP Irp,
1626: IN PVOID DeferredContext
1627: )
1628:
1629: /*++
1630:
1631: Routine Description:
1632:
1633: This is the DPC routine that complete driver's write operation.
1634:
1635: Arguments:
1636:
1637: DeviceObject - Pointer to the device object
1638:
1639: Irp - Pointer to the current Irp
1640:
1641: DeferredContext - Type of action
1642:
1643: Return Value:
1644:
1645: None.
1646:
1647: --*/
1648:
1649: {
1650:
1651: UNREFERENCED_PARAMETER(Dpc);
1652:
1653: ParDump(
1654: PARDPC,
1655: ("PARALLEL: In ParDpcRoutine - current irp is: %x\n",
1656: Irp)
1657: );
1658:
1659: if (Irp) {
1660:
1661: PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
1662: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp );
1663: PAR_DPC_ACTION action = (PAR_DPC_ACTION)DeferredContext;
1664: PAR_SYNCH_COUNT synchCount;
1665: KIRQL cancelIrql;
1666:
1667:
1668: //
1669: // No matter what, this irp is being completed.
1670: // Kill the cancel routine.
1671: //
1672:
1673: IoAcquireCancelSpinLock(&cancelIrql);
1674: Irp->CancelRoutine = NULL;
1675: IoReleaseCancelSpinLock(cancelIrql);
1676:
1677: synchCount.Extension = extension;
1678: synchCount.OldCount = 0;
1679: ParSynchronizeExecution(
1680: extension,
1681: ParSynchCount,
1682: &synchCount
1683: );
1684:
1685: switch (action) {
1686:
1687: case ParCompleteWrite :
1688:
1689: Irp->IoStatus.Status = STATUS_SUCCESS;
1690: Irp->IoStatus.Information = irpSp->Parameters.Write.Length -
1691: synchCount.OldCount;
1692: ParDump(
1693: PARDPC,
1694: ("PARALLEL: DPC - Complete Write\n"
1695: "-------- STATUS/INFORMATON: %x/%x\n",
1696: Irp->IoStatus.Status,
1697: Irp->IoStatus.Information)
1698: );
1699: break;
1700:
1701: case ParCompleteSetIoctl :
1702:
1703: Irp->IoStatus.Status = STATUS_SUCCESS;
1704: ParDump(
1705: PARDPC,
1706: ("PARALLEL: DPC - Complete Set Ioctl\n"
1707: "-------- STATUS/INFORMATON: %x/%x\n",
1708: Irp->IoStatus.Status,
1709: Irp->IoStatus.Information)
1710: );
1711: break;
1712:
1713: case ParPoweredOff :
1714:
1715: Irp->IoStatus.Status = STATUS_DEVICE_POWERED_OFF;
1716: ParDump(
1717: PARDPC,
1718: ("PARALLEL: DPC - powered off\n"
1719: "-------- STATUS/INFORMATON: %x/%x\n",
1720: Irp->IoStatus.Status,
1721: Irp->IoStatus.Information)
1722: );
1723: break;
1724:
1725: case ParNotConnected :
1726:
1727: Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
1728: ParDump(
1729: PARDPC,
1730: ("PARALLEL: DPC - not connected\n"
1731: "-------- STATUS/INFORMATON: %x/%x\n",
1732: Irp->IoStatus.Status,
1733: Irp->IoStatus.Information)
1734: );
1735: break;
1736:
1737: case ParOffline :
1738:
1739: Irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE;
1740: Irp->IoStatus.Information = irpSp->Parameters.Write.Length -
1741: synchCount.OldCount;
1742: ParDump(
1743: PARDPC,
1744: ("PARALLEL: DPC - off line\n"
1745: "-------- STATUS/INFORMATON: %x/%x\n",
1746: Irp->IoStatus.Status,
1747: Irp->IoStatus.Information)
1748: );
1749: break;
1750:
1751: case ParPaperEmpty :
1752:
1753: Irp->IoStatus.Status = STATUS_DEVICE_PAPER_EMPTY;
1754: Irp->IoStatus.Information = irpSp->Parameters.Write.Length -
1755: synchCount.OldCount;
1756: ParDump(
1757: PARDPC,
1758: ("PARALLEL: DPC - paper empty\n"
1759: "-------- STATUS/INFORMATON: %x/%x\n",
1760: Irp->IoStatus.Status,
1761: Irp->IoStatus.Information)
1762: );
1763: break;
1764:
1765: case ParUnknownError :
1766:
1767: Irp->IoStatus.Status = STATUS_DEVICE_NOT_CONNECTED;
1768: ParDump(
1769: PARDPC,
1770: ("PARALLEL: DPC - unknown error\n"
1771: "-------- STATUS/INFORMATON: %x/%x\n",
1772: Irp->IoStatus.Status,
1773: Irp->IoStatus.Information)
1774: );
1775: ParLogError(
1776: DeviceObject->DriverObject,
1777: DeviceObject,
1778: extension->OriginalController,
1779: ParPhysicalZero,
1780: extension->IrpSequence,
1781: irpSp->MajorFunction,
1782: 0,
1783: 38,
1784: Irp->IoStatus.Status,
1785: IO_ERR_NOT_READY
1786: );
1787: break;
1788:
1789: case ParBusy :
1790:
1791: Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
1792: Irp->IoStatus.Information = irpSp->Parameters.Write.Length -
1793: synchCount.OldCount;
1794: ParDump(
1795: PARDPC,
1796: ("PARALLEL: DPC - device busy\n"
1797: "-------- STATUS/INFORMATON: %x/%x\n",
1798: Irp->IoStatus.Status,
1799: Irp->IoStatus.Information)
1800: );
1801: break;
1802:
1803: case ParCancel:
1804:
1805: Irp->IoStatus.Status = STATUS_CANCELLED;
1806: Irp->IoStatus.Information = 0;
1807: ParDump(
1808: PARDPC,
1809: ("PARALLEL: DPC - cancel part of the case\n"
1810: "-------- STATUS/INFORMATON: %x/%x\n",
1811: Irp->IoStatus.Status,
1812: Irp->IoStatus.Information)
1813: );
1814: break;
1815:
1816:
1817: default :
1818:
1819: Irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
1820: ParDump(
1821: PARDPC,
1822: ("PARALLEL: DPC - default part of the case\n"
1823: "-------- STATUS/INFORMATON: %x/%x\n",
1824: Irp->IoStatus.Status,
1825: Irp->IoStatus.Information)
1826: );
1827: ParLogError(
1828: DeviceObject->DriverObject,
1829: DeviceObject,
1830: extension->OriginalController,
1831: ParPhysicalZero,
1832: extension->IrpSequence,
1833: irpSp->MajorFunction,
1834: 0,
1835: 39,
1836: Irp->IoStatus.Status,
1837: IO_ERR_NOT_READY
1838: );
1839: break;
1840: }
1841:
1842: IoStartNextPacket(
1843: DeviceObject,
1844: TRUE
1845: );
1846: ParDump(
1847: PARIRPCOMPLETE,
1848: ("PARALLEL: About to complete IRP: %x\n",Irp)
1849: );
1850: IoCompleteRequest(
1851: Irp,
1852: IO_PARALLEL_INCREMENT
1853: );
1854:
1855: }
1856:
1857: }
1858:
1859: BOOLEAN
1860: ParStartCriticalFunctions(
1861: IN PVOID Context
1862: )
1863:
1864: /*++
1865:
1866: Routine Description :
1867:
1868: This routine starts the writing operations on the device.
1869:
1870: Arguments :
1871:
1872: Context - Really a pointer to the device object for the parallel port
1873: device
1874:
1875: Return value :
1876:
1877: Always FALSE;
1878:
1879: --*/
1880:
1881: {
1882: PDEVICE_OBJECT deviceObject = Context;
1883: PIO_STACK_LOCATION irpSp =
1884: IoGetCurrentIrpStackLocation(deviceObject->CurrentIrp);
1885: PPAR_DEVICE_EXTENSION extension = deviceObject->DeviceExtension;
1886:
1887: extension->Command = ParWrite;
1888:
1889: //
1890: // Initialize the state machine for this packet so the remainder of the
1891: // driver can determine the number of characters that are to be written
1892: // to the device.
1893: //
1894:
1895: extension->CompletingIoControl = FALSE;
1896: extension->CountBuffer = irpSp->Parameters.Write.Length;
1897:
1898: //
1899: // patch for HP laserjet that hasn't INIT pin
1900: //
1901:
1902: if (!extension->Initialized) { //begin HP patch
1903:
1904: UCHAR deviceStatus = GetStatus(extension->Controller);
1905:
1906: ParDump(
1907: PARCRIT,
1908: ("PARALLEL: Critical - In HP patch\n")
1909: );
1910: if (PAR_OK(deviceStatus)) {
1911:
1912: ParDump(
1913: PARCRIT,
1914: ("PARALLEL: Critical - It was initialized\n")
1915: );
1916: extension->Initialized = TRUE;
1917:
1918: }
1919:
1920: } //end HP patch
1921:
1922:
1923: if (extension->Initialized) {
1924:
1925: ParDump(
1926: PARCRIT,
1927: ("PARALLEL: Critical - Sending a byte\n")
1928: );
1929: ParInitiateIo(deviceObject);
1930:
1931: } else {
1932:
1933: ParDump(
1934: PARCRIT,
1935: ("PARALLEL: Critical - reinitializing the device\n")
1936: );
1937: extension->AutoFeed = FALSE;
1938: ParInitializeDevice(extension);
1939:
1940: }
1941:
1942: //
1943: // If we are running off the timer then just
1944: // queue off the "polling" code.
1945: //
1946:
1947: if (extension->UsingATimer) {
1948:
1949: ParDump(
1950: PARCRIT,
1951: ("PARALLEL: Critical - queueing off the polling DPC\n")
1952: );
1953: KeInsertQueueDpc(
1954: &extension->PollingDpc,
1955: NULL,
1956: NULL
1957: );
1958:
1959: }
1960:
1961: return FALSE;
1962:
1963: }
1964:
1965: BOOLEAN
1966: ParManageIoDevice(
1967: IN PVOID Context
1968: )
1969:
1970: /*++
1971:
1972: Routine Description :
1973:
1974: This routine starts the IoControl commands.
1975:
1976: Arguments :
1977:
1978: Context - Really a pointer to a communication area between StartIo
1979: and ManageIoDevice
1980:
1981: Return Value :
1982:
1983: Always FALSE
1984:
1985: --*/
1986: {
1987: PCONTROL_AREA ioControlArea = Context;
1988: PPAR_DEVICE_EXTENSION extension = ioControlArea->Extension;
1989: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(ioControlArea->Irp);
1990:
1991: extension->CompletingIoControl = FALSE;
1992:
1993: if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
1994: IOCTL_PAR_SET_INFORMATION) {
1995:
1996: PPAR_SET_INFORMATION irpBuffer =
1997: ioControlArea->Irp->AssociatedIrp.SystemBuffer;
1998:
1999: extension->Command = ParSetInformation;
2000:
2001: extension->AutoFeed = (BOOLEAN)
2002: ((irpBuffer->Init & PARALLEL_AUTOFEED) != 0);
2003:
2004: ParInitializeDevice(extension);
2005:
2006: } else if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
2007: IOCTL_PAR_QUERY_INFORMATION) {
2008:
2009: ioControlArea->Status = GetStatus(extension->Controller);
2010: ioControlArea->Control = GetControl(extension->Controller);
2011: extension->Command = ParQueryInformation;
2012: extension->CompletingIoControl = TRUE;
2013:
2014: }
2015:
2016: return FALSE;
2017: }
2018:
2019: VOID
2020: ParStartIo(
2021: IN PDEVICE_OBJECT DeviceObject,
2022: IN PIRP Irp
2023: )
2024:
2025: /*++
2026:
2027: Routine Description:
2028:
2029: This routine starts an I/O operation for the driver and
2030: then returns
2031:
2032: Arguments:
2033:
2034: DeviceObject - Pointer to the device object of this device
2035:
2036: Irp - Pointer to the current IRP
2037:
2038: Return Value:
2039:
2040: None
2041:
2042: --*/
2043:
2044: {
2045: PPAR_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
2046: PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
2047:
2048: //
2049: // Increment the following value so that we can have a "unique"
2050: // value to give to the error log routine.
2051: //
2052:
2053: extension->IrpSequence++;
2054:
2055: ParDump(
2056: PARDISPATCH,
2057: ("PARALLEL: In startio with IRP: %x\n",
2058: Irp)
2059: );
2060: if (irpSp->MajorFunction == IRP_MJ_WRITE) {
2061:
2062: ParDump(
2063: PARSTART,
2064: ("PARALLEL - startio - Starting off a write\n")
2065: );
2066: ParSynchronizeExecution(
2067: extension,
2068: ParStartCriticalFunctions,
2069: DeviceObject
2070: );
2071:
2072: } else if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
2073:
2074: CONTROL_AREA ioControlArea;
2075:
2076: ioControlArea.Extension = extension;
2077: ioControlArea.Irp = Irp;
2078:
2079: ParDump(
2080: PARSTART,
2081: ("PARALLEL - startio - Starting off a device io control\n")
2082: );
2083: ParSynchronizeExecution(
2084: extension,
2085: ParManageIoDevice,
2086: &ioControlArea
2087: );
2088:
2089: if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
2090: IOCTL_PAR_QUERY_INFORMATION) {
2091:
2092: PPAR_QUERY_INFORMATION irpBuffer = Irp->AssociatedIrp.SystemBuffer;
2093:
2094: ParDump(
2095: PARSTART,
2096: ("PARALLEL - startio - Starting off a query\n")
2097: );
2098: Irp->IoStatus.Status = STATUS_SUCCESS;
2099:
2100: //
2101: // Interpretating Status & Control
2102: //
2103:
2104: irpBuffer->Status = 0x0;
2105:
2106: if (PAR_POWERED_OFF(ioControlArea.Status) ||
2107: PAR_NO_CABLE(ioControlArea.Status)) {
2108:
2109: irpBuffer->Status =
2110: (UCHAR)(irpBuffer->Status | PARALLEL_POWER_OFF);
2111:
2112: } else if (PAR_PAPER_EMPTY(ioControlArea.Status)) {
2113:
2114: irpBuffer->Status =
2115: (UCHAR)(irpBuffer->Status | PARALLEL_PAPER_EMPTY);
2116:
2117: } else if (PAR_OFF_LINE(ioControlArea.Status)) {
2118:
2119: irpBuffer->Status =
2120: (UCHAR)(irpBuffer->Status | PARALLEL_OFF_LINE);
2121:
2122: } else if (PAR_NOT_CONNECTED(ioControlArea.Status)) {
2123:
2124: irpBuffer->Status =
2125: (UCHAR)(irpBuffer->Status | PARALLEL_NOT_CONNECTED);
2126:
2127: }
2128:
2129: if ( PAR_BUSY( ioControlArea.Status ) ) {
2130:
2131: irpBuffer->Status =
2132: (UCHAR)(irpBuffer->Status | PARALLEL_BUSY);
2133:
2134: }
2135:
2136: if (PAR_SELECTED(ioControlArea.Status)) {
2137:
2138: irpBuffer->Status =
2139: (UCHAR)(irpBuffer->Status | PARALLEL_SELECTED);
2140:
2141: }
2142:
2143: if (PAR_AUTOFEED(ioControlArea.Control)) {
2144:
2145: irpBuffer->Status =
2146: (UCHAR)(irpBuffer->Status | PARALLEL_AUTOFEED);
2147:
2148: }
2149:
2150: Irp->IoStatus.Information = sizeof( PAR_QUERY_INFORMATION );
2151: IoStartNextPacket(
2152: DeviceObject,
2153: TRUE
2154: );
2155: ParDump(
2156: PARIRPCOMPLETE,
2157: ("PARALLEL: About to complete IRP: %x\n",Irp)
2158: );
2159: IoCompleteRequest(
2160: Irp,
2161: IO_NO_INCREMENT
2162: );
2163:
2164: }
2165:
2166: }
2167:
2168: }
2169:
2170: BOOLEAN
2171: ParInitiateIo(
2172: IN PDEVICE_OBJECT DeviceObject
2173: )
2174:
2175: /*++
2176:
2177: Routine Description:
2178:
2179: This routine writes UCHARs to the parallel port device.
2180: It is called from StartCriticalFunctions and ISR. In other
2181: words, it fully expects to be synchronized with the isr.
2182:
2183: Arguments:
2184:
2185: DeviceObject - Pointer to the device object of the device
2186:
2187: Return Value:
2188:
2189: Always FALSE.
2190:
2191: --*/
2192:
2193: {
2194: PPAR_DEVICE_EXTENSION extension;
2195: PIRP irp;
2196: PIO_STACK_LOCATION irpSp;
2197: PUCHAR irpBuffer;
2198:
2199: extension = DeviceObject->DeviceExtension;
2200:
2201: if (extension->Initialized) {
2202:
2203: //
2204: // We only want to write to the port when the device is online.
2205: //
2206:
2207: UCHAR deviceStatus;
2208: ULONG numberWritten = 0;
2209: ULONG maxNumberToWrite;
2210:
2211: if (extension->InterruptMode = Latched) {
2212:
2213: maxNumberToWrite = 256;
2214:
2215: } else {
2216:
2217: maxNumberToWrite = 32;
2218:
2219: }
2220: irp = DeviceObject->CurrentIrp;
2221: irpSp = IoGetCurrentIrpStackLocation(irp);
2222: irpBuffer = (PUCHAR)(irp->AssociatedIrp.SystemBuffer);
2223: irpBuffer = &irpBuffer[irpSp->Parameters.Write.Length -
2224: extension->CountBuffer];
2225: do {
2226:
2227: deviceStatus = GetStatus(extension->Controller);
2228:
2229: if (PAR_ONLINE(deviceStatus)) {
2230:
2231: StoreData(
2232: extension->Controller,
2233: *irpBuffer
2234: );
2235:
2236: irpBuffer++;
2237: extension->CountBuffer--;
2238: numberWritten++;
2239:
2240: } else {
2241:
2242: ParDump(
2243: PARCRIT,
2244: ("PARALLEL: Initiate IO - device is not on line, status: %x\n",
2245: deviceStatus)
2246: );
2247:
2248: break;
2249:
2250: }
2251:
2252: } while (extension->CountBuffer && (numberWritten < maxNumberToWrite));
2253:
2254: }
2255: extension->TimerCount = extension->TimerStart;
2256: return FALSE;
2257: }
2258:
2259: VOID
2260: ParCancelRequest(
2261: PDEVICE_OBJECT DeviceObject,
2262: PIRP Irp
2263: )
2264:
2265: /*++
2266:
2267: Routine Description:
2268:
2269: This routine is used to cancel any request in the parallel driver.
2270:
2271: Arguments:
2272:
2273: DeviceObject - Pointer to the device object for this device
2274:
2275: Irp - Pointer to the IRP to be canceled.
2276:
2277: Return Value:
2278:
2279: None.
2280:
2281: --*/
2282:
2283: {
2284:
2285: //
2286: // If this is the current request then just let normal
2287: // code detect that the current is cancelled.
2288: //
2289: // If this isn't the current request then remove the request
2290: // from the device queue and complete it.
2291: //
2292:
2293: if (Irp != DeviceObject->CurrentIrp) {
2294:
2295: KeRemoveEntryDeviceQueue(
2296: &DeviceObject->DeviceQueue,
2297: &Irp->Tail.Overlay.DeviceQueueEntry
2298: );
2299:
2300: Irp->IoStatus.Status = STATUS_CANCELLED;
2301: Irp->IoStatus.Information = 0;
2302:
2303: IoReleaseCancelSpinLock(Irp->CancelIrql);
2304:
2305: ParDump(
2306: PARIRPCOMPLETE,
2307: ("PARALLEL: About to complete IRP: %x\n",Irp)
2308: );
2309: IoCompleteRequest(
2310: Irp,
2311: IO_NO_INCREMENT
2312: );
2313:
2314: } else {
2315:
2316: ParDump(
2317: PARIRPCOMPLETE,
2318: ("PARALLEL: Can't complete (CANCEL) IRP: %x because it's current\n",
2319: Irp)
2320: );
2321: IoReleaseCancelSpinLock(Irp->CancelIrql);
2322:
2323: }
2324:
2325: }
2326:
2327: BOOLEAN
2328: ParSynchronizeExecution(
2329: IN PPAR_DEVICE_EXTENSION Extension,
2330: IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
2331: IN PVOID SynchronizeContext
2332: )
2333:
2334: /*++
2335:
2336: Routine Description:
2337:
2338: This routine is used to abstract whether we are using
2339: an interrupt object or a simple spin lock.
2340:
2341: Arguments:
2342:
2343: Extension - The device extension for the port.
2344:
2345: SynchronizeRoutine - A routine to call when the lock
2346: is aquired.
2347:
2348: SynchronizeContext - What to pass to the synchronization
2349: routine.
2350:
2351: Return Value:
2352:
2353: Whatever the synchronization routine returns.
2354:
2355: --*/
2356:
2357: {
2358:
2359: KIRQL oldIrql;
2360: BOOLEAN returnValue;
2361:
2362: KeAcquireSpinLock(
2363: &Extension->PollingLock,
2364: &oldIrql
2365: );
2366:
2367: if (Extension->Interrupt) {
2368:
2369: //
2370: // If we've haven't dropped down to using a timer
2371: // then the acquiring the polling lock is a bit
2372: // of extra overhead, but hopefully not too harmful.
2373: // We did have to pass through this irql anyway.
2374: //
2375:
2376: if (!Extension->UsingATimer) {
2377:
2378: //
2379: // We have a small race where the isr is just about
2380: // to set this to true. This is not really a big deal.
2381: // We will simply synchronize once using the interrupt
2382: // object and thereafter use the PollingLock. Overall
2383: // we are always protected by the polling lock.
2384: //
2385:
2386: returnValue = KeSynchronizeExecution(
2387: Extension->Interrupt,
2388: SynchronizeRoutine,
2389: SynchronizeContext
2390: );
2391:
2392: } else {
2393:
2394: returnValue = SynchronizeRoutine(
2395: SynchronizeContext
2396: );
2397:
2398: }
2399:
2400: } else {
2401:
2402: returnValue = SynchronizeRoutine(
2403: SynchronizeContext
2404: );
2405:
2406: }
2407:
2408: KeReleaseSpinLock(
2409: &Extension->PollingLock,
2410: oldIrql
2411: );
2412:
2413: return returnValue;
2414:
2415: }
2416:
2417: VOID
2418: ParPollingDpcRoutine(
2419: IN PKDPC Dpc,
2420: IN PVOID DeferredContext,
2421: IN PVOID SystemContext1,
2422: IN PVOID SystemContext2
2423: )
2424:
2425: /*++
2426:
2427: Routine Description:
2428:
2429: This routine is invoked by the polling timer. It will
2430: call the parsynchronizeexecution routine to call the
2431: real polling routine.
2432:
2433: Arguments:
2434:
2435: Dpc - Not Used.
2436:
2437: DeferredContext - Really points to the device extension.
2438:
2439: SystemContext1 - Not Used.
2440:
2441: SystemContext2 - Not Used.
2442:
2443: Return Value:
2444:
2445: None.
2446:
2447: --*/
2448:
2449: {
2450:
2451: PPAR_DEVICE_EXTENSION extension = DeferredContext;
2452:
2453: UNREFERENCED_PARAMETER(Dpc);
2454: UNREFERENCED_PARAMETER(SystemContext1);
2455: UNREFERENCED_PARAMETER(SystemContext2);
2456:
2457: ParSynchronizeExecution(
2458: extension,
2459: ParPolling,
2460: extension
2461: );
2462:
2463: }
2464:
2465: BOOLEAN
2466: ParPolling(
2467: IN PVOID Context
2468: )
2469:
2470: /*++
2471:
2472: Routine Description:
2473:
2474: This routine is used to drive write requests on a device
2475: that doesn't isn't using interrupts.
2476:
2477: Arguments:
2478:
2479: Context - really a pointer to the device extension
2480:
2481: Return Value:
2482:
2483: None.
2484:
2485: --*/
2486:
2487: {
2488:
2489: PPAR_DEVICE_EXTENSION extension = Context;
2490: KIRQL oldIrql;
2491: ULONG callToIsr;
2492: ULONG ticks;
2493: #define MAXTICKSTOWAIT 10000
2494: #define MINTICKSTOWAIT 1
2495: #define MAXTIMESCALLTOISR 10000
2496: #define MAXMIKESINHERE 100000
2497: ULONG maxTimesCallToIsr = MAXTIMESCALLTOISR;
2498: ULONG maxTicksToWait = MAXTICKSTOWAIT;
2499:
2500: //
2501: // We try to call the isr maxTimesCallToIsr per each invocation
2502: // of this routine.
2503: //
2504:
2505: ParDump(
2506: PARPOLLREPORT,
2507: ("PARALLEL: Chars starting poll: %d\n",
2508: extension->CountBuffer)
2509: );
2510: ParDump(
2511: PARPOLLREPORT,
2512: ("PARALLEL: Polling irp is: %x\n",
2513: extension->DeviceObject->CurrentIrp)
2514: );
2515:
2516: //
2517: // If there isn't a current irp (like it got canceled somehow)
2518: // then simply get out. This is only to write chars for the current
2519: // irp.
2520: //
2521:
2522: if (!extension->DeviceObject->CurrentIrp) {
2523:
2524: return FALSE;
2525:
2526: }
2527:
2528: for (
2529: callToIsr = 0;
2530: callToIsr < maxTimesCallToIsr;
2531: callToIsr++
2532: ) {
2533:
2534: //
2535: // We are willing to wait up to MAXTICKSTOWAIT uS "ticks" for each
2536: // call to the ISR to do something useful.
2537: //
2538:
2539: for (
2540: ticks = 0;
2541: ticks < maxTicksToWait;
2542: ticks++
2543: ) {
2544:
2545: if (ParInterruptServiceRoutine(
2546: extension->Interrupt,
2547: extension->DeviceObject
2548: )) {
2549:
2550: //
2551: // We'll we got something done. If the timercount
2552: // is -1 then means we are completing the operation
2553: // somehow. If we are completing, let the normal
2554: // completion code do its work.
2555: //
2556:
2557: if (extension->TimerCount == -1) {
2558:
2559: ParDump(
2560: PARPOLLREPORT,
2561: ("PARALLEL: Polling says we're done\n")
2562: );
2563: return FALSE;
2564:
2565: }
2566:
2567: //
2568: // Got did something useful. Go for more.
2569: //
2570: // If this is the second time we did something then
2571: // adjust the amount of work we do in this routine
2572: // based on how long it took the call to work.
2573: // We do the second call because the first call might have
2574: // been influenced by the fact that this we sitting in the
2575: // timer queue for a while and this lets the device get
2576: // all caught up.
2577: //
2578:
2579: if (callToIsr == 1) {
2580:
2581: if (ticks < MINTICKSTOWAIT) {
2582:
2583: ticks = MINTICKSTOWAIT;
2584:
2585: }
2586:
2587: //
2588: // The maximum amount of time we want to spend
2589: // in here is MAXMIKESINHERE. We divide it by
2590: // the number of ticks it took for the second
2591: // call to the isr.
2592: //
2593:
2594: maxTicksToWait = ticks;
2595:
2596: maxTimesCallToIsr = MAXMIKESINHERE / maxTicksToWait;
2597:
2598: if (maxTimesCallToIsr > MAXTIMESCALLTOISR) {
2599:
2600: //
2601: // If we are on a really fast machine, or
2602: // we are on a really fast printer (or both) let's
2603: // not use up our full "slice". Let's get out
2604: // after MAXTIMESCALLTOISR.
2605: //
2606:
2607: maxTimesCallToIsr = MAXTIMESCALLTOISR;
2608:
2609: }
2610:
2611: }
2612: goto doNextCallToIsr;
2613:
2614: } else {
2615:
2616: //
2617: // Not ready yet. Stall for a microsecond.
2618: //
2619:
2620: KeStallExecutionProcessor(1);
2621:
2622: }
2623:
2624: }
2625:
2626: //
2627: // We didn't write the character within the amount
2628: // of time allocated. Break out of the outer loop
2629: //
2630:
2631: break;
2632:
2633: doNextCallToIsr: ;
2634:
2635: }
2636:
2637: //
2638: // All done trying to write characters. Queue a timer to invoke us
2639: // again.
2640: //
2641:
2642: KeSetTimer(
2643: &extension->PollingTimer,
2644: extension->PollingDelayAmount,
2645: &extension->PollingDpc
2646: );
2647:
2648: ParDump(
2649: PARPOLLREPORT,
2650: ("PARALLEL: To go at end of poll: %d\n"
2651: "--------- Ticks per char is: %d\n"
2652: "--------- Calls to isr per: %d\n",
2653: extension->CountBuffer,
2654: maxTicksToWait,
2655: maxTimesCallToIsr)
2656:
2657: );
2658:
2659: return FALSE;
2660: #undef MAXTICKSTOWAIT
2661: #undef MINTICKSTOWAIT
2662: #undef MAXTIMESCALLTOISR
2663: #undef MAXMIKESINHERE
2664: }
2665:
2666: VOID
2667: ParStartBusyTimer(
2668: IN PKDPC Dpc,
2669: IN PVOID DeferredContext,
2670: IN PVOID SystemContext1,
2671: IN PVOID SystemContext2
2672: )
2673:
2674: /*++
2675:
2676: Routine Description:
2677:
2678: This routine is invoked by the dpc that is queued by the
2679: ISR when it finds that it has work to do yet the status
2680: is busy.
2681:
2682: Arguments:
2683:
2684: Dpc - Not Used.
2685:
2686: DeferredContext - Really points to the device extension.
2687:
2688: SystemContext1 - Not Used.
2689:
2690: SystemContext2 - Not Used.
2691:
2692: Return Value:
2693:
2694: None.
2695:
2696: --*/
2697:
2698: {
2699:
2700: PPAR_DEVICE_EXTENSION extension = DeferredContext;
2701:
2702: UNREFERENCED_PARAMETER(Dpc);
2703: UNREFERENCED_PARAMETER(SystemContext1);
2704: UNREFERENCED_PARAMETER(SystemContext2);
2705:
2706: ParDump(
2707: PARBUSYPATH,
2708: ("Parallel: In start busy timer dpc\n")
2709: );
2710: KeSetTimer(
2711: &extension->BusyTimer,
2712: extension->BusyDelayAmount,
2713: &extension->BusyTimerDpc
2714: );
2715:
2716: }
2717:
2718: VOID
2719: ParBusyTimer(
2720: IN PKDPC Dpc,
2721: IN PVOID DeferredContext,
2722: IN PVOID SystemContext1,
2723: IN PVOID SystemContext2
2724: )
2725:
2726: /*++
2727:
2728: Routine Description:
2729:
2730: This routine is invoked by the dpc that is queued by when
2731: the busy timer fires.
2732:
2733: Arguments:
2734:
2735: Dpc - Not Used.
2736:
2737: DeferredContext - Really points to the device extension.
2738:
2739: SystemContext1 - Not Used.
2740:
2741: SystemContext2 - Not Used.
2742:
2743: Return Value:
2744:
2745: None.
2746:
2747: --*/
2748:
2749: {
2750:
2751: PPAR_DEVICE_EXTENSION extension = DeferredContext;
2752:
2753: UNREFERENCED_PARAMETER(Dpc);
2754: UNREFERENCED_PARAMETER(SystemContext1);
2755: UNREFERENCED_PARAMETER(SystemContext2);
2756:
2757: ParDump(
2758: PARBUSYPATH,
2759: ("Parallel: In busy timer dpc\n")
2760: );
2761: ParSynchronizeExecution(
2762: extension,
2763: ParBusyCallIsr,
2764: extension
2765: );
2766:
2767: }
2768:
2769: BOOLEAN
2770: ParBusyCallIsr(
2771: IN PVOID Context
2772: )
2773:
2774: /*++
2775:
2776: Routine Description:
2777:
2778: This routine is invoked via KeSynchronize execution which
2779: was invoked by the dpc associated with the busy timer.
2780: Its sole purpose is to call the interrupt service routine.
2781:
2782: Arguments:
2783:
2784: Context - Really a pointer to the device extension.
2785:
2786: Return Value:
2787:
2788: Always False.
2789:
2790: --*/
2791:
2792: {
2793:
2794: PPAR_DEVICE_EXTENSION extension = Context;
2795:
2796: extension->BusyPath = FALSE;
2797:
2798: ParDump(
2799: PARBUSYPATH,
2800: ("Parallel: In busy timer - about to call isr\n")
2801: );
2802: ParInterruptServiceRoutine(
2803: extension->Interrupt,
2804: extension->DeviceObject
2805: );
2806:
2807: return FALSE;
2808:
2809: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.