From 6b8a368c51082fdd010ef5e1b0be4eb9b5059d1a Mon Sep 17 00:00:00 2001 From: Javier Date: Mon, 26 Oct 2026 00:50:06 +0100 Subject: refactor common parts into inc/ch375.h and add win9x, linux drivers --- inc/bda.h | 67 --------- inc/bpb.h | 83 ----------- inc/ch375.h | 361 +++++++++++++++++++++++++++++++++++++++++++++++ inc/chuver.h | 7 + inc/dlog.h | 439 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ inc/dosapi.h | 182 ------------------------ inc/dosdrv.h | 319 ------------------------------------------ inc/dosint.h | 250 --------------------------------- inc/mbr.h | 46 ------ inc/sassert.h | 2 - inc/scsi.h | 61 ++++++++ inc/usb.h | 45 ++++++ 12 files changed, 913 insertions(+), 949 deletions(-) delete mode 100644 inc/bda.h delete mode 100644 inc/bpb.h create mode 100644 inc/ch375.h create mode 100644 inc/chuver.h create mode 100644 inc/dlog.h delete mode 100644 inc/dosapi.h delete mode 100644 inc/dosdrv.h delete mode 100644 inc/dosint.h delete mode 100644 inc/mbr.h create mode 100644 inc/scsi.h create mode 100644 inc/usb.h (limited to 'inc') 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 -#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 . + */ + + +#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 +#include +#include +#include +#include + +// 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 -#include -#include -#include -#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 -#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 - #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, §ors) != 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 . + */ + + +#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 -- cgit v1.2.3