        page    ,132
;
;                   IBM Confidential
;                   Copyright (C) IBM Corporation 1991-1993
;                   All Rights Reserved.
;
        TITLE   ROMDRIVE

break   macro   arg
        subttl  arg             ; bogus macro for include files
        endm

;       adapted from RAMDRIVE.SYS from MS-DOS 5.0


.xlist
        include devsym.inc
        include biosseg.inc
.list

        include msgroup.inc
SUBTTL  <I/O Packet offset declarations>

;
; Define I/O packet offsets for useful values.
;
; SEE ALSO
;       MS-DOS Technical Reference manual section on Installable Device Drivers
;

; READ/WRITE PACKET OFFSETS
RW_COUNT        EQU     WORD PTR (SIZE SRHEAD) + 5
RW_TRANS        EQU     DWORD PTR (SIZE SRHEAD) + 1
RW_START        EQU     WORD PTR (SIZE SRHEAD) + 7

; MEDIA CHECK PACKET OFFSETS
MCH_RETVAL      EQU     BYTE PTR (SIZE SRHEAD) + 1
MCH_MEDIA       EQU     BYTE PTR (SIZE SRHEAD) + 0

; BUILD BPB PACKET OFFSETS
BPB_BUFFER      EQU     DWORD PTR (SIZE SRHEAD) + 1
BPB_MEDIA       EQU     BYTE PTR (SIZE SRHEAD) + 0
BPB_BPB         EQU     DWORD PTR (SIZE SRHEAD) + 5



SUBTTL  <Device header>


ASSUME  CS:bios_data,DS:NOTHING,ES:NOTHING,SS:NOTHING

        public  ptrsavx
        public  devexit
        public  rombase
        public  ssize,seclim,rdrivebpb
        public  bpb_rd_length
        extrn   xfer_from_rom:near
        extrn   ROM$INIT:near

        public  rdrive
rdrive:
ROMDEV  LABEL   WORD
        DW      -1,-1
DEVATS  DW      DEVOPCL
        DW      STRATEGY
        DW      ROM$IN
        DB      1                       ;1 ROMDRIVE


SUBTTL  <Command dispatch table>

;**
;
; This is the device driver command dispatch table.
;
;

ROMTBL  LABEL   WORD
        DB      15                      ; Max allowed command code
        DW      ROM$INIT
        DW      MEDIA$CHK
        DW      GET$BPB
        DW      CMDERR
        DW      ROM$READ
        DW      DEVEXIT
        DW      DEVEXIT
        DW      DEVEXIT
        DW      ROM$WRT ; writing not supported, read only
        DW      ROM$WRT ; writing not supported, read only
        DW      DEVEXIT
        DW      DEVEXIT
        DW      DEVEXIT
        DW      DEVEXIT
        DW      DEVEXIT
        DW      ROM$REM


RDRIVEBPB:
SSIZE   DW      512             ; Physical sector size in bytes
CSIZE   DB      0               ; Sectors/allocation unit
RESSEC  DW      1               ; Reserved sectors for DOS
FATNUM  DB      1               ; No. allocation tables
DIRNUM  DW      64              ; Number directory entries
SECLIM  DW      0               ; Number sectors
        DB      0F8H            ; Media descriptor
FATSEC  DW      1               ; Number of FAT sectors
        DW      1               ; Number of sectors per track
        DW      1               ; Number of heads
        DW      0               ; Number of hidden sectors

;       now allocate enough extra bytes so that we can guarantee that
;         the amount we read is always divisible by 4.  This allows
;         actual ROM interface modules to utilize DWORD moves without
;         a bunch of extra effort.

        db      ((offset rdrivebpb - offset $) and 3) dup (0)

bpb_rd_length = (offset $) - (offset rdrivebpb)


SUBTTL  <Common Device code>

rombase         dd      0

;       ROMDRIVE DEVICE ENTRY POINTS - STRATEGY, ROM$IN

ptrsavx         DD      0               ; Storage location for packet addr

;**     STRATEGY - Device strategy routine
;

STRATP  PROC    FAR

STRATEGY:
        MOV     WORD PTR [ptrsavx],BX   ; Save packet addr
        MOV     WORD PTR [ptrsavx+2],ES
        RET

STRATP  ENDP

;**     ROM$IN - Device interrupt routine
;
;       ENTRY   ptrsavx has packet address saved by previous STRATEGY call.
;       EXIT    Dispatch to appropriate function handler
;                       CX = Packet RW_COUNT
;                       DX = Packet RW_START
;                       ES:DI = Packet RW_TRANS
;                       DS = bios_data
;                       STACK has saved values of all regs but FLAGS
;                   All function handlers must return through one of
;                       the standard exit points
;       USES    FLAGS
;

ROM$IN:
        PUSH    SI
        PUSH    AX
        PUSH    CX
        PUSH    DX
        PUSH    DI
        PUSH    BP
        PUSH    DS
        PUSH    ES
        PUSH    BX

        LDS     BX,[ptrsavx]           ;GET POINTER TO I/O PACKET
    ;
    ; Set up registers for READ or WRITE since this is the most common case
    ;
        MOV     CX,DS:[BX.RW_COUNT]     ;CX = COUNT
        MOV     DX,DS:[BX.RW_START]     ;DX = START SECTOR
        MOV     AL,DS:[BX.REQFUNC]      ; Command code
        MOV     AH,BYTE PTR [ROMTBL]    ; Valid range
        CMP     AL,AH
        JA      CMDERR                  ; Out of range command code
        CBW                             ; Make command code a word
        mov     si,ax                   ; get to indexable register
        add     si,si
        les     di,ds:[bx.RW_TRANS]     ; es:di -> transfer address
        jmp     cs:word ptr ROMTBL+1[si] ; jump to routine


;**     EXIT - ALL ROUTINES RETURN THROUGH ONE OF THESE PATHS
;
;       Exit code entry points:
;
;


ROM$WRT:
        mov     al,0                    ; write protect error
        jmp     short err$exit
CMDERR:
        MOV     AL,3                    ;UNKNOWN COMMAND ERROR
        JMP     SHORT ERR$EXIT

ERR$CNT:
        LDS     BX,[ptrsavx]
        MOV     [BX.RW_COUNT],0         ; NO sectors transferred
ERR$EXIT:                               ; Error in AL
        MOV     AH,(STERR + STDON) SHR 8  ;MARK ERROR RETURN
        JMP     SHORT ERR1

EXITP   PROC    FAR

DEVEXIT:
        MOV    AH,STDON SHR 8
ERR1:
        LDS     BX,[ptrsavx]
        MOV     [BX.REQSTAT],AX         ; Set return status

        POP     BX
        POP     ES
        POP     DS
        POP     BP
        POP     DI
        POP     DX
        POP     CX
        POP     AX
        POP     SI
        RET                             ;RESTORE REGS AND RETURN
EXITP   ENDP


;**     MEDIA$CHK - Device Driver Media check routine
;
;       ROMDRIVE Media check routine. ALWAYS returns media not changed
;
;       ENTRY from ROM$IN
;       EXIT through DEVEXIT
;       USES DS,BX
;

MEDIA$CHK:
        LDS     BX,[ptrsavx]
        MOV     [BX.MCH_RETVAL],1       ; ALWAYS NOT CHANGED
        JMP     DEVEXIT

;**     GET$BPB - Device Driver Build BPB routine
;
;       ROMDRIVE Build BPB routine. Returns pointer to BPB at RDRIVEBPB
;
;       EXIT through DEVEXIT
;       USES DS,BX

GET$BPB:
        LDS     BX,[ptrsavx]
        MOV     WORD PTR [BX.BPB_BPB],OFFSET RDRIVEBPB
        MOV     WORD PTR [BX.BPB_BPB + 2],CS
        JMP     DEVEXIT

;**     ROM$REM - Device Driver Removable Media routine
;
;       ROMDRIVE Removable Media routine. ALWAYS returns media not removable
;       NOTE: This routine is never called if running on DOS 2.X
;
;       ENTRY from ROM$IN
;       EXIT through ERR1
;       USES AX
;

ROM$REM:
        MOV     AX,STBUI + STDON        ; Media NOT removable
        JMP     ERR1

;**     ROM$READ - Device Driver READ routine
;
;       ROMDRIVE READ routine. Perform device READ.
;
;               ES:DI is transfer address
;               CX is sector transfer count
;               DX is start sector number
;       EXIT through DEVEXIT or ERR$CNT
;       USES ALL
;

ROM$READ:
        jcxz    devexit         ; zero sectors, read okay.

        xchg    ax,dx           ; get start sector
        mul     ssize           ;  now dx:ax is the start of block
        push    dx              ; save dx for now
        mov     bx,ax           ; get low 16 bits into correct register
        mov     ax,cx           ; get sector count
        mul     ssize           ; get byte count
        or      dx,dx           ; if overflow, use 64k
        jz      romread1

        xor     ax,ax           ; 0 means 64K

romread1:
        mov     cx,ax           ; pass count in cx
        pop     dx              ; dx:bx is sector address
        call    xfer_from_rom   ; es:di is DMA address
        jnc     devexit
        JMP     ERR$CNT


bios_data ENDS
        END
