|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1990, 1991 Microsoft Corporation ! 4: ! 5: Module Name : ! 6: ! 7: par.h ! 8: ! 9: Abstract: ! 10: ! 11: Type definitions and data for the parallel port driver ! 12: ! 13: Author: ! 14: ! 15: ! 16: Revision History: ! 17: --*/ ! 18: ! 19: ! 20: #if DBG ! 21: #define PARCONFIG ((ULONG)0x00000001) ! 22: #define PARUNLOAD ((ULONG)0x00000002) ! 23: #define PARINITDEV ((ULONG)0x00000004) ! 24: #define PARTIMEOUT ((ULONG)0x00000008) ! 25: #define PARSTART ((ULONG)0x00000010) ! 26: #define PARISR ((ULONG)0x00000020) ! 27: #define PARDPC ((ULONG)0x00000040) ! 28: #define PARCRIT ((ULONG)0x00000080) ! 29: #define PARBUSYPATH ((ULONG)0x00000100) ! 30: #define PARIRPCOMPLETE ((ULONG)0x00000200) ! 31: #define PARDISPATCH ((ULONG)0x00000400) ! 32: #define PARISRACTION ((ULONG)0x00000800) ! 33: #define PARPOLLREPORT ((ULONG)0x00001000) ! 34: #define PARERRORS ((ULONG)0x40000000) ! 35: #define PARBUGCHECK ((ULONG)0x80000000) ! 36: extern ULONG ParDebugLevel; ! 37: #define ParDump(LEVEL,STRING) \ ! 38: do { \ ! 39: ULONG _level = (LEVEL); \ ! 40: if (ParDebugLevel & _level) { \ ! 41: DbgPrint STRING; \ ! 42: } \ ! 43: if (_level == PARBUGCHECK) { \ ! 44: ASSERT(FALSE); \ ! 45: } \ ! 46: } while (0) ! 47: #else ! 48: #define ParDump(LEVEL,STRING) do {NOTHING;} while (0) ! 49: #endif ! 50: ! 51: // ! 52: // This define gives the default Object directory ! 53: // that we should use to insert the symbolic links ! 54: // between the NT device name and namespace used by ! 55: // that object directory. ! 56: #define DEFAULT_DIRECTORY L"DosDevices" ! 57: ! 58: // ! 59: // For the above directory, the serial port will ! 60: // use the following name as the suffix of the serial ! 61: // ports for that directory. It will also append ! 62: // a number onto the end of the name. That number ! 63: // will start at 1. ! 64: #define DEFAULT_PARALLEL_NAME L"LPT" ! 65: // ! 66: // ! 67: // This define gives the default NT name for ! 68: // for serial ports detected by the firmware. ! 69: // This name will be appended to Device prefix ! 70: // with a number following it. The number is ! 71: // incremented each time encounter a serial ! 72: // port detected by the firmware. Note that ! 73: // on a system with multiple busses, this means ! 74: // that the first port on a bus is not necessarily ! 75: // \Device\Parallel0. ! 76: // ! 77: #define DEFAULT_NT_SUFFIX L"Parallel" ! 78: ! 79: ! 80: // ! 81: // Defines the number of interrupts it takes for us to decide that ! 82: // we have an interrupt storm on machine ! 83: // ! 84: #define PARALLEL_STORM_WATCH 500 ! 85: ! 86: #define PARALLEL_DATA_OFFSET 0 ! 87: #define PARALLEL_STATUS_OFFSET 1 ! 88: #define PARALLEL_CONTROL_OFFSET 2 ! 89: #define PARALLEL_REGISTER_SPAN 3 ! 90: ! 91: typedef struct _CONFIG_DATA { ! 92: // ! 93: // This list entry is used to link all of the "valid" ! 94: // configuration entries together. ! 95: // ! 96: LIST_ENTRY ConfigList; ! 97: ! 98: // ! 99: // The nt object directory into which to place the symbolic ! 100: // link to this port. ! 101: // ! 102: UNICODE_STRING ObjectDirectory; ! 103: ! 104: // ! 105: // The suffix to be used in the nt device name space for this ! 106: // port. ! 107: // ! 108: UNICODE_STRING NtNameForPort; ! 109: ! 110: // ! 111: // The name to be symbolic linked to the nt name. ! 112: // ! 113: UNICODE_STRING SymbolicLinkName; ! 114: ! 115: // ! 116: // The base address of the registry set for this device. ! 117: // ! 118: PHYSICAL_ADDRESS Controller; ! 119: ! 120: // ! 121: // The number of contiguous bytes take up by the register ! 122: // set for the device. ! 123: // ! 124: ULONG SpanOfController; ! 125: ! 126: // ! 127: // The bus number (with respect to the bus type) of the bus ! 128: // that this device occupies. ! 129: // ! 130: ULONG BusNumber; ! 131: ! 132: // ! 133: // Denotes whether this devices physical addresses live in io space ! 134: // or memory space. ! 135: // ! 136: ULONG AddressSpace; ! 137: ! 138: // ! 139: // Denotes whether this device is latched or level sensitive. ! 140: // ! 141: KINTERRUPT_MODE InterruptMode; ! 142: ! 143: // ! 144: // The kind of bus that this device lives on (e.g. Isa, Eisa, MCA, etc) ! 145: // ! 146: INTERFACE_TYPE InterfaceType; ! 147: ! 148: // ! 149: // The originalirql is what is optained from the firmware data. The level ! 150: // is also obtained from the firmware data. When we get a configuration ! 151: // record based on the services portion of the registry we will always set ! 152: // the vector equal to the irql unless overridden by user input. ! 153: // ! 154: ULONG OriginalVector; ! 155: ULONG OriginalIrql; ! 156: ! 157: // ! 158: // Denotes whether the device should be disabled after it has been ! 159: // initialized. ! 160: // ! 161: ULONG DisablePort; ! 162: ! 163: } CONFIG_DATA,*PCONFIG_DATA; ! 164: ! 165: typedef enum _PAR_COMMAND { ! 166: ParWrite, ! 167: ParSetInformation, ! 168: ParQueryInformation ! 169: } PAR_COMMAND, *PPAR_COMMAND; ! 170: ! 171: typedef struct _PAR_DEVICE_EXTENSION { ! 172: ! 173: // ! 174: // For reporting resource usage, we keep around the physical ! 175: // address we got from the registry. ! 176: // ! 177: PHYSICAL_ADDRESS OriginalController; ! 178: ! 179: // ! 180: // We keep a pointer around to our device name for dumps ! 181: // and for creating "external" symbolic links to this ! 182: // device. ! 183: // ! 184: UNICODE_STRING DeviceName; ! 185: ! 186: // ! 187: // This points to the object directory that we will place ! 188: // a symbolic link to our device name. ! 189: // ! 190: UNICODE_STRING ObjectDirectory; ! 191: ! 192: // ! 193: // This points to the device name for this device ! 194: // sans device prefix. ! 195: // ! 196: UNICODE_STRING NtNameForPort; ! 197: ! 198: // ! 199: // This points to the symbolic link name that will be ! 200: // linked to the actual nt device name. ! 201: // ! 202: UNICODE_STRING SymbolicLinkName; ! 203: ! 204: // ! 205: // Points to the device object that contains ! 206: // this device extension. ! 207: // ! 208: PDEVICE_OBJECT DeviceObject; ! 209: ! 210: // ! 211: // For value -1 when the interval timer maintained by the IO system ! 212: // fires, it implies that the timer routine is to do nothing. ! 213: // ! 214: // For value 0, then the timer routine should timeout the particular ! 215: // operation. ! 216: // ! 217: // For values > 0 then the timer should do nothing other then synchronize ! 218: // with the isr and decrement this value by 1. ! 219: // ! 220: LONG TimerCount; ! 221: ! 222: // ! 223: // This holds the current value to initialize TimerCount ! 224: // to when an operation starts. ! 225: // ! 226: ULONG TimerStart; ! 227: ! 228: // ! 229: // Unexpected interrupts are counted here. It is cleared ! 230: // every second by the timer management routine. On ! 231: // a device that is being interrupt driven, if the unexpected ! 232: // interrupt count exceeds a threshold, the interrupts will ! 233: // be disabled on the device and the device will go to polled ! 234: // mode. ! 235: // ! 236: ULONG UnexpectedCount; ! 237: ! 238: // ! 239: // The base address for the set of device registers ! 240: // of the port. ! 241: // ! 242: PUCHAR Controller; ! 243: ! 244: // ! 245: // Points to the interrupt object used by this device. ! 246: // ! 247: PKINTERRUPT Interrupt; ! 248: ! 249: // ! 250: // This value holds the span (in units of bytes) of the register ! 251: // set controlling this port. This is constant over the life ! 252: // of the port. ! 253: // ! 254: ULONG SpanOfController; ! 255: ! 256: // ! 257: // Set at intialization to indicate that on the current ! 258: // architecture we need to unmap the base register address ! 259: // when we unload the driver. ! 260: // ! 261: BOOLEAN UnMapRegisters; ! 262: ! 263: // ! 264: // These two variables denote the "staging" of initializing the ! 265: // device. Some devices won't respond with an interrupt when ! 266: // initializing. When we start initializing, we set the Initializing ! 267: // variable to TRUE and the Initialized flag to FALES. ! 268: // ! 269: // Whenever we go an access the hardware we check the initializing flag. ! 270: // If it is true, then we check the "status" of the device, and if the ! 271: // everything is ok, set initializing to FALSE and Initialized to TRUE. ! 272: // If the "status" of the device is not "good", then we process it as an ! 273: // error, and return the error indication to the caller. ! 274: // ! 275: BOOLEAN Initialized; ! 276: BOOLEAN Initializing; ! 277: ! 278: // ! 279: // This denotes the number of characters left in the current write. ! 280: // ! 281: ULONG CountBuffer; ! 282: ! 283: BOOLEAN AutoFeed; ! 284: BOOLEAN CompletingIoControl; ! 285: ! 286: // ! 287: // Records whether we actually created the symbolic link name ! 288: // at driver load time. If we didn't create it, we won't try ! 289: // to distroy it when we unload. ! 290: // ! 291: BOOLEAN CreatedSymbolicLink; ! 292: ! 293: // ! 294: // This field will denote that the driver is using a timer instead of ! 295: // interrupts to "schedule" work out to the device. ! 296: // ! 297: BOOLEAN UsingATimer; ! 298: ! 299: PAR_COMMAND Command; ! 300: ! 301: // ! 302: // Says whether this device can share interrupts with devices ! 303: // other than parallel devices. ! 304: // ! 305: BOOLEAN InterruptShareable; ! 306: ! 307: // ! 308: // Denotes to the timer routine whether it should log an error ! 309: // because we were blasted by to many interrupts. ! 310: // ! 311: BOOLEAN StormKnocksOutInterrupts; ! 312: ! 313: // ! 314: // We keep the following values around so that we can connect ! 315: // to the interrupt and report resources after the configuration ! 316: // record is gone. ! 317: // ! 318: // ! 319: // The following two values are obtained from HalGetInterruptVector ! 320: // ! 321: ULONG Vector; ! 322: KIRQL Irql; ! 323: ! 324: // ! 325: // The following two values are what is obtained (or deduced) from either ! 326: // the firmware created portion of the registry, or the user data. ! 327: // ! 328: ULONG OriginalVector; ! 329: ULONG OriginalIrql; ! 330: ! 331: // ! 332: // This is either what is deduced from the particular bus this port is ! 333: // on, or overridden by what the user placed in the registry. ! 334: // ! 335: KINTERRUPT_MODE InterruptMode; ! 336: ! 337: // ! 338: // Give back by HalGetInterruptVector. This says what processors this ! 339: // device can interrupt to. ! 340: // ! 341: KAFFINITY ProcessorAffinity; ! 342: ! 343: // ! 344: // The next three are supplied by the firmware or overridden by the user. ! 345: // ! 346: ULONG AddressSpace; ! 347: ULONG BusNumber; ! 348: INTERFACE_TYPE InterfaceType; ! 349: ! 350: // ! 351: // All irps go through the start io routine. Whenver ! 352: // we start out a new irp we increment this value. This ! 353: // is how we can have a unique irp value to give if we ! 354: // need to log an error during the processing of a particular ! 355: // irp. ! 356: // ! 357: ULONG IrpSequence; ! 358: ! 359: // ! 360: // This spinlock is used to synchronize access to the hardware ! 361: // when the port is being driver off of a timer, rather than ! 362: // when using interrupts. ! 363: // ! 364: KSPIN_LOCK PollingLock; ! 365: ! 366: // ! 367: // We use a timer so that we can try to do a bunch of ! 368: // operations, then give the rest of the system time ! 369: // to run ! 370: // ! 371: KTIMER PollingTimer; ! 372: ! 373: // ! 374: // This dpc is queued when the polling timer expires, and it is ! 375: // also queued after we start a write operations. ! 376: // ! 377: KDPC PollingDpc; ! 378: ! 379: // ! 380: // This is the length of time the timer will spend in the ! 381: // timer queue. ! 382: // ! 383: LARGE_INTEGER PollingDelayAmount; ! 384: ! 385: // ! 386: // This timer is used for polling the busy bit. ! 387: // ! 388: KTIMER BusyTimer; ! 389: ! 390: // ! 391: // This dpc is queued from the isr to start the above timer. ! 392: // ! 393: KDPC StartBusyTimerDpc; ! 394: ! 395: // ! 396: // This is the dpc queued when the above timer fires. ! 397: // ! 398: KDPC BusyTimerDpc; ! 399: ! 400: // ! 401: // This holds the delta time fed to above timer. ! 402: // ! 403: LARGE_INTEGER BusyDelayAmount; ! 404: ! 405: // ! 406: // We keep this boolean around to tell use that we've started off ! 407: // the busy "path of execution". If this variable is true when ! 408: // the isr would start off the busy path, it won't start it. If ! 409: // it is false, we set it to true and start the path. It is not ! 410: // set back to false until just before the path calls back the ! 411: // isr. ! 412: // ! 413: BOOLEAN BusyPath; ! 414: } PAR_DEVICE_EXTENSION, *PPAR_DEVICE_EXTENSION; ! 415: ! 416: // ! 417: // Bit Definitions in the status register. ! 418: // ! 419: ! 420: #define PAR_STATUS_NOT_ERROR 0x08 //not error on device ! 421: #define PAR_STATUS_SLCT 0x10 //device is selected (on-line) ! 422: #define PAR_STATUS_PE 0x20 //paper empty ! 423: #define PAR_STATUS_NOT_ACK 0x40 //not acknowledge (data transfer was not ok) ! 424: #define PAR_STATUS_NOT_BUSY 0x80 //operation in progress ! 425: ! 426: // ! 427: // Bit Definitions in the control register. ! 428: // ! 429: ! 430: #define PAR_CONTROL_STROBE 0x01 //to read or write data ! 431: #define PAR_CONTROL_AUTOFD 0x02 //to autofeed continuous form paper ! 432: #define PAR_CONTROL_NOT_INIT 0x04 //begin an initialization routine ! 433: #define PAR_CONTROL_SLIN 0x08 //to select the device ! 434: #define PAR_CONTROL_IRQ_ENB 0x10 //to enable interrupts ! 435: #define PAR_CONTROL_DIR 0x20 //direction = read ! 436: #define PAR_CONTROL_WR_CONTROL 0xc0 //the 2 highest bits of the control ! 437: // register must be 1 ! 438: ! 439: //VOID StoreData( ! 440: // IN PUCHAR RegisterBase, ! 441: // IN UCHAR DataByte ! 442: // ) ! 443: //Data must be on line before Strobe = 1; ! 444: // Strobe = 1, DIR = 0 ! 445: //Strobe = 0 ! 446: // ! 447: // We change the port direction to output (and make sure stobe is low). ! 448: // ! 449: // Note that the data must be available at the port for at least ! 450: // .5 microseconds before and after you strobe, and that the strobe ! 451: // must be active for at least 500 nano seconds. We are going ! 452: // to end up stalling for twice as much time as we need to, but, there ! 453: // isn't much we can do about that. ! 454: // ! 455: // We put the data into the port and wait for 1 micro. ! 456: // We strobe the line for at least 1 micro ! 457: // We lower the strobe and again delay for 1 micro ! 458: // We then revert to the original port direction. ! 459: // ! 460: // Thanks to Olivetti for advice. ! 461: // ! 462: ! 463: #define StoreData(RegisterBase,DataByte) \ ! 464: { \ ! 465: PUCHAR _Address = RegisterBase; \ ! 466: UCHAR _Control; \ ! 467: _Control = GetControl(_Address); \ ! 468: ASSERT(!(_Control & PAR_CONTROL_STROBE)); \ ! 469: StoreControl( \ ! 470: _Address, \ ! 471: (UCHAR)(_Control & ~(PAR_CONTROL_STROBE | PAR_CONTROL_DIR)) \ ! 472: ); \ ! 473: WRITE_PORT_UCHAR( \ ! 474: _Address+PARALLEL_DATA_OFFSET, \ ! 475: (UCHAR)DataByte \ ! 476: ); \ ! 477: KeStallExecutionProcessor((ULONG)1); \ ! 478: StoreControl( \ ! 479: _Address, \ ! 480: (UCHAR)((_Control | PAR_CONTROL_STROBE) & ~PAR_CONTROL_DIR) \ ! 481: ); \ ! 482: KeStallExecutionProcessor((ULONG)1); \ ! 483: StoreControl( \ ! 484: _Address, \ ! 485: (UCHAR)(_Control & ~(PAR_CONTROL_STROBE | PAR_CONTROL_DIR)) \ ! 486: ); \ ! 487: KeStallExecutionProcessor((ULONG)1); \ ! 488: StoreControl( \ ! 489: _Address, \ ! 490: (UCHAR)_Control \ ! 491: ); \ ! 492: } ! 493: ! 494: //UCHAR ! 495: //GetControl( ! 496: // IN PUCHAR RegisterBase ! 497: // ) ! 498: #define GetControl(RegisterBase) \ ! 499: (READ_PORT_UCHAR((RegisterBase)+PARALLEL_CONTROL_OFFSET)) ! 500: ! 501: ! 502: //VOID ! 503: //StoreControl( ! 504: // IN PUCHAR RegisterBase, ! 505: // IN UCHAR ControlByte ! 506: // ) ! 507: #define StoreControl(RegisterBase,ControlByte) \ ! 508: { \ ! 509: WRITE_PORT_UCHAR( \ ! 510: (RegisterBase)+PARALLEL_CONTROL_OFFSET, \ ! 511: (UCHAR)ControlByte \ ! 512: ); \ ! 513: } ! 514: ! 515: ! 516: //UCHAR ! 517: //GetStatus( ! 518: // IN PUCHAR RegisterBase ! 519: // ) ! 520: ! 521: #define GetStatus(RegisterBase) \ ! 522: (READ_PORT_UCHAR((RegisterBase)+PARALLEL_STATUS_OFFSET)) ! 523: ! 524: typedef enum _PAR_ERROR_TYPE { ! 525: PoweredOff, ! 526: NotConnected, ! 527: Offline, ! 528: PaperEmpty, ! 529: PowerFailure, ! 530: DataError, ! 531: Busy ! 532: } PAR_ERROR_TYPE, *PPAR_ERROR_TYPE; ! 533: ! 534: BOOLEAN ! 535: ParInitializeDevice( ! 536: IN PVOID Context ! 537: ); ! 538: ! 539: NTSTATUS ! 540: ParDispatch( ! 541: IN PDEVICE_OBJECT DeviceObject, ! 542: IN PIRP Irp ! 543: ); ! 544: ! 545: NTSTATUS ! 546: ParSetInformationFile( ! 547: IN PDEVICE_OBJECT DeviceObject, ! 548: IN PIRP Irp ! 549: ); ! 550: ! 551: NTSTATUS ! 552: ParQueryInformationFile( ! 553: IN PDEVICE_OBJECT DeviceObject, ! 554: IN PIRP Irp ! 555: ); ! 556: ! 557: VOID ! 558: ParDpcRoutine( ! 559: IN PKDPC Dpc, ! 560: IN PDEVICE_OBJECT DeviceObject, ! 561: IN PIRP Irp, ! 562: IN PVOID Context ! 563: ); ! 564: ! 565: VOID ! 566: ParTimerRoutine( ! 567: PDEVICE_OBJECT DeviceObject, ! 568: IN PVOID Context ! 569: ); ! 570: ! 571: BOOLEAN ! 572: ParManageTimeOut( ! 573: IN PVOID Context ! 574: ); ! 575: ! 576: BOOLEAN ! 577: ParInterruptServiceRoutine( ! 578: IN PKINTERRUPT InterruptObject, ! 579: IN PVOID Context ! 580: ); ! 581: ! 582: BOOLEAN ! 583: ParInitiateIo( ! 584: IN PDEVICE_OBJECT DeviceObject ! 585: ); ! 586: ! 587: VOID ! 588: ParStartIo( ! 589: IN PDEVICE_OBJECT DeviceObject, ! 590: IN PIRP Irp ! 591: ); ! 592: ! 593: VOID ! 594: ParUnload( ! 595: IN PDRIVER_OBJECT DriverObject ! 596: ); ! 597: ! 598: VOID ! 599: ParCancelRequest( ! 600: IN PDEVICE_OBJECT DeviceObject, ! 601: IN PIRP Irp ! 602: ); ! 603: ! 604: BOOLEAN ! 605: ParSynchronizeExecution( ! 606: IN PPAR_DEVICE_EXTENSION Extension, ! 607: IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, ! 608: IN PVOID SynchronizeContext ! 609: ); ! 610: ! 611: VOID ! 612: ParPollingDpcRoutine( ! 613: IN PKDPC Dpc, ! 614: IN PVOID DeferredContext, ! 615: IN PVOID SystemContext1, ! 616: IN PVOID SystemContext2 ! 617: ); ! 618: ! 619: BOOLEAN ! 620: ParPolling( ! 621: IN PVOID Context ! 622: ); ! 623: ! 624: VOID ! 625: ParLogError( ! 626: IN PDRIVER_OBJECT DriverObject, ! 627: IN PDEVICE_OBJECT DeviceObject OPTIONAL, ! 628: IN PHYSICAL_ADDRESS P1, ! 629: IN PHYSICAL_ADDRESS P2, ! 630: IN ULONG SequenceNumber, ! 631: IN UCHAR MajorFunctionCode, ! 632: IN UCHAR RetryCount, ! 633: IN ULONG UniqueErrorValue, ! 634: IN NTSTATUS FinalStatus, ! 635: IN NTSTATUS SpecificIOStatus ! 636: ); ! 637: ! 638: VOID ! 639: ParStartBusyTimer( ! 640: IN PKDPC Dpc, ! 641: IN PVOID DeferredContext, ! 642: IN PVOID SystemContext1, ! 643: IN PVOID SystemContext2 ! 644: ); ! 645: ! 646: VOID ! 647: ParBusyTimer( ! 648: IN PKDPC Dpc, ! 649: IN PVOID DeferredContext, ! 650: IN PVOID SystemContext1, ! 651: IN PVOID SystemContext2 ! 652: ); ! 653: ! 654: BOOLEAN ! 655: ParBusyCallIsr( ! 656: IN PVOID Context ! 657: ); ! 658:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.