home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
High Voltage Shareware
/
high1.zip
/
high1
/
DIR3
/
FINDIRQ.ZIP
/
FINDIRQ.DOC
< prev
Wrap
Text File
|
1993-09-18
|
43KB
|
868 lines
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.
---------------------------------------------------------------------------