1
0
mirror of synced 2026-01-30 05:34:52 +00:00

Add LTEMM and SDPP drivers for XTMax (#27)

* Add gitattributes to handle line endings.

* Import the unmodified LTEMM source.

From https://www.lo-tech.co.uk/wiki/LTEMM.EXE.

* Add DOSBox and TASM for build.

* Add build script for LTEMM.

* Modity LTEMM driver for XTMax.

* Import the unmodified SDPP source.

From https://forum.vcfed.org/index.php?threads/sd-card-to-parallel-port-driver-for-msdos-ver-1-1.42008/.

* Add Borland C++ 3.1 (Minimal) for build.

* Add build script for SDPP.

* Modify SDPP driver for XTMax.

* Commit pre-built binaries for LTEMM and SDPP.

* Reorganize the drivers into a new folder.
This commit is contained in:
Matthieu Bucchianeri
2024-11-16 16:21:49 -08:00
committed by GitHub
parent fdf154bb00
commit 693d05b755
56 changed files with 7965 additions and 0 deletions

2
XTMax/Drivers/.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,155 @@
/* conio.h
Direct MSDOS console input/output.
Copyright (c) 1987, 1992 by Borland International
All Rights Reserved.
*/
#if !defined(__CONIO_H)
#define __CONIO_H
#if !defined(___DEFS_H)
#include <_defs.h>
#endif
#if !defined(_Windows)
#define _NOCURSOR 0
#define _SOLIDCURSOR 1
#define _NORMALCURSOR 2
struct text_info {
unsigned char winleft;
unsigned char wintop;
unsigned char winright;
unsigned char winbottom;
unsigned char attribute;
unsigned char normattr;
unsigned char currmode;
unsigned char screenheight;
unsigned char screenwidth;
unsigned char curx;
unsigned char cury;
};
enum text_modes { LASTMODE=-1, BW40=0, C40, BW80, C80, MONO=7, C4350=64 };
#if !defined(__COLORS)
#define __COLORS
enum COLORS {
BLACK, /* dark colors */
BLUE,
GREEN,
CYAN,
RED,
MAGENTA,
BROWN,
LIGHTGRAY,
DARKGRAY, /* light colors */
LIGHTBLUE,
LIGHTGREEN,
LIGHTCYAN,
LIGHTRED,
LIGHTMAGENTA,
YELLOW,
WHITE
};
#endif
#define BLINK 128 /* blink bit */
extern int _Cdecl directvideo;
extern int _Cdecl _wscroll;
#endif /* !_Windows */
#ifdef __cplusplus
extern "C" {
#endif
void _Cdecl clreol( void );
void _Cdecl clrscr( void );
void _Cdecl gotoxy( int __x, int __y );
int _Cdecl wherex( void );
int _Cdecl wherey( void );
int _Cdecl getch( void );
int _Cdecl getche( void );
int _Cdecl kbhit( void );
int _Cdecl putch( int __c );
#ifndef _PORT_DEFS
unsigned char _Cdecl inportb( unsigned __portid );
unsigned _Cdecl inport ( unsigned __portid );
int _Cdecl inp( unsigned __portid );
unsigned _Cdecl inpw( unsigned __portid );
void _Cdecl outportb( unsigned __portid, unsigned char __value );
void _Cdecl outport ( unsigned __portid, unsigned __value );
int _Cdecl outp( unsigned __portid, int __value );
unsigned _Cdecl outpw( unsigned __portid, unsigned __value );
#endif /* !_PORT_DEFS */
#if !defined(_Windows)
void _Cdecl delline( void );
int _Cdecl gettext( int __left, int __top,
int __right, int __bottom,
void *__destin);
void _Cdecl gettextinfo (struct text_info *__r );
void _Cdecl highvideo( void );
void _Cdecl insline( void );
void _Cdecl lowvideo( void );
int _Cdecl movetext( int __left, int __top,
int __right, int __bottom,
int __destleft, int __desttop );
void _Cdecl normvideo( void );
int _Cdecl puttext( int __left, int __top,
int __right, int __bottom,
void *__source );
void _Cdecl textattr( int __newattr );
void _Cdecl textbackground( int __newcolor );
void _Cdecl textcolor( int __newcolor );
void _Cdecl textmode( int __newmode );
void _Cdecl window( int __left, int __top, int __right, int __bottom);
void _Cdecl _setcursortype( int __cur_t );
char * _Cdecl cgets( char *__str );
int _Cdecl cprintf( const char *__format, ... );
int _Cdecl cputs( const char *__str );
int _Cdecl cscanf( const char *__format, ... );
char * _Cdecl getpass( const char *__prompt );
int _Cdecl ungetch( int __ch );
#endif /* !_Windows */
#ifndef _PORT_DEFS
#define _PORT_DEFS
/* These are in-line functions. These prototypes just clean up
some syntax checks and code generation.
*/
unsigned char _Cdecl __inportb__ (unsigned __portid);
unsigned _Cdecl __inportw__ (unsigned __portid);
unsigned char _Cdecl __outportb__(unsigned __portid, unsigned char __value);
unsigned _Cdecl __outportw__(unsigned __portid, unsigned __value);
#define inportb(__portid) __inportb__(__portid)
#define outportb(__portid, __value) ((void) __outportb__(__portid, __value))
#define inport(__portid) __inportw__(__portid)
#define outport(__portid, __value) ((void) __outportw__(__portid, __value))
/* MSC-compatible macros for port I/O */
#define inp(__portid) __inportb__ (__portid)
#define outp(__portid, __value) __outportb__(__portid, (unsigned char)__value)
#define inpw(__portid) __inportw__ (__portid)
#define outpw(__portid, __value) __outportw__(__portid, __value)
#endif /* _PORT_DEFS */
#ifdef __cplusplus
}
#endif
#endif /* __CONIO_H */

View File

@@ -0,0 +1,520 @@
/* dos.h
Defines structs, unions, macros, and functions for dealing
with MSDOS and the Intel iAPX86 microprocessor family.
Copyright (c) 1987, 1992 by Borland International
All Rights Reserved.
*/
#ifndef __DOS_H
#define __DOS_H
#if !defined(___DEFS_H)
#include <_defs.h>
#endif
#if !defined(_RTLDLL)
extern int _Cdecl errno;
extern int _Cdecl _doserrno;
#else
#ifdef __cplusplus
extern "C" {
#endif
int far * far _Cdecl __getErrno(void);
int far * far _Cdecl __getDOSErrno(void);
#ifdef __cplusplus
}
#endif
#define errno (*__getErrno())
#define _doserrno (*__getDOSErrno())
#endif
#ifndef __DLL__
/* Variables */
extern int const _Cdecl _8087;
extern int _Cdecl _argc;
extern char **_Cdecl _argv;
extern char **_Cdecl environ;
extern unsigned _Cdecl _psp;
extern unsigned _Cdecl _heaplen;
extern unsigned char _Cdecl _osmajor;
extern unsigned char _Cdecl _osminor;
extern unsigned _Cdecl _stklen;
extern unsigned _Cdecl _fpstklen;
extern unsigned _Cdecl _version;
extern unsigned _Cdecl _osversion; /* MSC name for _version */
#endif /* __DLL__*/
#define FA_NORMAL 0x00 /* Normal file, no attributes */
#define FA_RDONLY 0x01 /* Read only attribute */
#define FA_HIDDEN 0x02 /* Hidden file */
#define FA_SYSTEM 0x04 /* System file */
#define FA_LABEL 0x08 /* Volume label */
#define FA_DIREC 0x10 /* Directory */
#define FA_ARCH 0x20 /* Archive */
/* MSC names for file attributes */
#define _A_NORMAL 0x00 /* Normal file, no attributes */
#define _A_RDONLY 0x01 /* Read only attribute */
#define _A_HIDDEN 0x02 /* Hidden file */
#define _A_SYSTEM 0x04 /* System file */
#define _A_VOLID 0x08 /* Volume label */
#define _A_SUBDIR 0x10 /* Directory */
#define _A_ARCH 0x20 /* Archive */
#define NFDS 20 /* Maximum number of fds */
struct fcb {
char fcb_drive; /* 0 = default, 1 = A, 2 = B */
char fcb_name[8]; /* File name */
char fcb_ext[3]; /* File extension */
short fcb_curblk; /* Current block number */
short fcb_recsize; /* Logical record size in bytes */
long fcb_filsize; /* File size in bytes */
short fcb_date; /* Date file was last written */
char fcb_resv[10]; /* Reserved for DOS */
char fcb_currec; /* Current record in block */
long fcb_random; /* Random record number */
};
struct xfcb {
char xfcb_flag; /* Contains 0xff to indicate xfcb */
char xfcb_resv[5];/* Reserved for DOS */
char xfcb_attr; /* Search attribute */
struct fcb xfcb_fcb; /* The standard fcb */
};
struct COUNTRY {
int co_date;
char co_curr[5];
char co_thsep[2];
char co_desep[2];
char co_dtsep[2];
char co_tmsep[2];
char co_currstyle;
char co_digits;
char co_time;
long co_case;
char co_dasep[2];
char co_fill[10];
};
#if defined(__MSC) && !defined(__cplusplus)
struct DOSERROR {
int exterror;
char class;
char action;
char locus;
};
#else
struct DOSERROR {
int de_exterror;
char de_class;
char de_action;
char de_locus;
};
#endif /* __MSC and not C++ */
struct dfree {
unsigned df_avail;
unsigned df_total;
unsigned df_bsec;
unsigned df_sclus;
};
struct diskfree_t {
unsigned total_clusters;
unsigned avail_clusters;
unsigned sectors_per_cluster;
unsigned bytes_per_sector;
};
struct fatinfo {
char fi_sclus;
char fi_fatid;
unsigned fi_nclus;
int fi_bysec;
};
struct devhdr {
long dh_next; /* Next device pointer */
short dh_attr; /* Attributes */
unsigned short dh_strat; /* Driver strategy routine */
unsigned short dh_inter; /* Driver interrupt routine */
char dh_name[8]; /* Device name */
};
struct time {
unsigned char ti_min; /* Minutes */
unsigned char ti_hour; /* Hours */
unsigned char ti_hund; /* Hundredths of seconds */
unsigned char ti_sec; /* Seconds */
};
struct dostime_t {
unsigned char hour; /* Hours */
unsigned char minute; /* Minutes */
unsigned char second; /* Seconds */
unsigned char hsecond; /* Hundredths of seconds */
};
struct date {
int da_year; /* Year - 1980 */
char da_day; /* Day of the month */
char da_mon; /* Month (1 = Jan) */
};
struct dosdate_t {
unsigned char day; /* 1-31 */
unsigned char month; /* 1-12 */
unsigned int year; /* 1980 - 2099 */
unsigned char dayofweek;/* 0 - 6 (0=Sunday) */
};
#ifndef _REG_DEFS
#define _REG_DEFS
struct WORDREGS {
unsigned int ax, bx, cx, dx, si, di, cflag, flags;
};
struct BYTEREGS {
unsigned char al, ah, bl, bh, cl, ch, dl, dh;
};
union REGS {
struct WORDREGS x;
struct BYTEREGS h;
};
struct SREGS {
unsigned int es;
unsigned int cs;
unsigned int ss;
unsigned int ds;
};
struct REGPACK {
unsigned r_ax, r_bx, r_cx, r_dx;
unsigned r_bp, r_si, r_di, r_ds, r_es, r_flags;
};
#endif /* _REG_DEFS */
typedef struct {
char ds_drive; /* do not change */
char ds_pattern [13]; /* these fields, */
char ds_reserved [7]; /* Microsoft reserved */
char ds_attrib;
short ds_time;
short ds_date;
long ds_size;
char ds_nameZ [13]; /* result of the search, asciiz */
} dosSearchInfo; /* used with DOS functions 4E, 4F */
#ifndef _FFBLK_DEF
#define _FFBLK_DEF
struct ffblk {
char ff_reserved[21];
char ff_attrib;
unsigned ff_ftime;
unsigned ff_fdate;
long ff_fsize;
char ff_name[13];
};
#endif /* _FFBLK_DEF */
/* The MSC find_t structure corresponds exactly to the ffblk structure */
struct find_t {
char reserved[21]; /* Microsoft reserved - do not change */
char attrib; /* attribute byte for matched file */
unsigned wr_time; /* time of last write to file */
unsigned wr_date; /* date of last write to file */
long size; /* size of file */
char name[13]; /* asciiz name of matched file */
};
#ifdef __MSC
#define _find_t find_t
#endif
/* axret values for _hardresume() */
#define _HARDERR_IGNORE 0 /* ignore error */
#define _HARDERR_RETRY 1 /* retry the operation */
#define _HARDERR_ABORT 2 /* abort program */
#define _HARDERR_FAIL 3 /* fail the operation */
#define SEEK_CUR 1
#define SEEK_END 2
#define SEEK_SET 0
#ifdef __cplusplus
extern "C" {
#endif
#if !defined( _Windows )
int _Cdecl absread( int __drive, int __nsects, long __lsect,
void _FAR *__buffer );
int _Cdecl abswrite( int __drive, int __nsects, long __lsect,
void _FAR *__buffer );
int _Cdecl allocmem( unsigned __size, unsigned _FAR *__segp );
#endif
int _CType _FARFUNC bdos( int __dosfun, unsigned __dosdx, unsigned __dosal );
int _CType bdosptr( int __dosfun, void _FAR *__argument,
unsigned __dosal );
struct COUNTRY _FAR *_Cdecl country( int __xcode, struct COUNTRY _FAR *__cp);
void _Cdecl ctrlbrk( int _Cdecl( *handler )( void ));
#if !defined( _Windows )
void _CType delay( unsigned __milliseconds );
#endif
void _Cdecl _FARFUNC disable( void );
int _Cdecl _FARFUNC dosexterr( struct DOSERROR _FAR *__eblkp );
long _Cdecl _FARFUNC dostounix( struct date _FAR *__d, struct time _FAR *__t );
unsigned _Cdecl _dos_allocmem( unsigned __size, unsigned _FAR *__segp );
unsigned _Cdecl _dos_close ( int __fd );
unsigned _Cdecl _dos_commit( int __fd );
unsigned _Cdecl _dos_creat( const char _FAR *__pathP, unsigned __attr,
int _FAR *__fd );
unsigned _Cdecl _dos_creatnew( const char _FAR *__pathP, unsigned __attr,
int _FAR *__fd );
unsigned _Cdecl _dos_findfirst( const char _FAR *__path,
unsigned __attrib,
struct find_t _FAR *__finfo );
unsigned _Cdecl _dos_findnext( struct find_t _FAR *__finfo );
unsigned _Cdecl _dos_freemem( unsigned __segx );
void _Cdecl _dos_getdate( struct dosdate_t _FAR *__datep );
unsigned _Cdecl _dos_getdiskfree( unsigned __drive,
struct diskfree_t _FAR *__dtable);
void _Cdecl _dos_getdrive( unsigned _FAR *__drive );
unsigned _Cdecl _dos_getfileattr( const char _FAR *__filename,
unsigned _FAR *__attrib );
unsigned _Cdecl _dos_getftime( int __fd, unsigned _FAR *__date,
unsigned _FAR *__time );
void _Cdecl _dos_gettime( struct dostime_t _FAR *__timep );
void _Cdecl _dos_keep(unsigned char __status, unsigned __size);
unsigned _Cdecl _dos_open( const char _FAR *__pathP, unsigned __oflag,
int _FAR *__fd );
unsigned _Cdecl _dos_read( int __fd, void far *__buf, unsigned __len,
unsigned _FAR *__nread );
unsigned _Cdecl _dos_setblock( unsigned __size, unsigned __segx,
unsigned _FAR *__maxp );
unsigned _Cdecl _dos_setdate( struct dosdate_t _FAR *__datep );
void _Cdecl _dos_setdrive( unsigned __drive, unsigned _FAR *__ndrives );
unsigned _Cdecl _dos_setfileattr( const char _FAR *__filename,
unsigned _FAR __attrib);
unsigned _Cdecl _dos_setftime( int __fd, unsigned __date, unsigned __time );
unsigned _Cdecl _dos_settime( struct dostime_t _FAR *__timep );
unsigned _Cdecl _dos_write( int __fd, const void far *__buf, unsigned __len,
unsigned _FAR *__nread );
void __emit__( unsigned char __byte, ...);
void _Cdecl _FARFUNC enable( void );
#if !defined( _Windows )
int _Cdecl freemem( unsigned __segx );
#endif
int _Cdecl getcbrk( void );
void _CType getdate( struct date _FAR *__datep );
void _Cdecl getdfree( unsigned char __drive,
struct dfree _FAR *__dtable );
int _Cdecl _getdrive( void );
void _Cdecl getfat( unsigned char __drive,
struct fatinfo _FAR *__dtable );
void _Cdecl getfatd( struct fatinfo _FAR *__dtable );
unsigned _Cdecl getpsp( void );
int _Cdecl getswitchar( void );
void _CType gettime( struct time _FAR *__timep );
int _Cdecl getverify( void );
#if !defined( _Windows )
#ifdef __cplusplus
void _Cdecl _harderr( void _Cdecl (far *__fptr)( unsigned __deverr,
unsigned __doserr, unsigned far *__hdr) );
#else
void _Cdecl _harderr( void _Cdecl (far *__fptr)( ) );
#endif
void _Cdecl _hardresume( int __axret );
void _Cdecl _hardretn( int __retn );
#ifdef __cplusplus
void _CType harderr( int _Cdecl( *__handler )( int __errval, int __ax,
int __bp, int __si) );
#else
void _CType harderr( int _Cdecl( *__handler )( ) );
#endif
void _CType hardresume( int __axret );
void _CType hardretn( int __retn );
#endif
#ifndef _PORT_DEFS
unsigned _Cdecl inport ( unsigned __portid );
unsigned char _Cdecl inportb( unsigned __portid );
unsigned _Cdecl inpw ( unsigned __portid );
int _Cdecl inp ( unsigned __portid );
#endif
int _Cdecl int86( int __intno,
union REGS _FAR *__inregs,
union REGS _FAR *__outregs );
int _Cdecl int86x( int __intno,
union REGS _FAR *__inregs,
union REGS _FAR *__outregs,
struct SREGS _FAR *__segregs );
int _Cdecl intdos( union REGS _FAR *__inregs,
union REGS _FAR *__outregs );
int _Cdecl intdosx( union REGS _FAR *__inregs,
union REGS _FAR *__outregs,
struct SREGS _FAR *__segregs );
void _Cdecl intr( int __intno, struct REGPACK _FAR *__preg );
#if !defined( _Windows )
void _Cdecl keep( unsigned char __status, unsigned __size );
void _Cdecl nosound( void );
#endif
#ifndef _PORT_DEFS
void _Cdecl outport ( unsigned __portid, unsigned __value );
void _Cdecl outportb( unsigned __portid, unsigned char __value );
unsigned _Cdecl outpw ( unsigned __portid, unsigned __value );
int _Cdecl outp ( unsigned __portid, int __value );
#endif
char _FAR * _Cdecl parsfnm( const char _FAR *__cmdline,
struct fcb _FAR *__fcb, int __opt );
int _Cdecl peek( unsigned __segment, unsigned __offset );
char _Cdecl peekb( unsigned __segment, unsigned __offset );
void _Cdecl poke( unsigned __segment, unsigned __offset, int __value);
void _Cdecl pokeb( unsigned __segment,
unsigned __offset, char __value );
#if !defined( _Windows )
int _Cdecl randbrd( struct fcb _FAR *__fcb, int __rcnt );
int _Cdecl randbwr( struct fcb _FAR *__fcb, int __rcnt );
#endif
void _Cdecl segread( struct SREGS _FAR *__segp );
#if !defined( _Windows )
int _Cdecl setblock( unsigned __segx, unsigned __newsize );
#endif
int _Cdecl setcbrk( int __cbrkvalue );
void _Cdecl setdate( struct date _FAR *__datep );
void _Cdecl setswitchar( char __ch );
void _Cdecl settime( struct time _FAR *__timep );
void _Cdecl setverify( int __value );
#if !defined( _Windows )
void _Cdecl sleep( unsigned __seconds );
void _Cdecl sound( unsigned __frequency );
#endif
void _Cdecl _FARFUNC unixtodos( long __time, struct date _FAR *__d,
struct time _FAR *__t );
int _CType unlink( const char _FAR *__path );
/* These are in-line functions. These prototypes just clean up
some syntax checks and code generation.
*/
void _Cdecl __cli__( void );
void _Cdecl __sti__( void );
void _Cdecl __int__( int __interruptnum );
#define disable( ) __emit__( (char )( 0xfa ) )
#define _disable( ) __emit__( (char )( 0xfa ) ) /* MSC name */
#define enable( ) __emit__( (char )( 0xfb ) )
#define _enable( ) __emit__( (char )( 0xfb ) ) /* MSC name */
#define geninterrupt( i ) __int__( i ) /* Interrupt instruction */
#ifndef _PORT_DEFS
#define _PORT_DEFS
unsigned char _Cdecl __inportb__ ( unsigned __portid );
unsigned _Cdecl __inportw__ ( unsigned __portid );
unsigned char _Cdecl __outportb__( unsigned __portid, unsigned char __value );
unsigned _Cdecl __outportw__( unsigned __portid, unsigned __value );
#define inportb(__portid) __inportb__(__portid)
#define outportb(__portid, __value) ((void) __outportb__(__portid, __value))
#define inport(__portid) __inportw__(__portid)
#define outport(__portid, __value) ((void) __outportw__(__portid, __value))
/* MSC-compatible macros for port I/O */
#define inp(__portid) __inportb__ (__portid)
#define outp(__portid, __value) __outportb__(__portid, (unsigned char)__value)
#define inpw(__portid) __inportw__ (__portid)
#define outpw(__portid, __value) __outportw__(__portid, __value)
#endif /* _PORT_DEFS */
#if !__STDC__
extern unsigned _Cdecl _ovrbuffer;
int cdecl far _OvrInitEms( unsigned __emsHandle, unsigned __emsFirst,
unsigned __emsPages );
int cdecl far _OvrInitExt( unsigned long __extStart,
unsigned long __extLength );
char far *cdecl getdta( void );
void cdecl setdta( char far *__dta );
#define MK_FP( seg,ofs )( (void _seg * )( seg ) +( void near * )( ofs ))
#define FP_SEG( fp )( (unsigned )( void _seg * )( void far * )( fp ))
#define FP_OFF( fp )( (unsigned )( fp ))
#ifdef __cplusplus
void _Cdecl _chain_intr ( void interrupt (far *__target)( ... ));
void interrupt( far * _Cdecl _dos_getvect( unsigned __interruptno ))( ... );
void interrupt( far * _CType getvect( int __interruptno ))( ... );
void _Cdecl _dos_setvect( unsigned __interruptno,
void interrupt( far *__isr )( ... ));
void _CType setvect( int __interruptno,
void interrupt( far *__isr )( ... ));
int inline _Cdecl peek( unsigned __segment, unsigned __offset )
{ return( *( (int far* )MK_FP( __segment, __offset )) ); }
char inline _Cdecl peekb( unsigned __segment, unsigned __offset )
{ return( *( (char far* )MK_FP( __segment, __offset )) ); }
void inline _Cdecl poke( unsigned __segment, unsigned __offset, int __value )
{( *( (int far* )MK_FP( __segment, __offset )) = __value ); }
void inline _Cdecl pokeb( unsigned __segment, unsigned __offset, char __value )
{( *( (char far* )MK_FP( __segment, __offset )) = __value ); }
#else
void _Cdecl _chain_intr ( void interrupt (far *__target)( ));
void interrupt( far * _Cdecl _dos_getvect( unsigned __interruptno ))( );
void interrupt( far * _CType getvect( int __interruptno ))( );
void _Cdecl _dos_setvect( unsigned __interruptno,
void interrupt( far *__isr )( ));
void _CType setvect( int __interruptno,
void interrupt( far *__isr )( ) );
#define peek( a,b )( *( (int far* )MK_FP( (a ),( b )) ))
#define peekb( a,b )( *( (char far* )MK_FP( (a ),( b )) ))
#define poke( a,b,c )( *( (int far* )MK_FP( (a ),( b )) ) =( int )( c ))
#define pokeb( a,b,c )( *( (char far* )MK_FP( (a ),( b )) ) =( char )( c ))
#endif /* __cplusplus */
#endif /* !__STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* __DOS_H */


View File

@@ -0,0 +1,91 @@
/* mem.h
Memory manipulation functions
Copyright (c) 1987, 1992 by Borland International
All Rights Reserved.
*/
#if !defined(__MEM_H)
#define __MEM_H
#if !defined(___DEFS_H)
#include <_defs.h>
#endif
#ifndef NULL
#include <_null.h>
#endif
#ifndef _STDDEF
#define _STDDEF
#ifndef _PTRDIFF_T
#define _PTRDIFF_T
#if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__)
typedef long ptrdiff_t;
#else
typedef int ptrdiff_t;
#endif
#endif
#ifndef _SIZE_T
#define _SIZE_T
typedef unsigned size_t;
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
void _FAR * _FARFUNC _Cdecl memccpy(void _FAR *__dest, const void _FAR *__src,
int __c, size_t __n);
void _FAR * _FARFUNC _Cdecl memchr(const void _FAR *__s, int __c, size_t __n);
int _FARFUNC _Cdecl memcmp(const void _FAR *__s1, const void _FAR *__s2,
size_t __n);
void _FAR * _FARFUNC _Cdecl memcpy(void _FAR *__dest, const void _FAR *__src,
size_t __n);
int _FARFUNC _Cdecl memicmp(const void _FAR *__s1, const void _FAR *__s2,
size_t __n);
void _FAR * _CType _FARFUNC memmove(void _FAR *__dest, const void _FAR *__src,
size_t __n);
void _FAR * _CType _FARFUNC memset(void _FAR *__s, int __c, size_t __n);
void _FARFUNC _Cdecl movedata(unsigned __srcseg, unsigned __srcoff,
unsigned __dstseg,unsigned __dstoff, size_t __n);
void _FARFUNC _Cdecl movmem(const void _FAR *__src, void _FAR *__dest,
unsigned __length);
void _FARFUNC _Cdecl setmem(void _FAR *__dest,unsigned __length, char __value);
#if !__STDC__
void far * _FARCALL cdecl _fmemccpy(void far *__dest, const void far *__src,
int __c, size_t __n);
void far * _FARCALL cdecl _fmemchr(const void far *__s, int __c, size_t __n);
int _FARCALL cdecl _fmemcmp(const void far *__s1, const void far *__s2,
size_t __n);
void far * _FARCALL cdecl _fmemcpy(void far *__dest, const void far *__src,
size_t __n);
int _FARCALL cdecl _fmemicmp(const void far *__s1, const void far *__s2,
size_t __n);
void far * _FARCALL cdecl _fmemmove(void far *__dest, const void far *__src,
size_t __n);
void far * _FARCALL cdecl _fmemset(void far *__s, int __c, size_t __n);
void _FARCALL cdecl _fmovmem(const void far *__src, void far *__dest,
unsigned __length);
void _FARCALL cdecl _fsetmem(void far *__dest, unsigned __length,
char __value);
#endif
#if !defined(__STRING_H)
/* Intrinsic functions */
void _FAR * _Cdecl _FARFUNC __memchr__ (const void _FAR *__s, int __c, size_t __n);
int _Cdecl _FARFUNC __memcmp__(const void _FAR *__s1,
const void _FAR *__s2, size_t __n);
void _FAR * _Cdecl _FARFUNC __memcpy__(void _FAR *__dest, const void _FAR *__src,
size_t __n);
void _FAR * _CType _FARFUNC __memset__(void _FAR *__s, int __c, size_t __n);
#endif
#ifdef __cplusplus
}
#endif
#endif /* __MEM_H */

View File

@@ -0,0 +1,38 @@
/* stdarg.h
Definitions for accessing parameters in functions that accept
a variable number of arguments.
Copyright (c) 1987, 1992 by Borland International
All Rights Reserved.
*/
#ifndef __STDARG_H
#define __STDARG_H
#ifdef __VARARGS_H
#error Can't include both STDARG.H and VARARGS.H
#endif
#if !defined(___DEFS_H)
#include <_defs.h>
#endif
typedef void _FAR *va_list;
#define __size(x) ((sizeof(x)+sizeof(int)-1) & ~(sizeof(int)-1))
#if defined(__cplusplus) && !defined(__STDC__)
#define va_start(ap, parmN) (ap = ...)
#else
#define va_start(ap, parmN) ((void)((ap) = (va_list)((char _FAR *)(&parmN)+__size(parmN))))
#endif
#define va_arg(ap, type) (*(type _FAR *)(((*(char _FAR *_FAR *)&(ap))+=__size(type))-(__size(type))))
#define va_end(ap) ((void)0)
#if !__STDC__
#define _va_ptr (...)
#endif
#endif

View File

@@ -0,0 +1,248 @@
/* stdio.h
Definitions for stream input/output.
Copyright (c) 1987, 1992 by Borland International
All Rights Reserved.
*/
#ifndef __STDIO_H
#define __STDIO_H
#if !defined(___DEFS_H)
#include <_defs.h>
#endif
#if !defined(___NFILE_H)
#include <_nfile.h>
#endif
#ifndef NULL
#include <_null.h>
#endif
#ifndef _SIZE_T
#define _SIZE_T
typedef unsigned size_t;
#endif
/* Definition of the file position type
*/
typedef long fpos_t;
/* Definition of the control structure for streams
*/
typedef struct {
int level; /* fill/empty level of buffer */
unsigned flags; /* File status flags */
char fd; /* File descriptor */
unsigned char hold; /* Ungetc char if no buffer */
int bsize; /* Buffer size */
unsigned char _FAR *buffer; /* Data transfer buffer */
unsigned char _FAR *curp; /* Current active pointer */
unsigned istemp; /* Temporary file indicator */
short token; /* Used for validity checking */
} FILE; /* This is the FILE object */
/* Bufferisation type to be used as 3rd argument for "setvbuf" function
*/
#define _IOFBF 0
#define _IOLBF 1
#define _IONBF 2
/* "flags" bits definitions
*/
#define _F_RDWR 0x0003 /* Read/write flag */
#define _F_READ 0x0001 /* Read only file */
#define _F_WRIT 0x0002 /* Write only file */
#define _F_BUF 0x0004 /* Malloc'ed Buffer data */
#define _F_LBUF 0x0008 /* line-buffered file */
#define _F_ERR 0x0010 /* Error indicator */
#define _F_EOF 0x0020 /* EOF indicator */
#define _F_BIN 0x0040 /* Binary file indicator */
#define _F_IN 0x0080 /* Data is incoming */
#define _F_OUT 0x0100 /* Data is outgoing */
#define _F_TERM 0x0200 /* File is a terminal */
/* End-of-file constant definition
*/
#define EOF (-1) /* End of file indicator */
/* Number of files that can be open simultaneously
*/
#if __STDC__
#define FOPEN_MAX (_NFILE_ - 2) /* (_NFILE_ - stdaux & stdprn) */
#else
#define FOPEN_MAX (_NFILE_) /* Able to have 20 files */
#define SYS_OPEN (_NFILE_)
#endif
#define FILENAME_MAX 80
/* Default buffer size use by "setbuf" function
*/
#define BUFSIZ 512 /* Buffer size for stdio */
/* Size of an arry large enough to hold a temporary file name string
*/
#define L_ctermid 5 /* CON: plus null byte */
#define P_tmpdir "" /* temporary directory */
#define L_tmpnam 13 /* tmpnam buffer size */
/* Constants to be used as 3rd argument for "fseek" function
*/
#define SEEK_CUR 1
#define SEEK_END 2
#define SEEK_SET 0
/* Number of unique file names that shall be generated by "tmpnam" function
*/
#define TMP_MAX 0xFFFF
/* Standard I/O predefined streams
*/
#if !defined( _RTLDLL )
extern FILE _Cdecl _streams[];
extern unsigned _Cdecl _nfile;
#define stdin (&_streams[0])
#define stdout (&_streams[1])
#define stderr (&_streams[2])
#if !__STDC__
#define stdaux (&_streams[3])
#define stdprn (&_streams[4])
#endif
#else
#ifdef __cplusplus
extern "C" {
#endif
FILE far * far __getStream(int);
#ifdef __cplusplus
}
#endif
#define stdin __getStream(0)
#define stdout __getStream(1)
#define stderr __getStream(2)
#define stdaux __getStream(3)
#define stdprn __getStream(4)
#endif
#ifdef __cplusplus
extern "C" {
#endif
void _Cdecl clearerr(FILE _FAR *__stream);
int _Cdecl _FARFUNC fclose(FILE _FAR *__stream);
int _Cdecl _FARFUNC fflush(FILE _FAR *__stream);
int _Cdecl _FARFUNC fgetc(FILE _FAR *__stream);
int _Cdecl fgetpos(FILE _FAR *__stream, fpos_t _FAR *__pos);
char _FAR *_Cdecl _FARFUNC fgets(char _FAR *__s, int __n, FILE _FAR *__stream);
FILE _FAR *_Cdecl _FARFUNC fopen(const char _FAR *__path, const char _FAR *__mode);
int _Cdecl _FARFUNC fprintf(FILE _FAR *__stream, const char _FAR *__format, ...);
int _Cdecl _FARFUNC fputc(int __c, FILE _FAR *__stream);
int _Cdecl _FARFUNC fputs(const char _FAR *__s, FILE _FAR *__stream);
size_t _Cdecl _FARFUNC fread(void _FAR *__ptr, size_t __size, size_t __n,
FILE _FAR *__stream);
FILE _FAR *_Cdecl _FARFUNC freopen(const char _FAR *__path, const char _FAR *__mode,
FILE _FAR *__stream);
int _Cdecl _FARFUNC fscanf(FILE _FAR *__stream, const char _FAR *__format, ...);
int _Cdecl _FARFUNC fseek(FILE _FAR *__stream, long __offset, int __whence);
int _Cdecl fsetpos(FILE _FAR *__stream, const fpos_t _FAR *__pos);
long _Cdecl _FARFUNC ftell(FILE _FAR *__stream);
size_t _Cdecl _FARFUNC fwrite(const void _FAR *__ptr, size_t __size, size_t __n,
FILE _FAR *__stream);
char _FAR *_Cdecl gets(char _FAR *__s);
void _Cdecl perror(const char _FAR *__s);
int _Cdecl printf(const char _FAR *__format, ...);
int _Cdecl puts(const char _FAR *__s);
int _CType remove(const char _FAR *__path);
int _CType _FARFUNC rename(const char _FAR *__oldname,const char _FAR *__newname);
void _Cdecl _FARFUNC rewind(FILE _FAR *__stream);
int _Cdecl scanf(const char _FAR *__format, ...);
void _Cdecl setbuf(FILE _FAR *__stream, char _FAR *__buf);
int _Cdecl _FARFUNC setvbuf(FILE _FAR *__stream, char _FAR *__buf,
int __type, size_t __size);
int _Cdecl _FARFUNC sprintf(char _FAR *__buffer, const char _FAR *__format, ...);
int _Cdecl _FARFUNC sscanf(const char _FAR *__buffer,
const char _FAR *__format, ...);
char _FAR *_Cdecl _FARFUNC strerror(int __errnum);
FILE _FAR *_Cdecl _FARFUNC tmpfile(void);
char _FAR *_Cdecl _FARFUNC tmpnam(char _FAR *__s);
int _Cdecl _FARFUNC ungetc(int __c, FILE _FAR *__stream);
int _Cdecl _FARFUNC vfprintf(FILE _FAR *__stream, const char _FAR *__format,
void _FAR *__arglist);
int _Cdecl _FARFUNC vfscanf(FILE _FAR *__stream, const char _FAR *__format,
void _FAR *__arglist);
int _CType vprintf(const char _FAR *__format, void _FAR *__arglist);
int _Cdecl vscanf(const char _FAR *__format, void _FAR *__arglist);
int _Cdecl _FARFUNC vsprintf(char _FAR *__buffer, const char _FAR *__format,
void _FAR *__arglist);
int _Cdecl _FARFUNC vsscanf(const char _FAR *__buffer, const char _FAR *__format,
void _FAR *__arglist);
int _CType unlink(const char _FAR *__path);
int _Cdecl getc(FILE _FAR *__fp);
int _Cdecl getchar(void);
int _Cdecl putchar(const int __c);
int _Cdecl putc(const int __c, FILE _FAR *__fp);
int _Cdecl feof(FILE _FAR *__fp);
int _Cdecl ferror(FILE _FAR *__fp);
#if !__STDC__
int _Cdecl _FARFUNC fcloseall(void);
FILE _FAR *_Cdecl _FARFUNC fdopen(int __handle, char _FAR *__type);
int _Cdecl _FARFUNC fgetchar(void);
int _Cdecl _FARFUNC flushall(void);
int _Cdecl _FARFUNC fputchar(int __c);
FILE _FAR * _Cdecl _fsopen (const char _FAR *__path, const char _FAR *__mode,
int __shflag);
int _Cdecl getw(FILE _FAR *__stream);
int _Cdecl putw(int __w, FILE _FAR *__stream);
int _Cdecl rmtmp(void);
char _FAR * _Cdecl _FARFUNC _strerror(const char _FAR *__s);
char _FAR * _Cdecl _FARFUNC tempnam(char _FAR *__dir, char _FAR *__pfx);
#define fileno(f) ((f)->fd)
#ifdef __MSC
#define _fileno(f) fileno(f)
#endif
#endif /* !__STDC__ */
int _Cdecl _FARFUNC _fgetc(FILE _FAR *__stream); /* used by getc() macro */
int _Cdecl _FARFUNC _fputc(char __c, FILE _FAR *__stream); /* used by putc() macro */
void _Cdecl _InitEasyWin(void); /* Initialization call for Easy Windows */
#ifdef __cplusplus
}
#endif
/* The following macros provide for common functions */
#define ferror(f) ((f)->flags & _F_ERR)
#define feof(f) ((f)->flags & _F_EOF)
#define getc(f) \
((--((f)->level) >= 0) ? (unsigned char)(*(f)->curp++) : \
_fgetc (f))
#define putc(c,f) \
((++((f)->level) < 0) ? (unsigned char)(*(f)->curp++=(c)) : \
_fputc ((c),f))
#define getchar() getc(stdin)
#define putchar(c) putc((c), stdout)
#define ungetc(c,f) ungetc((c),f) /* traditionally a macro */
#endif

View File

@@ -0,0 +1,104 @@
/* _defs.h
Common definitions for pointer size and calling conventions.
Copyright (c) 1991, 1992 by Borland International
All Rights Reserved.
*/
#if !defined(___DEFS_H)
#define ___DEFS_H
#if __STDC__
# define _Cdecl
#else
# define _Cdecl cdecl
#endif
#ifndef __PAS__
# define _CType _Cdecl
#else
# define _CType pascal
#endif
#ifdef __MSC
# define _emit db
# define __far _far
# define __near _near
# define __cdecl _cdecl
# define __pascal _pascal
# define __export _export
# ifdef __SMALL__
# define _M_I86SM
# endif
# ifdef __COMPACT__
# define _M_I86CM
# endif
# ifdef __MEDIUM__
# define _M_I86MM
# endif
# ifdef __LARGE__
# define _M_I86LM
# endif
# ifndef _Windows
# define _DOS
# else
# define _WINDOWS
# endif
#endif
#if defined(__STDC__)
# define _FAR
# define _FARFUNC
# define _CLASSTYPE
#else
# if defined(_BUILDRTLDLL)
# define _FARFUNC _export
# elif defined(_RTLDLL)
# define _FARFUNC far
# else
# define _FARFUNC
# endif
# if defined(__DLL__)
# if defined(_RTLDLL) || defined(_CLASSDLL)
# define _CLASSTYPE _export
# else
# define _CLASSTYPE far
# endif
# define _FAR far
# elif defined(_RTLDLL) || defined(_CLASSDLL)
# define _CLASSTYPE huge
# define _FAR far
# else
# define _FAR
# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
# define _CLASSTYPE near
# elif defined(__COMPACT__) || defined(__LARGE__)
# define _CLASSTYPE far
# else
# define _CLASSTYPE huge
# endif
# endif
#endif /* __STDC__ */
#if defined(_BUILDRTLDLL)
# define _FARCALL _export
#else
# define _FARCALL far
#endif
#if defined( __cplusplus )
# define _PTRDEF(name) typedef name _FAR * P##name;
# define _REFDEF(name) typedef name _FAR & R##name;
# define _REFPTRDEF(name) typedef name _FAR * _FAR & RP##name;
# define _PTRCONSTDEF(name) typedef const name _FAR * PC##name;
# define _REFCONSTDEF(name) typedef const name _FAR & RC##name;
# define _CLASSDEF(name) class _CLASSTYPE name; \
_PTRDEF(name) \
_REFDEF(name) \
_REFPTRDEF(name) \
_PTRCONSTDEF(name) \
_REFCONSTDEF(name)
#endif
#endif /* ___DEFS_H */

View File

@@ -0,0 +1,14 @@
/* _nfile.h
Maximum number of open files
Copyright (c) 1991, 1992 by Borland International
All Rights Reserved.
*/
#ifndef ___NFILE_H
#define ___NFILE_H
#define _NFILE_ 20
#endif

View File

@@ -0,0 +1,15 @@
/* _null.h
Definition of NULL.
Copyright (c) 1987, 1992 by Borland International
All Rights Reserved.
*/
#ifndef NULL
# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__)
# define NULL 0
# else
# define NULL 0L
# endif
#endif

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
-LD:\LIB

Binary file not shown.

View File

@@ -0,0 +1,2 @@
-ID:\INCLUDE
-LD:\LIB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

3
XTMax/Drivers/LTEMM/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.o
*.map
log.txt

20
XTMax/Drivers/LTEMM/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,20 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build in DOSBox",
"type": "shell",
"command": "..\\Driver_Build_Tools\\DOSBox\\DOSBox.exe -conf Build.conf",
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View File

@@ -0,0 +1,15 @@
[autoexec]
@ECHO OFF
CLS
MOUNT C .
MOUNT D ..\Driver_Build_Tools\TASM2
SET PATH=D:\
C:
MAKE > LOG.TXT
IF ERRORLEVEL 1 GOTO :ERROR
EXIT
:ERROR
TYPE LOG.TXT
ECHO Log saved to LOG.TXT
PAUSE
EXIT

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,226 @@
;*****************************************************************
;* *
;* *
;* EMM/EMS driver program for BOCARAM30 Memory board *
;* *
;* *
;*****************************************************************
;
; ‘âàãªâãà  ä¨§¨ç¥áª®© áâà ­¨æë EMS
;
phys_page_struct STRUC
Emm_Handle2 DW ? ;¤¥áªà¨¯â®à-¢« ¤¥«¥æ áâà ­¨æë
Phys_page_port DW ? ;physical page i/o port address
Phys_Seg_Addr DW ? ;䨧¨ç¥áª¨© ᥣ¬¥­â­ë©  ¤à¥á áâà ­¨æë
Log_Page_Data DB ? ;­®¬¥à «®£¨ç¥áª®© áâà ­¨æë,ª àâ¨à®¢ ­­®©
phys_page_struct ENDS ;­  íâã 䨧¨ç¥áªãî áâà ­¨æã
handle_page_struct STRUC
emm_handle3 DW ?
page_alloc_to_handle DW ?
handle_page_struct ENDS
partial_page_map_struct STRUC
mappable_segment_count DW ?
mappable_segment DW 4 DUP (?)
partial_page_map_struct ENDS
log_to_phys_map_struct STRUC
log_page_number1 DW ?
phys_page_number1 DW ?
log_to_phys_map_struct ENDS
log_to_seg_map_struct STRUC
log_page_number2 DW ?
mappable_seg_addr DW ?
log_to_seg_map_struct ENDS
handle_dir_struct STRUC
handle_value DW ?
handle_name1 DB 8 DUP (?)
handle_dir_struct ENDS
map_and_jump_struct STRUC
target_address1 DD ?
log_phys_map_len DB ?
log_phys_map_ptr DD ?
map_and_jump_struct ENDS
map_and_call_struct STRUC
target_address2 DD ?
new_page_map_len DB ?
new_page_map_ptr DD ?
old_page_map_len DB ?
old_page_map_ptr DD ?
reserved DW 4 DUP (?)
map_and_call_struct ENDS
move_info_struct STRUC
region_lenght DD ?
source_type DB ?
source_handle1 DW ?
source_offset DW ?
source_seg_page DW ?
dest_type DB ?
dest_handle1 DW ?
dest_offset DW ?
dest_seg_page DW ?
move_info_struct ENDS
mappable_phys_page_struct STRUC
phys_page_segment DW ?
phys_page_number2 DW ?
mappable_phys_page_struct ENDS
hardware_info_struct STRUC
raw_page_size DW ?
alternate_register_sets DW ?
context_save_area_size DW ?
DMA_register_sets DW ?
DMA_channel_operation DW ?
hardware_info_struct ENDS
HANDLE_CNT EQU 64 ;max handle count
PAGE_MAX EQU 255 ;max logical page count
BACK_MAX EQU 5 ;max mapping data backup count
I8042 EQU 60H ;i8042 i/o port address
TIME_OUT EQU 1000 ;
NOT_USE EQU 0AA55H ;not used logical page code
NON EQU 0FFFFH ;non or bad logical page code
CR EQU 0DH ;Carriage Return code
LF EQU 0AH ;Line Feed code
TAB EQU 09H ;TAB code
; JJP DIS_EMS EQU 0 ;physical page disable data
DIS_EMS EQU 0FFH ;physical page disable data (lo-tech cards)
HANDLE_NAME_SIZE EQU 8 ;EMM handle name byte size
UNMAP EQU 0FFFFH ;unmap code
UNALLOC EQU 0FFFFH ;unallocate code
PUSH_REG EQU 8 * 2 ;push register size
EMMWORK EQU 50 ;EMM driver work area size
RET_SP EQU EMMWORK+PUSH_REG+6+10 ;int67 stack size
PHYS_PAGES EQU 4 ;physical page count
RAW_PAGES EQU 400H ;raw page size (16KB)
CONTEXT_SIZE EQU SIZE phys_page_struct * PHYS_PAGES
ALTER_REGS EQU 0 ;alter map register set count
DMA_REGS EQU 0 ;alter DMA register set count
DMA_CHANNEL EQU 0 ;DMA channel number
VOLATILE EQU 0 ;volatile
NON_VOLATILE EQU 1 ;non volatile
F23_RETSP EQU 10 ;
LOG_SIZE EQU 2 ;logical page flag data size
FLAG_SIZE EQU 2 ;handle flag size
;
; function 15 struct
;
f15_struct STRUC
DW 8 DUP (?)
f15_map_data DB CONTEXT_SIZE DUP (?)
f15_struct ENDS
;
; function 16 struct
;
f16_struct STRUC
DW 8 DUP (?)
f16_map_len DW ?
f16_map_data DB CONTEXT_SIZE DUP (?)
f16_struct ENDS
;
; function 17 struct
;
f17_struct STRUC
DW 8 DUP (?)
f17_ax_save DW ?
f17_map_len DW ?
f17_map_data DB PHYS_PAGES * 4 DUP (?)
f17_struct ENDS
;
; function 22 struct
;
f22_struct STRUC
DW 8 DUP (?)
f22_ax_save DW ?
f22_target_off DW ?
f22_target_seg DW ?
f22_map_len DW ?
f22_map_data DB PHYS_PAGES * 4 DUP (?)
f22_struct ENDS
;
; function 23 struct
;
f23_struct STRUC
DW 8 DUP (?)
f23_target_off DW ?
f23_target_seg DW ?
f23_flag DW ?
f23_retoff DW ?
f23_retseg DW ?
f23_ax_save DW ?
f23_new_map_len DW ?
f23_new_map_data DB PHYS_PAGES * 4 DUP (?)
f23_old_map_len DW ?
f23_old_map_data DB PHYS_PAGES * 4 DUP (?)
f23_struct ENDS
;
; function 24 struct
;
f24_struct STRUC
DW 8 DUP (?)
region_low DW ?
region_high DW ?
source_off DW ?
source_seg DW ?
source_page DW ?
source_ea_low DW ?
source_ea_high DW ?
source_handle2 DW ?
dest_off DW ?
dest_seg DW ?
dest_page DW ?
dest_ea_low DW ?
dest_ea_high DW ?
dest_handle2 DW ?
f24_al_save DB ?
direct_move DB ?
source_type1 db ?
dest_type1 db ?
zero_low DW ?
f24_struct ENDS
;
; function 28 struct
;
f28_struct STRUC
DW 8 DUP (?)
f28_map_data DB CONTEXT_SIZE DUP (?)
f28_struct ENDS
;
; register back area struct
;
retreg STRUC
bx_save DW ? ;BX save area
cx_save DW ? ;CX save area
dx_save DW ? ;DX save area
si_save DW ? ;SI save area
di_save DW ? ;DI save area
bp_save DW ? ;BP save area
es_save DW ? ;ES save area
ds_save DW ? ;DS save area
retreg ENDS
;
; return address struct
;
ret_struct STRUC
DW 8 DUP (?)
DB EMMWORK DUP (?)
ret_offset DW ? ;return offset address
ret_segment DW ? ;return segment address
ret_flag DW ? ;return flags
ret_struct ENDS

View File

@@ -0,0 +1,100 @@
;*****************************************************************
;* *
;* *
;* EMM/EMS driver program for BOCARAM30 Memory board *
;* *
;* *
;*****************************************************************
; Some useful macros ...
;Ž¡¬¥­ ¡ ©â ¬¨ ¬¥¦¤ã SOURCE ¨ DESTINATION
Exbyte MACRO
mov al,[si]
xchg al,es:[di]
mov [si],al
inc si
inc di
ENDM
;Ž¡¬¥­ á«®¢ ¬¨ ¬¥¦¤ã SOURCE ¨ DESTINATION
Exword MACRO
mov ax,[si]
xchg ax,es:[di]
mov [si],ax
add di,2
add si,2
ENDM
;‚ëç¨á«¥­¨¥  ¡á®«îâ­®£®  ¤à¥á  FAR-㪠§ â¥«ï
;‚室 : 㪠§ â¥«ì ¢ ä®à¬ â¥ ᥣ¬¥­â:ᬥ饭¨¥
;‚ë室 : DX:AX =  ¡á®«îâ­ë©  ¤à¥á
FarPtrAddress MACRO Segment,Offset
mov dx,Segment
mov ax,Offset
mov bx,dx
mov cl,4
shl bx,cl
and dx,0F000h
rol dx,cl
add ax,bx
adc dx,0
ENDM
;‚ëç¨á«¥­¨¥  ¡á®«îâ­®£®  ¤à¥á  FAR-㪠§ â¥«ï
;‚室 : 㪠§ â¥«ì ᥣ¬¥­â:ᬥ饭¨¥ (DX:AX)
;‚ë室 : DX:AX =  ¡á®«îâ­ë©  ¤à¥á
FarAddress MACRO
mov bx,dx
mov cl,4
shl bx,cl
and dx,0F000h
rol dx,cl
add ax,bx
adc dx,0
ENDM
;‘¤¢¨£ ¢«¥¢® 32-à §à來®£® ç¨á«  (DX:AX) ­  COUNT à §
Shl32 MACRO Count
REPT Count
shl ax,1
rcl dx,1
ENDM
ENDM
;‘¤¢¨£ ¢¯à ¢® 32-à §à來®£® ç¨á«  (DX:AX) ­  COUNT à §
Shr32 MACRO Count
REPT Count
shr dx,1
rcr ax,1
ENDM
ENDM
;‘«®¦¥­¨¥ 32-à §à來ëå ç¨á¥« (DX:AX) + HIGH-LOW
Add32 MACRO High,Low
add ax,Low
adc dx,High
ENDM
;‚ëç¨â ­¨¥ 32-à §à來ëå ç¨á¥« (DX:AX) - HIGH-LOW
Sub32 MACRO High,Low
sub ax,Low
sbb dx,High
ENDM
;‡ £à㧪  32-à §à來®£® ç¨á«  ¢ (DX:AX)
Load32 MACRO High,Low
mov dx,High
mov ax,Low
ENDM
;‡ £à㧪  32-à §à來®£® ç¨á«  ¢ (DX:AX)
FLoad32 MACRO Strt
les ax,dword ptr Strt
mov dx,es
ENDM
;‘®åà ­¥­¨¥ 32-à §à來®£® ç¨á«  (DX:AX) ¢ HIGH-LOW
Save32 MACRO High,Low
mov High,dx
mov Low,ax
ENDM

View File

@@ -0,0 +1,5 @@
LTEMM.EXE: LTEMM.O
TLINK LTEMM.O
LTEMM.O: LTEMM.ASM LTEMM.INC LTEMM.MAC
TASM LTEMM.ASM LTEMM.O

View File

@@ -0,0 +1,38 @@
*************************************************************************
* *
* EMS 4.0 Driver for Lo-tech 2MB EMS Board, rev.01, Mar-14 *
* *
* http://www.lo-tech.co.uk/wiki/2MB-EMS-Board *
* http://www.lo-tech.co.uk/wiki/LTEMM.EXE *
* *
* This code is TASM source. *
* *
* Based on original works Copyright (c) 1988, Alex Tsourikov. *
* All rights reserved. *
* *
* Original source kindly provided subject to the BSD 3-Clause *
* License: http://opensource.org/licenses/BSD-3-Clause *
* *
* This software, as modified, is provided subject to the terms *
* of use at: *
* *
* http://www.lo-tech.co.uk/wiki/lo-tech.co.uk:General_disclaimer *
* *
* No charge has been made for this software. *
* *
*************************************************************************
Syntax: DEVICE=LTEMM.EXE [/switches]
/p:nnnn - Page frame address (E000)
/i:nnn - EMS i/o port base address (260)
/h:nnn - Maximal number of handles (64)
/d:nn - Depth of contest saves (5)
/f:nnn - First page number (0)
/n - Bypass memory test
/x - Perform long memory test
/3 - Use only EMS 3.2 functions
/q - Quiet mode
Defaults in parentheses. This driver has been tested under MS-DOS 6.22.

3
XTMax/Drivers/SDPP/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*.obj
*.map
log.txt

20
XTMax/Drivers/SDPP/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,20 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build in DOSBox",
"type": "shell",
"command": "..\\Driver_Build_Tools\\DOSBox\\DOSBox.exe -conf Build.conf",
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}

View File

@@ -0,0 +1,15 @@
[autoexec]
@ECHO OFF
CLS
MOUNT C .
MOUNT D ..\Driver_Build_Tools\BCC31
SET PATH=D:\
C:
MAKE > LOG.TXT
IF ERRORLEVEL 1 GOTO :ERROR
EXIT
:ERROR
TYPE LOG.TXT
ECHO Log saved to LOG.TXT
PAUSE
EXIT

123
XTMax/Drivers/SDPP/CPRINT.C Normal file
View File

@@ -0,0 +1,123 @@
/* cprint.c */
/* */
/* This file contains simple ASCII output routines. These are used */
/* by the device driver for debugging, and to issue informational */
/* messages (e.g. while loading). In general the C run time library */
/* functions probably aren't safe for use withing the context of a */
/* device driver and should be avoided. */
/* */
/* All these routines do their output thru the routine outchr, which */
/* is defined in DRIVER.ASM. It calls the BIOS INT 10 "dumb TTY" */
/* output function directly and does not use MSDOS at all. */
/* */
/* Copyright (C) 1994 by Robert Armstrong */
/* */
/* This program 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 program is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT- */
/* ABILITY 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, visit the website of the Free */
/* Software Foundation, Inc., www.gnu.org. */
#include <stdio.h> /* NULL, etc... */
#include <dos.h> /* used only for MK_FP ! */
#include <stdarg.h> /* needed for variable argument lists */
/* outchr - print a single ASCII character */
void outchr (char ch)
{
_DI = _SI = 0;
_AL = ch; _AH = 0xE; _BX = 0;
asm INT 0x10;
}
/* outstr - print an ASCIZ string */
void outstr (char *p)
{
while (*p != '\0')
outchr (*p++);
}
/* outdec - print a signed decimal integer */
void outdec (int val)
{
if (val < 0)
{outchr('-'); val = -val;}
if (val > 9)
{outdec( val/10 ); val %= 10;}
outchr('0' + val);
}
/* outhex - print a n digit hex number with leading zeros */
void outhex (unsigned val, int ndigits)
{
if (ndigits > 1)
outhex (val >> 4, ndigits-1);
val &= 0xf;
if (val > 9)
outchr('A'+val-10);
else
outchr('0'+val);
}
/* outhex - print a n digit hex number with leading zeros */
void outlhex (unsigned long lval)
{
int i;
for (i=3;i>=0;i--)
outhex(((unsigned char *)&lval)[i],2);
}
/* outcrlf - print a carriage return, line feed pair */
void outcrlf (void)
{
outchr ('\r'); outchr ('\n');
}
/* cprintf */
/* This routine provides a simple emulation for the printf() function */
/* using the "safe" console output routines. Only a few escape seq- */
/* uences are allowed: %d, %x and %s. A width modifier (e.g. %2x) is */
/* recognized only for %x, and then may only be a single decimal digit. */
void cdprintf (char near *msg, ...)
{
va_list ap; char *str; int size, ival; unsigned uval; unsigned long luval;
va_start (ap, msg);
while (*msg != '\0') {
/*outhex((unsigned) msg, 4); outchr('='); outhex(*msg, 2); outchr(' ');*/
if (*msg == '%') {
++msg; size = 0;
if ((*msg >= '0') && (*msg <= '9'))
{size = *msg - '0'; ++msg;}
if (*msg == 'c') {
ival = va_arg(ap, int); outchr(ival&0xff); ++msg;
} else if (*msg == 'd') {
ival = va_arg(ap, int); outdec (ival); ++msg;
} else if (*msg == 'x') {
uval = va_arg(ap, unsigned); ++msg;
outhex (uval, (size > 0) ? size : 4);
} else if (*msg == 'L') {
luval = va_arg(ap, unsigned long); ++msg;
outlhex (luval);
} else if (*msg == 's') {
str = va_arg(ap, char *); outstr (str); ++msg;
}
} else if (*msg == '\n') {
outchr('\r'); outchr('\n'); ++msg;
} else {
outchr(*msg); ++msg;
}
}
va_end (ap);
}

View File

@@ -0,0 +1,36 @@
/* */
/* This file contains simple ASCII output routines. These are used */
/* by the device driver for debugging, and to issue informational */
/* messages (e.g. while loading). In general the C run time library */
/* functions probably aren't safe for use withing the context of a */
/* device driver and should be avoided. */
/* */
/* All these routines do their output thru the routine outchr, which */
/* is defined in DRIVER.ASM. It calls the BIOS INT 10 "dumb TTY" */
/* output function directly and does not use MSDOS at all. */
/* */
/* Copyright (C) 1994 by Robert Armstrong */
/* */
/* This program 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 program is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT- */
/* ABILITY 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, visit the website of the Free */
/* Software Foundation, Inc., www.gnu.org. */
#ifndef _CPRINT_H
#define _CPRINT_H
void outchr (char ch);
void outstr (char *p);
void outdec (int val);
void outhex (unsigned val, int ndigits);
void outcrlf (void);
void cdprintf (char near *msg, ...);
#endif

View File

@@ -0,0 +1,87 @@
/*-----------------------------------------------------------------------
/ Low level disk interface modlue include file (C)ChaN, 2013
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
#define _DISKIO_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
void setportbase(BYTE val); /* set the port base */
/*---------------------------------------*/
/* Prototypes for disk control functions */
#define DOSFAR far
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_result (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE DOSFAR * buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE DOSFAR * buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void DOSFAR * buff);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (used by FatFs) */
#define CTRL_SYNC 0 /* Flush disk cache (for write functions) */
#define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */
//#define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */
#define CTRL_ERASE_SECTOR 4 /* Force erased a block of sectors (for only _USE_ERASE) */
/* Generic command (not used by FatFs) */
//#define CTRL_POWER 5 /* Get/Set power status */
//#define CTRL_LOCK 6 /* Lock/Unlock media removal */
//#define CTRL_EJECT 7 /* Eject media */
//#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
/* MMC card type flags (MMC_GET_TYPE) */
#define CT_MMC 0x01 /* MMC ver 3 */
#define CT_SD1 0x02 /* SD ver 1 */
#define CT_SD2 0x04 /* SD ver 2 */
#define CT_SDC (CT_SD1|CT_SD2) /* SD */
#define CT_BLOCK 0x08 /* Block addressing */
#ifdef __cplusplus
}
#endif
#endif

508
XTMax/Drivers/SDPP/DRIVER.C Normal file
View File

@@ -0,0 +1,508 @@
/* driver.c - MSDOS device driver functions */
/* */
/* Copyright (C) 1994 by Robert Armstrong */
/* */
/* This program 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 program is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT- */
/* ABILITY 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, visit the website of the Free */
/* Software Foundation, Inc., www.gnu.org. */
#include <stdio.h> /* NULL, etc... */
#include <dos.h> /* used only for MK_FP ! */
#include "standard.h" /* definitions for this project */
#include "sd.h" /* SD card glue */
#include "diskio.h" /* SD card library header */
#include "driver.h" /* MSDOS device driver interface */
#include "cprint.h" /* Console printing */
#define FORM_FACTOR 8 /* DOS form factor code used for SD */
/* Forward declarations for routines that need it... */
PRIVATE BOOLEAN parse_options (char far *);
PUBLIC void Initialize (rh_init_t far *);
PUBLIC void far SDDriver (rh_t far *);
/* These data structures are exported by the HEADER.ASM module... */
extern devhdr_t header; /* MSDOS device header for our driver */
extern bpb_t bpb; /* BIOS Parameter block " " " */
extern bpbtbl_t bpbtbl; /* BPB table (one for each drive unit) */
/* This double word is actually a far pointer to the entry point of */
/* this module. It's called by the assembly interface whenver DOS needs */
/* driver action. The second word of the far pointer contains the seg- */
/* ment address, which is actually computed and written by the assembly */
/* code. */
PUBLIC WORD c_driver[2] = {(WORD) &SDDriver, 0};
extern unsigned char com_flag;
/* Local data for this module... */
BOOLEAN Debug = FALSE; /* TRUE to enable debug (verbose) mode */
BOOLEAN InitNeeded = TRUE; /* TRUE if we need to (re) initialize */
WORD RebootVector[2]; /* previous INT 19H vector contents */
extern DWORD partitionoffset;
extern BYTE sd_card_check;
extern BYTE portbase;
BYTE partition_number;
/* fmemcpy */
/* This function is equivalent to the C RTL _fmemcpy routine. We have */
/* to define it here because BPC is unable to generate inline code for */
/* _fmemcpy (although it can generate equivalent code for memcpy!). */
void fmemcpy (void far *dst, void far *src, WORD n)
{
_asm {
les di,dword ptr dst
mov dx,word ptr src+2
mov si,word ptr src
mov cx,n
push ds
mov ds,dx
rep movsb
pop ds
}
}
/* fmemset */
/* This is the equivalent to _fmemset. It is here for exactly the */
/* same reasons as fmemcpy !!! */
void fmemset (void far *dst, BYTE c, WORD n)
{
_asm {
mov al,c
les di,dword ptr dst
mov cx,n
rep stosb
}
}
/* Media Check */
/* DOS calls this function to determine if the tape in the drive has */
/* been changed. The SD hardware can't determine this (like many */
/* older 360K floppy drives), and so we always return the "Don't Know" */
/* response. This works well enough... */
PUBLIC void MediaCheck (rh_media_check_t far *rh)
{
if (Debug) cdprintf("SD: media check: unit=%d\n", rh->rh.unit);
rh->media_status = SDMediaCheck(rh->rh.unit) ? -1 : 0;
rh->rh.status = DONE;
}
/* Build BPB */
/* DOS uses this function to build the BIOS parameter block for the */
/* specified drive. For diskettes, which support different densities */
/* and formats, the driver actually has to read the BPB from the boot */
/* sector on the disk. */
PUBLIC void BuildBPB (rh_get_bpb_t far *rh)
{
if (Debug)
cdprintf("SD: build BPB: unit=%d\n", rh->rh.unit);
rh->bpb = &bpb;
rh->rh.status = DONE;
}
/* Get Parameters */
/* This routine implements the Get Parameters subfunction of the DOS */
/* Generic IOCTL call. It gets a pointer to the device paramters block, */
/* which it then fills in. We do NOT create the track/sector map that */
/* is defined by recent DOS manuals to be at the end of the block - it */
/* never seems to be used... */
PUBLIC void GetParameters (device_params_t far *dp)
{
dp->form_factor = FORM_FACTOR; dp->attributes = 0; dp->media_type = 0;
dp->cylinders = bpb.total_sectors / (bpb.track_size * bpb.head_count);
fmemcpy(&(dp->bpb), &bpb, sizeof(bpb_t));
}
/* dos_error */
/* This routine will translate a SD error code into an appropriate */
/* DOS error code. This driver never retries on any error condition. */
/* For actual tape read/write errors it's pointless because the drive */
/* will have already tried several times before reporting the failure. */
/* All the other errors (e.g. write lock, communications failures, etc) */
/* are not likely to succeed without user intervention, so we go thru */
/* the usual DOS "Abort, Retry or Ignore" dialog. Communications errors */
/* are a special situation. In these cases we also set global flag to */
/* force a controller initialization before the next operation. */
int dos_error (int status)
{
switch (status) {
case RES_OK: return 0;
case RES_WRPRT: return WRITE_PROTECT;
case RES_NOTRDY: InitNeeded= TRUE; return NOT_READY;
case RES_ERROR: InitNeeded= TRUE; return BAD_SECTOR;
case RES_PARERR: return CRC_ERROR;
default:
cdprintf("SD: unknown drive error - status = 0x%2x\n", status);
return GENERAL_FAILURE;
}
}
/* drive_init */
/* This routine should be called before every I/O function. If the */
/* last I/O operation resulted in a protocol error, then this routine */
/* will re-initialize the drive and the communications. If the drive */
/* still won't talk to us, then it will set a general failure code in */
/* the request header and return FALSE. */
BOOLEAN drive_init (rh_t far *rh)
{
if (!InitNeeded) return TRUE;
if (!SDInitialize(rh->unit, partition_number, &bpb)) {
if (Debug) cdprintf("SD: drive failed to initialize\n");
rh->status = DONE | ERROR | GENERAL_FAILURE;
return FALSE;
}
InitNeeded = FALSE;
if (Debug) cdprintf("SD: drive initialized\n");
return TRUE;
}
/* Read Data */
PUBLIC void ReadBlock (rh_io_t far *rh)
{
DWORD lbn;
WORD count; int status; BYTE far *dta;
WORD sendct;
if (Debug)
cdprintf("SD: read block: unit=%d, start=%d, count=%d, dta=%4x:%4x\n",
rh->rh.unit, rh->start, rh->count, FP_SEG(rh->dta), FP_OFF(rh->dta));
if (!drive_init ((rh_t far *) rh)) return;
count = rh->count, lbn = rh->start, dta = rh->dta;
lbn = (rh->start == 0xFFFF) ? rh->longstart : rh->start;
while (count > 0) {
sendct = (count > 16) ? 16 : count;
status = SDRead(rh->rh.unit, lbn, dta, sendct);
if (status != RES_OK) {
if (Debug) cdprintf("SD: read error - status=%d\n", status);
fmemset(dta, 0, BLOCKSIZE);
rh->rh.status = DONE | ERROR | dos_error(status);
return;
}
lbn += sendct;
count -= sendct;
dta += (sendct*BLOCKSIZE);
}
rh->rh.status = DONE;
}
/* Write Data */
/* Write Data with Verification */
PUBLIC void WriteBlock (rh_io_t far *rh, BOOLEAN verify)
{
DWORD lbn;
WORD count; int status; BYTE far *dta;
WORD sendct;
if (Debug)
cdprintf("SD: write block: unit=%d, start=%d, count=%d, dta=%4x:%4x\n",
rh->rh.unit, rh->start, rh->count, FP_SEG(rh->dta), FP_OFF(rh->dta));
if (!drive_init ((rh_t far *) rh)) return;
count = rh->count, dta = rh->dta;
lbn = (rh->start == 0xFFFF) ? rh->longstart : rh->start;
while (count > 0) {
sendct = (count > 16) ? 16 : count;
status = SDWrite(rh->rh.unit, lbn, dta, sendct);
if (status != RES_OK) {
if (Debug) cdprintf("SD: write error - status=%d\n", status);
rh->rh.status = DONE | ERROR | dos_error(status);
return;
}
lbn += sendct;
count -= sendct;
dta += (sendct*BLOCKSIZE);
}
rh->rh.status = DONE;
}
/* Generic IOCTL */
/* The generic IOCTL functions are used by DOS programs to determine */
/* the device geometry, and especially by the FORMAT program to init- */
/* ialize new media. The DOS format program requires us to implement */
/* these three generic IOCTL functions: */
PUBLIC void GenericIOCTL (rh_generic_ioctl_t far *rh)
{
if (Debug)
cdprintf("SD: generic IOCTL: unit=%d, major=0x%2x, minor=0x%2x, data=%4x:%4x\n",
rh->rh.unit, rh->major, rh->minor, FP_SEG(rh->packet), FP_OFF(rh->packet));
if (rh->major == DISK_DEVICE)
switch (rh->minor) {
case GET_PARAMETERS: GetParameters ((device_params_t far *) rh->packet);
rh->rh.status = DONE;
return;
case GET_ACCESS: ((access_flag_t far *) (rh->packet))->allowed = 1;
rh->rh.status = DONE;
return;
case SET_MEDIA_ID:
case SET_ACCESS:
case SET_PARAMETERS:
case FORMAT_TRACK:
rh->rh.status = DONE;
return;
case GET_MEDIA_ID:
default: ;
}
cdprintf("SD: unimplemented IOCTL - unit=%d, major=0x%2x, minor=0x%2x\n",
rh->rh.unit, rh->major, rh->minor);
rh->rh.status = DONE | ERROR | UNKNOWN_COMMAND;
}
/* Generic IOCTL Query */
/* DOS programs can use this function to determine which generic */
/* IOCTL functions a device supports. The query IOCTL driver call will */
/* succeed for any function the driver supports, and fail for others. */
/* Nothing actually happens - just a test for success or failure. */
PUBLIC void IOCTLQuery (rh_generic_ioctl_t far *rh)
{
if (Debug)
cdprintf("SD: generic IOCTL query: unit=%d, major=0x%2x, minor=0x%2x\n",
rh->rh.unit, rh->major, rh->minor);
if (rh->major == DISK_DEVICE)
switch (rh->minor) {
case GET_ACCESS:
case SET_ACCESS:
case SET_MEDIA_ID:
case GET_PARAMETERS:
case SET_PARAMETERS:
case FORMAT_TRACK: rh->rh.status = DONE;
return;
default:
break;
}
rh->rh.status = DONE | ERROR | UNKNOWN_COMMAND;
}
/* SDDriver */
/* This procedure is called by the DRIVER.ASM interface module when */
/* MSDOS calls the driver INTERRUPT routine, and the C code is expected */
/* to define it. Note that the STRATEGY call is handled completely */
/* inside DRIVER.ASM and the address of the request header block is */
/* passed to the C interrupt routine as a parameter. */
PUBLIC void far SDDriver (rh_t far *rh)
{
/*
if (Debug)
cdprintf("SD: request at %4x:%4x, command=%d, length=%d\n",
FP_SEG(rh), FP_OFF(rh), rh->command, rh->length);
*/
switch (rh->command) {
case INITIALIZATION: Initialize ((rh_init_t far *) rh); break;
case MEDIA_CHECK: MediaCheck ((rh_media_check_t far *) rh); break;
case GET_BPB: BuildBPB ((rh_get_bpb_t far *) rh); break;
case INPUT: ReadBlock ((rh_io_t far *) rh); break;
case OUTPUT: WriteBlock ((rh_io_t far *) rh, FALSE); break;
case OUTPUT_VERIFY: WriteBlock ((rh_io_t far *) rh, TRUE); break;
case GENERIC_IOCTL: GenericIOCTL ((rh_generic_ioctl_t far *) rh); break;
case IOCTL_QUERY: IOCTLQuery ((rh_generic_ioctl_t far *) rh); break;
case GET_LOGICAL:
case SET_LOGICAL: rh->status = DONE; break;
default:
cdprintf("SD: unimplemented driver request - command=%d, length=%d\n",
rh->command, rh->length);
rh->status = DONE | ERROR | UNKNOWN_COMMAND;
}
}
PUBLIC void Shutdown (void)
{
long i;
cdprintf("SD: Shutdown\n");
for (i=0; i <100000; ++i);
/* SDClose(); */
JMPVECTOR(RebootVector);
}
/* WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! */
/* */
/* All code following this point in the file is discarded after the */
/* driver initialization. Make absolutely sure that no routine above */
/* this line calls any routine below it!! */
/* */
/* WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! WARNING!! */
/* Driver Initialization */
/* DOS calls this function immediately after the driver is loaded and */
/* expects it to perform whatever initialization is required. Since */
/* this function can never be called again, it's customary to discard */
/* the memory allocated to this routine and any others that are used */
/* only at initialization. This allows us to economize a little on the */
/* amount of memory used. */
/* */
/* This routine's basic function is to initialize the serial port, go */
/* and make contact with the SD card, and then return a table of BPBs to */
/* DOS. If we can't communicate with the drive, then the entire driver */
/* is unloaded from memory. */
PUBLIC void Initialize (rh_init_t far *rh)
{
WORD brkadr, reboot[2]; int status, i;
/* The version number is sneakily stored in the device header! */
cdprintf("SD Card driver for XTMax\n based on SD pport device driver V%c.%c (C) 2014 by Dan Marks\n based on TU58 by Robert Armstrong\n",
header.name[6], header.name[7]);
/* Parse the options from the CONFIG.SYS file, if any... */
if (!parse_options((char far *) rh->bpbtbl)) {
cdprintf("SD: bad options in CONFIG.SYS\n");
goto unload2;
}
/* Calculate the size of this driver by using the address of this */
/* routine. Note that C will return an offset for &Initialize which */
/* is relative to the _TEXT segment. We have to adjust this by adding */
/* the offset from DGROUP. See HEADER.ASM for a memory layout. */
brkadr = ((WORD) &Initialize) + ((_CS - _DS) << 4);
rh->brkadr = MK_FP(_DS, brkadr);
if (Debug)
cdprintf("SD: CS=%4x, DS=%4x, SS=%4x, SP=%4x, break=%4x\n",
_CS, _DS, _SS, _SP, brkadr);
/* Try to make contact with the drive... */
if (Debug) cdprintf("SD: initializing drive\n");
if (!SDInitialize(rh->rh.unit, partition_number, &bpb)) {
cdprintf("SD: drive not connected or not powered\n");
goto unload1;
}
cdprintf("SD: rh = %4x:%4x\n", FP_SEG(rh), FP_OFF(rh));
reboot[0] = ((WORD) &reboot) + ((_CS - _DS) << 4);
reboot[1] = _CS;
GETVECTOR(0x19, RebootVector);
SETVECTOR(0x19, reboot);
if (Debug)
cdprintf("SD: reboot vector = %4x:%4x, old vector = %4x, %4x\n",
reboot[1], reboot[0], RebootVector[1], RebootVector[0]);
/* All is well. Tell DOS how many units and the BPBs... */
cdprintf("SD initialized on DOS drive %c\n",
rh->drive+'A');
rh->nunits = 1; rh->bpbtbl = &bpbtbl;
rh->rh.status = DONE;
if (Debug)
{
cdprintf("SD: BPB data:\n");
cdprintf("Sector Size: %d ", bpb.sector_size);
cdprintf("Allocation unit: %d\n", bpb.allocation_unit);
cdprintf("Reserved sectors: %d ", bpb.reserved_sectors);
cdprintf("Fat Count: %d\n", bpb.fat_count);
cdprintf("Directory size: %d ", bpb.directory_size);
cdprintf("Total sectors: %d\n", bpb.total_sectors);
cdprintf("Media descriptor: %x ", bpb.media_descriptor);
cdprintf("Fat sectors: %d\n", bpb.fat_sectors);
cdprintf("Track size: %d ", bpb.track_size);
cdprintf("Head count: %d\n", bpb.head_count);
cdprintf("Hidden sectors: %d ", bpb.hidden_sectors);
cdprintf("Sector Ct 32 hex: %L\n", bpb.sector_count);
cdprintf("Partition offset: %L\n", partition_offset);
}
return;
/* We get here if there are any errors in initialization. In that */
/* case we can unload this driver completely from memory by setting */
/* (1) the break address to the starting address, (2) the number of */
/* units to 0, and (3) the error flag. */
unload1:
{ };
unload2:
rh->brkadr = MK_FP(_DS, 0); rh->nunits = 0; rh->rh.status = ERROR;
}
/* iseol - return TRUE if ch is any end of line character */
PRIVATE BOOLEAN iseol (char ch)
{ return ch=='\0' || ch=='\r' || ch=='\n'; }
/* spanwhite - skip any white space characters in the string */
PRIVATE char far *spanwhite (char far *p)
{ while (*p==' ' || *p=='\t') ++p; return p; }
/* option_value */
/* This routine will parse the "=nnn" part of an option. It should */
/* be called with a text pointer to what we expect to be the '=' char- */
/* acter. If all is well, it will return the binary value of the arg- */
/* ument and a pointer to the first non-numeric character. If there is */
/* a syntax error, then it will return NULL. */
PRIVATE char far *option_value (char far *p, WORD *v)
{
BOOLEAN null = TRUE;
if (*p++ != '=') return NULL;
for (*v=0; *p>='0' && *p<='9'; ++p)
*v = (*v * 10) + (*p - '0'), null = FALSE;
return null ? NULL : p;
}
/* parse_options */
/* This routine will parse our line from CONFIG.SYS and extract the */
/* driver options from it. The routine returns TRUE if it parsed the */
/* line successfully, and FALSE if there are any problems. The pointer */
/* to CONFIG.SYS that DOS gives us actually points at the first char- */
/* acter after "DEVICE=", so we have to first skip over our own file */
/* name by searching for a blank. All the option values are stored in */
/* global variables (e.g. DrivePort, DriveBaud, etc). */
PRIVATE BOOLEAN parse_options (char far *p)
{
WORD temp;
while (*p!=' ' && *p!='\t' && !iseol(*p)) ++p;
p = spanwhite(p);
while (!iseol(*p)) {
p = spanwhite(p);
if (*p++ != '/') return FALSE;
switch (*p++) {
case 'd', 'D':
Debug = TRUE;
break;
case 'k', 'K':
sd_card_check = 1;
break;
case 'p', 'P':
if ((p=option_value(p,&temp)) == NULL) return FALSE;
if ((temp < 1) || (temp > 4))
cdprintf("SD: Invalid partition number %x\n",temp);
else
partition_number = temp;
break;
case 'b', 'B':
if ((p=option_value(p,&temp)) == NULL) return FALSE;
if ((temp < 1) || (temp > 5))
cdprintf("SD: Invalid port base index %x\n",temp);
else
portbase = temp;
break;
default:
return FALSE;
}
p = spanwhite(p);
}
return TRUE;
}

232
XTMax/Drivers/SDPP/DRIVER.H Normal file
View File

@@ -0,0 +1,232 @@
/* driver.h - MSDOS commands for a device driver.... */
/* */
/* Copyright (C) 1994 by Robert Armstrong */
/* */
/* This program 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 program is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT- */
/* ABILITY 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, visit the website of the Free */
/* Software Foundation, Inc., www.gnu.org. */
#ifndef _DRIVER_H
#define _DRIVER_H
/* NOTE: B implies block device, C implies a character device. */
/* n.n+ implies DOS version n.n or later only! */
#define INITIALIZATION 0 /* (BC) initialize driver */
#define MEDIA_CHECK 1 /* (B) query media changed */
#define GET_BPB 2 /* (B) BIOS parameter block */
#define IOCTL_INPUT 3 /* (BC) read IO control data */
#define INPUT 4 /* (BC) read data */
#define ND_INPUT 5 /* (C) non-destructive input */
#define INPUT_STATUS 6 /* (C) query data available */
#define INPUT_FLUSH 7 /* (C) flush input buffers */
#define OUTPUT 8 /* (BC) write data */
#define OUTPUT_VERIFY 9 /* (BC) write data with verify */
#define OUTPUT_STATUS 10 /* (C) query output busy */
#define OUTPUT_FLUSH 11 /* (C) flush output buffers */
#define IOCTL_OUTPUT 12 /* (BC) write IO control data */
#define DEVICE_OPEN 13 /* (BC) (3.0+) device is to be opened */
#define DEVICE_CLOSE 14 /* (BC) (3.0+) " " " " closed */
#define REMOVABLE_MEDIA 15 /* (B) (3.0+) query removable media */
#define OUTPUT_BUSY 16 /* (C) (3.0+) output data until busy */
#define GENERIC_IOCTL 19 /* (B) (3.2+) */
#define GET_LOGICAL 23 /* (BC) (3.2+) */
#define SET_LOGICAL 24 /* (BC) (3.2+) */
#define IOCTL_QUERY 25 /* (BC) (5.0+) */
/* Flag bits for the request header status word... */
#define ERROR 0x8000 /* indicates any error condition */
#define BUSY 0x0200 /* prevents further operations */
#define DONE 0x0100 /* set on request completion */
/* Error codes that may be returned by a device driver... */
#define WRITE_PROTECT 0x00 /* diskette is write protected */
#define UNKNOWN_UNIT 0x01 /* unit number does not exist */
#define NOT_READY 0x02 /* device is not ready */
#define UNKNOWN_COMMAND 0x03 /* unknown command code */
#define CRC_ERROR 0x04 /* data check (CRC) error */
#define HDR_LEN_ERROR 0x05 /* bad request header length */
#define SEEK_ERROR 0x06 /* seek failure */
#define UNKNOWN_MEDIA 0x07 /* unknown media (e.g. wrong density) */
#define BAD_SECTOR 0x08 /* sector not found */
#define NO_PAPER 0x09 /* printer out of paper */
#define WRITE_FAULT 0x0A /* write failure */
#define READ_FAULT 0x0B /* read failure */
#define GENERAL_FAILURE 0x0C /* general failure */
#define MEDIA_CHANGED 0x0F /* invalid diskette change */
/* Values associated with function 19 - Generic IOCTL... */
#define SERIAL_DEVICE 0x01 /* device category: any serial device */
#define CONSOLE_DEVICE 0x03 /* " " : console (display) */
#define PARALLEL_DEVICE 0x05 /* " " : parallel printer */
#define DISK_DEVICE 0x08 /* " " : any disk (block) */
#define SET_PARAMETERS 0x40 /* disk device: set device parameters */
#define GET_PARAMETERS 0x60 /* " " : get " " " */
#define WRITE_TRACK 0x41 /* " " : write one track */
#define READ_TRACK 0x61 /* " " : read " " */
#define FORMAT_TRACK 0x42 /* " " : format " " */
#define VERIFY_TRACK 0x62 /* " " : verify " " */
#define SET_MEDIA_ID 0x46 /* " " : set media id byte */
#define GET_MEDIA_ID 0x66 /* " " : get " " " */
#define SENSE_MEDIA 0x68 /* " " : sense media type */
#define SET_ACCESS 0x67 /* " " : set access allowed flag */
#define GET_ACCESS 0x47 /* " " : get " " " */
struct _devhdr { /* Device header structure... */
struct _devhdr far *next; /* address of the next device */
WORD attribute; /* device attribute word */
void (near *strtgy) (void); /* strategy routine address */
void (near *intrpt) (void); /* interrupt " " */
BYTE name[8]; /* device name (blank filled!) */
};
typedef struct _devhdr devhdr_t;
struct _bpb { /* BIOS Parameter block structure... */
WORD sector_size; /* sector size, in bytes */
BYTE allocation_unit; /* allocation unit size */
WORD reserved_sectors; /* number of reserved (boot) sectors */
BYTE fat_count; /* number of FATs on disk */
WORD directory_size; /* root directory size, in files */
WORD total_sectors; /* device size, in sectors */
BYTE media_descriptor; /* media descriptor code from the BIOS */
WORD fat_sectors; /* number of sectors per FAT */
WORD track_size; /* track size, in sectors */
WORD head_count; /* number of heads */
LONG hidden_sectors; /* offset of this hard disk partition */
/* The following device size is used only for disks > 32Mb. In that */
/* case, the total_sectors field should be zero! */
LONG sector_count; /* device size, in sectors */
};
typedef struct _bpb bpb_t;
struct _rhfixed { /* Fixed preamble for every request... */
BYTE length; /* length of the header, in bytes */
BYTE unit; /* physical unit number requested */
BYTE command; /* device driver command code */
WORD status; /* status returned by the driver */
BYTE reserved[8]; /* reserved (unused) bytes */
};
typedef struct _rhfixed rh_t;
/* NOTE: count is in _bytes_ for character type device drivers, and */
/* in _sectors_ for block type drivers!! */
typedef near * (bpbtbl_t[]);
struct _rh_init { /* INITIALIZATION(0) */
rh_t rh; /* fixed portion of the header */
BYTE nunits; /* number of units supported by driver */
BYTE far *brkadr; /* break address (memory used) */
bpbtbl_t far *bpbtbl; /* pointer to array of BPBs */
BYTE drive; /* first available drive number */
};
typedef struct _rh_init rh_init_t;
struct _rh_media_check { /* MEDIA_CHECK(1) */
rh_t rh; /* fixed portion of the request */
BYTE media_type; /* media descriptor byte from BIOS */
BYTE media_status; /* new media status flags */
BYTE far *volume_id; /* pointer to volume ID string */
};
typedef struct _rh_media_check rh_media_check_t;
struct _rh_get_bpb { /* GET_BPB(2) */
rh_t rh; /* fixed portion of the request */
BYTE media_type; /* media descriptor byte from BIOS */
BYTE far *dta; /* address for data transfer */
bpb_t far *bpb; /* pointer to the BPB */
};
typedef struct _rh_get_bpb rh_get_bpb_t;
struct _rh_ioctl { /* IOCTL_INPUT(3), IOCTL_OUTPUT(12) */
rh_t rh; /* fixed portion of the request */
BYTE media_type; /* media descriptor byte from BIOS */
BYTE far *dta; /* address for data transfer */
WORD count; /* transfer count (bytes or sectors) */
WORD start; /* starting sector number */
};
typedef struct _rh_ioctl rh_ioctl_t;
struct _rh_io { /* INPUT(4),OUTPUT(8),OUTPUT_VERIFY(9) */
rh_t rh; /* fixed portion of the request */
BYTE media_type; /* media descriptor byte from BIOS */
BYTE far *dta; /* address for data transfer */
WORD count; /* transfer count (bytes or sectors) */
WORD start; /* starting sector number */
BYTE far *volume_id; /* address of volume ID string */
DWORD longstart; /* long start for lba */
};
typedef struct _rh_io rh_io_t;
struct _rh_ndinput { /* ND_INPUT(5) */
rh_t rh; /* fixed portion of the request */
BYTE ch; /* next input character (returned) */
};
typedef struct _rh_ndinput rh_ndinput_t;
/* INPUT_STATUS(6) has only a request header... */
/* INPUT_FLUSH(7) " " " " " ... */
/* OUTPUT_STATUS(10) " " " " " ... */
/* OUTPUT_FLUSH(11) " " " " " ... */
/* DEVICE_OPEN(13) " " " " " ... */
/* DEVICE_CLOSE(14) " " " " " ... */
/* REMOVABLE_MEDIA(15) " " " " " ... */
struct _rh_output_busy { /* OUTPUT_BUSY(16) */
rh_t rh; /* fixed portion of the request */
BYTE media_type; /* media descriptor byte from BIOS */
BYTE far *dta; /* address for data transfer */
WORD count; /* transfer count (bytes or sectors) */
};
typedef struct _rh_output_busy rh_output_busy_t;
struct _rh_generic_ioctl { /* GENERIC_IOCTL(19), IOCTL_QUERY(25) */
rh_t rh; /* fixed portion of the request */
BYTE major, minor; /* function code - major and minor */
WORD si, di; /* caller's SI and DI registers */
BYTE far *packet; /* address of IOCTL data packet */
};
typedef struct _rh_generic_ioctl rh_generic_ioctl_t;
struct _rh_logical { /* GET_LOGICAL(23), SET_LOGICAL(24) */
rh_t rh; /* fixed portion of the request */
BYTE io; /* unit code or last device */
BYTE command; /* command code */
WORD status; /* resulting status */
LONG reserved; /* reserved (unused) */
};
typedef struct _rh_logical rh_logical_t;
struct _device_params { /* Generic IOCTL, Get/Set Parameters */
BYTE special; /* special functions and flags */
BYTE form_factor; /* device (not media!) form factor */
WORD attributes; /* physical drive attributes */
WORD cylinders; /* number of cylinders */
BYTE media_type; /* media type (not the media id!) */
bpb_t bpb; /* the entire BIOS parameter block! */
WORD layout[]; /* track layout map */
};
typedef struct _device_params device_params_t;
struct _access_flag { /* Generic IOCTL Get/Set access allowed */
BYTE special; /* special functions and flags */
BYTE allowed; /* non-zero if access is allowed */
};
typedef struct _access_flag access_flag_t;
struct _media_type { /* Generic IOCTL Get media type */
BYTE default_media; /* 1 for default media type */
BYTE form_factor; /* media (not device!) form factor */
};
typedef struct _media_type media_type_t;
#endif

View File

@@ -0,0 +1,247 @@
PAGE 60, 132
TITLE HEADER - Interface for C Device Drivers
SUBTTL Bob Armstrong [23-Jul-94]
; header.asm - MSDOS device driver header...
;
; Copyright (C) 1994 by Robert Armstrong
;
; This program 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 program is distributed in the hope that it will be useful, but
; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT-
; ABILITY 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, visit the website of the Free
; Software Foundation, Inc., www.gnu.org.
; This module receives the DOS device driver calls (there are only two!)
; and sets up an environment suitable for executing C code. The original
; DOS device driver request is then handed off to the C code.
;
; There are two requirements that drive the memory layout of a device
; driver: (1) DOS requires the device header to be the first thing in the
; memory image, and (2) it is desirable to free the memory allocated to
; startup code once the driver has been initialized. These requirements
; force a memory layout like this diagram:
;
; DS, SS -> +----------------------+ <- driver load address
; | |
; | (device header) |
; | |
; \ _DATA \
; | |
; |----------------------|
; | |
; \ _BSS \
; | |
; | (stack) | <- C language stack
; | |
; CS -> |----------------------|
; | |
; \ _TEXT \
; | | <- driver break address
; | |
; \ (startup code) \
; | |
; +----------------------+
;
; This is very similar to the TINY (.COM file) model _except_ that the
; code is at the end of the memory image rather than the start. This
; turns out to be a major problem because the code generated by TURBO
; assumes that the CS register contains the start of the _TEXT segment
; and NOT the DGROUP. This is contrary to the documentation in the
; Borland manual and _I_ think it's a bug. Note that this bug is
; asymptomatic in .COM files because the _TEXT segment is normally the
; first thing in the DGROUP.
;
; To get around this problem we use the SMALL model (i.e. CS != DS).
; Trouble is, when this driver is loaded the only thing we know is the
; address of the start of the driver and that's in the CS register.
; This means that we have to calculate an appropriate CS value to use
; in the C code.
;
; Another unrelated issue is the stack size. The stack DOS uses when
; a driver is called has room for about 20 PUSHes. This isn't enough
; for any serious C code, so we only use the DOS stack to save all the
; registers. After that we switch to our own stack, which is located
; in the _BSS segment. Of course we have to put the DOS stack pointer
; back before returning.
;
; In order to ensure that the device header appears first in the load
; image it must be defined in this module. We also define the BIOS
; Parameter Block (BPB) and the table of BPB pointers in this module.
; These things are unfortunate because those parts of this file must be
; modified for each different driver.
;
; The only interface between this module and the C code is a single
; far pointer which must be exported by the C code. This pointer would
; be declared as:
;
; void (far *c_driver) (rh_t far *);
;
; The offset part (first word!) of this pointer must be initialized at
; link time with the offset (relative to _TEXT) of the routine that
; will handle DOS driver calls. The segment part of this pointer is
; filled in by this module with the CS value we compute before the
; first call. The C driver routine is passed a far pointer to the
; DOS request header. Everything else is up to the C code.
;
; Bob Armstrong [22-July-1994]
.8086
; This is the size of the new stack we create for the C code...
STACKSIZE EQU 256 ; use whatever seems appropriate...
; This DGROUP, and the order the segments appear in this module, will
; force the load order to be as described above!
DGROUP GROUP _DATA, _BSS, _TEXT
; The _DATA segment (initialized data) for this module contains the
; MSDOS device header and the BIOS parameter blocks...
_DATA SEGMENT WORD PUBLIC 'DATA'
PUBLIC _header, _bpb, _bpbtbl
; Header attribute bits for block devices:
;
; 0002H (B1) - 32 bit sector addresses
; 0040H (B6) - Generic IOCTL, Get/Set logical device
; 0080H (B7) - IOCTL Query
; 0800H (B11) - Open/Close device, Removable media
; 2000H (B13) - IBM format
; 4000H (B14) - IOCTL read/write
; 8000H (B15) - zero for block device!
; The DOS device header...
_header DD -1 ; link to the next device
DW 00C0H ; block device, non-IBM format, generic IOCTL
DW DGROUP:STRATEGY ; address of the strategy routine
DW DGROUP:INTERRUPT; " " " interrupt "
DB 1 ; number of drives
DB 'SDCDv11' ; DOS doesn't really use these bytes
; The geometry (sectors/track, tracks/cylinder) defined in the BPB is rather
; arbitrary in the case of the TU58, but there are things to watch out for.
; First, the DOS FORMAT program has a bug which causes it to crash or worse
; yet, exit silently without doing anything for devices with large numbers of
; sectors per track. Experiments show that 64 sectors/track is safe (at least
; for DOS v5) but 128 is not. Second, the DRIVER.C module must calculate the
; number of cylinders by cylinders = device_size / (sectors * heads). This
; value must always come out to an integer.
; The BIOS Parameter Block...
_bpb DW 512 ; sector size
DB 1 ; cluster size
DW 1 ; number of reserved sectors
DB 2 ; number of FAT copies
DW 48 ; number of files in root directory
DW 512 ; total number of sectors
DB 0F0H ; media descriptor
DW 2 ; number of sectors per FAT
DW 64 ; sectors per track
DW 2 ; number of heads
DD 0 ; number of hidden sectors
DD 0 ; large sector count
; This table contains one BPB pointer for each physical drive...
_bpbtbl DW DGROUP:_bpb ; the BPB for unit 0
; DW DGROUP:_bpb ; " " " " 1
; This doubleword points to the entry point of the C driver code...
EXTRN _c_driver:WORD
_DATA ENDS
; The _BSS segment contains uninitialized static data...
_BSS SEGMENT WORD PUBLIC 'BSS'
PUBLIC _STACK
; Local variables for this module...
RHPTR DW 2 DUP (?) ; offset and segment of the request header
OLDSTK DW 2 DUP (?) ; original stack offset and segment
; This is the stack while the C code is running...
DB STACKSIZE DUP (?)
_STACK LABEL WORD ; the address of a stack is at its _top_ !
_BSS ENDS
; WARNING! The _TEXT segment must be paragraph aligned!
_TEXT SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:DGROUP, DS:DGROUP, SS:DGROUP, ES:NOTHING
; These words give the offsets of the _TEXT segment and the stack, both
; relative to the DGROUP. Note that you can't define use "DGROUP:_TEXT"
; as this generates a segment relocation record in the .EXE file which
; will prevent you from converting to a .COM file. The way its written
; works, but assumes that it is the first thing in this module.
CSOFF DW DGROUP:CSOFF
NEWSTK DW DGROUP:_STACK
; This is the entry for the STRATEGY procedure. DOS calls this routine
; with the address of the request header, but all the work is expected
; to occur in the INTERRUPT procedure. All we do here is to save the
; address of the request for later processing. Since this function is
; trivial, we never call any C code...
PUBLIC STRATEGY
STRATEGY PROC FAR
MOV CS:RHPTR,BX ; save the request header offset
MOV CS:RHPTR+2,ES ; and its segment
RET ; that's all there is to do
STRATEGY ENDP
; And now the INTERRUPT routine. This routine has to save all the
; registers, switch to the new stack, set up the segment registers,
; and call the C language driver routine while passing it the address
; of the request header (saved by the strategy routine).
PUBLIC INTERRUPT
INTERRUPT PROC FAR
PUSH DS ES AX BX CX DX DI SI BP
CLI ; interrupts OFF while the stack is unsafe!
MOV CS:OLDSTK+2,SS ; save the current stack pointer
MOV CS:OLDSTK,SP ; ...
MOV BX,CS ; then setup the new stack
MOV SS,BX ; ...
MOV SP,NEWSTK ; ...
STI ; interrupts are safe once again
MOV AX,CSOFF ; compute the correct code segment address
SHR AX,4 ; ... for the _TEXT segment
ADD AX,BX ; ...
MOV _c_driver+2,AX ; fix the pointer appropriately
MOV DS,BX ; setup DS for the C code
CLD ; the C code will assume this state
PUSH CS:RHPTR+2 ; pass the request header
PUSH CS:RHPTR ; address as a parameter
CALL DWORD PTR _c_driver; call the C entry point
CLI ; interrupts OFF once again
MOV SS,CS:OLDSTK+2 ; and restore the original stack
MOV SP,CS:OLDSTK ; ...
STI ; ...
POP BP SI DI DX CX BX AX ES DS
RET
INTERRUPT ENDP
_TEXT ENDS
END

View File

@@ -0,0 +1,40 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef _INTEGER
#define _INTEGER
#ifdef _WIN32 /* FatFs development platform */
#include <windows.h>
#include <tchar.h>
#else /* Embedded platform */
/* These types must be 16-bit, 32-bit or larger integer */
typedef int INT;
typedef unsigned int UINT;
/* These types must be 8-bit integer */
typedef char CHAR;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
/* These types must be 16-bit integer */
typedef short SHORT;
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types must be 32-bit integer */
#ifndef DEFINEDLONG
#define DEFINEDLONG
typedef long LONG;
#endif
typedef unsigned long ULONG;
typedef unsigned long DWORD;
#endif
#endif

View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program 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 program 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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -0,0 +1,26 @@
# Makefile for the TU58 Device Driver project - RLA [12-Aug-94]
CC=bcc -c -ms -Z -O -Ol -Oe
ASM=tasm -mx
.c.obj:
$(CC) $<
.asm.obj:
$(ASM) $*
sd.sys: header.obj cprint.obj sd.obj sdmm.obj driver.obj
tlink -t -m -s -n header cprint sd sdmm driver, sd.sys
sd.com: header.obj cprint.obj sd.obj sdmm.obj driver.obj
tlink -t -m -s -n header cprint sd sdmm driver, sd.sys
rename sd.sys sd.com
clean:
del *.obj
del sd.sys
driver.obj: cprint.c sdmm.c driver.c cprint.c cprint.h standard.h driver.h sd.h
sd.obj: sd.c sd.h standard.h driver.h
sdmm.obj: sdmm.c diskio.h integer.h
header.obj: header.asm

View File

@@ -0,0 +1,72 @@
SD card driver for parallel port
I wrote this to simplify data transfer between my IBM PC and my laptop, because my laptop does
not have a 360k floppy drive but does have an SD card slot.
WARNING: I take **no responsibility** for any damage to your computer, parallel port, or SD
card, or any data. You use this driver at your own risk. It is highly recommended you use
an expendable parallel port card with your expendable SD card, and your expendable data.
It is recommended that you use a level converter IC with between your 5 volt parallel port
outputs and the SD card 3.3 volt inputs. This project is intended as a fun hack for hobbyists
and enthusiasts and not for serious work.
This driver is made available under the GNU General Public License version 2. It incorporates
modified code from ELM Chan Fat FS (http://elm-chan.org/fsw/ff/00index_e.html).
Usage:
In your config.sys file
DEVICE=SD.SYS /d /k /p=<partition #> /b=<port base index>
Loads and installs the SD card driver.
/d = debugging mode (displays copious debugging messsages)
/k = use card detect signal to inform dos that card is attached
/p = partition number (1-4) to partition in MBR to use. Default: first available.
/b = port base index of parallel port, one of
1=0x3BC, 2=0x378, 3=0x278, 4=0x3E8, 5=0x2E8
Default: 0x378
For best results, format your SD card with a FAT16 partition which is less than 32 MB in size.
NOTE: Many versions of DOS don't know how to handle FAT32, and many can't have FAT16 with a
partition size greater than 32 MB. Therefore, if you want to play with this, make your parition on
the card FAT16 and less than 32 MB. This assures the best compatibility. You can have multiple copies of the
driver loaded if there are multiple partitions on your SD card you want to use simultaneously.
I have used Adafruit's microSD adapter
(http://www.adafruit.com/products/254?gclid=CLH7l4iEkrwCFQPNOgod7BkAQA)
if you want a relatively simple way to interface your PC parallel port to
the SD card. The adapter provides the 3.3 volts needed to power the SD card, as well
as a the level shifting between the 5 volt parallel port output and the 3.3 volt input.
If you directly connect a 5 volt output to a 3.3 volt input, you risk latching up the
3.3 volt input and damaging the card or computer from exceesive current.
Some have used series resistors instead of the level converters, but I found this
to not be that reliable and still may have this problem. Also, some SD cards MISO/DO
outputs are unable to drive a TTL input of some parallel ports, so you may need to add
a buffer between the two as well. I have found quite a bit of variability in the drive
current required for the inputs of various parallel ports.
The driver uses the very slow serial peripheral interface (SPI) mode of the SD card. The
speed, which depends on your PC speed, could be as slow as 10 kilobytes/second. This is
not a replacement for your hard drive. Your parallel port should be configured for standard
mode (not bidirectional) if applicable.
The connections between the parallel port and the SD card are as follows:
Parallel port SD card
PIN 25 signal GND GND (Vss)
+3.3V Vdd (power)
PIN 2 signal D0 CMD / MOSI / DI (SPI data in)
PIN 3 signal D1 SCLK / CLK (SPI clock)
PIN 4 signal D2 DAT3 / CS (SPI chip select)
PIN 13 signal SELECT DAT0 / MISO / DO (SPI data out)
PIN 11 signal BUSY Card detect (if you SD card slot has one)
For similar setups, look up parallel port to JTAG adapters which are used for in circuit
programming and debugging.
Good luck and be careful!

236
XTMax/Drivers/SDPP/SD.C Normal file
View File

@@ -0,0 +1,236 @@
/* sd.c */
/* */
/* Copyright (C) 1994 by Robert Armstrong */
/* */
/* This program 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 program is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT- */
/* ABILITY 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, visit the website of the Free */
/* Software Foundation, Inc., www.gnu.org. */
/* */
/* */
/* The functions provided are: */
/* */
/* SDInitialize - establish two way communications with the drive */
/* SDRead - read one 512 byte logical block from the tape */
/* SDWrite - write one 512 byte logical block to the tape */
/* SDMediaCheck - see if card detect has changed */
/* */
/* Normally the SDInitialize routine would be called */
/* during the DOS device driver initialization, and then the SDRead and */
/* */
#include <stdio.h> /* needed for NULL, etc */
#include <mem.h> /* memset, memcopy, etc */
#include "standard.h" /* all definitions for this project */
#include "sd.h" /* device protocol and data defintions */
#include "diskio.h" /* stuff from sdmm.c module */
#include "driver.h"
#include "cprint.h"
DWORD partition_offset = 0;
/* FatFs refers the members in the FAT structures as byte array instead of
/ structure member because the structure is not binary compatible between
/ different platforms */
#define BS_jmpBoot 0 /* Jump instruction (3) */
#define BS_OEMName 3 /* OEM name (8) */
#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */
#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */
#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */
#define BPB_NumFATs 16 /* Number of FAT copies (1) */
#define BPB_RootEntCnt 17 /* Number of root directory entries for FAT12/16 (2) */
#define BPB_TotSec16 19 /* Volume size [sector] (2) */
#define BPB_Media 21 /* Media descriptor (1) */
#define BPB_FATSz16 22 /* FAT size [sector] (2) */
#define BPB_SecPerTrk 24 /* Track size [sector] (2) */
#define BPB_NumHeads 26 /* Number of heads (2) */
#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */
#define BPB_TotSec32 32 /* Volume size [sector] (4) */
#define BS_DrvNum 36 /* Physical drive number (2) */
#define BS_BootSig 38 /* Extended boot signature (1) */
#define BS_VolID 39 /* Volume serial number (4) */
#define BS_VolLab 43 /* Volume label (8) */
#define BS_FilSysType 54 /* File system type (1) */
#define BPB_FATSz32 36 /* FAT size [sector] (4) */
#define BPB_ExtFlags 40 /* Extended flags (2) */
#define BPB_FSVer 42 /* File system version (2) */
#define BPB_RootClus 44 /* Root directory first cluster (4) */
#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */
#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */
#define BS_DrvNum32 64 /* Physical drive number (2) */
#define BS_BootSig32 66 /* Extended boot signature (1) */
#define BS_VolID32 67 /* Volume serial number (4) */
#define BS_VolLab32 71 /* Volume label (8) */
#define BS_FilSysType32 82 /* File system type (1) */
#define FSI_LeadSig 0 /* FSI: Leading signature (4) */
#define FSI_StrucSig 484 /* FSI: Structure signature (4) */
#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */
#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */
#define MBR_Table 446 /* MBR: Partition table offset (2) */
#define SZ_PTE 16 /* MBR: Size of a partition table entry */
#define BS_55AA 510 /* Boot sector signature (2) */
BYTE local_buffer[BLOCKSIZE];
#define LD_WORD(x) *((WORD *)(BYTE *)(x))
#define LD_DWORD(x) *((DWORD *)(BYTE *)(x))
/*-----------------------------------------------------------------------*/
/* Load a sector and check if it is an FAT boot sector */
/*-----------------------------------------------------------------------*/
static
BYTE check_fs (BYTE unit,
/* 0:FAT boor sector, 1:Valid boor sector but not FAT, */
/* 2:Not a boot sector, 3:Disk error */
DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
)
{
if (disk_read (unit, local_buffer, sect, 1) != RES_OK)
return 3;
if (LD_WORD(&local_buffer[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */
return 2;
if ((LD_DWORD(&local_buffer[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
return 0;
if ((LD_DWORD(&local_buffer[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
return 0;
return 1;
}
/*-----------------------------------------------------------------------*/
/* Find logical drive and check if the volume is mounted */
/*-----------------------------------------------------------------------*/
static
int find_volume (
BYTE unit,
BYTE partno,
bpb_t *bpb
)
{
BYTE fmt;
DSTATUS stat;
WORD secsize;
DWORD bsect;
stat = disk_status(unit);
if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */
return 0; /* The file system object is valid */
}
/* The file system object is not valid. */
/* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */
stat = disk_initialize(unit); /* Initialize the physical drive */
if (stat & STA_NOINIT) /* Check if the initialization succeeded */
return -1; /* Failed to initialize due to no medium or hard error */
/* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */
bsect = 0;
fmt = check_fs(unit, bsect); /* Load sector 0 and check if it is an FAT boot sector as SFD */
if (fmt == 1 || (!fmt && (partno))) { /* Not an FAT boot sector or forced partition number */
UINT i;
DWORD br[4];
for (i = 0; i < 4; i++) { /* Get partition offset */
BYTE *pt = &local_buffer[MBR_Table + i * SZ_PTE];
br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0;
}
i = partno; /* Partition number: 0:auto, 1-4:forced */
if (i) i--;
do { /* Find an FAT volume */
bsect = br[i];
fmt = bsect ? check_fs(unit, bsect) : 2; /* Check the partition */
} while (!partno && fmt && ++i < 4);
}
if (fmt == 3) return -2; /* An error occured in the disk I/O layer */
if (fmt) return -3; /* No FAT volume is found */
/* An FAT volume is found. Following code initializes the file system object */
secsize = LD_WORD(local_buffer + BPB_BytsPerSec);
if (secsize != BLOCKSIZE)
return -3;
bpb->sector_size = BLOCKSIZE;
bpb->allocation_unit = local_buffer[BPB_SecPerClus]; /* Number of sectors per cluster */
bpb->reserved_sectors = LD_WORD(local_buffer+BPB_RsvdSecCnt); /* Number of reserved sectors */
if (!bpb->reserved_sectors) return -3; /* (Must not be 0) */
bpb->fat_count = local_buffer[BPB_NumFATs]; /* Number of FAT copies */
if (bpb->fat_count == 0)
bpb->fat_count = 2;
bpb->directory_size = LD_WORD(local_buffer+BPB_RootEntCnt);
bpb->total_sectors = LD_WORD(local_buffer+BPB_TotSec16);
if (!bpb->total_sectors)
bpb->sector_count = LD_DWORD(local_buffer+BPB_TotSec32);
else
bpb->sector_count = bpb->total_sectors;
bpb->media_descriptor = local_buffer[BPB_Media];
bpb->fat_sectors = LD_WORD(local_buffer+BPB_FATSz16); /* Number of sectors per FAT */
bpb->track_size = LD_WORD(local_buffer+BPB_SecPerTrk); /* Number of sectors per cluster */
bpb->head_count = LD_WORD(local_buffer+BPB_NumHeads); /* Number of sectors per cluster */
bpb->hidden_sectors = 1;
partition_offset = bsect;
return 0;
}
/* SDInitialize */
PUBLIC BOOLEAN SDInitialize (BYTE unit, BYTE partno, bpb_t *bpb)
{
if (find_volume(unit,partno,bpb) < 0)
return FALSE;
return TRUE;
}
/* SDMediaCheck */
PUBLIC BOOLEAN SDMediaCheck (BYTE unit)
{
return (disk_result(unit) == RES_OK) ? FALSE : TRUE;
}
/* SDRead */
/* IMPORTANT! Blocks are always 512 bytes! Never more, never less. */
/* */
/* INPUTS: */
/* unit - selects tape drive 0 (left) or 1 (right) */
/* lbn - logical block number to be read [0..511] */
/* buffer - address of 512 bytes to receive the data read */
/* */
/* RETURNS: operation status as reported by the TU58 */
/* */
PUBLIC int SDRead (WORD unit, DWORD lbn, BYTE far *buffer, WORD count)
{
return disk_read (unit, buffer, lbn + partition_offset, count);
}
/* SDWrite */
/* IMPORTANT! Blocks are always 512 bytes! Never more, never less. */
/* */
/* INPUTS: */
/* unit - selects tape drive 0 (left) or 1 (right) */
/* lbn - logical block number to be read [0..511] */
/* buffer - address of 512 bytes containing the data to write */
/* verify - TRUE to ask the TU58 for a verification pass */
/* */
/* RETURNS: operation status as reported by the TU58 */
/* */
PUBLIC int SDWrite (WORD unit, DWORD lbn, BYTE far *buffer, WORD count)
{
return disk_write (unit, buffer, lbn + partition_offset, count);
}

22
XTMax/Drivers/SDPP/SD.H Normal file
View File

@@ -0,0 +1,22 @@
/* sd.h - SD card driver glue */
#ifndef _SD_H
#define _SD_H
#include "integer.h"
#include "driver.h"
#define BLOCKSIZE 512
extern DWORD partition_offset;
/* SDInitialize - establish two way communications with the drive */
BOOLEAN SDInitialize (BYTE unit, BYTE partno, bpb_t *bpb);
/* SDRead - read one 512 byte logical block from the tape */
int SDRead (WORD, DWORD, BYTE far *, WORD count);
/* SDWrite - write one 512 byte logical block to the tape */
int SDWrite (WORD, DWORD, BYTE far *, WORD count);
/* SDMediaCheck - check if media changed */
BOOLEAN SDMediaCheck (BYTE unit);
#endif

BIN
XTMax/Drivers/SDPP/SD.SYS Normal file

Binary file not shown.

655
XTMax/Drivers/SDPP/SDMM.C Normal file
View File

@@ -0,0 +1,655 @@
/*------------------------------------------------------------------------/
/ Foolproof MMCv3/SDv1/SDv2 (in SPI mode) control module
/-------------------------------------------------------------------------/
/
/ Copyright (C) 2013, ChaN, all right reserved.
/
/ * This software is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/-------------------------------------------------------------------------/
Features and Limitations:
* No Media Change Detection
Application program needs to perform f_mount() after media change.
/-------------------------------------------------------------------------*/
#include <conio.h>
#include "diskio.h" /* Common include file for FatFs and disk I/O layer */
#include "cprint.h"
/*-------------------------------------------------------------------------*/
/* Platform dependent macros and functions needed to be modified */
/*-------------------------------------------------------------------------*/
static WORD portbases[5] = {0x3BC,0x378,0x278,0x3E8,0x2E8};
BYTE sd_card_check = 0;
BYTE portbase = 2;
WORD DATAPORT=0x378;
WORD CONTROLPORT=0x379;
#define VAR_INIT() {CONTROLPORT=DATAPORT+1;}
#if 1
#define TOUTCHR(x)
#define TOUTHEX(x)
#define TOUTWORD(x)
#else
#define TOUTCHR(x) toutchr(x)
#define TOUTHEX(x) touthex(x)
#define TOUTWORD(x) toutword(x)
static BYTE toutchr (unsigned char ch)
{
_DI = _SI = 0;
_AL = ch; _AH = 0xE; _BX = 0;
asm INT 0x10;
return 0;
}
static BYTE touthex(unsigned char c)
{
char d = c >> 4;
toutchr(d > 9 ? d+('A'-10) : d+'0');
d = c & 0x0F;
toutchr(d > 9 ? d+('A'-10) : d+'0');
return 0;
}
static BYTE toutword(WORD x)
{
touthex(x >> 8);
touthex(x);
return 0;
}
#endif
void setportbase(BYTE val)
{
if ((val >= 1) && (val <= (sizeof(portbases)/sizeof(portbases[0])) ))
DATAPORT = portbases[val-1];
VAR_INIT();
}
static
void dly_us (UINT n)
{
_CX = n;
loopit:
_asm {
loop loopit
}
}
#define NOSHIFT
#ifdef NOSHIFT
DWORD dwordlshift(DWORD d, int n)
{
int i;
WORD a = ((WORD *)d)[0];
WORD b = ((WORD *)d)[1];
DWORD r;
for (i=0;i<n;i++)
{
b <<= 1;
b |= (a & 0x8000) ? 1 : 0;
a <<= 1;
}
((WORD *)r)[0] = a;
((WORD *)r)[1] = b;
return r;
}
#define DWORDLSHIFT(d,n) dwordlshift(d,n)
DWORD dwordrshift(DWORD d, int n)
{
int i;
WORD a = ((WORD *)d)[0];
WORD b = ((WORD *)d)[1];
DWORD r;
for (i=0;i<n;i++)
{
a >>= 1;
a |= (b & 0x1) ? 0x8000 : 0;
b >>= 1;
}
((WORD *)r)[0] = a;
((WORD *)r)[1] = b;
return r;
}
#define DWORDRSHIFT(d,n) dwordrshift(d,n)
#else
#define DWORDLSHIFT(d,n) ((d) << (n))
#define DWORDRSHIFT(d,n) ((d) >> (n))
#endif
/*--------------------------------------------------------------------------
Module Private Functions
---------------------------------------------------------------------------*/
/* MMC/SD command (SPI mode) */
#define CMD0 (0) /* GO_IDLE_STATE */
#define CMD1 (1) /* SEND_OP_COND */
#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
#define CMD8 (8) /* SEND_IF_COND */
#define CMD9 (9) /* SEND_CSD */
#define CMD10 (10) /* SEND_CID */
#define CMD12 (12) /* STOP_TRANSMISSION */
#define CMD13 (13) /* SEND_STATUS */
#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
#define CMD16 (16) /* SET_BLOCKLEN */
#define CMD17 (17) /* READ_SINGLE_BLOCK */
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (23) /* SET_BLOCK_COUNT */
#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24 (24) /* WRITE_BLOCK */
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
#define CMD32 (32) /* ERASE_ER_BLK_START */
#define CMD33 (33) /* ERASE_ER_BLK_END */
#define CMD38 (38) /* ERASE */
#define CMD55 (55) /* APP_CMD */
#define CMD58 (58) /* READ_OCR */
static
DSTATUS Stat = STA_NOINIT; /* Disk status */
static
BYTE CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */
/*-----------------------------------------------------------------------*/
/* Transmit bytes to the card (bitbanging) */
/*-----------------------------------------------------------------------*/
static
void xmit_mmc (
const BYTE DOSFAR * buff, /* Data to be sent */
UINT bc /* Number of bytes to send */
)
{
#if 1
BYTE d;
do {
d = *buff++; /* Get a byte to be sent */
outp(DATAPORT, d);
} while (--bc);
#else
// Requires to add `-2' in the CC command line in the Makefile.
_asm {
mov cx,bc
mov dx,DATAPORT
push ds
lds si,dword ptr buff
rep outsb
pop ds
}
#endif
}
/*-----------------------------------------------------------------------*/
/* Receive bytes from the card (bitbanging) */
/*-----------------------------------------------------------------------*/
static
void rcvr_mmc (
BYTE DOSFAR *buff, /* Pointer to read buffer */
UINT bc /* Number of bytes to receive */
)
{
#if 1
BYTE r;
do {
r = inp(DATAPORT);
*buff++ = r; /* Store a received byte */
} while (--bc);
#else
// Requires to add `-2' in the CC command line in the Makefile.
_asm {
mov cx,bc
mov dx,DATAPORT
push es
les di,dword ptr buff
rep insb
pop es
}
#endif
}
/*-----------------------------------------------------------------------*/
/* Wait for card ready */
/*-----------------------------------------------------------------------*/
static
int wait_ready (void) /* 1:OK, 0:Timeout */
{
BYTE d;
UINT tmr;
for (tmr = 5000; tmr; tmr--) { /* Wait for ready in timeout of 500ms */
d = inp(DATAPORT);
if (d == 0xFF) break;
dly_us(100);
}
return tmr ? 1 : 0;
}
/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus */
/*-----------------------------------------------------------------------*/
static
void deselect (void)
{
outp(CONTROLPORT, 1); // CS high
#if 0
outp(DATAPORT, 0xFF); /* Dummy clock (force DO hi-z for multiple slave SPI) */
#endif
}
/*-----------------------------------------------------------------------*/
/* Select the card and wait for ready */
/*-----------------------------------------------------------------------*/
static
int select (void) /* 1:OK, 0:Timeout */
{
BYTE d;
outp(CONTROLPORT, 0); // CS low
#if 0
(void)inp(DATAPORT); /* Dummy clock (force DO enabled) */
#endif
if (wait_ready()) return 1; /* OK */
deselect();
return 0; /* Failed */
}
/*-----------------------------------------------------------------------*/
/* Receive a data packet from the card */
/*-----------------------------------------------------------------------*/
static
int rcvr_datablock ( /* 1:OK, 0:Failed */
BYTE DOSFAR *buff, /* Data buffer to store received data */
UINT btr /* Byte count */
)
{
BYTE d;
UINT tmr;
for (tmr = 1000; tmr; tmr--) { /* Wait for data packet in timeout of 100ms */
d = inp(DATAPORT);
if (d != 0xFF) break;
dly_us(100);
}
if (d != 0xFE) {
return 0; /* If not valid data token, return with error */
}
rcvr_mmc(buff, btr); /* Receive the data block into buffer */
(void)inp(DATAPORT); (void)inp(DATAPORT); /* Discard CRC */
return 1; /* Return with success */
}
/*-----------------------------------------------------------------------*/
/* Send a data packet to the card */
/*-----------------------------------------------------------------------*/
static
int xmit_datablock ( /* 1:OK, 0:Failed */
const BYTE DOSFAR *buff, /* 512 byte data block to be transmitted */
BYTE token /* Data/Stop token */
)
{
BYTE d;
if (!wait_ready()) return 0;
d = token;
xmit_mmc(&d, 1); /* Xmit a token */
if (token != 0xFD) { /* Is it data token? */
xmit_mmc(buff, 512); /* Xmit the 512 byte data block to MMC */
(void)inp(DATAPORT); (void)inp(DATAPORT); /* Xmit dummy CRC (0xFF,0xFF) */
d = inp(DATAPORT);; /* Receive data response */
if ((d & 0x1F) != 0x05) /* If not accepted, return with error */
{
return 0;
}
}
return 1;
}
/*-----------------------------------------------------------------------*/
/* Send a command packet to the card */
/*-----------------------------------------------------------------------*/
static
BYTE send_cmd ( /* Returns command response (bit7==1:Send failed)*/
BYTE cmd, /* Command byte */
DWORD arg /* Argument */
)
{
BYTE n, d, buf[6];
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
cmd &= 0x7F;
n = send_cmd(CMD55, 0);
if (n > 1) return n;
}
/* Select the card and wait for ready except to stop multiple block read */
if (cmd != CMD12) {
deselect();
if (!select()) return 0xFF;
}
/* Send a command packet */
buf[0] = 0x40 | cmd; /* Start + Command index */
#ifdef NOSHIFT
buf[1] = ((BYTE *)&arg)[3]; /* Argument[31..24] */
buf[2] = ((BYTE *)&arg)[2]; /* Argument[23..16] */
buf[3] = ((BYTE *)&arg)[1]; /* Argument[15..8] */
buf[4] = ((BYTE *)&arg)[0]; /* Argument[7..0] */
#else
buf[1] = (BYTE)(arg >> 24); /* Argument[31..24] */
buf[2] = (BYTE)(arg >> 16); /* Argument[23..16] */
buf[3] = (BYTE)(arg >> 8); /* Argument[15..8] */
buf[4] = (BYTE)arg; /* Argument[7..0] */
#endif
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0) n = 0x95; /* (valid CRC for CMD0(0)) */
if (cmd == CMD8) n = 0x87; /* (valid CRC for CMD8(0x1AA)) */
buf[5] = n;
TOUTCHR('L');
TOUTHEX(buf[0]);
TOUTHEX(buf[1]);
TOUTHEX(buf[2]);
TOUTHEX(buf[3]);
TOUTHEX(buf[4]);
TOUTHEX(buf[5]);
xmit_mmc(buf, 6);
/* Receive command response */
if (cmd == CMD12) (void)inp(DATAPORT); /* Skip a stuff byte when stop reading */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do
{
d = inp(DATAPORT);
}
while ((d & 0x80) && (--n));
TOUTCHR('P');
TOUTHEX(d);
return d; /* Return with the response value */
}
/*--------------------------------------------------------------------------
Public Functions
---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE drv /* Drive number (always 0) */
)
{
if (drv) return STA_NOINIT;
if ((sd_card_check) && (inp(CONTROLPORT) & 0x80))
{
Stat = STA_NOINIT;
return STA_NOINIT;
}
return Stat;
}
DRESULT disk_result (
BYTE drv /* Drive number (always 0) */
)
{
if (drv) return RES_NOTRDY;
if ((sd_card_check) && (inp(CONTROLPORT) & 0x80))
{
Stat = STA_NOINIT;
return RES_NOTRDY;
}
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0) */
)
{
BYTE n, ty, cmd, buf[4];
UINT tmr;
DSTATUS s;
setportbase(portbase);
if (drv) return RES_NOTRDY;
if ((sd_card_check) && (inp(CONTROLPORT) & 0x80))
return RES_NOTRDY;
ty = 0;
for (n = 5; n; n--) {
outp(CONTROLPORT, 1); // CS high
dly_us(10000); /* 10ms. time for SD card to power up */
for (tmr = 10; tmr; tmr--) outp(DATAPORT, 0xFF); /* Apply 80 dummy clocks and the card gets ready to receive command */
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
rcvr_mmc(buf, 4); /* Get trailing return value of R7 resp */
if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */
if (send_cmd(ACMD41, 1UL << 30) == 0) break;
dly_us(1000);
}
if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
rcvr_mmc(buf, 4);
ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */
}
}
} else { /* SDv1 or MMCv3 */
if (send_cmd(ACMD41, 0) <= 1) {
ty = CT_SD1; cmd = ACMD41; /* SDv1 */
} else {
ty = CT_MMC; cmd = CMD1; /* MMCv3 */
}
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */
if (send_cmd(cmd, 0) == 0) break;
dly_us(1000);
}
if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
ty = 0;
}
break;
}
}
CardType = ty;
s = ty ? 0 : STA_NOINIT;
Stat = s;
deselect();
return s;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0) */
BYTE DOSFAR *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
UINT count /* Sector count (1..128) */
)
{
DRESULT dr = disk_result(drv);
if (dr != RES_OK) return dr;
if (!(CardType & CT_BLOCK)) sector = DWORDLSHIFT(sector,9); /* Convert LBA to byte address if needed */
if (count == 1) { /* Single block read */
if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
&& rcvr_datablock(buff, 512))
count = 0;
}
else { /* Multiple block read */
if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
do {
if (!rcvr_datablock(buff, 512)) break;
buff += 512;
} while (--count);
send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
}
}
deselect();
return count ? RES_ERROR : RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0) */
const BYTE DOSFAR *buff, /* Pointer to the data to be written */
DWORD sector, /* Start sector number (LBA) */
UINT count /* Sector count (1..128) */
)
{
DRESULT dr = disk_result(drv);
if (dr != RES_OK) return dr;
if (!(CardType & CT_BLOCK)) sector = DWORDLSHIFT(sector,9); /* Convert LBA to byte address if needed */
if (count == 1) { /* Single block write */
if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
&& xmit_datablock(buff, 0xFE))
count = 0;
}
else { /* Multiple block write */
if (CardType & CT_SDC) send_cmd(ACMD23, count);
if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
do {
if (!xmit_datablock(buff, 0xFC)) break;
buff += 512;
} while (--count);
if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
count = 1;
if (!wait_ready()) count = 1; /* Wait for card to write */
}
}
deselect();
return count ? RES_ERROR : RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0) */
BYTE ctrl, /* Control code */
void DOSFAR *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
BYTE n, csd[16];
DWORD cs;
DRESULT dr = disk_result(drv);
if (dr != RES_OK) return dr;
res = RES_ERROR;
switch (ctrl) {
case CTRL_SYNC : /* Make sure that no pending write process */
if (select()) res = RES_OK;
break;
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
*(DWORD DOSFAR *)buff = DWORDLSHIFT(cs,10);
} else { /* SDC ver 1.XX or MMC */
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
*(DWORD DOSFAR *)buff = DWORDLSHIFT(cs,n-9);
}
res = RES_OK;
}
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
*(DWORD DOSFAR *)buff = 128;
res = RES_OK;
break;
default:
res = RES_PARERR;
}
deselect();
return res;
}

View File

@@ -0,0 +1,106 @@
/* standard.h - standard, project wide, declarations */
/* */
/* Copyright (C) 1994 by Robert Armstrong */
/* */
/* This program 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 program is distributed in the hope that it will be useful, but */
/* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT- */
/* ABILITY 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, visit the website of the Free */
/* Software Foundation, Inc., www.gnu.org. */
/* Datatypes of a known size ... */
typedef unsigned char BYTE; /* 8 bits, unsigned */
typedef unsigned short WORD; /* 16 " " */
#ifndef DEFINEDLONG
#define DEFINEDLONG
typedef unsigned long LONG; /* 32 " " */
#endif
/* The BOOLEAN type and associated constants ... */
typedef unsigned char BOOLEAN;/* any TRUE/FALSE result */
#define FALSE (0) /* logical falsity */
#define TRUE (~FALSE)/* if it's not FALSE, it's ... */
/* This magic declaration modifier will make the symbol defined be */
/* invisible to the linker. For example, "PRIVATE int foo;" or even */
/* "PRIVATE void fred () { ...}". This is used extensively to restrict */
/* the scope of a global declaration to the current module. */
#define PRIVATE static /* this works for most compilers! */
/* And this magic declaration modifier guarantees that the symbol so */
/* defined will be visible to other modules. It is the opposite of */
/* "PRIVATE". In C this is the default condition anyway, so this macro */
/* mostly serves as documentation. */
#define PUBLIC /* this is the way things are anyway */
/* Extract the high and low bytes of a 16 bit value... */
#define HIGH(x) (((x) >> 8) & 0xFF)
#define LOW(x) ((x) & 0xFF)
/* Test a value for odd/even... */
#define ODD(x) (((x) & 1) != 0)
/* These macros provide access to specific 8088 family hardware ins- */
/* tructions. From a performance viewpoint, it is highly desirable that */
/* these macros not be implemented by subroutine calls, but rather that */
/* they expand directly to inline assembler instructions. */
#ifdef __TURBOC__
/* These macros turn the interrupt system on and off. They should */
/* generate the STI (0xFB) and CLI (0xFA) instructions... */
#define INT_ON asm sti
#define INT_OFF asm cli
/* These macros read and write a bytes from an I/O port. They should */
/* generate the 0xE5 (IN AL,DX) or 0xEE (OUT DX,AL) instructions... */
#define INBYTE(p,v) { _DX = (p); asm IN AL,DX; v = _AL; }
#define OUTBYTE(p,v) { _DX = (p); _AL = (v); asm OUT DX,AL; }
/* These macros will set or clear specific bit(s) in an I/O port. */
/* They work by first reading the port, seting or clearing the bit(s), */
/* and then writing the port. Needless to say, they can only be used */
/* on ports that can safely be both read and written! */
#define IOSETBIT(p,m) { _DX = (p); _BL = (m); \
asm IN AL,DX; asm OR AL,BL; asm OUT DX,AL; }
#define IOCLRBIT(p,m) { _DX = (p); _BL = ~(m); \
asm IN AL,DX; asm AND AL,BL; asm OUT DX,AL; }
/* These macros use the DOS INT 21H functions to get and set the */
/* contents of interrupt vectors. They are used to save and restore */
/* the serial port interrupt service routine... */
#define GETVECTOR(v,a) { _AL = (v); _AH = 0x35; asm INT 0x21; \
asm MOV WORD PTR a, BX; asm MOV WORD PTR a+2, ES; }
#define SETVECTOR(v,a) { _AL = (v); _AH = 0x25; asm PUSH DS; \
asm LDS DX, DWORD PTR a; \
asm INT 0x21; asm POP DS; }
#define JMPVECTOR(a) { asm JMP DWORD PTR a; }
/* Compute dst += src with end-around carry, just like the TU58 does... */
#define ADC(dst,src) { asm MOV AX, dst; asm ADD AX, src; \
asm ADC AX, 0; asm MOV dst, AX; }
#endif /* ifdef __TURBOC__ */
/* Debugging output routines... */
void outchr (char);
void outstr (char *);
void outdec (int);
void outhex (unsigned, int);
void outcrlf (void);
void cprintf (char near *, ...);