;
;	FMR/FM-Towns 用 2HC Disk Driver
;	 by S.Hagihira 
;	(NEW ON)
;	 Nifty ID:PGB00174)
;	 Nanno-Net Staff
;	  1991.03.14	Ver 1.00
;	  1991.03.16	Ver 1.01	drive No. 表示
;
;	増設ドライブも使う場合はN_Drvを4 とし、
;	dskbpbとinit_tblを4 台分作成するとよい
;
;	現在のところ読み込みのみのサポート
;
N_Drv	equ	2
DSK_1MB	equ	20h
CR	equ	0Dh
LF	equ	0Ah
;
code	segment
	assume	cs:code,ds:code,es:code,ss:code
;
;	device header
;
dskdev	label	word
	dd	-1		;last device
	dw	0000h		;block device/IBM format
	dw	strategy	;strategy entry point
	dw	dsk_int		;interrupt entry point
dsknum	db	N_Drv		;units

dsktbl	label	word
	dw	_init		;initialize
	dw	media_chk	;media check
	dw	get_bpb		;build bpb
	dw	cmd_err		;ioctl input
	dw	dsk_read	;disk read
	dw	exit
	dw	exit
	dw	exit
	dw	dsk_wrt		;disk write
	dw	dsk_wrtv	;disk write and verify
	dw	exit
	dw	exit
	dw	exit
;
packet	dd	0
;
;	strategy
;
stratp	proc	far
strategy:
	mov	word ptr cs:[packet],bx
	mov	word ptr cs:[packet+2],es
	ret
stratp	endp
;
;	defintion of BPB
;
bpb		struc
		dw	?	;logical sector size
allc_sec	db	?	;sector/allocation bit
		dw	?	;resetve sector
		db	?	;copy of FAT
dir_ent		dw	?	;directory entry
tot_sct		dw	?	;sector/volume
		db	?	;media descriptor byte
fat_sec		dw	?	;sector/fat
bpb		ends
;
;	defintion of reqest header for Read/Write/Verify
;
req_head	struc
cmdlen		db	?	;command length
unit		db	?	;unit code
cmd		db	?	;command code
status		dw	?	;status
		db	8 dup (?)
media		db	?	;media descripter byte
trans		dd	?	;transfer address
count		dw	?	;sector count
start		dw	?	;start sector number
req_head	ends
;
;	definition of requset header for Init
;
req_head_i	struc
		db	13
n_unit		db	?	; unit count
break_adr	dd	?	; break address
bpb_ptr		dd	?	; pointer for BPB
block_dev_n	db	?	; block device number
req_head_i	ends
;
;	interrupt routine
;
dsk_int:
	push	si
	push	ax
	push	cx
	push	dx
	push	di
	push	bp
	push	ds
	push	es
	push	bx

	lds	bx,cs:[packet]

	mov	al,[bx].unit
	mov	ah,[bx].media
	mov	cs:[unit_no],al
	mov	cx,[bx].count
	mov	dx,[bx].start
	xchg	ax,di
	mov	al,[bx].cmd
	cmp	al,11
	ja	cmd_err
	xor	ah,ah
	shl	ax,1
	mov	si,offset dsktbl
	add	si,ax
	xchg	ax,di
	les	di,[bx].trans
	push	cs
	pop	ds
	jmp	[si]
;
;	exit
;

cmd_err:
	mov	al,3

err_exit:
	mov	ah,81h
	jmp	short exit1

exitp	proc	far
exit:
	mov	ah,1
exit1:
	lds	bx,cs:[packet]
	mov	[bx].status,ax

	pop	bx
	pop	es
	pop	ds
	pop	bp
	pop	di
	pop	dx
	pop	cx
	pop	ax
	pop	si
	ret
exitp	endp
;
;	command process routines
;

media_chk:			;media check
	lds	bx,[packet]
	mov	byte ptr [bx].trans,1
	jmp	exit

;
get_bpb:
	mov	ah,es:[di]
	mov	si,offset dskbpb
	lds	bx,[packet]
	mov	[bx].media,ah
	mov	al,[bx].unit
	mov	ah,13
	mul	ah
	add	si,ax
	mov	[bx].count,si
	mov	[bx].count+2,cs
	jmp	exit

;
dsk_read:
	mov	rw_flg,0
	mov	vrfy_flg,0
	jmp	rw_common
;
dsk_wrt:
;	mov	rw_flg,1
;	mov	vrfy_flg,0
;	jmp	rw_common
;
dsk_wrtv:
;	mov	rw_flg,1
;	mov	vrfy_flg,1
;	jmp	rw_common
	mov	al,10	; Write Error
	push	ds
	xor	cx,cx
	lds	bx,cs:[packet]
	mov	[bx].count,cx	;set transmitted sector no.
	pop	ds
	jmp	err_exit
;
rw_common:
	push	di	; transfer offset
	push	es	; transfer segment
	push	cx	; transfer count
	push	dx	; start sector
;
;	Get Drive mode
;
	mov	ax,0100h+DSK_1MB
	add	al,byte ptr unit_no
	mov	byte ptr dev_no,al
	int	93h
	mov	byte ptr drv_mode1,dl
	mov	word ptr drv_mode2,bx
;
;	Set Drive mode to 2HC (2ED)
;
	xor	ah,ah	
	mov	al,byte ptr dev_no
	mov	dl,42h	; 2ED, 512 bytes/sector
	mov	bx,0212h	; 2 heads, 18 sectors/track
	int	93h
;
;	Logical Sector No. => Physical Sector No.
;
	pop	ax
;	shl	ax,1
	xor	dx,dx
	mov	cx,18	; (18 sectors/ track)
	div	cx	; dl = sector no.
	inc	dl	; physical sector starts from 1
	mov	cx,ax
	xor	dh,dh
	shr	cx,1	; track no.set ( /2 ... 2 sides)
	adc	dh,0	; side no. set
	mov	al,byte ptr dev_no
	mov	ah,5	; Secter Read command
	cmp	byte ptr rw_flg,0
	jz	rw_r
	mov	ah,6	; Sector Write command
rw_r:	pop	bx	; transfer count
;	shl	bx,1
	pop	ds	; transfer segment
	pop	di	; transfer offset
	push	bx
	int	93h
	mov	dx,cx	; error code convert
	pop	cx
	sub	cx,bx	; r/w sector count
	lds	bx,cs:[packet]
	mov	[bx].count,cx	;set transmitted sector no.
	push	ax	; error status save
;
;	Reset Drive mode
;
	push	cs
	pop	ds
	xor	ah,ah
	mov	al,byte ptr dev_no
	mov	dl,byte ptr drv_mode1
	mov	bx,word ptr drv_mode2
	int	93h
;
;	Error check
;
	pop	ax
	mov	al,ah
	cmp	al,0
	jz	rw_ok
	cmp	byte ptr rw_flg,0
	jz	r_err
	mov	al,10	; Write Error
	jmp	err_exit
r_err:	mov	al,11	; Read Error
	jmp	err_exit
rw_ok:	jmp	exit
;
;	data
;
rw_flg		db	?	;0 : read
				;1 : write
vrfy_flg	db	?	;0 : verify off
				;1 : verify on
unit_no		db	?
dev_no		db	?
drv_mode1	db	?
drv_mode2	dw	?
;
dskbpb:
	include	bpb_2hc.asm
;
op_mesa:
	db	CR,LF,' FMR/FM-Towns 2HC Disk Driver Ver 1.01',CR,LF
	db	'   1991.03.14 Read only supported',CR,LF
	db	'  by S.Hagihira (NEW ON/ Nifty ID: PGB00174)',CR,LF,LF
	db	'内蔵ドライブ0,1をドライブ'
d_no0:	db	?
	db	','
d_no1:	db	?
	db	'で2HC モードアクセス可能です。',CR,LF,LF,'$'
;
_init:
;
	push	cs
	pop	ds
;
	mov	al,N_Drv
	push	ds
;
	lds	bx,[packet]	;get strategy pointer
	mov	[bx].media,al	;set unit count
	mov	al,byte ptr [bx].count+4	; get block device No.
	mov	word ptr [bx].trans,offset op_mesa	;set break address
	mov	word ptr [bx].trans+2,cs
	mov	word ptr [bx].count+2,cs	;set pointer for BPB
	mov	word ptr [bx].count,offset init_tbl
;
	pop	ds
	add	al,'A'
	mov	byte ptr d_no0,al
	inc	al
	mov	byte ptr d_no1,al
	mov	dx,offset op_mesa
	mov	ah,9
	int	21h
	jmp	exit
;
code	ends
	end
