home *** CD-ROM | disk | FTP | other *** search
- FINDIRQ.COM (VERSION 1.0) Copyright (c) Rick Knoblaugh
- -------------------------------------------------------------------------
- First Published in PC Magazine September 25, 1993 (Utilities)
- -------------------------------------------------------------------------
- FINDIRQ BY RICK KNOBLAUGH
-
- FINDIRQ reports which interrupt request lines (IRQs) in a system
- are assigned to specific devices and which are free to use for installing a
- new peripheral device.
-
- When you purchase a scanner or other peripheral device, the installation
- instructions usually tell you to set the jumpers on the board for an
- ``available IRQ.'' Even if you know what an IRQ is, however, chances are you
- don't know which ones are in use and which are still free. If you install
- your new device to use an already-assigned IRQ, it may well cause a system
- crash.
-
- What you need is FINDIRQ, a utility that tells you which devices in your
- system are using which IRQs and which IRQs are unassigned.
-
- An IRQ is simply a hardware interrupt request line that allows a
- peripheral to signal the computer's central processing unit that an event
- requiring the CPU's attention has occurred. AT-style machines have 16 IRQ
- lines; older PCs have but 8. A few IRQ assignments are more or less
- standard on AT-type machines: The timer uses IRQ0 and the keyboard uses
- IRQ1, for example. But if you've added optional peripherals, such as a
- scanner, mouse, or fax modem, you need a program like FINDIRQ to learn
- which IRQs the peripherals have appropriated.
-
- Users of Windows 3.1 and/or DOS 6.0 may wonder whether the new
- Microsoft Diagnostics (MSD) program makes FINDIRQ unnecessary. MSD does
- a good job of showing IRQ assignments for standard devices, such as COM
- and LPT ports. However, MSD will not report the IRQ assigned to any
- device that is not on its internal list. MSD will tell you the name of
- the program controlling a given IRQ only if you have not disabled STACKS
- in your CONFIG.SYS file (more on this later).
-
- Further, since it lacks FINDIRQ's TSR option, MSD overlooks IRQs
- that are enabled only while a device--such as a sound board--is active.
- FINDIRQ's TSR option also allows it to detect IRQ usage for devices that
- are only activated under Windows. If you have a Microsoft InPort mouse,
- for example, and you use it only under Windows (and no DOS driver for it
- is installed), most DOS-based diagnostic programs will never detect that
- the device is present. And while there are a number of commercial
- IRQ-detecting programs, each with its strengths and limitations, FINDIRQ
- can hold its own against any of them.
-
- To work from the source files, you will need the Microsoft MASM
- assembler (or compatible), and the LINK and EXE2BIN utilities.
-
- USING FINDIRQ
-
- If you keep FIND IRQ.COM in a subdirectory on your path, simply
- entering FINDIRQ from a DOS prompt will bring up an opening display.
- The IRQ usage of all standard devices (those of which the BIOS has
- knowledge: COMn and LPTn) will be shown, along with that of any optional
- devices (like sound boards or SCSI adapters) that are currently enabled.
- IRQ assignments for devices controlled by TSR programs will also be
- displayed if the TSR is loaded in conventional memory.
-
- To report IRQ information for devices controlled by TSRs that are
- loaded in high memory, FINDIRQ must be invoked with LOADHIGH, thus
- LH FINDIRQ. Note that when FINDIRQ is loaded high, it can still detect
- TSRs loaded into low memory, so if you use high memory on your system,
- it's always a good idea to load FINDIRQ high.
-
- In listing the IRQ usage, FINDIRQ assumes certain standard device
- IRQ assignments. For example, if the BIOS reports that two COM ports
- are present, it assumes that COM1 uses IRQ4 and COM2 uses IRQ3; these
- are the standard AT assignments. If your system supports steerable
- IRQs and you have routed them to nonstandard assignments (a rare
- situation), FINDIRQ will not properly report the IRQs used by those
- devices.
-
- For standard devices, FINDIRQ displays the device name. For
- optional character devices, FINDIRQ displays the name of the device as
- specified by the device driver. For optional block devices,
- ``Block Device'' is displayed. If a device is being handled by a TSR,
- FINDIRQ displays the name of the TSR program.
-
- FINDIRQ SYNTAX OPTIONS
-
- To document even unusual and elusive interrupts, FINDIRQ provides
- a variety of optional parameters. In summary form, the syntax for the
- command is
-
- [LH] FINDIRQ [/t] [/i] [/u] [/d] [/h]
-
- As indicated initially, some interrupts are enabled only when the
- devices that use them are active. To detect such devices--sound boards,
- for instance--FINDIRQ must be memory-resident at the time the devices
- are activated. FINDIRQ can be installed as a TSR, therefore, by entering
- FINDIRQ /t .
-
- When the TSR component of FINDIRQ is loaded, your system is
- constantly being monitored in the background for IRQ activity. When a
- previously unassigned IRQ is enabled, its IRQ information is stored in a
- tiny, 2-byte data file, FINDIRQ.DAT, which FINDIRQ creates in its
- subdirectory. FINDIRQ uses the information in this file to supplement
- what it knows about IRQ usage. This scheme can't tell you whether a
- temporarily activated IRQ is currently in use, but it can tell you that
- the IRQ has been used at some point and is probably not available for
- other devices.
-
- If you change your system configuration--by removing or rejumpering
- a board, for example--you must reinitialize the FINDIRQ.DAT file. This
- is done by executing the /i option FINDIRQ /i. Regardless of whether
- the TSR component is resident, you display IRQ usage in the same way--by
- typing FINDIRQ with no switches. If the resident portion is currently
- loaded, a notation will appear on the left side of the display. Although
- the resident portion of FINDIRQ is very small (less than 3K), you can
- unload it if you wish by typing FINDIRQ /u .
-
- In certain cases, programs can erroneously enable IRQs; that is,
- the IRQs can appear to be in use when in fact they are not. To guard
- against false reporting, FINDIRQ normally verifies that enabled IRQs
- have valid handlers before reporting that they are unavailable. This is
- done by checking that the handler is not simply a ROM default interrupt
- handler, whose job is to field spuriously generated interrupts.
-
- When an IRQ is enabled under Windows and no DOS device driver for
- the device is installed, however, the handler cannot be verified. There
- are also other instances in which interrupt handlers cannot be verified,
- such as when IRQ enabling is intermittent or when a memory manager has
- remapped ROM. In these circumstances, FINDIRQ will incorrectly report that
- the IRQ is available. To suppress FINDIRQ's verification requirement and
- so avoid this problem, you can execute FINDIRQ with its ``don't verify''
- switch: FINDIRQ /d . Finally, to remind yourself of the range of FINDIRQ
- options, simply execute the program with its help switch: FINDIRQ /h.
- The help screen lists and describes all program options.
-
- IRQ REVIEW
-
- Before delving into FIND IRQ's inner workings, a brief review of
- interrupt processing may be helpful. Interrupts provide a time-saving
- alternative to periodically polling all the peripherals attached to the
- system to determine whether they require the CPU's attention. Under an
- interrupt system, peripheral devices receive recognition only when they
- ask for it. Thus, the system processor does not waste processing time
- repeatedly checking for characters being typed at the keyboard or data
- bytes being received by an attached modem.
-
- Devices such as the keyboard controller and the communications UART
- chip utilize the interrupt lines labeled IRQ0 through IRQ15. These lines
- go to the 8259 Programmable Interrupt Controllers (PICs), which arbitrate
- the interrupt requests and then activate the processor's single interrupt
- request line. A detailed discussion of this process can be found in
- The IBM PC from the Inside Out, by Sargent and Shoemaker (Addison-Wesley,
- 1984, 1986).
-
- Figure 2 (See below) depicts this arrangement and shows the standard
- IRQ assignments used by an AT-class machine. Each 8259 PIC handles eight
- interrupt lines; to accommodate additional interrupt lines, multiple 8259s
- are tied together. One serves as the master and has a cascade line that
- connects it to slave 8259s. On the AT, IRQ2 is used for this purpose.
- Note, however, that you can still attach devices that utilize IRQ2.
- The adapter-card edge connector used for IRQ2 in PC-class machines is
- wired to IRQ9 in AT machines. It is then routed via a software interrupt
- to the interrupt for IRQ2. This round-about arrangement was implemented
- to provide compatibility with original PC adapter boards.
-
- When each 8259 is initialized, the interrupt base value is written
- to the PIC. This value determines which interrupt number is generated.
- The master PIC starts at 8, so IRQs 0 through 7 generate interrupts 8
- through 15. The slave PIC starts at 70h, so IRQs 8 thru 15 generate
- interrupts 70h through 77h. The PIC registers are accessible in I/O
- space; the master PIC is based at 20h and the slave starts at A0h.
-
- FINDIRQ checks the PIC's Interrupt Mask Register to detect active
- interrupts. In this 8-bit register, each bit position corresponds to
- one of the interrupt lines. The BIOS and other device handlers use
- this register to enable or disable the generation of interrupts.
- Interrupts are disabled or ``masked'' when a 1 is written to the
- corresponding bit position, while a 0 means that they are enabled.
-
- HOW FINDIRQ WORKS
-
- FINDIRQ starts by checking the system model ID byte at 0F000:FFFE
- to ascertain whether the system is an AT-class machine (16 IRQ lines)
- or an older, PC-type machine (8 IRQ lines). The program next attempts
- to read FINDIRQ.DAT, which exists if FINDIRQ has previously been executed
- as a TSR. The file FINDIRQ.DAT contains 2 bytes (16 bits) that show the
- IRQs that have at some point been enabled.
-
- After checking the data file, the PIC mask registers are read to
- determine which IRQs are currently enabled. FINDIRQ maintains its own
- copies of the PIC mask registers and sets the bits appropriately as it
- learns about the devices present on the system.
-
- IRQs assigned to COM and LPT devices may not be enabled if the
- devices are not being used. The INT 11h equipment check call is used
- to determine the number of COM and LPT ports available, and the IRQs
- corresponding to these are recorded in the FINDIRQ PIC mask variables.
- If a mouse is present and its driver is loaded, determining its IRQ is
- easy: Software interrupt 33h, function 24h returns information about
- the type of mouse and its IRQ assignment. For PS/2 mice, the IRQ is not
- returned, but the IRQ assignment is always IRQ12.
-
- If an IRQ is enabled and has a standard system assignment, FINDIRQ
- can easily display the description for the device. For example, if IRQ6
- is enabled, the utility knows that the device description is ``Floppy.''
- For optional devices, FIND IRQ displays the name of the device as it is
- specified by the device driver (for character devices) or the name of
- the controlling program (in the case of a TSR). In order to do this,
- FINDIRQ must locate these items in memory.
-
- FINDING THE DRIVER OR TSR
-
- The first step in finding a device driver or TSR program is to look
- at the interrupt vector corresponding to the IRQ. For device drivers,
- if stacks have been disabled (that is, if STACKS 0,0 has been entered
- in the CONFIG.SYS file), the vector will provide the address directly.
- Since most systems have stacks enabled (the default is STACKS 9,128 on
- AT-class machines), however, the search must usually continue.
-
- When stacks are enabled, DOS intercepts hardware interrupts, and
- when interrupts occur, DOS sets up a stack from its pool of stacks
- before dispatching them to the original interrupt handler. This ensures
- that stack space will not be exhausted during hardware interrupt
- servicing. Figure 3 (below) shows the techniques used to identify the
- code segment of the DOS STACKS interrupt handlers. Also shown in
- Figure 3 is the way FINDIRQ inspects the code in those handlers as it
- looks for the original interrupt service routine (ISR) address.
-
- For later versions of DOS, FINDIRQ takes advantage of the memory
- control block's subsegment control blocks (these only exist in DOS 4.0
- and later). FINDIRQ uses the undocumented ``list of lists,'' DOS
- function 52h, to establish a pointer to the memory control block (MCB)
- chain. Using the subsegment control blocks within the MCBs, the STACKS
- entry can be located, yielding the segment of the STACKS area. (For more
- information, see the June 12, 1990, Utilities column.)
-
- FINDING THE NAME
-
- Once the ISR address is determined, FINDIRQ searches the DOS device
- driver chain for an entry whose code segment matches that of the
- interrupt handler. Again, the ``list of lists'' DOS function is
- utilized, this time to retrieve the pointer to the DOS driver chain.
- Andrew Schulman's text, Undocumented DOS (Addison Wesley, 1990), contains
- an excellent discussion of the requisite techniques. If a match is found
- in the driver chain and if the driver is a character device driver,
- FINDIRQ copies the name of the device contained in the device driver
- header into its description area. For block devices, which are referenced
- by drive letters instead of device names, ``Block Device'' is used as
- the description. If the ISR address does not belong to a device driver,
- it presumably belongs to a TSR. Thus the next step is to search the MCB
- chain for entries that point to executable code.
-
- The procedures used for searching the driver and MCB chains are
- listed in Figure 4 (below). All programs loaded by DOS begin with a
- program segment prefix (PSP), the information that includes a pointer
- to the program's copy of the environment. The job at hand is to locate
- the PSP for the TSR.
-
- The 16-byte MCB immediately precedes the block of memory it
- describes. Within each MCB is one field that contains the PSP segment
- of the program that owns the memory block and another field that tells
- how large the block is. If the block of memory described by the MCB is
- also the owner, then the block contains a program; it's not an
- environment block or another allocated chunk of memory. If the ISR
- address falls in the block of memory (as defined by its size), then the
- TSR is found. Once the TSR is located, the PSP's pointer to the
- environment is used to retrieve the program name. With DOS 3.0 and
- later, the program name is stored in the last portion of the environment
- block.
-
- One complication that can arise here is that the environment may
- have been freed by the TSR. In such a case, the address space may
- actually contain the environment for another program. To ensure that
- it has the right environment, FIND IRQ compares the owner field of the
- MCB for the environment with the PSP segment. If these are different,
- the environment has been freed. Even in such a case, however, the
- program name can sometimes still be retrieved; DOS versions 4.0 and
- later place the program name in the MCB itself. If all else fails,
- FINDIRQ uses ``Other'' for the description of the program that handles
- the interrupt. IRQ usage that can only be detected with FINDIRQ's TSR
- component will usually list ``Other'' as its description.
-
- TSR APPROACH
-
- When FINDIRQ is invoked with the TSR option, it becomes resident in
- the system and monitors the enabling of IRQs in the 8259 PIC interrupt
- mask registers. The TSR component of FINDIRQ chains into the user timer
- interrupt (INT 1Ch), and the PIC mask registers are read approximately
- once a second. When a new IRQ is enabled, FINDIRQ sets a flag so that
- it can update its .DAT file when it is safe to do so. Interrupt 28h,
- the DOS idle handler, provides the means of detecting the period in which
- it is safe to use DOS functions from within a TSR (see ``The Inner Life
- of a TSR,'' PC Magazine, August 1990). As mentioned earlier, this data
- file is read by FINDIRQ when it is invoked to display IRQ status
- information.
-
- SUMMARY
-
- Adding new devices to your system can be a challenge. The difficulties
- are sufficient to have prompted Microsoft to spearhead development of the
- Plug and Play Industry Standard Architecture Specification which may
- someday make manual configuration obsolete. In fact, IBM's MCA architecture
- already supports ``plug and play,'' though it is not in wide use. But
- until automatic configuration becomes a standard, the next time you need
- to add a peripheral that uses an IRQ, fire up FINDIRQ and make your IRQ
- selection with ease.
- -----------------------------------------------------------------------------
- RICK KNOBLAUGH IS A FREQUENT CONTRIBUTOR TO PC MAGAZINE.
- -----------------------------------------------------------------------------
- QUICK REFERENCE GUIDE
-
- FINDIRQ
-
- Rick Knoblaugh September 28, 1993 (Utilities)
-
-
- Purpose:
-
- Reports which interrupt request lines (IRQs) in a system are
- assigned to specific devices and which are free to use for installing
- a new peripheral device.
-
- Format:
- [LH] FINDIRQ [/t] [/i] [/u] [/d] [/h]
-
- Remarks:
-
- Executed from a DOS prompt and without any of its optional
- parameters, FINDIRQ identifies installed standard (AT) IRQ devices and
- optional character devices by device name. Optional block devices are
- designated by ``Block Device.'' TSR-controlled devices are identified
- by their program names.
-
- The command FINDIRQ will detect devices controlled by TSR programs
- that are loaded in conventional memory. Devices controlled by TSRs
- loaded in high memory require entering the command as LH FINDIRQ.
- Since this latter command form also detects conventionally sited TSRs,
- LH FINDIRQ should be used on systems that use high memory.
-
- Peripherals such as sound boards, whose IRQ numbers are enabled only
- when the devices are active, can be detected only by activating them
- while FINDIRQ is memory-resident. The command FINDIRQ /t installs the
- utility as a TSR; FINDIRQ /u uninstalls it. While memory-resident,
- FINDIRQ records IRQs in the file FINDIRQ.DAT, which is read before
- displaying its on-screen report. Since any configuration changes render
- the previous contents of FINDIRQ.DAT obsolete, the data file can be
- reinitialized by entering FINDIRQ /i.
-
- FINDIRQ verifies its interrupt information before presenting it.
- In some circumstances, however, such as when an IRQ is enabled under
- Windows but no DOS interrupt handler is located, no verification is
- possible, so the interrupt will appear to be free when it is not.
- To check for such a possibility, the verification requirement can be
- turned off with the command FINDIRQ /d.
-
- Finally, a help screen can be displayed by entering FINDIRQ /h.
- A Microsoft MASM assembler (or compatible), LINK, and EXE2BIN are required
- if the program is to be rebuilt.
- ---------------------------------------------------------------------------
- Standard IRQ Assignments
-
- _________________ _________________
- Timer IRQ0 | | | |
- Keyboard IRQ1 | | | |
- IRQ2 | Master | INTR | |
- Serial port2 -IRQ3---| 8259 |-------| CPU |
- Serial port1 | IRQ4 | programmable | | |
- Parallel port 2 | IRQ5 | Interrupt | | |
- Floppy disk controller | IRQ6 | controller | | |
- Parallel | IRQ7 |_______________| |_______________|
- |
- |_________________________________________
- |
- _________________ |
- Real-time clock IRQ8 | | |
- IRQ9 | | |
- IRQ10 | Slave |---------------
- IRQ11 | 8259 |
- PS/2 mouse IRQ12 | programmable |
- Math coprocessor IRQ13 | Interrupt |
- Hard disk controller IRQ14 | controller |
- IRQ15 |_______________|
-
- -----------------------------------------------------------------------------
- Figure 2: Shown here are the master and slave 8259 interrupt controllers
- and the standard IRQ assignments utilized in AT-class platforms.
- -----------------------------------------------------------------------------
- STACKS Routines
-
- ;-------------------------------------------------------------|
- ;get_stacks_seg - Determine the segment where the DOS STACKS |
- ; code resides. This will be used later |
- ; for tracing back through the STACKS |
- ; interrupt handlers to find the original |
- ; ISRs. |
- ; |
- ; Enter: |
- ; ds = local data segment |
- ; atclassf = TRUE if AT class machine |
- ; dos_ver = DOS minor ver/major ver |
- ; |
- ; Exit: |
- ; |
- ; dos_handler_seg = segment for DOS STACKS. |
- ; |
- ; ds preserved. |
- ;-------------------------------------------------------------|
- get_stacks_seg proc near
- push ds
- xor bx, bx
- mov ds, bx ;vectors
- assume ds:nothing
- ;
- ;Use the segment found in the floppy handler as our default guess of
- ;where the STACKS code is.
- ;
- ;
- mov bx, ((pcflop + BEG_INTS) shl 2) ;vector for IRQ6
- mov ax, [bx].d_segment
-
- cmp byte ptr cs:dos_ver, 4 ;DOS 4 or better?
- jb get_stacks800
- ;
- ;If DOS 4 or better, memory control block, subsegment control blocks
- ;can be used to find STACKS.
- ;
- mov ah, DOS_LIST_LISTS
- int 21h
- mov dx, es:[bx - 2] ;segment of first MCB
- mov ds, dx
- mov cx, dx ;save it
- xor bx, bx
- cmp [bx].mcb_sig, 'M' ;valid MCB?
- jne get_stacks800 ;MCBs corrupted
-
- mov di, [bx].mcb_size ;get first size
- inc di ;add para for the MCB
- add dx, di ;after DOS data seg
-
- inc cx ;1st subsegment block
- get_stacks300:
- cmp cx, dx ;at end of info?
- jae get_stacks800 ;if so, search done
- mov ds, cx ;load the segment
- cmp [bx].mcb_sig, 'S' ;STACKS?
- je get_stacks500
- mov cx, [bx].mcb_owner
- add cx, [bx].mcb_size ;advance to next block
- jmp short get_stacks300
-
- get_stacks500:
- mov ax, [bx].mcb_owner
- get_stacks800:
- mov cs:dos_handler_seg, ax ;save it
- get_stacks900:
- pop ds
- assume ds:code
- ret
- get_stacks_seg endp
-
- ;-------------------------------------------------------------|
- ;ck_for_dos - Given a ptr to an interrupt vector, determine if|
- ; the handler is one of those inserted by DOS |
- ; to first check stack before dispatching to |
- ; original ISR. If it is, attempt to get the |
- ; address of the original ISR. |
- ; |
- ; Enter: |
- ; ds = local data segment |
- ; es:bx = ptr to vector |
- ; dos_handler_seg = segment of the DOS handlers |
- ; |
- ; Exit: |
- ; |
- ; Carry set if no DOS handler present or |
- ; can't find original ISR. |
- ; |
- ; else es:bx = ptr to original ISR |
- ; |
- ; All other registers preserved. |
- ;--------------------------------------------------------------|
- ck_for_dos proc near
- push ax
- push cx
- push di
-
- mov ax, dos_handler_seg
- cmp es:[bx].d_segment, ax ;same seg STACKS?
- jne ck_for_900
- les di, es:[bx] ;es:di = &handler
- mov al, es:[di] ;get byte of code
-
-
- ;
- ;Several different flavors of these stack handlers are used in the
- ;various iterations of DOS. Look for the following cases:
- ;
- ;case 1: jmp label
- ; dd &old_isr
- ;
- ; label: call handler ;put offset of &ISR on stack
- ; dw offset var ;and go get it and call it
- ;
- ;
- ;case 2: call handler ;put offset of &ISR on stack
- ; dd &old_isr
- ;
- ;
- ;case 3: jmp label
- ; dd &old_isr
- ;
- ; label: ...
- ;
- ; pushf
- ; cs:
- ; call far [xxxx] ;also this it may not follow the
- ; ;jmp
-
- ;case 4: push ax
- ; ...
- ; ...
- ;
- ; pushf
- ; cs:
- ; call far [xxxx] ;xxxx is the offset of the
- ; ;variable that holds the &ISR
-
- cmp al, OP_JMP ;is it a jmp
- jne ck_for_200
- inc di
- sub ah, ah
- mov al, es:[di] ;get next type of code
- inc di ;past 2nd byte of rel jmp
- add di, ax ;get to location of jmp
-
- mov al, es:[di] ;get byte of code there
- ck_for_200:
- cmp al, OP_CALL ;is it a call
- jne ck_for_300
- mov di, es:[di + 3] ;offset to dd that holds &ISR
- les bx, es:[di] ;&ISR
- jmp short ck_for_999 ;exit with carry clear
-
- ck_for_300:
- mov cx, BYTES_TO_SEARCH
- ck_for_400:
- mov al, OP_PUSHF
- repne scasb ;pushf instruction?
- jcxz ck_for_900
- mov al, OP_CS ;CS override?
- scasb
- jnz ck_for_400
- mov ax, OP_CALL_MEM16
- scasw ;call?
- jnz ck_for_400
- mov di, es:[di] ;offset of var that holds &ISR
- les bx, es:[di] ;get &ISR
-
- ck_for_800:
- jmp short ck_for_999 ;exit with carry clear
- ck_for_900:
- stc
- ck_for_999:
- pop di
- pop cx
- pop ax
- ret
- ck_for_dos endp
-
- -----------------------------------------------------------------------
- Figure 3: These routines identify the segment where the DOS STACKS
- interrupt handlers reside and retrieve the original interrupt service
- routine address.
- -------------------------------------------------------------------------
- Search Procedures
-
- ;-------------------------------------------------------------|
- ;find_drivers - For all IRQs that are active, look to see if |
- ; we have a description for the device. If we |
- ; don't, the device using this IRQ must be |
- ; something we don't know about, such as a |
- ; sound board, SCSI adapter, etc. In this case,|
- ; go get the driver name or program name and |
- ; put it in the description for the IRQ. |
- ; |
- ; In the event that a driver or TSR (with |
- ; PSP) is not found, assign "Other" for the |
- ; device description. |
- ; |
- ; |
- ; Enter: |
- ; ds=local data segment |
- ; atclassf = TRUE if AT class machine |
- ; |
- ; pic_mask = PIC mask values. |
- ; |
- ; device_desc = offset to array of description |
- ; offsets. |
- ; |
- ; Exit: |
- ; |
- ; ds, bp preserved, es trashed. |
- ;--------------------------------------------------------------|
- find_drivers proc near
- push bp
- mov ah, DOS_LIST_LISTS
- int 21h ;get es:bx ptr to lists
-
- cmp dos_ver, 0003h ;DOS 3.0?
- jne find_drv_050
- lea bx, es:[bx].nul_dev_head30 ;ptr to NUL device
- jmp short find_Drv_080
- find_drv_050:
- lea bx, es:[bx].nul_dev_head ;ptr to NUL device
- find_drv_080:
- mov ax, es
- mov drv_ptr.d_segment, ax ;save ptr to start
- mov drv_ptr.d_offset, bx ;of driver chain
-
- xor al, al ;IRQ counter
- mov bp, pic_mask
- mov cx, 16 ;16 IRQs on AT
- cmp atclassf, TRUE ;AT machine?
- je find_drv_100
- shr cx, 1 ;only 8 IRQs on PC
- find_drv_100:
- shr bp, 1 ;check IRQ
- jc find_drv_600 ;skip if not active
- find_drv_110:
- call get_desc_entry ;description for IRQ
- xor bx, bx
- cmp [di], bx ;is there one?
- je find_drv_125
- ;
- ;If there is already a description for the device, don't need to look
- ;for driver. However, there is one exception. If we are on an AT,
- ;we always assign an initial description of "cascade" to IRQ2. If
- ;that is the only description we have (e.g. we haven't got a mouse on
- ;IRQ2, etc.), go ahead and look for a driver using IRQ2.
- ;
-
- cmp atclassf, TRUE ;AT machine?
- jne find_drv_600 ;if not, no cascade
- cmp al, 2 ;doing IRQ2?
- jne find_drv_600 ;if not, no test
- cmp [di + 2], bx ;check 2nd desc (bx=0)
- jne find_drv_600
- add di, 2 ;next desc entry
-
- find_drv_125:
- mov es, bx ;point to vector
-
- mov bl, al ;irq number
- cmp al, 8
- jb find_drv_150
- add bl, (BEG_SLAVE_INTS - 8)
- jmp short find_drv_175
-
- find_drv_150:
- add bl, BEG_INTS
- find_drv_175:
- shl bx, 1
- shl bx, 1 ;offset into vectors
- ;See if pointing to DOS stack handlers. If so, carry is not set and
- ;es:bx points to address of original ISR.
- ;
- call ck_for_dos
- jnc find_drv_200 ;es:bx point to ISR
-
- les bx, es:[bx] ;point to ISR
-
- find_drv_200:
- call load_drv_desc
- find_drv_600:
- inc al ;advance IRQ counter
- loop find_drv_100
- find_drv_900:
- pop bp
- ret
- find_drivers endp
-
-
-
-
- ;-------------------------------------------------------------|
- ;load_drv_desc - Retrieve and load driver description. |
- ; |
- ; Enter: |
- ; ds=local data segment |
- ; di=offset of entry for description |
- ; es:bx=ptr to ISR for which description is |
- ; needed. |
- ; device_desc = offset to array of description |
- ; offsets. |
- ; drv_desc_ptr = offset of next work description area. |
- ; |
- ; Exit: |
- ; [di]=offset of description. |
- ; drv_desc_ptr advanced to next work description area.|
- ; |
- ; all registers saved. |
- ;--------------------------------------------------------------|
- load_drv_desc proc near
- push ax ;save picmask/IRQ counter
- push cx ;save loop count
- push di ;save offset of desc entry
-
- push bx ;save offset
- mov dx, es ;address in dx:bx
- call is_it_driver ;see if driver or TSR
- pop dx ;get back offset (bx)
- jnc load_drv_300 ;jmp if not a driver
- mov dx, offset block_desc ;"Block Device"
- cmp al, 2 ;IRQ2? if so, may have
- jne load_drv_290 ;"Cascade" if AT - use
- mov dx, offset block_abbrv ;abbrev desc to fit
-
- load_drv_290:
- test es:[bx].dev_attrib, 8000h ;char driver?
- jz load_drv_550 ;if not, use "Block Device"
- call mov_char_name ;if so, move char device name
- jmp short load_drv_450
- load_drv_300:
- ;
- ;Wasn't a driver. Must be a TSR. Using the pointer to environment
- ;from the TSR's PSP, find the name of executable.
- ;
- ;
- mov bx, dx ;offset of ISR
- call determine_psp ;return nc if PSP found
- ;
- ;If a PSP is found, carry will NOT be set. Also, if PSP is found, and
- ;ax is nonzero, ax holds the segment of the environment. If ax is
- ;zero then the environment was freed. If such cases, es:bx will be
- ;returned as a pointer to the filename description in the MCB
- ; (if DOS is 4.x or better - otherwise bx=0)
- ;
- jnc load_drv_350
- load_drv_330:
- mov dx, offset other_desc ;can't get filename
- jmp short load_drv_550 ;so, go assign "Other"
- load_drv_350:
- or ax, ax ;environment found?
- jnz load_drv_370 ;if so, get filename
- or bx, bx ;name in MCB?
- jz load_drv_330 ;if not, print "Other"
- jmp short load_drv_400 ;go get name
- load_drv_370:
- mov es, ax
- call retrieve_path ;get ptr to filename
- jc load_drv_330 ;if data not right
- load_drv_400:
- mov di, drv_desc_ptr
- mov dx, di ;save desc offset
- call mov_file_name
- load_drv_450:
- mov al, STR_TERM
- stosb ;terminate it
- add drv_desc_ptr, size drv_descrip
- load_drv_550:
- pop di
- pop cx
- pop ax
- mov [di], dx ;store offset of name
- ret
- load_drv_desc endp
-
-
-
- ;-------------------------------------------------------------|
- ;determine_psp - An ISR was found and it is not part of a |
- ; device driver. Search the MCB chain for |
- ; PSP associated with code that would contain |
- ; the ISR. If found, check the environment |
- ; entry for the PSP. If environment has not |
- ; been freed, return ax=environment segment. If|
- ; not found and DOS is 4.x or better, return |
- ; es:bx as ptr to filename in MCB. |
- ; |
- ; |
- ; Enter: |
- ; es:bx = ptr to ISR |
- ; |
- ; Exit: |
- ; cy set if PSP NOT found else nc |
- ; also if found ax=environment seg (zero |
- ; if it was freed) |
- ; |
- ; if found and ax=0, es:bx=ptr |
- ; to filename in MCB |
- ; (zero if < DOS 4) |
- ; |
- ; ds preserved. |
- ;-------------------------------------------------------------|
- determine_psp proc near
- push ds
- mov dx, es ;segment of ISR
- mov cl, 4
- shr bx, cl ;convert to paragraphs
- add dx, bx ;para location of code
-
- mov ah, DOS_LIST_LISTS
- int 21h
- mov di, es:[bx - 2] ;segment of first MCB
- mov es, di
- xor bx, bx ;offset zero in MCB
- mov si, es ;save MCB segment
- determine_p200:
- inc si ;ready for next one
-
- cmp es:[bx].mcb_sig, 'Z' ;at end of chain?
- je determine_p900 ;if so, not found
- cmp es:[bx].mcb_sig, 'M' ;valid entry?
- jne determine_p900 ;if not, MCBs wrong
-
- determine_p300:
- mov cx, es:[bx].mcb_owner ;get MCB owner seg
- mov di, cx ;save it
- mov ax, es:[bx].mcb_size ;and its size
- cmp cx, si ;is this a PSP?
- jne determine_p700 ;if not, go next PSP
-
- cmp dx, cx ;compare segment
- jb determine_p700 ;beneath the segment
- add cx, ax ;get end of the area
- cmp dx, cx
- ja determine_p700 ;above the segment
-
- assume ds:nothing
- mov ds, di ;ds=seg of owner
- mov ax, [bx].psp_environ_seg
-
- or ax, ax ;freed environment?
- jz determine_p400 ;if so, try plan b
-
- dec ax ;1 paragraph back
- mov ds, ax ;is seg of MCB for it
- inc ax ;back to "environment"
- cmp [bx].mcb_owner, di ;belongs to PSP?
- je determine_p999 ;yes, exit nc, ax=seg
-
- determine_p400:
- xor ax, ax ;indicate none
- cmp byte ptr cs:dos_ver, 4 ;DOS 4 or better?
- ;
- ;if yes, we can return filename
- ;if not, bx=0 indicating must print "Other"
- ;
- cmc ;carry clear if < DOS 4
- jnb determine_p999 ;nc and bx=0 if < DOS 4
-
- determine_p500:
- clc
- lea bx, es:[bx].mcb_fname
- jmp short determine_p999 ;nc, es:bx = &filename
-
- determine_p700:
- add si, ax ;get to next MCB
- mov es, si
- jmp short determine_p200
-
- determine_p900:
- stc
- determine_p999:
- assume ds:code
- pop ds
- ret
- determine_psp endp
- ---------------------------------------------------------------------------
- Figure 4: The procedures listed above are used to search the driver and
- MCB chains.
- ---------------------------------------------------------------------------