CDEVIO.A86
资源名称:drdossrc.zip [点击查看]
上传用户:xiaogehua
上传日期:2007-01-08
资源大小:1183k
文件大小:16k
源码类别:
操作系统开发
开发平台:
Asm
- title 'F_DOS Character device I/O'
- ; File : $CDEVIO.A86$
- ;
- ; Description :
- ;
- ; Original Author : DIGITAL RESEARCH
- ;
- ; Last Edited By : $CALDERA$
- ;
- ;-----------------------------------------------------------------------;
- ; Copyright Work of Caldera, Inc. All Rights Reserved.
- ;
- ; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
- ; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
- ; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
- ; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
- ; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
- ; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
- ; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
- ; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
- ; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
- ; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
- ; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
- ; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
- ; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
- ; CIVIL LIABILITY.
- ;-----------------------------------------------------------------------;
- ;
- ; *** Current Edit History ***
- ; *** End of Current Edit History ***
- ; $Log: $
- ; CDEVIO.A86 1.18 94/12/21 11:16:29
- ; Changed dev_dup to refuse from duplicating remote devices rather
- ; than refuse from duplicating FCBs
- ; Made open_dev return IFN rather than XFN for FCB opens
- ; Made open_dev put the current time/date into DHNDL_TIME/DHNDL_DATE
- ; CDEVIO.A86 1.16 94/10/07 09:00:18
- ; Added patch 004 as source fix. Changed request header length for character
- ; device to 16h. Used RH4_CDEV_LEN instead of RH4_LEN.
- ; CDEVIO.A86 1.15 93/12/10 00:09:17
- ; Move non-inherited bit to correct place in file handle
- ; CDEVIO.A86 1.14 93/11/26 16:17:14
- ; Update char_error so ES:SI -> device driver header itself;
- ; ENDLOG
- eject ! include i:psp.def
- eject ! include i:modfunc.def
- eject ! include i:fdos.equ
- eject ! include i:mserror.equ
- eject ! include i:doshndl.def
- eject ! include i:driver.equ
- eject ! include rh.equ
- BDOS_DATA dseg
- extrn fdos_buf:byte ; caveat: in PCMODE data segment
- extrn fdos_pb:word
- extrn fdos_ret:word
- ;
- ; Critical Error responses from the default INT 24 handler and
- ; the DO_INT24 routine.
- ;
- ERR_IGNORE equ 0 ; Ignore Error
- ERR_RETRY equ 1 ; Retry the Operation
- ERR_ABORT equ 2 ; Terminate the Process
- ERR_FAIL equ 3 ; Fail Function
- BDOS_CODE cseg
- public open_dev
- public close_dev
- public dup_dev
- public read_dev
- public write_dev
- public first_dev
- public ioc6_dev
- public ioc7_dev
- extrn cooked_write:near ; write to cooked console
- extrn read_line:near ; read edited line
- extrn break_check:near ; look for CTRL C
- extrn char_error:near ; generate Int 24
- extrn current_dsk2al:near ; get default drive in AL
- extrn device_driver:near
- extrn alloc_dhndl:near ; find free DHNDL_ structure
- extrn alloc_xfn:near
- extrn les_di_dmaptr:near
- extrn release_handle:near
- extrn get_xftptr:near
- extrn timestamp_dhndl:near
- ; Character device functions
- ; ==========================
- open_dev:
- ;--------
- ; Entry: ES:BX -> character device header
- ; Note: We own the MXdisk here, fdos_pb -> parameter data
- push es ! push bx ; save device driver address
- call alloc_xfn ; DI = XFN
- push di ; save XFN
- call alloc_dhndl ; ES:BX -> DHNDL, AX = IFN
- pop dx ; DX = XFN
- xchg ax,si ; SI = IFN
- xor ax,ax
- lea di,DHNDL_DATRB[bx] ; point at start of area to fill
- mov cx,DHNDL_UID-DHNDL_DATRB
- rep stosb
- mov es:DHNDL_SHARE[bx],ax ; also zap share word
- pop es:DHNDL_DEVOFF[bx]
- pop es:DHNDL_DEVSEG[bx] ; save device driver address
- push si ! push dx ; save IFN/XFN
- mov es:DHNDL_COUNT[bx],1
- push ds
- mov ax,fdos_pb+6 ; AX = open mode
- mov cx,DHAT_DEV+DHAT_CLEAN+DHAT_TIMEOK
- lds si,es:DHNDL_DEVPTR[bx] ; DS:SI -> device driver
- or cl,ds:byte ptr DH_ATTRIB[si]
- ; get attrib from device driver
- test al,DHM_LOCAL ; is it private ?
- jz open_dev10
- and al,not DHM_LOCAL ; clear inherit bit
- or ch,DHAT_LOCAL/256 ; rememmber it's local
- open_dev10:
- mov es:DHNDL_MODE[bx],ax
- mov es:DHNDL_WATTR[bx],cx
- lea si,DH_NAME[si] ; copy the device name
- lea di,DHNDL_NAME[bx] ; from the device header
- mov cx,8/WORD
- rep movsw
- mov al,' '
- mov cl,3 ; space the file extension
- rep stosb
- pop ds
- pop dx ! pop ax ; AX = IFN, DX = XFN
- push es
- call get_xftptr ; ES:DI -> PSP_XFTPTR for current_psp
- jc open_dev20 ; no PSP, skip updating XFN
- add di,dx ; ES:DI -> entry in PSP
- stosb ; update entry in PSP
- xchg ax,dx
- open_dev20:
- pop es
- mov fdos_ret,ax ; save XFN (IFN for FCB open) to return
- call timestamp_dhndl
- or es:DHNDL_ATTR[bx],DHAT_READY
- ; jmp open_dup_dev
- open_dup_dev:
- ;------------
- ; On Entry:
- ; ES:BX = DHNDL_
- ; On Exit:
- ; None
- ;
- mov al,CMD_DEVICE_OPEN
- ; jmp open_close_dev ; call device open routine
- open_close_dev:
- ;--------------
- ; entry: ES:BX = DHNDL_
- ; AL = cmd_type (CMD_DEVICE_OPEN/CMD_DEVICE_CLOSE)
- ;
- push ds ! push es
- push bx ! push si
- lds si,es:DHNDL_DEVPTR[bx] ; DS:SI -> device driver
- test ds:DH_ATTRIB[si],DA_REMOVE
- jz ocdev1 ; does the device support OPEN/CLOSE/RM
- sub sp,RH13_LEN-2*word ; make space on stack for RH_
- push ax ; RH_CMD = AL
- mov ax,RH13_LEN
- push ax ; RH_LEN = RH13_LEN
- push ss ! pop es
- mov bx,sp ; ES:BX -> RH_
- call device_driver ; call the device driver
- add sp,RH13_LEN ; recover stack space
- ocdev1:
- pop si ! pop bx
- pop es ! pop ds
- ret
- dup_dev:
- ;-------
- ; On Entry:
- ; ES:BX -> DHNDL_
- ; On Exit:
- ; None
- ; AX trashed
- ;
- mov ax,es:DHNDL_WATTR[bx]
- test al,DHAT_DEV
- jz dup_dev10 ; skip if disk file
- test ax,DHAT_REMOTE ; or remote
- jz open_dup_dev
- dup_dev10:
- ret
- close_dev: ; close character device handle
- ;---------
- ; entry: FDOS_PB+2 = user file handle
- ; ES:BX = file handle
- ; NOTE: This is called with the MXdisk owned
- mov al,CMD_DEVICE_CLOSE
- call open_close_dev ; call device close routine
- call release_handle ; release the XFN
- dec es:DHNDL_COUNT[bx] ; one less XFN refers to this IFN
- ret
- write_dev: ; write to character device handle
- ;---------
- ; entry: ES:BX -> DHNDL_ structure
- ;
- mov cl,CMD_OUTPUT ; OUTPUT driver function
- or es:DHNDL_ATTR[bx],DHAT_READY
- mov al,es:DHNDL_ATTR[bx] ; get file info
- and al,DHAT_BIN+DHAT_NUL+DHAT_CIN+DHAT_COT
- cmp al,DHAT_CIN+DHAT_COT ; is it cooked console?
- jne inst_io ; no, device driver i/o
- mov si,2[bp] ; SI -> parameter block
- mov cx,ds:8[si] ; CX = string length
- jcxz write_dev20 ; exit if nothing to write
- les di,ds:4[si] ; ES:DI -> string to print
- mov al,'Z'-40h ; we have to stop at ^Z
- repne scasb ; scan for ^Z character
- jne write_dev10 ; skip if ^Z not found
- inc cx ; include ^Z in count of chars to skip
- sub ds:8[si],cx ; subtract from total count
- write_dev10:
- mov bx,ds:2[si] ; BX = handle number
- mov cx,ds:8[si] ; CX = string length
- mov si,ds:4[si] ; ES:SI -> string to print
- call cooked_write ; write w/ tab expansion & ^C checking
- write_dev20:
- sub bx,bx ; no errors
- ret ; return the result
- read_dev: ; read to character device handle
- ;--------
- ; entry: ES:BX -> DHNDL_ structure
- mov al,es:DHNDL_ATTR[bx] ; get the file info
- mov ah,al ; save ioctl info
- and al,DHAT_BIN+DHAT_CIN+DHAT_COT
- cmp al,DHAT_CIN+DHAT_COT ; is it cooked console?
- jne rddev1 ; skip if binary or not console
- jmp read_con ; read from console handle
- ; return the result
- rddev1:
- test ah,DHAT_READY ; previous EOF ?
- jnz rddev2 ; yes we return now
- mov di,2[bp] ; DI -> parameter block
- mov ds:word ptr 8[di],0 ; zero bytes xfered
- ret
- rddev2:
- mov cl,CMD_INPUT
- inst_io:
- ; ES:BX = DHNDL_, CL = command
- sub sp,RH4_CDEV_LEN ; make RH_ on stack
- mov di,bx ; save address DHNDL_ in DI
- mov bx,sp ; SS:BX -> request header
- mov ds:RH_CMD[bx],cl
- mov ds:RH_LEN[bx],RH4_CDEV_LEN
- mov ds:RH_STATUS[bx],0 ; status OK in case of zero chars
- mov si,2[bp] ; DS:SI -> parameter block
- lea si,4[si] ; point at buffer offset
- lodsw ; get buffer offset
- ; Normalising the address has been unnecessary so far
- ; push ax
- ; and ax,15 ; normalise the address
- ; pop cx
- ; shr cx,1 ! shr cx,1
- ; shr cx,1 ! shr cx,1
- mov ds:RH4_BUFOFF[bx],ax ; set buffer offset in request header
- lodsw ; get buffer segment
- ; add ax,cx ; add in normalised offset/16
- mov ds:RH4_BUFSEG[bx],ax ; get buffer segment in request header
- lodsw ; get byte count
- xchg ax,cx ; byte count in CX
- ; Parameter block created on stack at SS:BX and initialised for xfer
- ; ES:DI -> DHNDL_, CX = total number of bytes to xfer
- inst_io20:
- mov ds:RH4_COUNT[bx],cx ; try and do this many
- test es:DHNDL_ATTR[di],DHAT_BIN+DHAT_NUL
- ; are we in binary mode ?
- jcxz inst_io30 ; return on zero length xfer
- jnz inst_io25 ; binary, skip calling PCMODE
- mov ds:RH4_COUNT[bx],1 ; do one char at a time
- call break_check ; call the break check routine
- cmp ds:RH_CMD[bx],CMD_OUTPUT ; which way are we going
- jne inst_io25
- call inst_io_getchar ; AL = 1st char in the buffer
- cmp al,1Ah ; EOF - don't send it or anything after
- je inst_io30 ; and exit without xfering any
- inst_io25:
- push ds ! push es ! push di ! push cx
- lds si,es:DHNDL_DEVPTR[di] ; DS:SI -> device driver
- push ss ! pop es ; ES:BX -> RH_
- call device_driver ; execute the command
- pop cx ! pop di ! pop es ! pop ds
- jns inst_io_continue ; if no errors carry on
- push es
- les si,es:DHNDL_DEVPTR[di] ; ES:SI -> device driver
- call char_error ; this will handle the Int 24
- pop es
- cmp al,ERR_RETRY ; what should we do ?
- je inst_io20 ; retry the operation
- ja inst_io30 ; fail - return error
- mov ds:RH_STATUS[bx],RHS_DONE
- jmps inst_io_ignore ; ignore - fiddle status and
- inst_io_continue: ; say we did it all
- mov dx,ds:RH4_COUNT[bx] ; how many did we xfer ?
- test dx,dx ; if we haven't done any
- jz inst_io30 ; we are stuck so exit now
- inst_io_ignore:
- call inst_io_getchar ; AL = 1st char in the buffer
- add ds:RH4_BUFOFF[bx],dx ; it may not enough so adjust offset
- sub cx,dx ; and number still to do
- cmp ds:RH_CMD[bx],CMD_INPUT ; which way are we going - if input
- jne inst_io20 ; we need to check for CR/EOF
- test es:DHNDL_ATTR[di],DHAT_BIN+DHAT_NUL
- jnz inst_io30 ; if BIN then exit now
- cmp al,13 ; is it a CR character ?
- je inst_io30 ; yes, we stop now
- cmp al,1Ah ; is it the EOF character ?
- jne inst_io20 ; yes, we aren't ready
- and es:DHNDL_ATTR[di],not DHAT_READY
- inst_io30:
- mov di,2[bp] ; DI -> parameter block
- sub ds:8[di],cx ; subtract # not xfered from byte count
- mov ax,ds:RH_STATUS[bx] ; get result for later
- sub bx,bx ; assume no errors
- test ax,ax ; test error bit (8000h)
- jns rddev_no_err ; skip if ERROR set
- mov bl,al ; AL is error code
- neg bx ; make it negative code
- add bx,ED_PROTECT ; normalize for extended errors
- rddev_no_err:
- add sp,RH4_CDEV_LEN ; free up RH_ on stack
- ret ; return BX
- inst_io_getchar:
- push ds
- lds si,ds:RH4_BUFFER[bx] ; point to the users buffer
- lodsb ; get 1st char in the buffer
- pop ds
- ret
- read_con: ; handle read from cooked console
- ;--------
- ; entry: AH = DHNDL_ATTR
- ; ES:BX -> DHNDL_
- ; 2[BP] -> F_DOS parameter block
- ; exit: BX = return value
- xor cx,cx ; assume we've already had EOF
- test ah,DHAT_READY ; now see if we have
- jnz con_dev_not_eof
- jmp con_dev_exit ; yes, just return zero chars read
- con_dev_not_eof:
- push es
- push bx ; save DHNDL_
- con_dev_loop:
- mov bx,word ptr fdos_buf ; get # of bytes already used
- xor ax,ax
- xchg al,bh ; get # bytes in the buffer
- inc ax ! inc ax ; also count the CR/LF
- sub ax,bx ; have we any bytes left in the buffer?
- ja con_dev_cont ; yes, return them
- ; no, we need a fresh input line
- mov fdos_buf,128 ; read up to 128 characters
- mov si,2[bp] ; SI -> parameter block
- mov bx,ds:2[si] ; BX = input handle
- push ds ! pop es
- mov dx,offset fdos_buf ; ES:DX -> console buffer
- mov cx,bx ; output to same handle as input
- push bx
- push bp
- call read_line ; read edited line
- pop bp
- mov bl,fdos_buf+1 ; # byte we have read
- mov bh,0 ; BX = # of characters read
- mov word ptr fdos_buf+2[bx],0A0Dh; append carriage return/line feed
- mov fdos_buf,0 ; start reading at beginning
- lea si,fdos_buf+3[bx] ; Echo the LF character to the
- pop bx ; Same Output handle
- mov cx,1 ; Only One Character
- call cooked_write
- jmps con_dev_loop
- con_dev_cont: ; BX = buffer offset
- mov di,2[bp] ; DI -> parameter block
- mov cx,ds:8[di] ; CX = # of bytes to read
- cmp cx,ax ; reading more than available?
- jbe con_dev_ok ; no, read as much as you want
- mov cx,ax ; else take all that there is
- con_dev_ok:
- add fdos_buf,cl ; update buffer index for next time
- les di,ds:4[di] ; ES:DI -> buffer to read into
- lea si,fdos_buf+2[bx] ; DS:SI -> function 10 buffer
- push cx ; save count
- rep movsb ; read all the data
- pop cx ; restore count
- mov al,1Ah ; now we look for EOF mark...
- push ds ! pop es
- lea di,fdos_buf+2[bx] ; ES:DI -> function 10 buffer
- mov si,cx ; keep count safe
- repne scasb
- xchg cx,si ; restore count
- pop bx ; recover DHNDL_
- pop es
- jne con_dev_exit ; if no EOF, skip to exit
- sub cx,si ; subtract any after EOF mark
- dec cx ; and the EOF mark itself
- and es:DHNDL_ATTR[bx],not DHAT_READY
- con_dev_exit:
- mov di,2[bp] ; DI -> parameter block
- mov ds:8[di],cx ; set # of characters read
- sub bx,bx ; good return code
- ret
- eject
- first_dev: ; F_DOS FIRST call on device performed
- ;--------- ; Called with MXDisk
- ; On Entry:
- ; ES:BX -> device header
- ; On Exit:
- ; dma_buffer initialised with device name
- ;
- mov dx,es ; DX:BX -> device header
- call les_di_dmaptr ; ES:DI -> DMA buffer
- mov al,0FFh ; invalidate search state for NEXT
- mov cx,21
- rep stosb
- mov al,40h ; mark it as a device
- stosb
- sub ax,ax
- mov cx,4
- rep stosw ; zero time, date, file size
- lea si,10[bx]
- push ds
- mov ds,dx ; DS:SI -> name in device header
- mov cx,4
- rep movsw ; copy device name across
- pop ds
- mov cx,8
- frstdev1: ; scan off trailing spaces
- cmp es:byte ptr 0-1[di],' '
- jne frstdev2
- dec di
- loop frstdev1
- frstdev2:
- mov al,0
- stosb ; add a trailing NUL
- ret
- eject
- ioc6_dev: ; IOCTL(6) - input status for device
- ;--------
- ; entry: ES:BX -> DHNDL_
- mov al,CMD_INPUT_NOWAIT
- jmps ioc67d ; call the device driver
- ioc7_dev: ; IOCTL(7) - output status for device
- ;--------
- ; entry: ES:BX -> DHNDL_
- mov al,CMD_OUTPUT_STATUS ; OUTPUT STATUS
- ioc67d: ; common code for I/O STATUS
- push ds
- sub sp,RH5_LEN-2*word ; allocate request header on stack
- push ax ; RH_CMD = AL
- mov ax,RH5_LEN
- push ax ; RH_LEN = RH5_LEN
- lds si,es:DHNDL_DEVPTR[bx] ; DS:SI -> device driver
- push ss ! pop es
- mov bx,sp ; ES:BX -> RH_
- mov es:RH5_CHAR[bx],0 ; zero the char
- call device_driver ; do the CALLF's to the device driver
- xor dl,dl ; assume not ready
- mov dh,es:RH5_CHAR[bx] ; possible peeked character
- add sp,RH5_LEN ; recover stack space
- pop ds
- test ax,RHS_ERROR+RHS_BUSY ; test if BUSY bit set in status
- jnz ioc67d_ret ; device not ready if error or busy
- dec dl ; return ready DL = FF
- ioc67d_ret:
- mov si,2[bp] ; SI -> user's parameter block
- mov ds:6[si],dx ; update returned status
- sub bx,bx ; no error occurred
- ret ; for now
- end ; of CDEVIO.A86