aboutsummaryrefslogtreecommitdiff
path: root/inc
diff options
context:
space:
mode:
authorJavier <dev.git@javispedro.com>2026-10-26 00:50:06 +0100
committerJavier <dev.git@javispedro.com>2026-10-26 00:50:06 +0100
commit6b8a368c51082fdd010ef5e1b0be4eb9b5059d1a (patch)
treee274d41a8dd5e912e20617a937a1fda5af91f8de /inc
parent9b1cf601360fb194047e6dcc2af75c2f38c611ec (diff)
downloadchu-6b8a368c51082fdd010ef5e1b0be4eb9b5059d1a.tar.gz
chu-6b8a368c51082fdd010ef5e1b0be4eb9b5059d1a.zip
refactor common parts into inc/ch375.h and add win9x, linux drivers
Diffstat (limited to 'inc')
-rw-r--r--inc/bda.h67
-rw-r--r--inc/bpb.h83
-rw-r--r--inc/ch375.h361
-rw-r--r--inc/chuver.h7
-rw-r--r--inc/dlog.h439
-rw-r--r--inc/dosapi.h182
-rw-r--r--inc/dosdrv.h319
-rw-r--r--inc/dosint.h250
-rw-r--r--inc/mbr.h46
-rw-r--r--inc/sassert.h2
-rw-r--r--inc/scsi.h61
-rw-r--r--inc/usb.h45
12 files changed, 913 insertions, 949 deletions
diff --git a/inc/bda.h b/inc/bda.h
deleted file mode 100644
index b447221..0000000
--- a/inc/bda.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * VBMouse - BIOS data area access routines
- * Copyright (C) 2022 Javier S. Pedro
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef BDA_H
-#define BDA_H
-
-#define BIOS_DATA_AREA_SEGMENT 0x40
-
-static inline uint32_t bda_get_dword(unsigned int offset) {
- uint32_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset);
- return *p;
-}
-
-static inline uint16_t bda_get_word(unsigned int offset) {
- uint16_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset);
- return *p;
-}
-
-static inline uint8_t bda_get_byte(unsigned int offset) {
- uint8_t __far *p = MK_FP(BIOS_DATA_AREA_SEGMENT, offset);
- return *p;
-}
-
-#define bda_get_ebda_segment() bda_get_word(0x0e)
-
-#define bda_get_equipment() bda_get_word(0x10)
-
-#define bda_get_video_mode() bda_get_byte(0x49)
-#define bda_get_num_columns() bda_get_word(0x4a)
-#define bda_get_video_page_size() bda_get_word(0x4c)
-#define bda_get_cur_video_page() bda_get_word(0x62)
-#define bda_get_last_row() bda_get_byte(0x84)
-#define bda_get_char_height() bda_get_word(0x85)
-
-#define bda_get_tick_count() bda_get_dword(0x6c)
-#define bda_get_tick_count_lo() bda_get_word(0x6c)
-
-static inline void bda_wait_tick() {
- uint16_t cur_ticks = bda_get_tick_count_lo();
- do {
- //pause();
- } while (cur_ticks == bda_get_tick_count_lo());
-}
-
-static inline void bda_wait_ticks(unsigned int ticks) {
- for (; ticks > 0; ticks--) {
- bda_wait_tick();
- }
-}
-
-#endif // BDA_H
diff --git a/inc/bpb.h b/inc/bpb.h
deleted file mode 100644
index 8df04a1..0000000
--- a/inc/bpb.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef BPB_H
-#define BPB_H
-
-#include <stdint.h>
-#include "sassert.h"
-
-#define DOS_BPB_OFFSET_ON_DISK 0x0B
-
-typedef _Packed struct DOS_BPB_DOS3
-{
- /** Number of bytes per sector. */
- uint16_t bytesPerSector;
- /** Number of sectors per cluster. Must be power of 2. */
- uint8_t sectorsPerCluster;
- /** Number of reserved sectors. */
- uint16_t reservedSectors;
- /** Number of FATs. */
- uint8_t numberOfFATs;
- /** Maximum number of entries in the root directory. */
- uint16_t rootDirEntries;
- /** Total number of sectors on the drive. If drive larger than 32MB, this field is zero, see numberOfSectorsLarge. */
- uint16_t numberOfSectors;
- /** Media descriptor byte. */
- uint8_t mediaType;
- /** Number of sectors used by a FAT. */
- uint16_t sectorsPerFAT;
- /** Number of sectors per track. */
- uint16_t sectorsPerTrack;
- /** Number of heads. */
- uint16_t numberOfHeads;
- /** Number of hidden sectors on the drive, from the start of the drive. */
- uint32_t hiddenSectors;
- /** Number of sectors, only used if drive > 32MB. */
- uint32_t numberOfSectorsLarge;
-} DOS_BPB_DOS3;
-STATIC_ASSERT(sizeof(DOS_BPB_DOS3) == 25);
-
-typedef _Packed struct DOS_BPB_DOS4
-{
- struct DOS_BPB_DOS3;
- uint8_t physicalDriveNumber;
- uint8_t flags;
- uint8_t extendedBootSignature;
- uint32_t volumeSerialNumber;
- char volumeLabel[11];
- char fsType[8];
-} DOS_BPB_DOS4;
-STATIC_ASSERT(sizeof(DOS_BPB_DOS4) == 25 + 26);
-
-typedef _Packed struct DOS_BPB_FAT32
-{
- struct DOS_BPB_DOS3;
- uint32_t sectorPerFatLarge;
- uint16_t extendedFlags;
- uint16_t version;
- uint32_t rootDirCluster;
- uint16_t infoSector;
- uint16_t backupBootSector;
-
- char bootFileName[12];
- uint8_t physicalDriveNumber;
- uint8_t flags;
- uint8_t extendedBootSignature;
- uint32_t volumeSerialNumber;
- char volumeLabel[11];
- char fsType[8];
-} DOS_BPB_FAT32;
-STATIC_ASSERT(sizeof(DOS_BPB_FAT32) == 25 + 54);
-
-/** Union of all BPB types. Default is DOS4 / FAT16. */
-typedef union DOS_BPB
-{
- struct DOS_BPB_DOS3;
- struct DOS_BPB_DOS4 fat16;
- struct DOS_BPB_FAT32 fat32;
-} DOS_BPB;
-
-typedef enum DOS_BPB_MEDIA_TYPE
-{
- DOS_BPB_MEDIA_HDD = 0xF8
-} DOS_BPB_MEDIA_TYPE;
-
-#endif // BPB_H
diff --git a/inc/ch375.h b/inc/ch375.h
new file mode 100644
index 0000000..5ce90a2
--- /dev/null
+++ b/inc/ch375.h
@@ -0,0 +1,361 @@
+/*
+ * CH375 hardware header
+ * Copyright (C) 2024 Javier S. Pedro
+ *
+ * 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 3 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, see <https://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef CH375_H
+#define CH375_H
+
+#include "usb.h"
+
+/** Standard defines */
+
+struct ch375;
+
+enum {
+ CH375_PORT_DATA = 0,
+ CH375_PORT_CMD = 1,
+};
+
+enum ch375_command {
+ /** Returns chip and firmware version in bit 5-0.
+ * output: 1byte.
+ * C375B is 0x37. */
+ CH375_GET_IC_VERSION = 0x01,
+ /** (Host mode) Set serial port baud rate. */
+ CH375_SET_BAUDRATE = 0x02,
+ /** Enter low power mode. Wakes up with USB or host activity. */
+ CH375_ENTER_SLEEP = 0x03,
+ /** Manualy force USB speed.
+ * Input: 1 byte:
+ * 0: Full speed
+ * 1: Full speed with low speed clock frequency (??)
+ * 2: Low speed */
+ CH375_SET_USB_SPEED = 0x04,
+ /** Hardware reset. May take up to 40ms. */
+ CH375_RESET = 0x05,
+ /** Simple eco function. Returns input byte negated.
+ * Input: 1 byte: x
+ * Output: 1 byte: ~x */
+ CH375_CHECK_EXIST = 0x06,
+
+ CH375_READ_REG = 0x0A,
+ CH375_WRITE_REG = 0x0B,
+ /** Sets a 100us timer.
+ * Output: infinite bytes. 0 while timer not expired, non-0 when expired. */
+ CH375_DELAY_100US = 0x0F,
+ /** (Device mode) set our USB vid and PID.
+ * Input: 4 bytes: VID LSB, VID MSB, PID LSB, PID MSB */
+ CH375_SET_USB_ID = 0x12,
+ /** (Device mode) set USB address. ?? */
+ CH375_SET_USB_ADDR = 0x13,
+ /** Set USB mode. Usually takes 20µs.
+ * Input: 1 byte:
+ * 0 : Device mode disabled (i.e. device plug-in detection)
+ * 1 : Device mode with external firmware
+ * 2 : Device mode with built-in firmware
+ * 4 : Host mode disabled (i.e. device plug-in detection)
+ * 5 : Host mode without automatic SOF packets.
+ * 6 : Host mode with automatic SOF packets.
+ * 7 : Host mode, initiate bus reset
+ * Output: 1 byte:
+ * CMD_RET_SUCCESS if OK
+ * CMD_RET_ABORT, etc. if error
+ */
+ CH375_SET_USB_MODE = 0x15,
+ /** (Host mode) Check the connection status.
+ * Output: 1 byte: either USB_INT_CONNECT or USB_INT_DISCONNECT or USB_INT_USB_READY. */
+ CH375_TEST_CONNECT = 0x16,
+ /** Abandon retrying and return NAK. */
+ CH375_ABORT_NAK = 0x17,
+
+ CH375_SET_ENDP2 = 0x18,
+ CH375_SET_ENDP3 = 0x19,
+ CH375_SET_ENDP4 = 0x1A,
+ CH375_SET_ENDP5 = 0x1B,
+ CH375_SET_ENDP6 = 0x1C,
+ CH375_SET_ENDP7 = 0x1D,
+
+ /** Get interrupt status and ack pending interrupts.
+ * Output: 1 byte */
+ CH375_GET_INT_STATUS = 0x22,
+ /** (Device mode) Release current USB buffer. */
+ CH375_UNLOCK_USB = 0x23,
+ /** Read buffer of endpoint of current interrupt.
+ * Output: length byte + data. */
+ CH375_RD_USB_DATA0 = 0x27,
+ /** Equivalent to RD_USB_DATA0 + UNLOCK_USB. */
+ CH375_RD_USB_DATA = 0x28,
+ CH375_WR_USB_DATA3 = 0x29,
+ CH375_WR_USB_DATA5 = 0x2A,
+ CH375_WR_USB_DATA7 = 0x2B,
+ /** (Host mode) Clear error state on endpoint.
+ * Input: 1 byte: endpoint number.
+ * On done: Triggers interrupt. */
+ CH375_CLR_STALL = 0x41,
+ /** (Host mode) Set USB address.
+ * Input: USB address.
+ * On done: Triggers interrupt. */
+ CH375_SET_ADDRESS = 0x45,
+ CH375_GET_DESCR = 0x46,
+ CH375_SET_CONFIG = 0x49,
+ CH375_AUTO_SETUP = 0x4D,
+ CH375_ISSUE_TKN_X = 0x4E,
+ CH375_ISSUE_TOKEN = 0x4F,
+
+ CH375_DISK_BOC = 0x50,
+ CH375_DISK_INIT = 0x51,
+ CH375_DISK_RESET = 0x52,
+ CH375_DISK_SIZE = 0x53,
+ CH375_DISK_READ = 0x54,
+ CH375_DISK_RD_GO = 0x55,
+ CH375_DISK_WRITE = 0x56,
+ CH375_DISK_WR_GO = 0x57,
+ CH375_DISK_INQUIRY = 0x58,
+ CH375_DISK_READY = 0x59,
+ CH375_DISK_R_SENSE = 0x5A,
+};
+
+enum ch375_cmd_ret {
+ CH375_RET_SUCESS = 0x51,
+ CH375_RET_ABORT = 0x5F
+};
+
+enum ch375_int {
+ /** if (x & mask) == val, this is a USB device mode interrupt. */
+ CH375_INT_DEVICE_MASK = 0xF0,
+ CH375_INT_DEVICE_VAL = 0x00,
+
+ CH375_INT_HOST_MASK = 0xE0,
+ CH375_INT_HOST_VAL = 0x20,
+
+ CH375_INT_BUS_RESET1 = 0x03,
+ CH375_INT_BUS_RESET2 = 0x07,
+ CH375_INT_BUS_RESET3 = 0x0B,
+ CH375_INT_BUS_RESET4 = 0x0F,
+
+ /** USB bus suspend event. */
+ CH375_INT_USB_SUSPEND = 0x05,
+ /** Wakeup from USB suspend. */
+ CH375_INT_USB_WAKE_UP = 0x06,
+ CH375_INT_USB_SUCCESS = 0x14,
+ CH375_INT_USB_CONNECT = 0x15,
+ CH375_INT_USB_DISCONNECT = 0x16,
+ CH375_INT_USB_BUF_OVER = 0x17,
+ CH375_INT_USB_READY = 0x18,
+ CH375_INT_USB_DISK_READ = 0x1D,
+ CH375_INT_USB_DISK_WRITE = 0x1E,
+ CH375_INT_USB_DISK_ERR = 0x1F,
+};
+
+enum CH375_REG {
+ /** (Host mode) Get data rate of current USB device.
+ * Bit 4: if 1= Low Speed. if 0 = Full Speed.*/
+ CH375_REG_DEV_RATE = 0x0A,
+ /** (Device mode): how to check USB bus suspend status.
+ * 0: Do not check
+ * 4: Check at 50ms intervals
+ * 5: Check at 10ms intervals */
+ CH375_REG_CHK_SUSPEND = 0x10,
+ CH375_REG_TOGGLE = 0x1A,
+
+ /** ???
+ * Bit 5 : set after disk is online? but never unset... */
+ CH375_REG_DISK_STATUS = 0x20,
+ /** (Host mode) Set the number of retries for USB transactions.
+ * If bit 7 is 0, no retry is performed when NAK is received.
+ * If bit 7 is 1 and bit 6 is 0, unlimited retries are performed when NAK is received.
+ * If bit 7 is 1 and bit 6 is 1, the maximum retry is 2 seconds when NAK is received.
+ * Bits 5-0 are the number of retries after timeout. */
+ CH375_REG_RETRY = 0x25,
+ /** (Host disk mode) Set the current LUN. */
+ CH375_REG_DISK_LUN = 0x34,
+ CH375_REG_DISK_MAX_LUN = 0x38,
+ /** (Host disk mode) Set the total number of 64-byte packets per sector.
+ * E.g. 8 = 512 byte sectors. */
+ CH375_REG_DISK_PKT_P_SEC = 0x39,
+ /// Drive letter (in ASCII) currently assigned. This is set by software.
+ CH375_REG_DISK_NAME = 0x3E
+
+ // 0x1B what's on this register ? 0x7F , 0x80 values seen
+ // 0x20 ?? some type of status ?
+ // 0x31, 0x32, 0x33 ??
+
+};
+
+#define CH375_BLOCK_SIZE 64
+
+// HELPER ROUTINES
+
+/* You have to define these routines for the helper functions to work. */
+
+static inline uint8_t ch375_read_data(struct ch375 *dev);
+static inline void ch375_write_data(struct ch375 *dev, uint8_t data);
+
+static inline void ch375_send_command(struct ch375 *dev, enum ch375_command cmd);
+static inline bool ch375_poll_interrupt(struct ch375 *dev);
+
+// GLOBAL COMMANDS
+
+static inline uint8_t ch375_get_version(struct ch375 *dev)
+{
+ ch375_send_command(dev, CH375_GET_IC_VERSION);
+ return ch375_read_data(dev) & 0x3F;
+}
+
+static inline void ch375_enter_sleep(struct ch375 *dev)
+{
+ ch375_send_command(dev, CH375_ENTER_SLEEP);
+}
+
+static inline void ch375_reset(struct ch375 *dev)
+{
+ ch375_send_command(dev, CH375_RESET);
+}
+
+static inline uint8_t ch375_check_exists(struct ch375 *dev, uint8_t val)
+{
+ ch375_send_command(dev, CH375_CHECK_EXIST);
+ ch375_write_data(dev, val);
+ return ch375_read_data(dev);
+}
+
+static inline uint8_t ch375_get_int_status(struct ch375 *dev)
+{
+ ch375_send_command(dev, CH375_GET_INT_STATUS);
+ return ch375_read_data(dev);
+}
+
+static uint8_t ch375_read_reg(struct ch375 *dev, enum CH375_REG reg)
+{
+ ch375_send_command(dev, CH375_READ_REG);
+ ch375_write_data(dev, reg);
+ return ch375_read_data(dev);
+}
+
+static void ch375_write_reg(struct ch375 *dev, enum CH375_REG reg, uint8_t value)
+{
+ ch375_send_command(dev, CH375_WRITE_REG);
+ ch375_write_data(dev, reg);
+ ch375_write_data(dev, value);
+}
+
+enum ch375_usb_mode {
+ CH375_USB_MODE_DEVICE_DISABLED = 0,
+ CH375_USB_MODE_DEVICE_EXTERNAL_FIRMWARE = 1,
+ CH375_USB_MODE_DEVICE_INTERNAL_FIRMWARE = 2,
+ CH375_USB_MODE_HOST_DISABLED = 4,
+ CH375_USB_MODE_HOST = 5,
+ CH375_USB_MODE_HOST_AUTO_SOF = 6,
+ CH375_USB_MODE_HOST_RESET = 7
+};
+
+static void ch375_set_usb_mode(struct ch375 *dev, enum ch375_usb_mode mode) {
+ ch375_send_command(dev, CH375_SET_USB_MODE);
+ ch375_write_data(dev, mode);
+}
+
+enum ch375_usb_speed {
+ CH375_USB_SPEED_FULL = 0,
+ CH375_USB_SPEED_LOW = 2
+};
+
+// Seems to be for CH375B only. See below for CH375A alternative.
+static void ch375_set_usb_speed(struct ch375 *dev, enum ch375_usb_speed speed) {
+ ch375_send_command(dev, CH375_SET_USB_SPEED);
+ ch375_write_data(dev, speed);
+}
+
+static void ch375a_set_low_speed(struct ch375 *dev) {
+ // Undocumented.
+ ch375_write_reg(dev, 0x17, 0xd8);
+}
+
+// HOST COMMANDS
+
+static void ch375_test_connect(struct ch375 *dev) {
+ ch375_send_command(dev, CH375_TEST_CONNECT);
+}
+
+static void ch375_auto_setup(struct ch375 *dev) {
+ ch375_send_command(dev, CH375_AUTO_SETUP);
+}
+
+enum ch375_retry_mode {
+ CH375_RETRY_NAK_INFINITE = 0x80,
+ CH375_RETRY_NAK_2S = 0xC0,
+ CH375_RETRY_NAK_NONE = 0x00,
+
+ CH375_RETRY_TIMEOUT_MAX = 0x1F
+};
+
+static void ch375_set_retry(struct ch375 *dev, enum ch375_retry_mode mode) {
+ ch375_write_reg(dev, CH375_REG_RETRY, mode);
+}
+
+static void ch375_get_descriptor(struct ch375 *dev, usb_descriptor_type type) {
+ ch375_send_command(dev, CH375_GET_DESCR);
+ ch375_write_data(dev, type);
+}
+
+// DISK COMMANDS
+
+enum ch375_reg_disk_status {
+ CH375_REG_DISK_STATUS_READY = 0x20
+};
+
+static inline bool ch375_is_disk_ready(struct ch375 *dev)
+{
+ return ch375_read_reg(dev, CH375_REG_DISK_STATUS) & CH375_REG_DISK_STATUS_READY;
+}
+
+static void ch375_disk_init(struct ch375 *dev)
+{
+ ch375_send_command(dev, CH375_DISK_INIT);
+}
+
+static void ch375_disk_read(struct ch375 *dev, uint32_t lba, uint8_t nsectors)
+{
+ ch375_send_command(dev, CH375_DISK_READ);
+ ch375_write_data(dev, (lba >> 0) & 0xFF);
+ ch375_write_data(dev, (lba >> 8) & 0xFF);
+ ch375_write_data(dev, (lba >> 16) & 0xFF);
+ ch375_write_data(dev, (lba >> 24) & 0xFF);
+ ch375_write_data(dev, nsectors);
+}
+
+static void ch375_disk_write(struct ch375 *dev, uint32_t lba, uint8_t nsectors)
+{
+ ch375_send_command(dev, CH375_DISK_WRITE);
+ ch375_write_data(dev, (lba >> 0) & 0xFF);
+ ch375_write_data(dev, (lba >> 8) & 0xFF);
+ ch375_write_data(dev, (lba >> 16) & 0xFF);
+ ch375_write_data(dev, (lba >> 24) & 0xFF);
+ ch375_write_data(dev, nsectors);
+}
+
+static void ch375_test_disk_ready(struct ch375 *dev)
+{
+ ch375_send_command(dev, CH375_DISK_READY);
+}
+
+static void ch375_disk_r_sense(struct ch375 *dev)
+{
+ ch375_send_command(dev, CH375_DISK_R_SENSE);
+}
+
+#endif
diff --git a/inc/chuver.h b/inc/chuver.h
new file mode 100644
index 0000000..f816114
--- /dev/null
+++ b/inc/chuver.h
@@ -0,0 +1,7 @@
+#ifndef CHUVER_H
+#define CHUVER_H
+
+#define CHUDISK_VERSION_MAJOR 1
+#define CHUDISK_VERSION_MINOR 0x0
+
+#endif /* CHUVER_H */
diff --git a/inc/dlog.h b/inc/dlog.h
new file mode 100644
index 0000000..ab6f4e9
--- /dev/null
+++ b/inc/dlog.h
@@ -0,0 +1,439 @@
+/*
+ * VBMouse - printf & logging routines
+ * Copyright (C) 2022 Javier S. Pedro
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef DLOG_H
+#define DLOG_H
+
+#include <stdarg.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <i86.h>
+#include <conio.h>
+
+// Customizable defines
+/** If 0, these routines become nops */
+#ifndef ENABLE_DLOG
+#define ENABLE_DLOG 0
+#endif
+/** Target of logging messages. See DLOG_TARGET_* below. */
+#ifndef DLOG_TARGET
+#define DLOG_TARGET DLOG_TARGET_UNDEF
+#endif
+/** When using DLOG_TARGET_IOPORT, which IO port to target.
+ * VirtualBox uses 0x504, Bochs, DOSBox and descendants use 0xE9.
+ * When using DLOG_TARGET_SERIAL, the desired UART IO base port. (e.g. COM1 = 0x3F8). */
+#ifndef DLOG_TARGET_PORT
+#define DLOG_TARGET_PORT 0x504
+#endif
+
+// End of customizable defines
+
+/** You provide your own dlog_init and dputc routines. */
+#define DLOG_TARGET_UNDEF 0
+/** Output to the screen using BIOS TTY interface. */
+#define DLOG_TARGET_BIOSTTY 1
+/** Output to a serial port. UART io base defined in DLOG_TARGET_PORT. */
+#define DLOG_TARGET_SERIAL 2
+/** Output to a raw IO port defined in DLOG_TARGET_PORT.*/
+#define DLOG_TARGET_IOPORT 3
+
+#if ENABLE_DLOG
+
+/** Initializes the debug log port. */
+static void dlog_init();
+
+/** Logs a single character to the debug message IO port. */
+static inline void dputc(char c);
+
+#if DLOG_TARGET == DLOG_TARGET_BIOSTTY
+
+static inline void dlog_init()
+{
+ // No initialization required
+}
+
+static inline void dconputc(char c);
+#pragma aux dconputc = \
+ "mov ah, 0x0E" \
+ "xor bx, bx" \
+ "int 0x10" \
+ __parm [AL] \
+ __modify __exact [AH AL BH BL];
+
+static inline void dputc(char c)
+{
+ // Need to convert CR into CRLF...
+ if (c == '\n') {
+ dconputc('\n');
+ dconputc('\r');
+ } else {
+ dconputc(c);
+ }
+}
+
+
+#elif DLOG_TARGET == DLOG_TARGET_SERIAL
+
+static void dlog_init()
+{
+ // Comes from https://wiki.osdev.org/Serial_Ports#Initialization
+ outp(DLOG_TARGET_PORT + 1, 0x00); // Disable all interrupts
+ outp(DLOG_TARGET_PORT + 3, 0x80); // Enable DLAB (set baud rate divisor)
+ outp(DLOG_TARGET_PORT + 0, 0x01); // Set divisor to 1 (lo byte) 115200 baud
+ outp(DLOG_TARGET_PORT + 1, 0x00); // (hi byte)
+ outp(DLOG_TARGET_PORT + 3, 0x03); // 8 bits, no parity, one stop bit
+ outp(DLOG_TARGET_PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
+ outp(DLOG_TARGET_PORT + 4, 0x03); // RTS/DSR set, IRQs disabled
+}
+
+static inline void dputc(char c)
+{
+ while (!(inp(DLOG_TARGET_PORT + 5) & 0x20));
+ outp(DLOG_TARGET_PORT, c);
+}
+
+#elif DLOG_TARGET == DLOG_TARGET_IOPORT
+
+static inline void dlog_init()
+{
+ // No initialization required
+}
+
+static inline void dputc(char c)
+{
+ outp(DLOG_TARGET_PORT, c);
+}
+
+#endif /* DLOG_TARGET */
+
+static void d_utoa(unsigned num, unsigned base)
+{
+#if UINT_MAX > 99999
+ char buf[12];
+#else
+ char buf[6];
+#endif
+ int i = 0;
+
+ do {
+ unsigned digit = num % base;
+
+ if (digit < 10) {
+ buf[i] = '0' + digit;
+ } else {
+ buf[i] = 'a' + (digit - 10);
+ }
+
+ i++;
+ num /= base;
+ } while (num > 0 && i < sizeof(buf));
+
+ while (i--) {
+ dputc(buf[i]);
+ }
+}
+
+static void d_ultoa(unsigned long num, unsigned base)
+{
+ char buf[12];
+ int i = 0;
+
+ do {
+ unsigned digit = 0;
+
+ // Do unsigned long division with remained on whichever platform we are
+ static inline void uldiv(void);
+#if M_I86
+ // 16-bit code
+ #if _M_IX86 >= 300
+ // 16-bit compiler, but for running on 386+: preserve 32-bit regs and use them.
+ #pragma aux uldiv = \
+ "push eax" /* save 32-bit regs, compiler does not know about them*/ \
+ "push ecx" \
+ "push edx" \
+ "mov eax, [num]" \
+ "movzx ecx, [base]" \
+ "xor edx, edx" \
+ \
+ "div ecx" \
+ \
+ "mov [num], eax" \
+ "mov [digit], dx" \
+ \
+ "pop edx" \
+ "pop ecx" \
+ "pop eax" \
+ __modify __exact [];
+ #else
+ // 16-bit compiler, 16-bit code: 16-bit division
+ #pragma aux uldiv = \
+ "mov cx, word ptr [num]" \
+ "mov ax, word ptr [num+2]" \
+ "mov bx, [base]" \
+ "xor dx, dx" \
+ \
+ "div bx" /* ax = HI(num)/base -> HI quotient, dx = HI(num)%base -> HI remainder */ \
+ "xchg ax,cx" /* cx = HI(num)/base, ax = LO(num) */ \
+ "div bx" /* ax = (HI(num)%base)/base -> true quotient , dx = (HI(num)%base)%base -> true remainder */ \
+ \
+ "mov word ptr [num], ax" \
+ "mov word ptr [num+2], cx" \
+ "mov [digit], dx" \
+ __modify __exact [];
+ #endif
+#elif M_I386
+ // 32-bit compiler, 32-bit code
+ #pragma aux uldiv = \
+ "mov eax, [num]" \
+ "mov ecx, [base]" \
+ "xor edx, edx" \
+ \
+ "div ecx" \
+ \
+ "mov [num], eax" \
+ "mov [digit], edx" \
+ __modify __exact [eax ecx edx];
+#else
+ #error unknown platform
+#endif
+ uldiv();
+
+ if (digit < 10) {
+ buf[i] = '0' + digit;
+ } else {
+ buf[i] = 'a' + (digit - 10);
+ }
+
+ i++;
+ } while (num > 0 && i < sizeof(buf));
+
+ while (i--) {
+ dputc(buf[i]);
+ }
+}
+
+static void d_itoa(int num, unsigned base)
+{
+ unsigned unum;
+
+ if (num < 0) {
+ dputc('-');
+ unum = -num;
+ } else {
+ unum = num;
+ }
+
+ d_utoa(unum, base);
+}
+
+static void d_ltoa(long num, unsigned base)
+{
+ unsigned long unum;
+
+ if (num < 0) {
+ dputc('-');
+ unum = -num;
+ } else {
+ unum = num;
+ }
+
+ d_ultoa(unum, base);
+}
+
+static unsigned d_strtou(const char * __far *str)
+{
+ unsigned i = 0;
+ const char *s = *str;
+ char c = *s;
+ while (c >= '0' && c <= '9') {
+ i = (i * 10) + (c - '0');
+ c = *(++s);
+ }
+ *str = s;
+ return i;
+}
+
+static void d_printstr(const char __far *s, unsigned l)
+{
+ while (l > 0 && *s) {
+ dputc(*s++);
+ l--;
+ }
+}
+
+static void dprintf(const char *fmt, ...)
+{
+ va_list va;
+ char c;
+
+ va_start(va, fmt);
+
+ while ((c = *(fmt++))) {
+ if (c == '%') {
+ unsigned width, precision, size;
+ bool is_far = false;
+
+ width = d_strtou(&fmt);
+
+ if ((c = *fmt) == '.') {
+ fmt++;
+ precision = d_strtou(&fmt);
+ } else {
+ precision = UINT_MAX;
+ }
+
+ switch ((c = *fmt)) {
+ case 'l':
+ size = sizeof(long);
+ fmt++;
+ break;
+ case 'h':
+ size = sizeof(short);
+ fmt++;
+ break;
+ case 'F':
+ is_far = true;
+ fmt++;
+ break;
+ default:
+ size = sizeof(int);
+ break;
+ }
+
+ switch ((c = *fmt)) {
+ case 'd':
+ switch (size) {
+#if INT_MAX != SHRT_MAX
+ case sizeof(short):
+ d_itoa(va_arg(va, short), 10);
+ break;
+#endif
+ case sizeof(int):
+ d_itoa(va_arg(va, int), 10);
+ break;
+#if INT_MAX != LONG_MAX
+ case sizeof(long):
+ d_ltoa(va_arg(va, long), 10);
+ break;
+#endif
+ }
+ break;
+ case 'u':
+ switch (size) {
+#if INT_MAX != SHRT_MAX
+ case sizeof(short):
+ d_utoa(va_arg(va, unsigned short), 10);
+ break;
+#endif
+ case sizeof(int):
+ d_utoa(va_arg(va, unsigned int), 10);
+ break;
+#if INT_MAX != LONG_MAX
+ case sizeof(long):
+ d_ultoa(va_arg(va, unsigned long), 10);
+ break;
+#endif
+ }
+ break;
+ case 'x':
+ switch (size) {
+#if INT_MAX != SHRT_MAX
+ case sizeof(short):
+ d_utoa(va_arg(va, unsigned short), 16);
+ break;
+#endif
+ case sizeof(int):
+ d_utoa(va_arg(va, unsigned int), 16);
+ break;
+#if INT_MAX != LONG_MAX
+ case sizeof(long):
+ d_ultoa(va_arg(va, unsigned long), 16);
+ break;
+#endif
+ }
+ break;
+ case 'b':
+ switch (size) {
+#if INT_MAX != SHRT_MAX
+ case sizeof(short):
+ d_utoa(va_arg(va, unsigned short), 2);
+ break;
+#endif
+ case sizeof(int):
+ d_utoa(va_arg(va, unsigned int), 2);
+ break;
+#if INT_MAX != LONG_MAX
+ case sizeof(long):
+ d_ultoa(va_arg(va, long), 2);
+ break;
+#endif
+ }
+ break;
+ case 'p':
+ if (is_far) {
+ void __far *p = va_arg(va, void __far *);
+ d_utoa(FP_SEG(p), 16);
+ dputc(':');
+ d_utoa(FP_OFF(p), 16);
+ } else {
+ d_utoa((unsigned) va_arg(va, void*), 16);
+ }
+ break;
+ case 's':
+ d_printstr(is_far ? va_arg(va, const char __far *)
+ : va_arg(va, const char *),
+ precision);
+ break;
+ case 'c':
+ dputc(va_arg(va, char));
+ break;
+ case '%':
+ dputc('%');
+ break;
+ }
+ fmt++;
+ } else {
+ dputc(c);
+ }
+ }
+
+ va_end(va);
+}
+
+static void dputs(const char *s)
+{
+ char c;
+ while ((c = *(s++))) {
+ dputc(c);
+ }
+ dputc('\n');
+}
+
+#else /* ENABLE_DLOG */
+
+#define dlog_nop() do { } while(0)
+#define dlog_init() dlog_nop()
+#define dputc(c) dlog_nop()
+#define dputs(s) dlog_nop()
+#define dprintf(...) dlog_nop()
+
+
+#endif /* ENABLE_DLOG */
+
+#endif /* DLOG_H */
diff --git a/inc/dosapi.h b/inc/dosapi.h
deleted file mode 100644
index 18dbde0..0000000
--- a/inc/dosapi.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * VBMouse - Interface to some DOS int 21h services
- * Copyright (C) 2022 Javier S. Pedro
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef INT21DOS_H
-#define INT21DOS_H
-
-#include <stddef.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <dos.h>
-#include "sassert.h"
-
-#define DOS_PSP_SIZE 256
-
-enum dos_error {
- DOS_ERROR_SUCCESS = 0,
- DOS_ERROR_INVALID_FUNCTION = 1,
- DOS_ERROR_FILE_NOT_FOUND = 2,
- DOS_ERROR_PATH_NOT_FOUND = 3,
- DOS_ERROR_TOO_MANY_OPEN_FILES = 4,
- DOS_ERROR_ACCESS_DENIED = 5,
- DOS_ERROR_INVALID_HANDLE = 6,
- DOS_ERROR_ARENA_TRASHED = 7,
- DOS_ERROR_NOT_ENOUGH_MEMORY = 8,
- DOS_ERROR_INVALID_BLOCK = 9,
- DOS_ERROR_BAD_ENVIRONMENT = 10,
- DOS_ERROR_BAD_FORMAT = 11,
- DOS_ERROR_INVALID_ACCESS = 12,
- DOS_ERROR_INVALID_DATA = 13,
- DOS_ERROR_OUT_OF_MEMORY = 14,
- DOS_ERROR_INVALID_DRIVE = 15,
- DOS_ERROR_CURRENT_DIRECTORY = 16,
- DOS_ERROR_NOT_SAME_DEVICE = 17,
- DOS_ERROR_NO_MORE_FILES = 18,
- DOS_ERROR_WRITE_PROTECT = 19,
- DOS_ERROR_BAD_UNIT = 20,
- DOS_ERROR_NOT_READY = 21,
- DOS_ERROR_BAD_COMMAND = 22,
- DOS_ERROR_CRC = 23,
- DOS_ERROR_BAD_LENGTH = 24,
- DOS_ERROR_SEEK = 25,
- DOS_ERROR_NOT_DOS_DISK = 26,
- DOS_ERROR_SECTOR_NOT_FOUND = 27,
-
- DOS_ERROR_GEN_FAILURE = 31,
-
- DOS_ERROR_HANDLE_EOF = 38,
- DOS_ERROR_HANDLE_DISK_FULL = 39,
-
- DOS_ERROR_FILE_EXISTS = 80,
- DOS_ERROR_CANNOT_MAKE = 82,
-};
-
-// General functions
-
-static inline void dos_print_char(char c);
-#pragma aux dos_print_char = \
- "mov ah, 0x02" \
- "int 0x21" \
- __parm [dl] \
- __modify [ah]
-
-static inline uint8_t dos_read_char(void);
-#pragma aux dos_read_char = \
- "mov ah, 0x08" \
- "int 0x21" \
- __value [al] \
- __modify [ax]
-
-static inline void dos_print_string(const char *s);
-#pragma aux dos_print_string = \
- "mov ah, 0x09" \
- "int 0x21" \
- __parm [dx] \
- __modify [ah]
-
-static inline uint16_t dos_get_version(void);
-#pragma aux dos_get_version = \
- "mov ah, 0x30" \
- "int 0x21" \
- __value [ax] \
- __modify [bx cx]
-
-// Memory manipulation functions
-
-typedef __segment segment_t;
-
-enum dos_allocation_strategy {
- DOS_FIT_FIRST = 0,
- DOS_FIT_BEST = 1,
- DOS_FIT_LAST = 2,
-
- DOS_FIT_HIGH = 0x80,
- DOS_FIT_HIGHONLY = 0x40,
-};
-
-/** Converts bytes to paragraphs (16 bytes), rounding up. */
-static inline unsigned get_paragraphs(unsigned bytes)
-{
- return (bytes + 15) / 16;
-}
-
-static unsigned dos_query_allocation_strategy(void);
-#pragma aux dos_query_allocation_strategy = \
- "mov ax, 0x5800" \
- "int 0x21" \
- __value [ax]
-
-static int dos_set_allocation_strategy(unsigned strategy);
-#pragma aux dos_set_allocation_strategy = \
- "clc" \
- "mov ax, 0x5801" \
- "int 0x21" \
- "jc end" \
- "mov ax, 0" \
- "end:" \
- __parm [bx] \
- __value [ax]
-
-static bool dos_query_umb_link_state(void);
-#pragma aux dos_query_umb_link_state = \
- "mov ax, 0x5802" \
- "int 0x21" \
- __value [al]
-
-static int dos_set_umb_link_state(bool state);
-#pragma aux dos_set_umb_link_state = \
- "clc" \
- "mov ax, 0x5803" \
- "int 0x21" \
- "jc end" \
- "mov ax, 0" \
- "end:" \
- __parm [bx] \
- __value [ax]
-
-/** Allocates a new DOS segment.
- * @returns either the allocated segment or 0 if any error. */
-static __segment dos_alloc(unsigned paragraphs);
-#pragma aux dos_alloc = \
- "clc" \
- "mov ah, 0x48" \
- "int 0x21" \
- "jnc end" \
- "mov ax, 0xB" \
- "end:" \
- __parm [bx] \
- __value [ax]
-
-/** Frees DOS segment. */
-static void dos_free(segment_t segment);
-#pragma aux dos_free = \
- "mov ah, 0x49" \
- "int 0x21" \
- __parm [es] \
- __modify [ax]
-
-/** Sets a given PSP as the current active process. */
-static void dos_set_psp(segment_t psp);
-#pragma aux dos_set_psp = \
- "mov ah, 0x50" \
- "int 0x21" \
- __parm [bx] \
- __modify [ax]
-
-#endif // INT21DOS_H
diff --git a/inc/dosdrv.h b/inc/dosdrv.h
deleted file mode 100644
index 0c33c54..0000000
--- a/inc/dosdrv.h
+++ /dev/null
@@ -1,319 +0,0 @@
-#ifndef DOSDRV_H
-#define DOSDRV_H
-
-#include <stdint.h>
-#include "bpb.h"
-#include "sassert.h"
-
-typedef enum DOS_DD_ERROR
-{
- DOS_DD_ERR_WRITE_PROTECT = 0,
- DOS_DD_ERR_UNKNOWN_UNIT = 1,
- DOS_DD_ERR_DRIVE_NOT_READY = 2,
- DOS_DD_ERR_UNKNOWN_COMMAND = 3,
- DOS_DD_ERR_CRC = 4,
- DOS_DD_ERR_BAD_DRS_LEN = 5,
- DOS_DD_ERR_SEEK = 6,
- DOS_DD_ERR_UNKNOWN_MEDIA = 7,
- DOS_DD_ERR_SECTOR_NOT_FOUND = 8,
- DOS_DD_ERR_PRINTER_OUT_OF_PAPER = 9,
- DOS_DD_ERR_WRITE_FAULT = 10,
- DOS_DD_ERR_READ_FAULT = 11,
- DOS_DD_ERR_GENERAL_FAILURE = 12,
- DOS_DD_ERR_MEDIA_UNAVAILABLE = 0xE,
- DOS_DD_ERR_INVALID_DISK_CHANGE = 0xF
-} DOS_DD_ERROR;
-
-typedef enum DOS_DD_STATUS {
- DOS_DD_STATUS_DONE = 1 << 8,
- DOS_DD_STATUS_BUSY = 1 << 9,
- DOS_DD_STATUS_ERROR = 1 << 15,
-
- DOS_DD_STATUS_ERROR_DONE = DOS_DD_STATUS_ERROR | DOS_DD_STATUS_DONE
-} DOS_DD_STATUS;
-
-typedef enum DOS_DD_MEDIAQUERY_RESULT {
- DOS_DD_MEDIAQUERY_CHANGED = -1,
- DOS_DD_MEDIAQUERY_UNKNOWN = 0,
- DOS_DD_MEDIAQUERY_NOT_CHANGED = 1
-} DOS_DD_MEDIAQUERY_RESULT;
-
-typedef _Packed struct DOS_DRS
-{
- /** The length of this structure. */
- uint8_t len;
- /** The subunit the operation is for. */
- uint8_t unit;
-
- uint8_t function;
-
- uint16_t status;
-
- uint32_t reserved1;
- uint32_t reserved2;
-
- union {
- union {
- struct {
- uint8_t reserved;
- /** End of memory available for driver. */
- void __far * avail_addr;
- /** Command line (i.e. the DEVICE= line used to load this driver. ) */
- const char __far * cmdline;
- /** First drive that is going to be allocated for this driver. */
- uint8_t first_drive_number;
- } in;
- struct {
- /** Number of units/drive letters to allocate for this driver. */
- uint8_t number_units;
- /** Break addr: everything after this address is deallocated after init. */
- void __far * break_addr;
- /** Pointer to the BPB array. */
- DOS_BPB * __far * bpbs;
- uint8_t reserved;
- /** Display error message on failure. */
- uint16_t error_msg_flag;
- } out;
- } init;
- union {
- struct {
- /** Media descriptor of the current media. */
- uint8_t cur_media_desc;
- } in;
- struct {
- uint8_t reserved;
- uint8_t result;
- /** Volume ID of previous loaded media. */
- char far * volume_id;
- } out;
- } mediacheck;
- union {
- struct {
- /** Media descriptor of the current media. */
- uint8_t cur_media_desc;
- /** Buffer with sector 0 of the disk, depending on driver flags */
- void __far * sector_zero;
- } in;
- struct {
- uint8_t reserved;
- void __far * sector_zero;
- /** Address for the new BPB. */
- DOS_BPB __far * bpb;
- } out;
- } buildbpb;
- struct {
- uint8_t data;
- /** Input: pointer to buffer. */
- void __far * buffer;
- /** Input/Output: buffer len / actual len */
- uint16_t len;
- } ioctlrw;
- struct {
- /** Input: current media descriptor byte. */
- uint8_t cur_media_desc;
- /** Input: pointer to buffer. */
- void __far * buffer;
- /** Input: Number of sectors to read/write. Output: number sectors actually read/written. */
- uint16_t len;
- /** Input: Begin sector. Or, if 0xFFFF, see start_sector_huge. */
- uint16_t start_sector;
- /** Output: Current Volume ID. */
- char far * volume_id;
- uint32_t start_sector_huge;
- } rw;
- struct {
- uint8_t category;
- uint8_t minor;
- uint32_t reserved;
- void __far * data;
- } ioctl;
- } cmd;
-} DOS_DRS;
-
-typedef void (DOS_DD_STRATEGY)(DOS_DRS __far *drs);
-typedef void (DOS_DD_INTERRUPT)(DOS_DRS __far *drs);
-#pragma aux DOS_DD_STRATEGY __parm __caller [es bx] __modify [] __loadds __far
-#pragma aux DOS_DD_INTERRUPT __parm __caller [] __modify [] __loadds __far
-
-typedef enum DOS_DD_FUNCTIONS
-{
- DOS_DD_FUNC_INIT = 0,
- DOS_DD_FUNC_MEDIA_CHECK = 1,
- DOS_DD_FUNC_BUILD_BPB = 2,
- DOS_DD_FUNC_IOCTL_READ = 3,
- DOS_DD_FUNC_READ = 4,
- DOS_DD_FUNC_NONDESTRUCTIVE_READ = 5,
- DOS_DD_FUNC_INPUT_STATUS = 6,
- DOS_DD_FUNC_INPUT_FLUSH = 7,
- DOS_DD_FUNC_WRITE = 8,
- DOS_DD_FUNC_WRITE_VERIFY = 9,
- DOS_DD_FUNC_OUTPUT_STATUS = 10,
- DOS_DD_FUNC_OUTPUT_FLUSH = 11,
- DOS_DD_FUNC_IOCTL_WRITE = 12,
- DOS_DD_FUNC_DEVICE_OPEN = 13,
- DOS_DD_FUNC_DEVICE_CLOSE = 14,
- DOS_DD_FUNC_REMOVEABLE_MEDIA = 15,
- DOS_DD_FUNC_OUTPUT_UNTIL_BUSY = 16,
- DOS_DD_FUNC_IOCTL_GENERIC = 19,
- DOS_DD_FUNC_GET_LOGICAL_DEVICE = 23,
- DOS_DD_FUNC_SET_LOGICAL_DEVICE = 24,
- DOS_DD_FUNC_IOCTL_QUERY = 25,
-} DOS_DD_COMMAND;
-
-
-/** Device driver (.sys) header */
-typedef _Packed struct DOS_DD_HEADER
-{
- void __far *nextDevice;
- uint16_t attributes;
- DOS_DD_STRATEGY *strategyCb;
- DOS_DD_INTERRUPT *interrupCb;
- char name[8];
-} DOS_DD_HEADER;
-
-typedef enum DOS_DD_ATTRIBUTES
-{
- /** Character-device driver. */
- DOS_DD_CHAR = 1 << 15,
- /** Block-device driver. */
- DOS_DD_BLOCK = 0,
-
- /** Supports IOCTL Read/Write funcs */
- DOS_DD_SUPPORT_IOCTL_RW = 1 << 14,
-
- /** Support IOCTL query funcs. */
- DOS_DD_SUPPORT_IOCTL_QUERY = 1 << 7,
-
- // Character-device specific
- DOS_CHAR_CURRENT_STDIN_DEVICE = 1 << 0,
- DOS_CHAR_CURRENT_STDOUT_DEVICE = 1 << 1,
- DOS_CHAR_CURRENT_NUL_DEVICE = 1 << 2,
- DOS_CHAR_CURRENT_CLOCK_DEVICE = 1 << 3,
- DOS_CHAR_SPECIAL_FAST_CONSOLE_IO = 1 << 4,
- DOS_CHAR_OUTPUT_UNTIL_BUSY = 1 << 13,
-
- // Block-device specific
- /** The driver support 32-bit sector address. (Can use the _huge fields. ) */
- DOS_BLOCK_SUPPORT_32BIT_ADDRESSES = 1 << 1,
-
- /** Support Get/Set Logical Drive and generic IOCTL funcs. */
- DOS_BLOCK_SUPPORT_IOCTL_GENERIC = 1 << 6,
-
- /** Supports Open/Close/Removable media funcs */
- DOS_BLOCK_SUPPORT_REMOVABLE_MEDIA = 1 << 11,
-
- /** if set, DOS not read the 1st sector of the 1st FAT during build bpb. */
- DOS_BLOCK_FORMAT_NON_IBM = 1 << 13,
-} DOS_DD_ATTRIBUTES;
-
-// Generic IOCTLs
-
-typedef enum DOS_IOCTL_CATEGORY
-{
- DOS_IOCTL_SERIAL = 0x1,
- DOS_IOCTL_CONSOLE = 0x3,
- DOS_IOCTL_PARALLEL = 0x5,
- DOS_IOCTL_DISK = 0x8,
-} DOS_IOCTL_CATEGORY;
-
-typedef enum DOS_IOCTL_MINOR
-{
- DOS_IOCTL_CONSOLE_SET_ITERATION_COUNT = 0x45,
- DOS_IOCTL_CONSOLE_SELECT_CODE_PAGE = 0x4A,
- DOS_IOCTL_CONSOLE_START_CODE_PAGE_PREPARE = 0x4C,
- DOS_IOCTL_CONSOLE_END_CODE_PAGE_PREPARE = 0x4D,
- DOS_IOCTL_CONSOLE_GET_IERATION_COUNT = 0x65,
- DOS_IOCTL_CONSOLE_QUERY_SELECTED_CODE_PAGE = 0x6A,
- DOS_IOCTL_CONSOLE_QUERY_CODE_PAGE_PREPARE_LIST = 0x6B,
-
- DOS_IOCTL_DISK_SET_DEVICE_PARAMETERS = 0x40,
- DOS_IOCTL_DISK_WRITE_TRACK_ON_LOGICAL_DEVICE = 0x41,
- DOS_IOCTL_DISK_FORMAT_TRACK_ON_LOGICAL_DEVICE = 0x42,
- DOS_IOCTL_DISK_SET_MEDIA_ID = 0x46,
- DOS_IOCTL_DISK_GET_DEVICE_PARAMETERS = 0x60,
- DOS_IOCTL_DISK_READ_TRACK_ON_LOGICAL_DEVICE = 0x61,
- DOS_IOCTL_DISK_VERIFY_TRACK_ON_LOGICAL_DEVICE = 0x62,
- DOS_IOCTL_DISK_GET_MEDIA_ID = 0x66,
- DOS_IOCTL_DISK_SENSE_MEDIA_TYPE = 0x68,
-} DOS_IOCTL_MINOR;
-
-
-// Block-device / disk data structures
-
-typedef _Packed struct DOS_DEVICEPARAMS
-{
- uint8_t specialFunctions;
- uint8_t deviceType;
- uint16_t deviceAttributes;
- uint16_t numberOfCylinders;
- uint8_t mediaType;
- DOS_BPB_DOS3 bpb;
-} DOS_DEVICEPARAMS;
-
-enum DOS_DEVICEPARAMS_SPECIAL_FUNCTIONS
-{
- /** Use the device BPB for all subsequent Build BPB requests. */
- DOS_DEVICEPARAMS_USE_DEVICE_BPB = (1 << 0),
- /** Ignore all fields except the TRACKLAYOUT structure appended after DEVICEPARAMS */
- DOS_DEVICEPARAMS_TRACKLAYOUT = (1 << 1),
- /** The sectors in the track are all the same size, and sector numbers are in the range [1..N]
- * where N is the total number of sectors in the track. */
- DOS_DEVICEPARAMS_REGULARTRACKS = (1 << 2),
-};
-
-enum DOS_DEVICEPARAMS_DEVICE_TYPE
-{
- DOS_DEVICEPARAMS_320_360K = 0x0,
- DOS_DEVICEPARAMS_1_2_MB = 0x1,
- DOS_DEVICEPARAMS_720K = 0x2,
- DOS_DEVICEPARAMS_8INCH_SD = 0x3,
- DOS_DEVICEPARAMS_8INCH_DD = 0x4,
- DOS_DEVICEPARAMS_HDD = 0x5,
- DOS_DEVICEPARAMS_TAPE = 0x6,
- DOS_DEVICEPARAMS_1_44_MB = 0x7,
- DOS_DEVICEPARAMS_OPTICAL = 0x8,
- DOS_DEVICEPARAMS_2_88_MB = 0x9
-};
-
-enum DOS_DEVICEPARAMS_DEVICE_ATTR
-{
- DOS_DEVICEPARAMS_REMOVABLE = 0,
- DOS_DEVICEPARAMS_FIXED = 1,
- DOS_DEVICEPARAMS_HAS_DOORLOCK = 1 << 1
-};
-
-typedef _Packed struct DOS_MEDIA_ID
-{
- /** Must be zero. */
- uint16_t infoLevel;
- uint32_t serialNumber;
- char volumeLabel[11];
- char fsType[8];
-} DOS_MEDIA_ID;
-
-typedef _Packed struct DOS_RWBLOCK
-{
- uint8_t specialFunctions;
- uint16_t head;
- uint16_t cylinder;
- uint16_t firstSector;
- uint16_t sectors;
- void far * buffer;
-} DOS_RWBLOCK;
-
-typedef _Packed struct DOS_FVBLOCK
-{
- uint8_t specialFunctions;
- uint16_t head;
- uint16_t cylinder;
-} DOS_FVBLOCK;
-
-typedef _Packed union DOS_IOCTL_DISK_DATA
-{
- DOS_DEVICEPARAMS devparams;
- DOS_MEDIA_ID mid;
- DOS_FVBLOCK fv;
- DOS_RWBLOCK rw;
-} DOS_IOCTL_DISK_DATA;
-
-#endif // DOSSYS_H
diff --git a/inc/dosint.h b/inc/dosint.h
deleted file mode 100644
index cfa855d..0000000
--- a/inc/dosint.h
+++ /dev/null
@@ -1,250 +0,0 @@
-#ifndef DOSINT_H
-#define DOSINT_H
-
-// Internal DOS structures
-
-// For documentation of these, better grab "Undocumented DOS" or similar book
-// These are probably valid only on DOS >= 4
-
-typedef _Packed struct dos_current_directory_structure {
- char curr_path[67];
- uint16_t flags;
- uint32_t disk_blk;
- void __far * info;
- char pad1[11];
-} DOSCDS;
-STATIC_ASSERT(sizeof(DOSCDS) == 88);
-
-enum dos_cds_flags {
- DOS_CDS_FLAG_PHYSICAL = 0x4000,
- DOS_CDS_FLAG_NETWORK = 0x8000
-};
-
-typedef _Packed struct dos_system_file_table_entry {
- uint16_t num_handles;
- uint16_t open_mode;
- uint8_t attr;
- uint16_t dev_info;
- void __far *dpb;
- uint16_t start_cluster;
- uint16_t f_time;
- uint16_t f_date;
- uint32_t f_size;
- uint32_t f_pos;
- uint16_t last_rel_cluster;
- uint16_t last_abs_cluster;
- uint16_t dir_sector;
- uint8_t dir_entry;
- char filename[11];
-} DOSSFT;
-STATIC_ASSERT(sizeof(DOSSFT) == 43);
-
-enum dos_sft_dev_flags {
- DOS_SFT_FLAG_NETWORK = 0x8000,
- DOS_SFT_FLAG_TIME_SET = 0x4000,
- DOS_SFT_FLAG_CLEAN = 0x0040,
- DOS_SFT_DRIVE_MASK = 0x001F
-};
-
-typedef _Packed struct dos_search_data_block {
- uint8_t drive;
- char search_templ[11];
- uint8_t search_attr;
- uint16_t dir_entry;
- uint16_t par_clstr;
- char pad1[4];
-} DOSSDB;
-STATIC_ASSERT(sizeof(DOSSDB) == 21);
-
-enum dos_sdb_drive_flags {
- DOS_SDB_DRIVE_FLAG_NETWORK = 0x80,
- DOS_SDB_DRIVE_MASK = 0x1F
-};
-
-typedef _Packed struct dos_lock_params {
- uint32_t start_offset;
- uint32_t region_size;
-} DOSLOCK;
-
-typedef _Packed struct dos_direntry {
- char filename[11];
- uint8_t attr;
- char pad1[10];
- uint16_t f_time;
- uint16_t f_date;
- uint16_t start_cluster;
- uint32_t f_size;
-} DOSDIR;
-STATIC_ASSERT(sizeof(DOSDIR) == 32);
-
-typedef _Packed struct dos_swappable_area {
- uint8_t criterr;
- uint8_t indos;
- uint8_t drive_num;
- uint8_t lasterr_dum[9];
- uint8_t __far *cur_dta;
- uint16_t cur_psp;
- uint8_t pad1[4];
- uint8_t cur_drive;
- uint8_t pad2[135];
- char fn1[128];
- char fn2[128];
- DOSSDB sdb;
- DOSDIR found_file;
- DOSCDS drive_cdscopy;
- uint8_t fcb_fn1[11];
- uint8_t pad3[1];
- uint8_t fcb_fn2[11];
- uint8_t pad4[11];
- uint8_t search_attr;
- uint8_t open_mode;
- uint8_t pad5[51];
- DOSCDS __far *drive_cds;
- uint8_t pad6[12];
- uint16_t fn1_csoffset;
- uint16_t fn2_csoffset;
- uint8_t pad7[71];
- uint16_t openex_act;
- uint16_t openex_attr;
- uint16_t openex_mode;
- uint8_t pad8[29];
- DOSSDB rename_srcfile;
- DOSDIR rename_file;
-} DOSSDA;
-STATIC_ASSERT(offsetof(DOSSDA, cur_dta) == 0xC);
-STATIC_ASSERT(offsetof(DOSSDA, cur_drive) == 0x16);
-STATIC_ASSERT(offsetof(DOSSDA, fn1) == 0x9E);
-STATIC_ASSERT(offsetof(DOSSDA, fn2) == 0x11E);
-STATIC_ASSERT(offsetof(DOSSDA, sdb) == 0x19E);
-STATIC_ASSERT(offsetof(DOSSDA, found_file) == 0x1B3);
-STATIC_ASSERT(offsetof(DOSSDA, search_attr) == 0x24D);
-STATIC_ASSERT(offsetof(DOSSDA, open_mode) == 0x24E);
-STATIC_ASSERT(offsetof(DOSSDA, drive_cds) == 0x282);
-STATIC_ASSERT(offsetof(DOSSDA, openex_act) == 0x2DD);
-STATIC_ASSERT(offsetof(DOSSDA, openex_mode) == 0x2E1);
-
-typedef _Packed struct dos_list_of_lists {
- char pad1[22];
- DOSCDS __far *cds;
- char pad2[7];
- uint8_t last_drive;
-} DOSLOL;
-
-typedef _Packed struct dos_nls_table {
- uint8_t table_id;
- void __far *table_data;
-} NLSTABLE;
-
-typedef _Packed struct file_char_table {
- uint16_t size; // table size (not counting this word)
- uint8_t unk1; // ??? (01h for MS-DOS 3.30-6.00)
- uint8_t lowest; // lowest permissible character value for filename
- uint8_t highest; // highest permissible character value for filename
- uint8_t unk2; // ??? (00h for MS-DOS 3.30-6.00)
- uint8_t first_x; // first excluded character in range \ all characters in this
- uint8_t last_x; // last excluded character in range / range are illegal
- uint8_t unk3; // ??? (02h for MS-DOS 3.30-6.00)
- uint8_t n_illegal; // number of illegal (terminator) characters
- uint8_t illegal[1]; // characters which terminate a filename: ."/\[]:|<>+=;,
-} FCHAR;
-
-static inline int drive_letter_to_index(char letter)
-{
- if (letter >= 'A' && letter <= 'Z') return letter - 'A';
- else if (letter >= 'a' && letter <= 'z') return letter - 'a';
- else return -1;
-}
-
-static inline char drive_index_to_letter(int index)
-{
- return 'A' + index;
-}
-
-static inline DOSSDA __far * dos_get_swappable_dos_area(void);
-#pragma aux dos_get_swappable_dos_area = \
- "push ds" \
- "mov ax, 0x5D06" \
- "int 0x21" \
- "jnc success" \
- "xor si, si" \
- "mov es, si" \
- "jmp end" \
- "success: mov ax, ds" \
- "mov es, ax" \
- "end: pop ds" \
- __value [es si] \
- __modify [ax cx dx]
-
-static inline DOSLOL __far * dos_get_list_of_lists(void);
-#pragma aux dos_get_list_of_lists = \
- "mov ax, 0x5200" \
- "int 0x21" \
- __value [es bx] \
- __modify [ax]
-
-static inline uint16_t dos_sft_decref(DOSSFT __far *sft);
-#pragma aux dos_sft_decref = \
- "mov ax, 0x1208" \
- "int 0x2F" \
- __parm [es di] \
- __value [ax]
-
-// Network redirector interface
-
-enum DOS_REDIR_SUBFUNCTION {
- DOS_FN_RMDIR = 0x01,
- DOS_FN_MKDIR = 0x03,
- DOS_FN_CHDIR = 0x05,
- DOS_FN_CLOSE = 0x06,
- DOS_FN_COMMIT = 0x07,
- DOS_FN_READ = 0x08,
- DOS_FN_WRITE = 0x09,
- DOS_FN_LOCK = 0x0A,
- DOS_FN_UNLOCK = 0x0B,
- DOS_FN_GET_DISK_FREE = 0x0C,
- DOS_FN_SET_FILE_ATTR = 0x0E,
- DOS_FN_GET_FILE_ATTR = 0x0F,
- DOS_FN_RENAME = 0x11,
- DOS_FN_DELETE = 0x13,
- DOS_FN_OPEN = 0x16,
- DOS_FN_CREATE = 0x17,
- DOS_FN_FIND_FIRST = 0x1B,
- DOS_FN_FIND_NEXT = 0x1C,
- DOS_FN_CLOSE_ALL = 0x1D,
- DOS_FN_DO_REDIR = 0x1E,
- DOS_FN_PRINTSETUP = 0x1F,
- DOS_FN_FLUSH = 0x20,
- DOS_FN_SEEK_END = 0x21,
- DOS_FN_ATEXIT = 0x22,
- DOS_FN_QUALIFY = 0x23,
- DOS_FN_OPEN_EX = 0x2E
-};
-
-enum OPENEX_ACTIONS {
- OPENEX_FAIL_IF_EXISTS = 0x00,
- OPENEX_OPEN_IF_EXISTS = 0x01,
- OPENEX_REPLACE_IF_EXISTS = 0x02,
- OPENEX_FAIL_IF_NEW = 0x00,
- OPENEX_CREATE_IF_NEW = 0x10,
-};
-
-enum OPENEX_MODE {
- OPENEX_MODE_READ = 0,
- OPENEX_MODE_WRITE = 1,
- OPENEX_MODE_RDWR = 2,
- OPENEX_MODE_MASK = 3,
- OPENEX_SHARE_COMPAT = 0x00,
- OPENEX_SHARE_DENYALL = 0x10,
- OPENEX_SHARE_DENYWRITE = 0x20,
- OPENEX_SHARE_DENYREAD = 0x30,
- OPENEX_SHARE_DENYNONE = 0x40,
- OPENEX_SHARE_MASK = 0x70,
-};
-
-enum OPENEX_RESULT {
- OPENEX_FILE_OPENED = 1,
- OPENEX_FILE_CREATED = 2,
- OPENEX_FILE_REPLACED = 3,
-};
-
-#endif // DOSINT_H
diff --git a/inc/mbr.h b/inc/mbr.h
deleted file mode 100644
index d45727d..0000000
--- a/inc/mbr.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef MBR_H
-#define MBR_H
-
-#include "sassert.h"
-
-enum MBR_PARTTYPE
-{
- MBR_EMPTY = 0,
- MBR_FAT12 = 0x01,
- MBR_FAT16_32MB = 0x04,
- MBR_EXT = 0x05,
- MBR_FAT16 = 0x06,
- MBR_IFS = 0x07,
- MBR_FAT32 = 0x0B,
- MBR_FAT32_LBA = 0x0C,
- MBR_FAT16_LBA = 0x0E,
- MBR_EXT_LBA = 0x0F,
- MBR_LINUX_SWAP = 0x82,
- MBR_LINUX = 0x83,
-};
-
-typedef _Packed struct MBR_CHS
-{
- uint8_t head;
- unsigned sector : 6;
- unsigned cyl : 10;
-} MBR_CHS;
-
-STATIC_ASSERT(sizeof(MBR_CHS) == 3);
-
-typedef _Packed struct MBR_PARTENTRY
-{
- uint8_t status;
- MBR_CHS chsFirst;
- uint8_t type;
- MBR_CHS chsLast;
- uint32_t lbaFirst;
- uint32_t lbaLen;
-} MBR_PARTENTRY;
-
-STATIC_ASSERT(sizeof(MBR_PARTENTRY) == 16);
-
-#define MBR_PARTENTRY_OFFSET_ON_DISK 446
-#define MBR_SIGNATURE_OFFSET_ON_DISK 510
-
-#endif // MBR_H
diff --git a/inc/sassert.h b/inc/sassert.h
index 71a0c0e..465c7fe 100644
--- a/inc/sassert.h
+++ b/inc/sassert.h
@@ -1,8 +1,6 @@
#ifndef SASSERT_H
#define SASSERT_H
-#include <stddef.h>
-
#define STATIC_ASSERT(expr) typedef int STATIC_ASSERT_FAILED[(expr) ? 1 : -1]
#endif // SASSERT_H
diff --git a/inc/scsi.h b/inc/scsi.h
new file mode 100644
index 0000000..a9d8b05
--- /dev/null
+++ b/inc/scsi.h
@@ -0,0 +1,61 @@
+#ifndef SCSICAM_H
+#define SCSICAM_H
+
+/** (from SCSICAM) converts a capacitity in sectors to CHS
+ * keeps cylinders <= 1024 and sectors <= 62,
+ * but may give very large head numbers, though. */
+static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs)
+{
+ unsigned int rv = 0;
+ unsigned long heads, sectors, cylinders, temp;
+
+ cylinders = 1024L; /* Set number of cylinders to max */
+ sectors = 62L; /* Maximize sectors per track */
+
+ temp = cylinders * sectors; /* Compute divisor for heads */
+ heads = capacity / temp; /* Compute value for number of heads */
+ if (capacity % temp) { /* If no remainder, done! */
+ heads++; /* Else, increment number of heads */
+ temp = cylinders * heads; /* Compute divisor for sectors */
+ sectors = capacity / temp; /* Compute value for sectors per
+ track */
+ if (capacity % temp) { /* If no remainder, done! */
+ sectors++; /* Else, increment number of sectors */
+ temp = heads * sectors; /* Compute divisor for cylinders */
+ cylinders = capacity / temp; /* Compute number of cylinders */
+ }
+ }
+ if (cylinders == 0)
+ rv = (unsigned) -1; /* Give error if 0 cylinders */
+
+ *cyls = (unsigned int) cylinders; /* Stuff return values */
+ *secs = (unsigned int) sectors;
+ *hds = (unsigned int) heads;
+ return (rv);
+}
+
+static void guess_geometry(uint32_t num_sectors, unsigned int *cyls, unsigned int *hds, unsigned int *secs)
+{
+ unsigned int cylinders, heads, sectors;
+ // First try to use SCSI CAM approach
+ if (setsize(num_sectors, &cylinders, &heads, &sectors) != 0
+ || cylinders > 1024 || heads > 255 || sectors > 63) {
+ // Didn't work. So now we just use max heads and sectors but a crazy number of cyls
+ if (num_sectors <= 64 * 32 * 65534) {
+ // This follows the same behavior as Linux,
+ // which uses smaller values for heads/sects as long as cyls fits < 65535
+ heads = 64;
+ sectors = 32;
+ } else {
+ heads = 255;
+ sectors = 63;
+ }
+ cylinders = num_sectors / (heads * sectors);
+ }
+
+ *cyls = cylinders;
+ *hds = heads;
+ *secs = sectors;
+}
+
+#endif // SCSICAM_H
diff --git a/inc/usb.h b/inc/usb.h
new file mode 100644
index 0000000..3ea18ad
--- /dev/null
+++ b/inc/usb.h
@@ -0,0 +1,45 @@
+/*
+ * CHU - driver for CH375 in disk mode
+ * Copyright (C) 2024 Javier S. Pedro
+ *
+ * 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 3 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, see <https://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef USB_H
+#define USB_H
+
+typedef enum usb_descriptor_type {
+ USB_DESCRIPTOR_TYPE_DEVICE = 1,
+ USB_DESCRIPTOR_TYPE_CONFIG = 2
+} usb_descriptor_type;
+
+typedef struct usb_device_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t bNumConfigurations;
+} _Packed usb_device_descriptor;
+
+#endif // USB_H