/* TOS 4.04 Xbios dispatcher for the CT60/CTPCI boards
 * and USB-disk / Ram-Disk utility
 * Didier Mequignon 2005-2009, e-mail: aniplay@wanadoo.fr
 *
 * Modified to be used as an application by David Gálvez 2010.
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This file is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 

 
#include "config.h"
#include "vars.h"

#define old_pun_ptr 	0x516

#undef pun_ptr
#define pun_ptr pun_ptr_usb

.global	_max_logical_drive

#define MAX_LOGICAL_DRIVE	_max_logical_drive

.chip 68040

.global ___mint

#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || defined(CONFIG_USB_EHCI) || \
	defined(CONFIG_USB_ISP116X_HCD) || defined(CONFIG_USB_ARANYM_HCD)
#ifdef CONFIG_USB_STORAGE
	.global _install_usb_stor,_usb_stor_read,_usb_stor_write,_usb_1st_disk_drive,_SuperFromUser, _SuperTouser
#endif /* CONFIG_USB_STORAGE */
#endif /* CONFIG_USB_UHCI || CONFIG_USB_OHCI || CONFIG_USB_EHCI || CONFIG_USB_ISP116X_HCD */



#if defined(CONFIG_USB_KEYBOARD) || (CONFIG_USB_MOUSE)
.global _asm_set_ipl
.global _call_ikbdvec,_call_mousevec
#endif

#ifdef DEBUG_BIOS_LAYER
	.global display_string,hex_long,hex_word,hex_byte,display_char,wait_key,_debug
#endif

	.data

/* XHDI */

#define XH_DL_SECSIZ 0 // maximal sector size (BIOS level)
#define XH_DL_MINFAT 1 // minimal number of FATs
#define XH_DL_MAXFAT 2 // maximal number of FATs
#define XH_DL_MINSPC 3 // sectors per cluster minimal
#define XH_DL_MAXSPC 4 // sectors per cluster maximal
#define XH_DL_CLUSTS 5 // maximal number of clusters of a 16 bit FAT
#define XH_DL_MAXSEC 6 // maximal number of sectors
#define XH_DL_DRIVES 7 // maximal number of BIOS drives supported by the DOS

	
/* AHDI */

#define PUN_DEV           0x1F /* device number of HD */
#define PUN_UNIT          0x07 /* Unit number */
#define PUN_SCSI          0x08 /* 1=SCSI 0=ACSI */
#define PUN_IDE           0x10 /* Falcon IDE */
#define PUN_USB           0x20 /* USB */
#define PUN_REMOVABLE     0x40 /* Removable media */
#define PUN_VALID         0x80 /* zero if valid */

#define pinfo_puns      0  // 2 bytes
#define pinfo_pun       2  // 32 bytes
#define pinfo_pstart   34  // 32 x 4 bytes
#define pinfo_cookie  162  // 4 bytes
#define pinfo_cookptr 166  // 4 bytes
#define pinfo_vernum  170  // 2 bytes
#define pinfo_maxsiz  172  // 2 bytes
#define pinfo_ptype   174  // 32 x 4 bytes
#define pinfo_psize   302  // 32 x 4 bytes
#define pinfo_flags   430  // 32 x 2 bytes, internal use: B15:swap, B7:change, B0:bootable
#define pinfo_bpb     494  // 32 x 32 bytes
#define pinfo_devnum 1518  // 32 bytes 
#define pinfo_size   1550


#if 1//#ifdef DEBUG_BIOS_LAYER
//debug1:	.asciz "XBIOS #0x"
//debug2:	.asciz "Setscreen 0x"
debug3:	.asciz "hdv_rw 0x"
debug4:	.ascii "hdv_bpb"
	.byte 13,10,0
debug5:	.ascii "hdv_mediach"
	.byte 13,10,0
//debug6:	.asciz "Vsetmode 0x"
//debug7:	.asciz "ValidMode 0x"
//debug8:	.asciz "Gettime 0x
debug132:	.asciz "XHDI XHReadWrite 0x"
debug133:	.ascii "XHDI XHInqTarget2"
	.byte 13,10,0
debug134:	.ascii "XHDI XHInqDev"
	.byte 13,10,0
debug135:	.ascii "XHDI XHInqDriver"
	.byte 13,10,0
debug136:	.ascii "XHDI XHInqDev2"
	.byte 13,10,0
debug137:	.ascii "XHDI XHDOSLimits"
	.byte 13,10,0
debug138:	.ascii "GALVEZ DEBUG"		/* Galvez: DEBUG */
	.byte 13,10,0
debug139:	.ascii "XHDI XHReadWrite"	/* Galvez: DEBUG */
	.byte 13,10,0
	.align 2
#endif


//	dc.l 0x58425241          // XBRA
//	dc.l 0x5F504349          // _PCI
//	dc.l 0                   // cannot store here because we are in flash



text_color:

	moveq #0,D0
	move.w 0x3E86,D0         // number of planes
	cmp.l #2,D0
	bls.s .black_and_white
	pea (A0)
	move.w #9,-(SP)
	trap #1                  // Cconws
	addq.l #6,SP
.black_and_white:
	rts
	
#if defined(CONFIG_USB_KEYBOARD) || (CONFIG_USB_MOUSE)
_asm_set_ipl:
	link A6,#-8
	movem.l D6-D7,(SP)
	move.w SR,D7            //  current SR 
	move.l D7,D0            //  prepare return value
	and.l #0x0700,D0        // mask out IPL 
	lsr.l #8,D0             // IPL 
	move.l 8(A6),D6         // get argument 
	and.l #7,D6             // least significant three bits 
	lsl.l #8,D6             // move over to make mask 
	and.l #0x0000F8FF,D7    // zero out current IPL 
	or.l D6,D7              // place new IPL in SR 
	move.w D7,SR
	movem.l (SP),D6-D7
	lea 8(SP),SP
	unlk A6
	rts
	
_call_ikbdvec:

	lea -24(SP),SP
	movem.l D0-D2/A0-A2,(SP)
	move.l 28(SP),D0         // ikbd code 
	move.l 32(SP),A0         // iorec 
	and.l #0xFF,D0
	move.l 0x1132,A2         // ikbdvec 
	jsr (A2)
	movem.l (SP),D0-D2/A0-A2
	lea 24(SP),SP
	rts

_call_mousevec:

	lea -24(SP),SP
	movem.l D0-D2/A0-A2,(SP)
	move.l 28(SP),A0         // data 
	move.l 32(SP),A2
	move.l (A2),A2           // mousevec 
	jsr (A2)
	movem.l (SP),D0-D2/A0-A2
	lea 24(SP),SP
	rts
#endif

install_xbra:	// A0: handler, D0: vector, D1: ID 

	lea -28(SP),SP
	movem.l D1-D3/A0-A3,(SP)
	moveq #0,D3
	move.w D0,D3             // vector
	move.l A0,A3             // handler
	move.l D1,-(SP)
	move.w #3,-(SP)          // TT ram if possible
	move.l #18,-(SP)         // size
	move.w #0x44,-(SP)       // Mxalloc
	trap #1 
	addq.l #8,SP
	move.l (SP)+,D1
	tst.l D0
	beq.s .error_xbra
	move.l D0,A0
	move.l #0x58425241,(A0)+ // XBRA
	move.l D1,(A0)+
	clr.l (A0)+	
	move.w #0x4EF9,(A0)+     // JMP
	move.l A3,(A0)+          // handler
	lea -10(A0),A0

	cpusha BC

	move.l D3,A1
	move.l (A1),D0
	move.l D0,(A0)+          // old vector
	move.l A0,(A1)           // JMP, new vector
.error_xbra:
	tst.l D0
	movem.l (SP),D1-D3/A0-A3
	lea 28(SP),SP
	rts
#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || defined(CONFIG_USB_EHCI) || \
	defined(CONFIG_USB_ISP116X_HCD) || defined(CONFIG_USB_ARANYM_HCD)
#ifdef CONFIG_USB_STORAGE
_install_usb_stor:
	lea -32(SP),SP
	movem.l D1-D4/A0-A3,(SP)
	move.l 36(SP),D0         // dev_num
	cmp.l #PUN_DEV,D0
	bhi .no_pinfo            // error
	move.l 40(SP),D2         // part_type
	move.l D2,D1
	and.l #0xFFFFFF,D1       // ID
	// GEMDOS
	cmp.l #0x47454D,D1       // GEM up to 16M
	beq.s .partition_ok
	cmp.l #0x42474D,D1       // BGM over 16M
	beq.s .partition_ok
	cmp.l #0x524157,D1       // RAW
	beq.s .partition_ok
	// DOS 1:FAT12, 0xB/0xC:FAT32
	cmp.l #0x4,D2            // FAT16 up to 32M
	beq.s .partition_ok
	cmp.l #0x6,D2            // FAT16 over 32M
	beq.s .partition_ok
	tst.l ___mint		// Galvez: NOT MiNT? then go out
	beq .invalid_partition_type
	cmp.l #0xE,D2            // WIN95 FAT16
	beq .partition_ok
	cmp.l #0xB,D2		// FAT32
	beq.s .partition_ok
	cmp.l #0xC,D2		// FAT32
	bne .partition_ok
	cmp.l #0x81,D2		// MINIX
	bne .partition_ok
	cmp.l #0x83,D2		// EXT2/LNX
	bne .partition_ok
.partition_ok:
	move.l old_pun_ptr,A2	// Galvez: we need it to update hd driver pun struct
	move.l pun_ptr,D0
	bne.s .pinfo_ok
	move.w #3,-(SP)          // TT ram if possible
	move.l #pinfo_size,-(SP)
	move.w #0x44,-(SP)       // Mxalloc
	trap #1 
	addq.l #8,SP
	move.l D0,pun_ptr
	beq.s .no_pinfo
	move.l D0,A3
	clr.w pinfo_puns(A3)
	move.w #0x0300,D0
	move.w D0,pinfo_vernum(A3)
	move.w #0x4000,D0
	move.w D0,pinfo_maxsiz(A3)
	lea pinfo_pun(A3),A0
	moveq #-1,D0
	move.w D0,(A0)+          // drives A/B
	move.l D0,(A0)+
	move.l D0,(A0)+
	move.l D0,(A0)+
	move.l D0,(A0)+
	move.l D0,(A0)+
	move.l D0,(A0)+
	move.l D0,(A0)+
	move.w D0,(A0)
	lea pinfo_pstart(A3),A0
	lea pinfo_size(A3),A1
.clrpun:
	clr.w -(A1)
	cmp.l A0,A1
	bgt.s .clrpun
	move.l A3,D0             // pun_ptr 
.pinfo_ok:
	move.l D0,A3             // pun_ptr 
	moveq #2,D4              // drive C 
	move.l _drvbits,D0
.search_empty_drive_usb:
	btst D4,D0
	beq.s .drive_not_exist_usb
	addq.l #1,D4
	cmp.l #MAX_LOGICAL_DRIVE,D4
	bcs.s .search_empty_drive_usb
	bra .drive_full_usb          // all drives already used 
.no_pinfo:
	moveq #0,D0              // not installed 
	bra .end_usb_disk
.drive_not_exist_usb:
	move.w pinfo_puns(A3),D0
	addq.l #1,D0
	move.w D0,pinfo_puns(A3)
	moveq #0,D0
	bset #7,D0               // changed
	lea pinfo_flags(A3),A0
	move.l D0,(A0,D4.l*4)    // B15:swap, B7:change, B0:bootable
	lea pinfo_psize(A3),A0
	move.l 48(SP),D3         // part_size
	move.l 44(SP),D1         // part_offset
	move.l 40(SP),D2         // part_type
	move.l 36(SP),D0         // dev_num
	move.b D0,pinfo_devnum(A3,D4.l)
	move.l D2,pinfo_ptype(A3,D4.l*4)
	move.l D4,D2
	or.l #PUN_USB,D2
	move.b D2,pinfo_pun(A3,D4.l)
	cmp.l #15,D4			// Galvez: update AHDI pun struct:
	bgt .ahdi_part_num_limit	// Galvez: if logical part. > 16
	move.b D2,pinfo_pun(A2,D4.l)	// Galvez: don't update pun struct,
	move.w D0,-(SP)			// Galvez: to avoid corruption.
	move.w pinfo_puns(A2),D0	// Galvez: update hd driver pun stuct
	addq.l #1,D0			// Galvez: othewise MiNT only handles 16MB
	move.w D0,pinfo_puns(A2)	// Galvez: when not using XHDI
	move.w (SP)+,D0			// Galvez: see BLOCK_IO.c (MiNT sources)
.ahdi_part_num_limit:			
	move.l D3,(A0,D4.l*4)    // size
	move.l D1,pinfo_pstart(A3,D4.l*4)	
	move.l _dskbufp,A0 
	move.l A0,-(SP)          // buffer
	move.l #1,-(SP)          // blkcnt	
	move.l D1,-(SP)          // blknr
	move.l D0,-(SP)          // devnum
	jsr _usb_stor_read
	lea 16(SP),SP
	tst.l D0
	beq .end_usb_disk        // read error
	tst.l _usb_1st_disk_drive
	bne .usb_1st_drive_ok    // hdv vectors installed
	move.l D4,_usb_1st_disk_drive
	move.w SR,D0
	move.w D0,-(SP)
	or.l #0x700,D0           // mask interrupts
	move.w D0,SR
	move.l #0x5F555342,D1    // _USB
	lea det_hdv_bpb_usb(PC),A0
	move.w #hdv_bpb,D0
	bsr install_xbra
	move.l D0,old_hdv_bpb_usb
	lea det_hdv_rw_usb(PC),A0
	move.w #hdv_rw,D0
	bsr install_xbra	
	move.l D0,old_hdv_rw_usb
	lea det_hdv_mediach_usb(PC),A0
	move.w #hdv_mediach,D0
	bsr install_xbra
	move.l D0,old_hdv_mediach_usb
	move.l cookie,D0
	beq.s .no_cookie_jar
	move.l D0,A0
	move.l #0x58484449,D1    // XHDI
.find_cookie_jar:
	tst.l (A0)
	beq.s .cookie_slot_free
	cmp.l (A0),D1
	beq.s .cookie_found
	addq.l #8,A0
	bra.s .find_cookie_jar
.cookie_found:
	move.l 4(A0),D0
	move.l D0,old_xhdi
	lea xhdi(PC),A1
	clr.l -(SP)              	// XHGetVersion
	move.l D0,A0
	jsr (A0)
	addq.l #4,SP
	move.l D0,old_xhdi_version
	move.l A1,-(SP)			
	move.w #9,-(SP)			// Galvez: XHNewCookie
	jsr (A0)
	add.l #6,SP
	tst.l D0
	beq.s .no_cookie_jar
	move.l A1,4(A0)			// Galvez: Replace cookie "by-hand"			
	bra.s .no_cookie_jar
.cookie_slot_free:
	move.l 4(A0),12(A0)      // copy size
	lea xhdi(PC),A1
	move.l A1,(A0)+
	clr.l (A0)
	clr.l old_xhdi
	move.l #0x120,D0         //  protocol version
	move.l D0,old_xhdi_version
.no_cookie_jar:
	move.w (SP)+,D0
	move.w D0,SR		// restore interrupts
.usb_1st_drive_ok:
	move.l _dskbufp,A0       // boot sector 
	lea pinfo_bpb(A3),A1
	move.l D4,D2             // logical drive 
	asl.l #5,D2              // * 32 
	add.l D2,A1
	moveq #0,D2
	move.b 0xC(A0),D2
	asl.l #8,D2
	move.b 0xB(A0),D2        // BPS 
	move.w D2,(A1)           // sector size 
	moveq #0,D1
	move.b 0xD(A0),D1        // SPC 
	move.w D1,2(A1)          // cluster size in sectors 
	move.w D1,D0
	mulu D2,D0	
	move.w D0,4(A1)          // cluster size in bytes 
	moveq #0,D0
	move.b 0x12(A0),D0
	asl.l #8,D0
	move.b 0x11(A0),D0       // NDIRS 
	asl.l #5,D0              // * 32 

	divu D2,D0               // / sector size 

	move.w D0,6(A1)          // size directory in sectors 
	moveq #0,D2
	move.b 0x17(A0),D2
	asl.l #8,D2
	move.b 0x16(A0),D2       // SPF 
	move.w D2,8(A1)          // FAT size 
	moveq #0,D0
	move.b 0xF(A0),D0
	asl.l #8,D0
	move.b 0xE(A0),D0        // RES 
	move.l D0,D3
	add.l D2,D3              // + FAT size 
	move.w D3,10(A1)         // 1st sector of FAT2  
	moveq #0,D3
	move.b 0x10(A0),D3       // NFATS 
	mulu D2,D3               // * FAT size 
	add.l D0,D3              // + RES 
	moveq #0,D0
	move.w 6(A1),D0          // size directory in sectors 
	add.l D3,D0
	move.w D0,12(A1)         // 1st data sector 
	moveq #0,D2
	move.b 0x14(A0),D2
	asl.l #8,D2
	move.b 0x13(A0),D2       // NSECTS 
	bne.s .nsects_ok_usb
	lea pinfo_psize(A3),A2
	move.l (A2,D4.w*4),D2    // partition size in sectors 
	sub.l D0,D2              // - 1st data sector 
.nsects_ok_usb:
	divu D1,D2

	move.w D2,14(A1)         // total clusters 
	moveq #1,D0 
	move.w D0,16(A1)         // FAT 16 
	clr.w 18(A1)
	clr.l 20(A1)
	clr.l 24(A1)
	clr.l 28(A1)	
	move.l _drvbits,D0
	bset D4,D0
	move.l D0,_drvbits
	moveq #2,D0              // drive C 
	cmp.l D4,D0
	bne.s .no_set_drive_usb
	move.w D0,_bootdev
	move.w D0,-(SP)
	move.w #0xE,-(SP)        // Dsetdrv 
	trap #1
	addq.l #4,SP
.no_set_drive_usb:
	move.l 36(SP),D0         // devnum        
	movem.l 52(SP),A1/A2/A3  // vendor / revision / product
	move.l product_name,A0      // save product name pointer for XHDI
#if DEBUG_BIOS_LAYER	
	move.l D0, -(SP)
	move.b D4,D0
	jsr hex_byte		/* Galvez: DEBUG device */	
	move.l (SP)+,D0
#endif
	move.l A3,(A0,D4.l*4)
	bsr display_drive_usb
	pea message2b(PC)
	move.w #9,-(SP)
	trap #1                  // Cconws
	addq.l #6,SP
	moveq #0x41,D0           // A
	add.l D4,D0
	move.w D0,-(SP)
	move.w #2,-(SP)
	trap #1                  // Cconout
	addq.l #4,SP
	pea crlf(PC)
	move.w #9,-(SP)
	trap #1                  // Cconws
	addq.l #6,SP
	move.l D4,D0             // OK
	bra.s .end_usb_disk
.invalid_partition_type:
	pea error4(PC)
	bra.s .display_error_usb
.drive_full_usb:
	pea error2(PC)
.display_error_usb:
	move.l 36+4(SP),D0       // devnum 
        movem.l 52+4(SP),A1/A2/A3 // vendor / revision / product 
	bsr display_drive_usb
	move.w #0x2C,-(SP)
	move.w #2,-(SP)
	trap #1                  // Cconout 
	addq.l #4,SP
	move.w #0x20,-(SP)
	move.w #2,-(SP)
	trap #1                  // Cconout 
	addq.l #4,SP
	move.w #9,-(SP)
	trap #1                  // Cconws 
	addq.l #6,SP
	moveq #0,D0              // not installed 
.end_usb_disk:
	movem.l (SP),D1-D4/A0-A3
	lea 32(SP),SP
	rts

display_drive_usb:

	move.l A1,-(SP)
	moveq #0x30,D1
	add.l D1,D0	            // dev_num 
	move.w D0,-(SP)         
	lea blue(PC),A0
	bsr text_color
	pea message2(PC)         // USB-disk installed 
	move.w #9,-(SP)
	trap #1                  // Cconws 
	addq.l #6,SP
	move.w #2,-(SP)
	trap #1                  // Cconout 
	addq.l #4,SP
	move.w #0x2E,-(SP)
	move.w #2,-(SP)
	trap #1                  // Cconout 
	addq.l #4,SP
	move.w #0x30,-(SP)
	move.w #2,-(SP)
	trap #1                  // Cconout 
	addq.l #4,SP
	lea black(PC),A0
	bsr text_color
	move.w #0x20,-(SP)
	move.w #2,-(SP)
	trap #1                  // Cconout 
	addq.l #4,SP
	move.w #9,-(SP)
	trap #1                  // Cconws 
	addq.l #6,SP    
	move.w #0x20,-(SP)
	move.w #2,-(SP)
	trap #1                  // Cconout 
	addq.l #4,SP
        move.l A2,-(SP)
	move.w #9,-(SP)
	trap #1                  // Cconws 
	addq.l #6,SP             
	move.w #0x20,-(SP)
	move.w #2,-(SP)
	trap #1                  // Cconout 
	addq.l #4,SP
        move.l A3,-(SP)
	move.w #9,-(SP)
	trap #1                  // Cconws 
	addq.l #6,SP
	rts

det_hdv_bpb_usb:
	move.l A0,-(SP)
	move.l pun_ptr,A0
 	moveq #0,D0
	move.w 4+4(SP),D0        // drive
	cmp.l _usb_1st_disk_drive,D0
	bcs.s .dhbu2
	cmp.l #MAX_LOGICAL_DRIVE,D0
	bcc.s .dhbu2
	tst.b pinfo_pun(A0,D0.l)
	bpl.s .dhbu1
.dhbu2:
	move.l (SP)+,A0
	moveq #0,D0
	move.l old_hdv_bpb_usb,-(SP)
	rts
.dhbu1:
	move.l D1,-(SP)
	move.l pinfo_ptype(A0,D0.l*4),D1
	and.l #0xFFFFFF,D1
	cmp.l #0x524157,D1       // RAW
	beq.s .dhbu4
	cmp.l #0x81,D1       	 // MINIX
	beq.s .dhbu4
	cmp.l #0x83,D1       	 // EXT2/LNX
	bne.s .dhbu3
.dhbu4:
	move.l (SP)+,D1
	move.l (SP)+,A0
	moveq #0,D0
	rts	
.dhbu3:
	lea pinfo_bpb(A0),A0
	asl.l #5,D0              // * 32
	add.l A0,D0
#if DEBUG_BIOS_LAYER
	move.l D0,-(SP)
	moveq #0x30,D0
	jsr display_char
	moveq #0x78,D0
	jsr display_char
	move.l (SP),D0
	jsr hex_long
	moveq #0x20,D0
	jsr display_char
	lea debug4(PC),A0
	jsr display_string
	move.l (SP)+,D0
#endif
	move.l (SP)+,D1
	move.l (SP)+,A0
	rts

det_hdv_rw_usb:

	lea -28(SP),SP
	movem.l D1-D4/A0-A2,(SP)
#if DEBUG_BIOS_LAYER
	lea debug3(PC),A0
	jsr display_string	
	move.w 4+28(SP),D0       // rwflag
	jsr hex_word
	moveq #0x20,D0
	jsr display_char
	moveq #0x30,D0
	jsr display_char
	moveq #0x78,D0
	jsr display_char
	move.l 6+28(SP),D0       // buffer
	jsr hex_long
	moveq #0x20,D0
	jsr display_char
	moveq #0x30,D0
	jsr display_char
	moveq #0x78,D0
	jsr display_char
	move.w 10+28(SP),D0      // num sectors
	jsr hex_word
	moveq #0x20,D0
	jsr display_char
	moveq #0x30,D0
	jsr display_char
	moveq #0x78,D0
	jsr display_char
	move.w 12+28(SP),D0      // logical sector
	jsr hex_word
	moveq #0x20,D0
	jsr display_char
	moveq #0x30,D0
	jsr display_char
	moveq #0x78,D0
	jsr display_char
	move.w 16+28(SP),D0      // Galvez: logical sector (lrecno)
	jsr hex_long
	moveq #0x20,D0
	jsr display_char
	moveq #0x30,D0
	jsr display_char
	moveq #0x78,D0
	jsr display_char
	move.w 14+28(SP),D0      // drive
	jsr hex_word
	moveq #13,D0
	jsr display_char
	moveq #10,D0
	jsr display_char
#endif
	btst #3,5+28(SP)         // rwflag
	bne.s .dhru8             // physical
	move.l pun_ptr,A0
 	moveq #0,D0
	move.w 14+28(SP),D0      // drive
	cmp.l _usb_1st_disk_drive,D0
	bcs.s .dhru8
	cmp.l #MAX_LOGICAL_DRIVE,D0
	bcc.s .dhru8
	moveq #0,D4
	move.b pinfo_pun(A0,D0.l),D4
	bpl.s .dhru1             // valid
.dhru8:
	movem.l (SP),D1-D4/A0-A2
	lea 28(SP),SP
	moveq #0,D0
	move.l old_hdv_rw_usb,-(SP)
	rts
.dhru1:
	move.l D4,D2
	and.l #PUN_USB,D2
	beq.s .dhru8             // not USB
	and.l #PUN_DEV,D4
	moveq #0,D2
	move.w 12+28(SP),D2      // logical sector
	cmp.w #0xffff,D2         // Galvez: check recno <> -1
	bne.s .dhru6		
	move.l 16+28(SP),D2      // logical sector
.dhru6:
	tst.l D2
	bmi .dhru2               // negative logical sector
	move.l 6+28(SP),D1       // buffer
	beq .dhru4               // no buffer
	move.l pinfo_pstart(A0,D0.l*4),D3
	move.l pinfo_devnum(A0,D0.l),D4	 // devnum in the USB bus
	lea pinfo_bpb(A0),A0
	asl.l #5,D0              // * 32
	add.l D0,A0
	move.w 14(A0),D0         // total clusters
	mulu.w 2(A0),D0          // cluster size in sectors
	cmp.l D0,D2              // logical sector to hight
	bcc .dhru2
	moveq #0,D0
	move.w (A0),D0           // sector size
	lsr.l #8,D0
	lsr.l #1,D0              // / 512
	move.l D1,A0             // buffer
	move.w 10+28(SP),D1      // num sectors
	beq .dhru4               // no sectors
	mulu D0,D1
	mulu.l D0,D2
	add.l D3,D2              // start sector
	move.l D1,D3             // count
	btst #0,5+28(SP)         // rwflag
	beq.s .dhru7             // read
	// write
	tst.l D2                 // logical sector
	beq.s .dhru2             // root sector
	move.l A0,-(SP)          // buffer
	move.l D3,-(SP)          // blkcnt	
	move.l D2,-(SP)          // blknr
	move.l D4,-(SP)          // USB devnum 
	jsr _usb_stor_write
	bra.s .dhru5
.dhru2:
	moveq #-1,D0             // error
	bra.s .dhru3
.dhru4:
	moveq #0,D0              // OK
	bra.s .dhru3
.dhru7:
	move.l A0,-(SP)          // buffer
	move.l D3,-(SP)          // blkcnt	
	move.l D2,-(SP)          // blknr
	move.l D4,-(SP)          // USB devnum
	jsr _usb_stor_read
.dhru5:
	lea 16(SP),SP
	tst.l D0
	seq.b D0
	ext.w D0
	ext.l D0
	bclr #0,D0               // OK or device not responding -2
.dhru3:
	movem.l (SP),D1-D4/A0-A2
	lea 28(SP),SP
 	rts

det_hdv_mediach_usb:

	move.l A0,-(SP)
	move.l pun_ptr,A0
 	moveq #0,D0
	move.w 4+4(SP),D0        // drive
	cmp.l _usb_1st_disk_drive,D0
	bcs.s .dhmu2
	cmp.l #MAX_LOGICAL_DRIVE,D0
	bcc.s .dhmu2
	tst.b pinfo_pun(A0,D0.l)
	bpl.s .dhmu1
.dhmu2:
	move.l (SP)+,A0
	moveq #0,D0
	move.l old_hdv_mediach_usb,-(SP)
	rts
.dhmu1:
#if 0 // #if DEBUG_BIOS_LAYER
	move.l A0,-(SP)
	lea debug5(PC),A0
	jsr display_string
	move.l (SP)+,A0
#endif
	lea pinfo_flags(A0),A0
	add.l D0,A0
	add.l D0,A0
	bclr #7,1(A0)
	sne.b D0
	and.l #2,D0
	move.l (SP)+,A0
	rts

	// XHDI
	
	dc.l 0x27011992
	
xhdi:
	link A6,#0
	movem.l D1-A5,-(SP)
	moveq #0,D1
	move.w 8(A6),D1

	move.w D1,D0
#if DEBUG_BIOS_LAYER	
	move.w D0, -(SP)
	jsr hex_word		/* Galvez: DEBUG. XHDI function */
	move.w (SP)+,D0
#endif	
	moveq #-32,D0            // invalid function
	cmp.l #18,d1
	bcc.s .bad_xhdi
	move.w SR,D0             // supervisor only
	moveq #-1,d0             // error
	move.w tab_xhdi(PC,D1.l*2),D1
	jsr tab_xhdi(PC,D1.W)
	
.bad_xhdi:
	movem.l (SP)+,D1-A5
	unlk A6
	rts
#if DEBUG_BIOS_LAYER
debug:
	lea debug138(PC),A0
	jsr display_string
	rts
#endif
	
tab_xhdi:
	dc.w XHGetVersion-tab_xhdi    // 0
	dc.w XHInqTarget-tab_xhdi     // 1
	dc.w XHReserve-tab_xhdi       // 2
	dc.w XHLock-tab_xhdi          // 3
	dc.w XHStop-tab_xhdi          // 4
	dc.w XHEject-tab_xhdi         // 5
	dc.w XHDrvMap-tab_xhdi        // 6
	dc.w XHInqDev-tab_xhdi        // 7
	dc.w XHInqDriver-tab_xhdi     // 8
	dc.w XHNewCookie-tab_xhdi     // 9
	dc.w XHReadWrite-tab_xhdi     // 10
	dc.w XHInqTarget2-tab_xhdi    // 11
	dc.w XHInqDev2-tab_xhdi       // 12
	dc.w XHDriverSpecial-tab_xhdi // 13
	dc.w XHGetCapacity-tab_xhdi   // 14
	dc.w XHMediumChanged-tab_xhdi // 15
	dc.w XHMiNTInfo-tab_xhdi      // 16
	dc.w XHDOSLimits-tab_xhdi     // 17
	
XHGetVersion:
#if DEBUG_BIOS_LAYER
	move.l A0,-(SP)
	lea debug138(PC),A0
	jsr display_string
	move.l (SP)+,A0
#endif
	move.l #0x120,D0         //  protocol version
	move.l old_xhdi_version,D1
	cmp.l D1,D0
	bcs.s .xv1
	move.l D1,D0             // minimum version
.xv1:	
	rts
	
XHInqTarget:

	moveq #32,D2             // stringlen
	bra.s .xi1
	
XHInqTarget2:

#if DEBUG_BIOS_LAYER
	move.l A0,-(SP)
	lea debug133(PC),A0
	jsr display_string
	move.l (SP)+,A0
#endif
	move.w 26(A6),D2         // stringlen
.xi1:
	tst.w 12(A6)             // minor
	bne.s .xi2
	moveq #0,D0
	move.w 10(A6),D0         // major
	cmp.w #PUN_USB,D0
	bcs.s .xi2
	cmp.w #PUN_USB+PUN_DEV,D0
	bls.s .xi3
.xi2:
	tst.l old_xhdi
	beq.s .xi7
	moveq #-15,D0            // unknown device
	rts
.xi7:
	move.l old_xhdi,-(SP)
	rts
.xi3:
	tst.l 14(A6)
	beq.s .xi8
	move.l 14(A6),A0
	move.l #512,(A0)
.xi8:
	tst.l 18(A6)
	beq.s .xi9
	move.l 18(A6),A0	 // flags
	move.l #0x00000002,(A0)  // removable
.xi9:
	move.l 22(A6),D1         // product_name
	beq.s .xi6		 // no pointer
	move.l D1,A0

	and.b #PUN_DEV,D0
	move.l product_name,A1
	move.l (A1,D0.l*4),D0    // Galvez: D0 should be the bios drive number			
	beq.s .xi6               // no pointer
	move.l D0,A1
.xi5:
	move.b (A1)+,(A0)+
	beq.s .xi4
	subq.w #1,D2
	bpl.s .xi5		// Galvez: test
.xi4:
	clr.b -1(A0)
.xi6:
	moveq #0,D0
	rts

XHReserve:
XHLock:
XHStop:
XHEject:

	tst.l old_xhdi
	beq.s .xnu1
	moveq #0,D0
	rts
.xnu1:
	move.l old_xhdi,-(SP)
	rts
	
XHDrvMap:

	move.l _drvbits,D0
	rts

XHInqDev:

#if DEBUG_BIOS_LAYER
	lea debug134(PC),A0
	jsr display_string
#endif
	
	move.l pun_ptr,A0
 	moveq #0,D0
	move.w 10(A6),D0         // bios_device
	cmp.l _usb_1st_disk_drive,D0
	bcs.s .xd2
	cmp.l #MAX_LOGICAL_DRIVE,D0
	bcc.s .xd2
	moveq #0,D1
	move.b pinfo_pun(A0,D0.l),D1
	bpl.s .xd1
.xd2:	

	tst.l old_xhdi
	beq.s .xd3
	moveq #-46,D0            // invalid drive number
		
	rts
.xd3:
	move.l old_xhdi,-(SP)
	rts
.xd1:	
	move.l D1,D2
	and.l #PUN_USB+PUN_DEV,D2
	beq.s .xd2
	tst.l 12(A6)
	beq.s .xd4
	move.l 12(A6),A1         // major
	move.w D1,(A1)
.xd4:
	tst.l 16(A6)
	beq.s .xd5
	move.l 16(A6),A1         // minor
	clr.w (A1)
.xd5:
	tst.l 20(A6)
	beq.s .xd6
	move.l pinfo_pstart(A0,D0.l*4),D1
	move.l 20(A6),A1         // start_sector
	move.l D1,(A1)
.xd6:
	lea pinfo_bpb(A0),A0
	asl.l #5,D0              // * 32
	add.l A0,D0
	tst.l 24(A6)
	beq.s .xd7
	move.l 24(A6),A1         // bpb
	move.l D0,(A1)
.xd7:
	moveq #0,D0
	rts

XHInqDriver:

#if DEBUG_BIOS_LAYER
	lea debug135(PC),A0
	jsr display_string
#endif	
	move.l pun_ptr,A0
 	moveq #0,D0
	move.w 10(A6),D0         // bios_device
	cmp.l _usb_1st_disk_drive,D0
	bcs.s .xdr2
	cmp.l #MAX_LOGICAL_DRIVE,D0
	bcc.s .xdr2
	moveq #0,D1
	move.b pinfo_pun(A0,D0.l),D1
	bpl.s .xdr1
.xdr2:	
	tst.l old_xhdi
	beq.s .xdr8
	moveq #-46,D0            // invalid drive number
	rts
.xdr8:
	move.l old_xhdi,-(SP)
	rts
.xdr1:
	move.l D1,D0
	and.l #PUN_USB,D0
	beq.s .xdr2
	move.l 12(A6),D0         // name, 17 characters
	beq.s .xdr3
	move.l D0,A1
	lea message1(PC),A0
	moveq #17,D1
.xdr6:
	move.b (A0)+,D0
	beq.s .xdr7
	move.b D0,(A1)+
	subq.l #1,D1
	bpl.s .xdr6
.xdr7:
	clr.b (A1)
.xdr3:
	move.l 16(A6),D0         // version, 7 characters
	beq.s .xdr4
	move.l D0,A1
	move.b #0x34,(A1)+       // ??? TOS 4.04
	move.b #0x2E,(A1)+
	move.b #0x30,(A1)+
	move.b #0x34,(A1)+
	clr.b (A1)
.xdr4:
	move.l 20(A6),D0         // company, 17 characters
	beq.s .xdr5
	move.l D0,A1
	clr.b (A1)
.xdr5:
	move.l 24(A6),A1         // ahdi_version
	move.w pinfo_vernum(A0),(A1)
	move.l 28(A6),A1         // maxIPL
	moveq #5,D0
	move.w D0,(A1)	
	moveq #0,D0
	rts

XHReadWrite:                      // read / write physical sectors
#if DEBUG_BIOS_LAYER
	lea debug139(PC),A0
	jsr display_string
#endif	

	tst.w 12(A6)             // minor
	bne.s .xr4
	moveq #0,D4
	move.w 10(A6),D4         // major
	cmp.l #PUN_USB,D4
	bcs.s .xr4
	cmp.l #PUN_USB+PUN_DEV,D4
	bls.s .xr1
.xr4:
	tst.l old_xhdi
	beq.s .xr6
	moveq #-15,D0            // unknown device
	rts
.xr6:
	move.l old_xhdi,-(SP)
	rts
.xr1:
#if DEBUG_BIOS_LAYER
	lea debug132(PC),A0
	jsr display_string
	move.w 14(A6),D0         // rwflag
	jsr hex_word
	moveq #0x20,D0
	jsr display_char
	moveq #0x30,D0
	jsr display_char
	moveq #0x78,D0
	jsr display_char
	move.l 24(A6),D0         // buffer
	jsr hex_long
	moveq #0x20,D0
	jsr display_char
	moveq #0x30,D0
	jsr display_char
	moveq #0x78,D0
	jsr display_char
	move.w 20(A6),D0         // num sectors
	jsr hex_word
	moveq #0x20,D0
	jsr display_char
	moveq #0x30,D0
	jsr display_char
	moveq #0x78,D0
	jsr display_char
	move.l 16(A6),D0         // logical sector
	jsr hex_long
	moveq #13,D0
	jsr display_char
	moveq #10,D0
	jsr display_char	
#endif
	move.l 22(A6),A0         // buffer
	moveq #0,D3
	move.w 20(A6),D3         // count
	beq .xr2                 // no sectors
        move.l 16(A6),D2         // start sector
	btst #0,15(A6)           // rwflag
	beq.s .xr7               // read
	// write
	move.l A0,-(SP)          // buffer
	move.l D3,-(SP)          // blkcnt	
	move.l D2,-(SP)          // blknr
	move.l D4,D0             // major
	and.l #PUN_DEV,D0
	move.l pun_ptr,A0	
	move.b pinfo_devnum(A0,D0.l),D0 // devnum in the USB bus
	move.l D0,-(SP)          // USB devnum
	jsr _usb_stor_write
	bra.s .xr5
.xr2:
	moveq #-1,D0             // error
	bra.s .xr3
.xr7:
	move.l A0,-(SP)          // buffer
	move.l D3,-(SP)          // blkcnt	
	move.l D2,-(SP)          // blknr
	move.l D4,D0             // major
	and.l #PUN_DEV,D0
	move.l pun_ptr,A0	
	move.b pinfo_devnum(A0,D0.l),D0 // devnum in the USB bus
	move.l D0,-(SP)          // USB devnum
	jsr _usb_stor_read
.xr5:
	lea 16(SP),SP
	tst.l D0
	seq.b D0
	ext.w D0
	ext.l D0
	bclr #0,D0               // OK or device not responding -2
.xr3:
 	rts

XHInqDev2:

#if DEBUG_BIOS_LAYER
	lea debug136(PC),A0
	jsr display_string	// Galvez: changed bsr by jsr to avoid linker error
#endif
	move.l pun_ptr,A0
 	moveq #0,D0
	move.w 10(A6),D0         // bios_device
	cmp.l _usb_1st_disk_drive,D0
	bcs.s .xdd2
	cmp.l #MAX_LOGICAL_DRIVE,D0
	bcc.s .xdd2
	moveq #0,D1
	move.b pinfo_pun(A0,D0.l),D1
	bpl.s .xdd1
.xdd2:	
	tst.l old_xhdi
	beq.s .xdd4
	moveq #-46,D0            // invalid drive number
	rts
.xdd4:
	move.l old_xhdi,-(SP)
	rts
.xdd1:	
	move.w D1,D2
	and.b #PUN_USB+PUN_DEV,D2
	beq.s .xdd2
	tst.l 12(A6)
	beq.s .xdd5
	move.l 12(A6),A1         // major
	move.w D2,(A1)
.xdd5:
	tst.l 16(A6)
	beq.s .xdd6
	move.l 16(A6),A1         // minor
	clr.w (A1)
.xdd6:
	tst.l 20(A6)
	beq.s .xdd7
	move.l pinfo_pstart(A0,D0.l*4),D1
	move.l 20(A6),A1         // start_sector
	move.l D1,(A1)
.xdd7:
	tst.l 24(A6)
	beq.s .xdd8
	lea pinfo_bpb(A0),A2
	move.l D0,D1
	asl.l #5,D1              // * 32
	add.l A2,D1
	move.l 24(A6),A1         // bpb
	move.l D1,(A1)
.xdd8:
	tst.l 28(A6)
	beq.s .xdd9
	move.l 28(A6),A1         // blocks
	lea pinfo_psize(A0),A2
	move.l (A2,D0.l*4),(A1)
.xdd9:
	tst.l 32(A6)
	beq.s .xdd10
	move.l 32(A6),A1         // partid
	clr.l (A1)
	move.b pinfo_ptype+3(A0,D0.l*4),D1   
	move.w #0x0044,(A1)          		// NULL+ 'D'
	move.b D1,2(A1)
.xdd10:
	moveq #0,D0
	rts
 
XHDriverSpecial:
XHGetCapacity:
XHMediumChanged:
XHMiNTInfo:
XHNewCookie:

	tst.l old_xhdi
	beq.s .xn1
	moveq #-32,D0            //  invalid function number 
	rts
.xn1:
	move.l old_xhdi,-(SP)
	rts

XHDOSLimits:

	tst.l old_xhdi
	bne.s .xn1
#if DEBUG_BIOS_LAYER
	lea debug137(PC),A0
	jsr display_string
#endif
	moveq #0,D0
	move.w 10(A6),D0         // which
	cmp.l #XH_DL_SECSIZ,D0   // maximal sector size (BIOS level)
	bne.s .xl1
	move.l #0x4000,D0
	rts	
.xl1:
	cmp.l #XH_DL_MINFAT,D0   // minimal number of FATs
	bne.s .xl2
	moveq #1,D0
	rts
.xl2:
	cmp.l #XH_DL_MAXFAT,D0   // maximal number of FATs
	bne.s .xl3
	moveq #2,D0
	rts
.xl3:
	cmp.l #XH_DL_MINSPC,D0   // sectors per cluster minimal
	bne.s .xl4
	moveq #2,D0
	rts
.xl4:
	cmp.l #XH_DL_MAXSPC,D0   // sectors per cluster maximal
	bne.s .xl5
#ifdef COLDFIRE
	moveq #64,D0             // for this Coldfire version of BDOS, else 2
#else
	moveq #2,D0
#endif
	rts
.xl5:
	cmp.l #XH_DL_CLUSTS,D0   // maximal number of clusters of a 16 bit FAT
	bne.s .xl6
	move.l #0x8000,D0
	rts	
.xl6:
	cmp.l #XH_DL_MAXSEC,D0   // maximal number of sectors
	bne.S .xl7
#ifdef COLDFIRE
	move.l #0x200000,D0      // for this Coldfire version of BDOS, else 0x10000
#else
	move.l #0x10000,D0
#endif
	rts
.xl7:
	cmp.l #XH_DL_DRIVES,D0   // maximal number of BIOS drives supported by the DOS
	bne.s .xl8
	moveq #16,D0
	rts
.xl8:
	moveq #-32,D0            // invalid function number 
	rts

	


#endif /* CONFIG_USB_STORAGE */
#endif /* CONFIG_USB_UHCI || CONFIG_USB_OHCI || CONFIG_USB_EHCI || CONFIG_USB_ISP116X_HCD */


#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || defined(CONFIG_USB_EHCI) || \
	defined(CONFIG_USB_ISP116X_HCD) || defined(CONFIG_USB_ARANYM_HCD)
#ifdef CONFIG_USB_STORAGE
message1:	.ascii "TOS4.04 "
message2:	.asciz "USB  "
message2b:	.asciz ", disk installed in "
#endif
#endif

crlf:	.byte 13,10,0
error:	.asciz "No ram-disk installed, "
error1:	.ascii "no enough radeon memory"
	.byte 13,10,0
error2:	.ascii "all drives already used"
	.byte 13,10,0
error3:	.ascii "error disk name"
	.byte 13,10,0
error4:	.ascii "partition type not supported"
	.byte 13,10,0
blue:	.byte 0x1B,0x62,0x34,0
black:	.byte 0x1B,0x62,0x3F,0

	.align 2

#if defined(CONFIG_USB_UHCI) || defined(CONFIG_USB_OHCI) || defined(CONFIG_USB_EHCI) \
	|| defined(CONFIG_USB_ISP116X_HCD) || defined(CONFIG_USB_ARANYM_HCD)
#ifdef CONFIG_USB_STORAGE

	.lcomm pun_ptr_usb,4
	.lcomm user_sp,4

	.lcomm _usb_1st_disk_drive,4
	.lcomm old_hdv_bpb_usb,4
	.lcomm old_hdv_rw_usb,4
	.lcomm old_hdv_mediach_usb,4
	.lcomm old_xhdi,4
	.lcomm old_xhdi_version,4
	.lcomm product_name,4*(PUN_DEV+1)
#endif /* CONFIG_USB_STORAGE */
#endif /* CONFIG_USB_UHCI || CONFIG_USB_OHCI || CONFIG_USB_EHCI || CONFIG_USB_ISP116X_HCD */


