; ; File: ; io.asm ; Description: ; DOS-C I/O Subsystem ; ; Copyright (c) 1998 ; Pasquale J. Villani ; All Rights Reserved ; ; This file is part of DOS-C. ; ; DOS-C is free software; you can redistribute it and/or ; modify it under the terms of the GNU General Public License ; as published by the Free Software Foundation; either version ; 2, or (at your option) any later version. ; ; DOS-C is distributed in the hope that it will be useful, but ; WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ; the GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public ; License along with DOS-C; see the file COPYING. If not, ; write to the Free Software Foundation, 675 Mass Ave, ; Cambridge, MA 02139, USA. ; ; $Header$ ; %include "segs.inc" %include "stacks.inc" extern ConTable extern LptTable extern ComTable extern uPrtNo extern CommonNdRdExit ;!! extern _NumFloppies extern blk_stk_top extern clk_stk_top extern _reloc_call_blk_driver extern _reloc_call_clk_driver extern _TEXT_DGROUP ;--------------------------------------------------- ; ; Device entry points ; ; This really should be a struct and go into a request.inc file ; cmdlen equ 0 ; Length of this command unit equ 1 ; Subunit Specified cmd equ 2 ; Command Code status equ 3 ; Status media equ 13 ; Media Descriptor trans equ 14 ; Transfer Address count equ 18 ; Count of blocks or characters start equ 20 ; First block to transfer vid equ 22 ; Volume id pointer huge equ 26 ; First block (32-bit) to transfer ; ; The following is the "array" of device driver headers for the internal ; devices. There is one header per device including special aux: and prn: ; pseudo devices. These psuedo devices are necessary for printer ; redirection, i.e., serial or parallel ports, and com port aux selection. ; ; The devices are linked into each other and terminate with a -1 next ; pointer. This saves some time on boot up and also allows us to throw all ; device initialization into a single io_init function that may be placed ; into a discardable code segmemnt. ; segment _IO_FIXED_DATA ; ; The "CON" device ; ; This device is the standard console device used by ; DOS-C and kernel ; global _con_dev _con_dev equ $ dw _prn_dev,LGROUP dw 8013h ; con device (stdin & stdout) dw GenStrategy dw ConIntr db 'CON ' ; ; Generic prn device that can be redirected via mode ; global _prn_dev _prn_dev dw _aux_dev,LGROUP dw 0A040h dw GenStrategy dw PrnIntr db 'PRN ' ; ; Generic aux device that can be redirected via mode ; global _aux_dev _aux_dev dw _Lpt1Dev,LGROUP dw 8000h dw GenStrategy dw AuxIntr db 'AUX ' ; ; Printer device drivers ; _Lpt1Dev dw _Lpt2Dev,LGROUP dw 0A040h dw GenStrategy dw Lpt1Intr db 'LPT1 ' _Lpt2Dev dw _Lpt3Dev,LGROUP dw 0A040h dw GenStrategy dw Lpt2Intr db 'LPT2 ' _Lpt3Dev dw _Com1Dev,LGROUP dw 0A040h dw GenStrategy dw Lpt3Intr db 'LPT3 ' ; ; Com device drivers ; _Com1Dev dw _Com2Dev,LGROUP dw 8000h dw GenStrategy dw AuxIntr db 'COM1 ' _Com2Dev dw _Com3Dev,LGROUP dw 8000h dw GenStrategy dw Com2Intr db 'COM2 ' _Com3Dev dw _Com4Dev,LGROUP dw 8000h dw GenStrategy dw Com3Intr db 'COM3 ' _Com4Dev dw _clk_dev,LGROUP dw 8000h dw GenStrategy dw Com4Intr db 'COM4 ' ; ; Header for clock device ; global _clk_dev _clk_dev equ $ dw _blk_dev,LGROUP dw 8008h ; clock device dw GenStrategy dw clk_entry db 'CLOCK$ ' ; ; Header for device ; global _blk_dev _blk_dev equ $ dd -1 dw 08c2h ; block device with ioctl dw GenStrategy dw blk_entry db 4 db 0,0,0,0,0,0,0 ; ; Temporary table until next release ; segment _IO_FIXED_DATA DiskTable db 0 ; ; Local storage ; %if 0 segment _BSS blk_dos_stk resw 1 blk_dos_seg resw 1 clk_dos_stk resw 1 clk_dos_seg resw 1 %endif segment _IO_TEXT global _ReqPktPtr _ReqPktPtr dd 0 uUnitNumber dw 0 ; ; Name: ; GenStrategy ; ; Function: ; Store the pointer to the request packet passed in es:bx ; ; Description: ; Generic strategy routine. Unlike the original multitasking versions, ; this version assumes that no more thank one device driver is active ; at any time. The request is stored into memory in the one and only ; location available for that purpose. ; global GenStrategy GenStrategy: mov word [cs:_ReqPktPtr],bx mov word [cs:_ReqPktPtr+2],es retf ; ; Name: ; XXXXIntr ; ; Function: ; Individual Interrupt routines for each device driver ; ; Description: ; This is actually a single routine with entry points for each device. ; The name used for the entry point is the device name with Intr ; appended to it. ; ; Funtionally, each device driver has an entry and an associated ; table. The table is a structure that consists of a control byte ; followed by an array of pointers to C functions or assembly ; subroutines that implement the individual device driver functions. ; This allows the usage of common error dummy filler code to be used. ; It also allows standardization of the calling procedure for these ; internal device driver functions. ; ; Assembler call/return convention: ; Each driver function is entered by a jump into the function and ; exits by a jump to the appropriate success or error exit routine. ; This speeds up the call and return and helps to minimize the stack ; useage. The contents of the request packet are passed to each ; routine in registers as follows: ; ; Register Function Description ; -------- -------- ----------- ; al unit Subunit Specified ; ah media Media Descriptor ; cx count Count of blocks or characters ; dx start First block to transfer ; es:di trans Transfer Address ; ds:bx reqptr Request pointer ; cs kernel code segment ; ds kernel data segment ; ; The exit routines generally set the status based on the individual ; routine. For example, _IOSuccess will clear the count where ; _IOErrCnt will subtract the remaining amount in cx from the original ; count. See each utility routine for expectations. ; ; C call/return convention: ; The C calling convention simply sets up the C stack and passes the ; request packet pointer as a far pointer to the function. Although ; the utility routine names are such that they are accesible from the ; C name space, they are cannot used. Instead, the common interrupt ; code expects a return status to set in the request packet. It is up ; to the device driver function to set the appropriate fields such as ; count when an error occurs. ; ; How to differntiate between the two calling conventions: ; This code is entirely table driven. The table is a structure that ; is generally in the _IO_FIXED_DATA segment. It consists of a flag ; byte followed by short pointers to the driver functions. Selecting ; a driver type is accomplished by setting the type bit in the flag ; (see below). ; ; 7 6 5 4 3 2 1 0 ; +---+---+---+---+---+---+---+---+ ; | | | | | | | | | ; +---+---+---+---+---+---+---+---+ ; | | | |--- Number of table entries ; | | +-------------------+ ; | | |----------------------- Reserved ; | +-------+ ; +--------------------------------- type bit (1 == C / 0 == asm) ; ConIntr: push si mov si,ConTable jmp short CharIntrEntry PrnIntr: push si push ax xor ax,ax jmp short LptCmnIntr Lpt1Intr: push si push ax xor al,al mov ah,1 jmp short LptCmnIntr Lpt2Intr: push si push ax mov al,1 mov ah,2 jmp short LptCmnIntr Lpt3Intr: push si push ax mov al,2 mov ah,3 LptCmnIntr: mov si,LptTable mov [cs:uPrtNo],ah jmp short DiskIntrEntry AuxIntr: push si push ax xor al,al jmp short ComCmnIntr Com2Intr: push si push ax mov al,1 jmp short ComCmnIntr Com3Intr: push si push ax mov al,2 jmp short ComCmnIntr Com4Intr: push si push ax mov al,3 jmp short ComCmnIntr ComCmnIntr: mov si,ComTable jmp short DiskIntrEntry DskIntr: push si mov si,DiskTable CharIntrEntry: push ax DiskIntrEntry: push cx push dx push di push bp push ds push es push bx mov byte [cs:uUnitNumber],al lds bx,[cs:_ReqPktPtr] test byte [cs:si],80h je AsmType mov al,[bx+cmd] cmp al,[cs:si] ja _IOCommandError cbw shl ax,1 add si,ax xchg di,ax push ds push bx mov bp,sp mov ds,[cs:_TEXT_DGROUP] cld call word [cs:si+1] pop cx pop cx jmp short StoreStatus AsmType: mov al,[bx+unit] mov ah,[bx+media] mov cx,[bx+count] mov dx,[bx+start] xchg di,ax mov al,[bx+cmd] cmp al,[cs:si] ja _IOCommandError cbw shl ax,1 add si,ax xchg di,ax les di,[bx+trans] mov ds,[cs:_TEXT_DGROUP] cld jmp word [cs:si+1] ; ; Name: ; _IOXXXXXXX ; ; Function: ; Exit routines for internal device drivers. ; ; Description: ; These routines are the exit for internal device drivers. _IOSuccess ; is for read/write functions and correctly returns for a successful ; read/write operation by setting the remainng count to zero. _IOExit ; simply sets success bit and returns. _IODone returns complete and ; busy status. _IOCommandError returns and error status for invalid ; commands. _IOErrCnt corrects the remaining bytes for errors that ; occurred during partial read/write operation. _IOErrorExit is a ; generic error exit that sets done and error. ; global _IOSuccess _IOSuccess: lds bx,[cs:_ReqPktPtr] xor ax,ax mov [bx+count],ax global _IOExit _IOExit: mov ah,1 StoreStatus: lds bx,[cs:_ReqPktPtr] mov [bx+status],ax pop bx pop es pop ds pop bp pop di pop dx pop cx pop ax pop si retf global _IODone _IODone: mov ah,3 jmp short StoreStatus global _IOCommandError _IOCommandError: mov al,3 global _IOErrCnt _IOErrCnt: lds bx,[cs:_ReqPktPtr] sub [bx+count],cx global _IOErrorExit _IOErrorExit: mov ah,81h jmp short StoreStatus ; ; Name: ; GetUnitNum ; ; Function: ; Return the internally set unit number. ; ; Description: ; Simply return the contents of uUnitNumber. This version relies on ; no segment registers and makes a safe call regardless of driver ; state. ; global GetUnitNum GetUnitNum: mov dx,[cs:uUnitNumber] ret ; ; These are still old style DOS-C drivers. I'll replace ; them in the next release ; ; ; block device interrupt ; ; NOTE: This code is not standard device driver handlers ; It is written for sperate code and data space. ; blk_driver_params: dw blk_stk_top dw _reloc_call_blk_driver dw DGROUP clk_driver_params: dw clk_stk_top dw _reloc_call_clk_driver dw DGROUP ; clock device interrupt clk_entry: pushf push bx mov bx, clk_driver_params jmp short clk_and_blk_common ; block device interrupt blk_entry: pushf push bx mov bx, blk_driver_params clk_and_blk_common: push ax push cx push dx ; small model mov ax,sp ; use internal stack mov dx,ss pushf ; put flags in cx pop cx cli ; no interrupts mov ss,[cs:_TEXT_DGROUP] mov sp,[cs:bx] push cx popf ; restore interrupt flag push ax ; save old SS/SP push dx ; push these registers on push ds ; BLK_STACK push bp ; to save stack space push si push di push es Protect386Registers mov ds,[cs:_TEXT_DGROUP] ; push word [cs:_ReqPktPtr+2] push word [cs:_ReqPktPtr] call far [cs:bx+2] pop cx pop cx les bx,[cs:_ReqPktPtr] ; now return completion code mov word [es:bx+status],ax ; mark operation complete Restore386Registers pop es pop di pop si pop bp pop ds pop dx ; get back old SS/SP pop ax cli ; no interrupts mov ss,dx ; use dos stack mov sp,ax pop dx pop cx pop ax pop bx popf retf