1
0
mirror of synced 2026-01-13 15:27:51 +00:00
Matthieu Bucchianeri 693d05b755
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.
2024-11-16 16:21:49 -08:00

237 lines
10 KiB
C

/* 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);
}