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