;       SCCSID = @(#)comdd.asm  6.4 92/02/24

        page    ,132
        title   MVDM device drivers for COM1..COM4

;***********************************************************************;BN040;
;  29Jul93 - J.M.Hare    defect 71358                                   ;BN040;
; Add propogating of DOSFLAG through files system for exec_only test.   ;BN040;
;***********************************************************************;BN040;

INCL_ERRORS equ 1
.xlist
.xcref
include struc30.inc
include bseerr.inc
include demsvc.inc
include mvdmexp.inc
.cref
.list

.286c


;**********************************************************************

;------ # of COM ports to install
max_com_ports equ 4

;**********************************************************************
Done    equ     00000001b
Busy    equ     00000010b
Error   equ     10000000b
EXECOPEN        EQU     1               ; exec_only BN040

RequestPacket   struc
                db      ?               ;
                db      ?               ;
Command         db      ?               ; command code
Status          dw      ?               ; status word
                db      8 dup (?)       ;
IOpeek          db      ?               ;
XferAddr        dd      ?               ; terminating address of Device driver
                                        ; also the data transfer address
IOcount         dw      ?               ; # of bytes transferred
RequestPacket   ends
;**********************************************************************
DDhdr   macro   numb,next
        local   Inter
prev    =       numb -1
header&numb label word
        ife     numb - max_com_ports
        DW      -1
        else
        DW      offset &next
        endif
        DW      -1
        DW      8000h+0040h+0020h
                                        ;8000h=character device driver
                                        ;0040h=generic ioctl supported
                                        ;0020h=binary (no ^Z checking)
        DW      Strategy
        DW      Inter
        DB      "COM&numb    "
Inter:
        mov     word ptr cs:[COM_port],&prev
        jmp     near ptr Interrupt
        ENDM
;**********************************************************************
;------ line status

zTimeOut        equ     10000000b
zXmitShiftEmpty equ     01000000b
zXmitHoldEmpty  equ     00100000b
zBreakDetect    equ     00010000b
zFramingError   equ     00001000b
zParityError    equ     00000100b
zOverrunError   equ     00000010b
zDataReady      equ     00000001b

;------ modem status

zRX_lineDetect  equ     10000000b
zRingIndicator  equ     01000000b
zDataSetReady   equ     00100000b
zClearToSend    equ     00010000b
zDelta_rX       equ     00001000b
zTrailing_RD    equ     00000100b
zDelta_DSR      equ     00000010b
zDelta_CTS      equ     00000001b
;**********************************************************************





CSEG    segment
        org     0
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
start:

        DDhdr   1,header2

Aux_table       label   word
        dw      offset $INIT            ;  00h
        dw      offset $EXIT            ;  01h
        dw      offset $EXIT            ;  02h
        dw      offset $CmdErr          ;  03h
        dw      offset $Read            ;  04h
        dw      offset $RdNd            ;  05h
        dw      offset $EXIT            ;  06h
        dw      offset $Flush           ;  07h
        dw      offset $Write           ;  08h
        dw      offset $Write           ;  09h
        dw      offset $Status          ;  0Ah 10
        dw      offset $CmdErr          ;  0Bh 11
        dw      offset $CmdErr          ;  0Ch 12
        dw      offset $CmdErr          ;  0Dh 13
        dw      offset $CmdErr          ;  0Eh 14
        dw      offset $CmdErr          ;  0Fh 15
        dw      offset $CmdErr          ;  10h 16
        dw      offset $CmdErr          ;  11h 17
        dw      offset $CmdErr          ;  12h 18
        dw      offset $Gioctl          ;  13h 19
MaxCall equ     $ - Aux_table
        dw      offset $CmdErr          ; >13h

com_asciiz      db      'COM1',0
Request_header  dd      ?
Com_port        dw      ?
AUXBUF          db      max_com_ports dup (?)
gio_execdw      dd      0                     ; exec_only BN040


;**********************************************************************
Strategy proc   far
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
        mov     word ptr cs:[Request_header],bx
        mov     word ptr cs:[Request_header]+2,es
        ret
Strategy endp
;**********************************************************************
$CmdErr proc    near
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
;input:  DS:BX=&Request header
;        ES:DI=&Transfer address
;        DX=COM port#
;        CX=# of bytes to transfer
;output: AX=status word
;        DS:BX=&Request header (unchanged)

        mov     ds:[bx].IOcount,0
        mov     ax,((Error+Done) shl 8)+ERROR_I24_BAD_COMMAND   ;=3
        ret
$CmdErr endp
;**********************************************************************
$Gioctl proc    near
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
;input:  DS:BX=&Request header
;        ES:DI=&Transfer address
;        DX=COM port#
;        CX=# of bytes to transfer
;output: AX=status word
;        DS:BX=&Request header (unchanged)

;------ check major code == COMx
        .if     <<byte ptr ds:[bx+0Dh]> ne 1>
          mov     ax,((Error+Done) shl 8)+ERROR_I24_BAD_COMMAND   ;=3
          ret
        .endif

;------ save request header
        push    ds
        push    bx

;------ Open "COMx"
        add     dl,'1'
        mov     cs:[com_asciiz+3],dl
        xor     ax,ax
        mov     cx,ax
        mov     di,ax
        dec     di
        mov     es,ax
        mov     bx,0040h
        push    cs
        pop     ds
        mov     si,offset com_asciiz

;------ initialize Not Exec_only flag from the loader                                exec_only BN040
                                               ; put in 386 mode for edx usage       exec_only BN040
.386
        push    edx                            ; 112811
        xor     edx,edx                        ; only need Edl part                  exec_only BN040
        mov     dword ptr cs:[gio_execdw],edx  ; zero save area                      exec_only BN040
        and     dh, not EXECOPEN               ; set exec_only bit off               exec_only BN040
        mov     word ptr cs:[gio_execdw+1],dx
        mov     edx,dword ptr cs:[gio_execdw]  ; restore edx with edl as DOSFLAG     exec_only BN040
        mov     dx,ax
        inc     dx
                                               ; put in 286 mode for space reasons
.286c

        SVC     SVC_DEMOPEN
        ;return ax=os/2 handle
        ;       bx=dos sft flags
        ;       cx=action taken
.386
        pop     edx                            ; 112811
.286c
;;;;??? .if     <BIT BX nand RMDI_DEVICE> or
        .if     c
          mov     ax,((Error+Done) shl 8)+ERROR_I24_GEN_FAILURE   ;=12
        .else
          ;------ ES:BX=request header
          pop     bx
          pop     es
          push    es
          push    bx

          mov     ch,es:[bx]+0Dh
          mov     cl,es:[bx]+0Eh
          mov     si,es:[bx]+0Fh
          mov     di,es:[bx]+11h
          LDS     DX,es:[bx]+13h

          mov     bx,ax                 ;=OS/2 handle
          push    bx

          mov     ax,000Ch              ;IOCTL, generic ioctl function
          SVC     SVC_DEMIOCTL          ; do all work in protect mode

          ;------ close the handle
          pop     bx                    ;=OS/2 handle
          SVC     SVC_DEMCLOSE

          mov     ah,Done
        .endif

;------ restore request header
        pop     bx
        pop     ds

        ret

$Gioctl endp
;**********************************************************************
$Read   proc    near
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
;input:  DS:BX=&Request header
;        ES:DI=&Transfer address
;        DX=COM port#
;        CX=# of bytes to transfer
;output: AX=status word
;        DS:BX=&Request header (unchanged)

        .if     ncxz
          mov     si,dx
          xor     al,al
          xchg    al,cs:[AUXBUF+si]
          or      al,al         ;\  jump if the buffered char
          jnz     aux2          ;/        is not 0.
          .repeat
            mov     ah,2
            ;Aux read: AH=2, DX=port#
            int     14h
            ;returns: AL=char read, AH=line status
            .if     <BIT AH and <zFramingError+zParityError+zOverrunError>>
              sub     ds:[bx].IOcount,cx
              mov     ax,((Error+done) shl 8)+ERROR_I24_READ_FAULT    ;=11
              ret
            .endif
aux2:
            stosb
          .loop
        .endif

$EXIT:
;input:  DS:BX=&Request header
;        ES:DI=&Transfer address
;        DX=COM port#
;        CX=# of bytes to transfer
;output: AX=status word
;        DS:BX=&Request header (unchanged)

        mov     ah,Done
        ret
$Read   endp
;**********************************************************************
$RdNd   proc    near
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
;input:  DS:BX=&Request header
;        ES:DI=&Transfer address
;        DX=COM port#
;        CX=# of bytes to transfer
;output: AX=status word
;        DS:BX=&Request header (unchanged)

        mov     si,dx
        mov     al,cs:[AUXBUF+si]
        .if     <ZERO al>
          ;Aux status: ah=3, dx=port#
          mov     ah,3
          int     14h
          ;returns: al=modem status ah=line status
          .if     <BIT ah nand zDataReady> or
          .if     <BIT al nand zDataSetReady>
            mov     ah,Busy+Done
            ret
          .endif
          ;Aux read: AH=2, DX=port#
          mov     ah,2
          int     14h
          ;returns: AL=char read, AH=line status
          .if     <BIT AH and <zFramingError+zParityError+zOverrunError>>
            sub     ds:[bx].IOcount,cx
            mov     ax,((Error+done) shl 8)+ERROR_I24_READ_FAULT    ;=11
            ret
          .endif
          mov     si,dx
          mov     cs:[AUXBUF+si],al
        .endif
        mov     ds:[BX].IOpeek,al
        mov     ah,Done
        ret
$RdNd   endp
;**********************************************************************
Interrupt proc  far
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
;------ save registers
        cld
        pusha
        push    ds
        push    es

;------
        LDS     BX,cs:[Request_header]
        LES     DI,ds:[bx].XferAddr
        mov     cx,ds:[bx].IOcount
        mov     al,ds:[bx].Command
        xor     ah,ah
        shl     ax,1
        .if     <AX ae MaxCall>
          mov     ax,MaxCall
        .endif
        add     ax,offset Aux_table
        mov     si,ax
        mov     dx,cs:[COM_port]

;       DX=COM port#
;       CX=# of bytes to transfer
;       DS:BX=&Request header
;       ES:DI=&Transfer address
        call    cs:[si]
;       AX=status word
;       DS:BX=&Request header (unchanged)

        mov     ds:[bx].Status,ax

;------ restore registers
        pop     es
        pop     ds
        popa

        ret
Interrupt endp
;**********************************************************************
$Flush  proc    near
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
;input:  DS:BX=&Request header
;        ES:DI=&Transfer address
;        DX=COM port#
;        CX=# of bytes to transfer
;output: AX=status word
;        DS:BX=&Request header (unchanged)

        mov     si,dx
        mov     byte ptr cs:[AUXBUF+si],0
        mov     ah,Done
        ret
$Flush  endp
;**********************************************************************
$Write  proc    near
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
;input:  DS:BX=&Request header
;        ES:DI=&Transfer address
;        DX=COM port#
;        CX=# of bytes to transfer
;output: AX=status word
;        DS:BX=&Request header (unchanged)

        .if     ncxz
          .repeat
            mov     al,es:[di]
            inc     di
            ;Aux write: ah=1, dx=port#, al=char to send
            mov     ah,1
            int     14h
            ;returns: ah=line status, al=no change
            .if     <BIT ah and zTimeOut>
              sub     ds:[bx].IOcount,cx
              mov     ax,((Error+done) shl 8)+ERROR_I24_WRITE_FAULT   ;=10
              ret
            .endif
          .loop
        .endif
        mov     ah,Done
        ret
$Write  endp
;**********************************************************************
$Status proc    near
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
;input:  DS:BX=&Request header
;        ES:DI=&Transfer address
;        DX=COM port#
;        CX=# of bytes to transfer
;output: AX=status word
;        DS:BX=&Request header (unchanged)

        ;AUX status: ah=3, dx=port#
        mov     ah,3
        int     14h
        ;returns: al=modem status, ah=line status
        .if     <BIT al and zDataSetReady>  and
        .if     <BIT ah and zXmitHoldEmpty>
          mov     ah,Done
        .else
          mov     ah,Done+busy
        .endif
        ret
$Status endp
;**********************************************************************

        DDhdr   2,header3
        DDhdr   3,header4
        DDhdr   4

TSR:

$Init   proc    near
        assume  cs:CSEG,ds:nothing,es:nothing,ss:nothing
;input:  DS:BX=&Request header
;        ES:DI=&Transfer address
;        DX=COM port#
;        CX=# of bytes to transfer
;output: AX=status word
;        DS:BX=&Request header (unchanged)

        mov     word ptr ds:[bx].XferAddr,offset TSR
        mov     word ptr ds:[bx].XferAddr+2,cs
        mov     ah,Done
        ret
$Init   endp
;**********************************************************************

CSEG    ends
        end     start
