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