home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / dos_ency / 15 / tinydisk.asm < prev   
Encoding:
Assembly Source File  |  1988-08-11  |  13.2 KB  |  381 lines

  1.         name    tinydisk
  2.         title   TINYDISK example block-device driver
  3.  
  4. ; TINYDISK.ASM --- 64 KB RAMdisk
  5. ;
  6. ; Ray Duncan, July 1987
  7. ; Example of a simple installable block-device driver.
  8.  
  9. _TEXT   segment public 'CODE'
  10.  
  11.         assume  cs:_TEXT,ds:_TEXT,es:_TEXT
  12.  
  13.         org     0
  14.  
  15. MaxCmd  equ     12              ; max driver command code
  16.                                 ; (no MS-DOS 3.x functions)
  17.  
  18. cr      equ     0dh             ; ASCII carriage return
  19. lf      equ     0ah             ; ASCII linefeed
  20. blank   equ     020h            ; ASCII space code
  21. eom     equ     '$'             ; end-of-message signal
  22.  
  23. Secsize equ     512             ; bytes/sector, IBM-compatible media
  24.  
  25.                                 ; device-driver header
  26. Header  dd      -1              ; link to next driver in chain
  27.         dw      0               ; device attribute word
  28.         dw      Strat           ; "Strategy" routine entry point
  29.         dw      Intr            ; "Interrupt" routine entry point
  30.         db      1               ; number of units, this device
  31.         db      7 dup (0)       ; reserved area (block-device drivers)
  32.  
  33. RHPtr   dd      ?               ; segment:offset of request header
  34.  
  35. Secseg  dw      ?               ; segment base of sector storage
  36.  
  37. Xfrsec  dw      0               ; current sector for transfer
  38. Xfrcnt  dw      0               ; sectors successfully transferred
  39. Xfrreq  dw      0               ; number of sectors requested
  40. Xfraddr dd      0               ; working address for transfer
  41.  
  42. Array   dw      BPB             ; array of pointers to BPB
  43.                                 ; for each supported unit
  44.  
  45.  
  46. Bootrec equ     $
  47.  
  48.         jmp     $               ; phony JMP at start of
  49.         nop                     ; boot sector; this field
  50.                                 ; must be 3 bytes
  51.  
  52.         db      'MS   2.0'      ; OEM identity field
  53.  
  54.                                 ; BIOS Parameter Block (BPB)
  55. BPB     dw      Secsize         ; 00H - bytes per sector
  56.         db      1               ; 02H - sectors per cluster
  57.         dw      1               ; 03H - reserved sectors
  58.         db      1               ; 05H - number of FATs
  59.         dw      32              ; 06H - root directory entries
  60.         dw      128             ; 08H - sectors = 64 KB/secsize
  61.         db      0f8h            ; 0AH - media descriptor
  62.         dw      1               ; 0BH - sectors per FAT
  63.  
  64. Bootrec_len equ $-Bootrec
  65.  
  66.  
  67. Strat   proc    far             ; RAMdisk strategy routine
  68.  
  69.                                 ; save address of request header
  70.         mov     word ptr cs:RHPtr,bx
  71.         mov     word ptr cs:[RHPtr+2],es
  72.         ret                     ; back to MS-DOS kernel
  73.  
  74. Strat   endp
  75.  
  76.  
  77. Intr    proc    far             ; RAMdisk interrupt routine
  78.  
  79.         push    ax              ; save general registers
  80.         push    bx
  81.         push    cx
  82.         push    dx
  83.         push    ds
  84.         push    es
  85.         push    di
  86.         push    si
  87.         push    bp
  88.  
  89.         mov     ax,cs           ; make local data addressable
  90.         mov     ds,ax
  91.  
  92.         les     di,[RHPtr]      ; ES:DI = request header
  93.  
  94.         mov     bl,es:[di+2]    ; get command code
  95.         xor     bh,bh
  96.         cmp     bx,MaxCmd       ; make sure it's valid
  97.         jle     Intr1           ; jump, function code is ok
  98.         mov     ax,8003h        ; set Error bit and
  99.         jmp     Intr3           ; "Unknown Command" error code
  100.  
  101. Intr1:  shl     bx,1            ; form index to dispatch table and
  102.                                 ; branch to command-code routine
  103.         call    word ptr [bx+Dispatch]
  104.                                 ; should return AX = status
  105.  
  106.         les     di,[RHPtr]      ; restore ES:DI = request header
  107.  
  108. Intr3:  or      ax,0100h        ; merge Done bit into status and store
  109.         mov     es:[di+3],ax    ; status into request header
  110.  
  111. Intr4:  pop     bp              ; restore general registers
  112.         pop     si
  113.         pop     di
  114.         pop     es
  115.         pop     ds
  116.         pop     dx
  117.         pop     cx
  118.         pop     bx
  119.         pop     ax
  120.         ret                     ; return to MS-DOS kernel
  121.  
  122. Intr    endp
  123.  
  124.  
  125. Dispatch:                       ; command-code dispatch table
  126.                                 ; all command-code routines are
  127.                                 ; entered with ES:DI pointing
  128.                                 ; to request header and return
  129.                                 ; the operation status in AX
  130.         dw      Init            ;  0 = initialize driver
  131.         dw      MediaChk        ;  1 = media check on block device
  132.         dw      BuildBPB        ;  2 = build BIOS parameter block
  133.         dw      Dummy           ;  3 = I/O control read
  134.         dw      Read            ;  4 = read (input) from device
  135.         dw      Dummy           ;  5 = nondestructive read
  136.         dw      Dummy           ;  6 = return current input status
  137.         dw      Dummy           ;  7 = flush device input buffers
  138.         dw      Write           ;  8 = write (output) to device
  139.         dw      Write           ;  9 = write with verify
  140.         dw      Dummy           ; 10 = return current output status
  141.         dw      Dummy           ; 11 = flush output buffers
  142.         dw      Dummy           ; 12 = I/O control write
  143.  
  144.  
  145. MediaChk proc  near             ; command code 1 = Media Check
  146.  
  147.                                 ; return "not changed" code
  148.         mov     byte ptr es:[di+0eh],1
  149.         xor     ax,ax           ; and success status
  150.         ret
  151.  
  152. MediaChk endp
  153.  
  154.  
  155. BuildBPB proc  near             ; command code 2 = Build BPB
  156.  
  157.                                 ; put BPB address in request header
  158.         mov     word ptr es:[di+12h],offset BPB
  159.         mov     word ptr es:[di+14h],cs
  160.         xor     ax,ax           ; return success status
  161.         ret
  162.  
  163. BuildBPB endp
  164.  
  165.  
  166. Read    proc    near            ; command code 4 = Read (Input)
  167.  
  168.         call    Setup           ; set up transfer variables
  169.  
  170. Read1:  mov     ax,Xfrcnt       ; done with all sectors yet?
  171.         cmp     ax,Xfrreq
  172.         je      Read2           ; jump if transfer completed
  173.         mov     ax,Xfrsec       ; get next sector number
  174.         call    Mapsec          ; and map it
  175.         mov     ax,es
  176.         mov     si,di
  177.         les     di,Xfraddr      ; ES:DI = requester's buffer
  178.         mov     ds,ax           ; DS:SI = RAMdisk address
  179.         mov     cx,Secsize      ; transfer logical sector from
  180.         cld                     ; RAMdisk to requestor
  181.         rep movsb
  182.         push    cs              ; restore local addressing
  183.         pop     ds
  184.         inc     Xfrsec          ; advance sector number
  185.                                 ; advance transfer address
  186.         add     word ptr Xfraddr,Secsize
  187.         inc     Xfrcnt          ; count sectors transferred
  188.         jmp     Read1
  189.  
  190. Read2:                          ; all sectors transferred
  191.         xor     ax,ax           ; return success status
  192.         les     di,RHPtr        ; put actual transfer count
  193.         mov     bx,Xfrcnt       ; into request header
  194.         mov     es:[di+12h],bx
  195.         ret
  196.  
  197. Read    endp
  198.  
  199.  
  200. Write   proc    near            ; command code 8 = Write (Output)
  201.                                 ; command code 9 = Write with Verify
  202.  
  203.         call    Setup           ; set up transfer variables
  204.  
  205. Write1: mov     ax,Xfrcnt       ; done with all sectors yet?
  206.         cmp     ax,Xfrreq
  207.         je      Write2          ; jump if transfer completed
  208.  
  209.         mov     ax,Xfrsec       ; get next sector number
  210.         call    Mapsec          ; and map it
  211.         lds     si,Xfraddr
  212.         mov     cx,Secsize      ; transfer logical sector from
  213.         cld                     ; requester to RAMdisk
  214.         rep movsb
  215.         push    cs              ; restore local addressing
  216.         pop     ds
  217.         inc     Xfrsec          ; advance sector number
  218.                                 ; advance transfer address
  219.         add     word ptr Xfraddr,Secsize
  220.         inc     Xfrcnt          ; count sectors transferred
  221.         jmp     Write1
  222.  
  223. Write2:                         ; all sectors transferred
  224.         xor     ax,ax           ; return success status
  225.         les     di,RHPtr        ; put actual transfer count
  226.         mov     bx,Xfrcnt       ; into request header
  227.         mov     es:[di+12h],bx
  228.         ret
  229.  
  230. Write   endp
  231.  
  232.  
  233. Dummy   proc    near            ; called for unsupported functions
  234.  
  235.         xor     ax,ax           ; return success flag for all
  236.         ret
  237.  
  238. Dummy   endp
  239.  
  240.  
  241. Mapsec  proc    near            ; map sector number to memory address
  242.                                 ; call with AX = logical sector no.
  243.                                 ; return ES:DI = memory address
  244.  
  245.         mov     di,Secsize/16   ; paragraphs per sector
  246.         mul     di              ; * logical sector number
  247.         add     ax,Secseg       ; + segment base of sector storage
  248.         mov     es,ax
  249.         xor     di,di           ; now ES:DI points to sector
  250.         ret
  251.  
  252. Mapsec  endp
  253.  
  254.  
  255. Setup   proc    near            ; set up for read or write
  256.                                 ; call ES:DI = request header
  257.                                 ; extracts address, start, count
  258.  
  259.         push    es              ; save request header address
  260.         push    di
  261.         mov     ax,es:[di+14h]  ; starting sector number
  262.         mov     Xfrsec,ax
  263.         mov     ax,es:[di+12h]  ; sectors requested
  264.         mov     Xfrreq,ax
  265.         les     di,es:[di+0eh]  ; requester's buffer address
  266.         mov     word ptr Xfraddr,di
  267.         mov     word ptr Xfraddr+2,es
  268.         mov     Xfrcnt,0        ; initialize sectors transferred count
  269.         pop     di              ; restore request header address
  270.         pop     es
  271.         ret
  272.  
  273. Setup   endp
  274.  
  275.  
  276. Init    proc    near            ; command code 0 = Initialize driver
  277.                                 ; on entry ES:DI = request header
  278.  
  279.         mov     ax,cs           ; calculate segment base for sector
  280.         add     ax,Driver_len   ; storage and save it
  281.         mov     Secseg,ax
  282.         add     ax,1000h        ; add 1000H paras (64 KB) and
  283.         mov     es:[di+10h],ax  ; set address of free memory
  284.         mov     word ptr es:[di+0eh],0
  285.  
  286.         call    Format          ; format the RAMdisk
  287.  
  288.         call    Signon          ; display driver identification
  289.  
  290.         les     di,cs:RHPtr     ; restore ES:DI = request header
  291.                                 ; set logical units = 1
  292.         mov     byte ptr es:[di+0dh],1
  293.                                 ; set address of BPB array
  294.         mov     word ptr es:[di+12h],offset Array
  295.         mov     word ptr es:[di+14h],cs
  296.  
  297.         xor     ax,ax           ; return success status
  298.         ret
  299.  
  300. Init    endp
  301.  
  302.  
  303. Format  proc    near            ; format the RAMdisk area
  304.  
  305.         mov     es,Secseg       ; first zero out RAMdisk
  306.         xor     di,di
  307.         mov     cx,8000h        ; 32 K words = 64 KB
  308.         xor     ax,ax
  309.         cld
  310.         rep stosw
  311.  
  312.         mov     ax,0            ; get address of logical
  313.         call    Mapsec          ; sector zero
  314.         mov     si,offset Bootrec
  315.         mov     cx,Bootrec_len
  316.         rep movsb               ; and copy boot record to it
  317.  
  318.         mov     ax,word ptr BPB+3
  319.         call    Mapsec          ; get address of 1st FAT sector
  320.         mov     al,byte ptr BPB+0ah
  321.         mov     es:[di],al      ; put media ID byte into it
  322.         mov     word ptr es:[di+1],-1
  323.  
  324.         mov     ax,word ptr BPB+3
  325.         add     ax,word ptr BPB+0bh
  326.         call    Mapsec          ; get address of 1st directory sector
  327.         mov     si,offset Volname
  328.         mov     cx,Volname_len
  329.         rep movsb               ; copy volume label to it
  330.  
  331.         ret                     ; done with formatting
  332.  
  333. Format  endp
  334.  
  335.  
  336. Signon  proc    near            ; driver identification message
  337.  
  338.         les     di,RHPtr        ; let ES:DI = request header
  339.         mov     al,es:[di+22]   ; get drive code from header,
  340.         add     al,'A'          ; convert it to ASCII, and
  341.         mov     drive,al        ; store into sign-on message
  342.  
  343.         mov     ah,30h          ; get MS-DOS version
  344.         int     21h
  345.         cmp     al,2
  346.         ja      Signon1         ; jump if version 3.0 or later
  347.         mov     Ident1,eom      ; version 2.x, don't print drive
  348.  
  349. Signon1:                        ; print sign-on message
  350.         mov     ah,09H          ; Function 09H = print string
  351.         mov     dx,offset Ident ; DS:DX = address of message
  352.         int     21h             ; transfer to MS-DOS
  353.  
  354.         ret                     ; back to caller
  355.  
  356. Signon  endp
  357.  
  358.  
  359. Ident   db      cr,lf,lf        ; driver sign-on message
  360.         db      'TINYDISK 64 KB RAMdisk'
  361.         db      cr,lf
  362. Ident1  db      'RAMdisk will be drive '
  363. Drive   db      'X:'
  364.         db      cr,lf,eom
  365.  
  366.  
  367. Volname db      'DOSREF_DISK'   ; volume label for RAMdisk
  368.         db      08h             ; attribute byte
  369.         db      10 dup (0)      ; reserved area
  370.         dw      0               ; time = 00:00
  371.         dw      0f01h           ; date = August 1, 1987
  372.         db      6 dup (0)       ; reserved area
  373.  
  374. Volname_len equ $-volname
  375.  
  376. Driver_len dw (($-header)/16)+1 ; driver size in paragraphs
  377.  
  378. _TEXT   ends
  379.  
  380.         end
  381.