diff options
Diffstat (limited to 'dos')
| -rw-r--r-- | dos/chud.c | 84 | ||||
| -rw-r--r-- | dos/chudisk.c | 22 | ||||
| -rw-r--r-- | dos/chudisk.h | 14 | ||||
| -rw-r--r-- | dos/inc/dosapi.h | 4 | ||||
| -rw-r--r-- | dos/utest.c | 194 |
5 files changed, 250 insertions, 68 deletions
@@ -20,11 +20,13 @@ #include <stdlib.h> #include <stdint.h> #include <string.h> +#include <errno.h> #include <dos.h> #include <dosfunc.h> #include <io.h> #include "inc/mbr.h" +#include "inc/dosapi.h" #include "inc/dosdrv.h" #include "chudisk.h" @@ -56,11 +58,10 @@ static int ioctl_read_control(uint8_t drive, void *buffer, int len) regs.x.dx = FP_OFF(buffer); intdos(®s, ®s); - if (regs.x.cflag) { - return -1; + return -1; // Generic error, but errno should be properly set } else { - return regs.x.ax; + return regs.x.ax; // Number of bytes read } } @@ -74,7 +75,6 @@ static int ioctl_write_control(uint8_t drive, void *buffer, int len) regs.x.dx = FP_OFF(buffer); intdos(®s, ®s); - if (regs.x.cflag) { return -1; } else { @@ -99,8 +99,67 @@ static int ioctl_read_abs_sector(uint8_t drive, void *buffer, uint32_t sector, i regs.x.dx = FP_OFF(&ciod); intdos(®s, ®s); - - return regs.x.cflag ? -1 : 0; + if (regs.x.cflag) { + struct DOSERROR err; + // Get the extended error from DOS, more useful than a simple EACCES + // and translate to watcom's errno + switch (dosexterr(&err)) { + case DOS_ERROR_INVALID_FUNCTION: + case DOS_ERROR_BAD_COMMAND: + errno = EINVAL; + break; + case DOS_ERROR_FILE_NOT_FOUND: + case DOS_ERROR_PATH_NOT_FOUND: + case DOS_ERROR_NO_MORE_FILES: + errno = ENOENT; + break; + case DOS_ERROR_NOT_ENOUGH_MEMORY: + errno = ENOMEM; + break; + case DOS_ERROR_INVALID_DRIVE: + case DOS_ERROR_BAD_UNIT: + errno = ENODEV; + break; + case DOS_ERROR_INVALID_HANDLE: + errno = EBADF; + break; + case DOS_ERROR_BAD_FORMAT: + case DOS_ERROR_NOT_DOS_DISK: + errno = ENOEXEC; + break; + case DOS_ERROR_SEEK: + case DOS_ERROR_SECTOR_NOT_FOUND: + errno = ESPIPE; + break; + case DOS_ERROR_INVALID_DATA: + errno = ERANGE; + break; + case DOS_ERROR_NOT_READY: + errno = EAGAIN; + break; + case DOS_ERROR_READ_FAULT: + case DOS_ERROR_WRITE_FAULT: + case DOS_ERROR_GEN_FAILURE: + case DOS_ERROR_CRC: + errno = EIO; + break; + case DOS_ERROR_ACCESS_DENIED: + errno = EACCES; + break; + case DOS_ERROR_HANDLE_DISK_FULL: + errno = ENOSPC; + break; + case DOS_ERROR_WRITE_PROTECT: + errno = EROFS; + break; + default: + errno = EFAULT; + break; + } + return -errno; + } else { + return 0; // No error + } } static void dos_disk_reset() @@ -123,6 +182,11 @@ static int parse_chudisk_control_string(const char *b, int len) } i = 0; #endif + // signature + if (b[i] != 'C' || b[i+1] != 'H') { + return -1; + } + i+=2; while (i < len) { char c = b[i++]; switch (c) { @@ -345,7 +409,7 @@ static void usage() int main(int argc, const char *argv[]) { - static char buffer[16]; + static char buffer[32]; int i; unsigned part; @@ -399,10 +463,12 @@ int main(int argc, const char *argv[]) dos_disk_reset(); // Flush caches before we swap the drive... i = 0; - buffer[i++] = 'S'; + buffer[i++] = 'C'; // Signature + buffer[i++] = 'H'; + buffer[i++] = 'S'; // Partition start sector memcpy(&buffer[i], &partinfo[part-1].start_sector, sizeof(uint32_t)); i+=sizeof(uint32_t); - buffer[i++] = 'L'; + buffer[i++] = 'L'; // Partition len memcpy(&buffer[i], &partinfo[part-1].num_sectors, sizeof(uint32_t)); i+=sizeof(uint32_t); buffer[i] = '\0'; diff --git a/dos/chudisk.c b/dos/chudisk.c index c7c0968..d822110 100644 --- a/dos/chudisk.c +++ b/dos/chudisk.c @@ -598,10 +598,13 @@ void interrupt_routine() return; } // If there's enough space, return our internal config string. - if (saved_drs->cmd.ioctlrw.len >= 3 + 2 + 1 + 5 + 1) { + if (saved_drs->cmd.ioctlrw.len >= 2 + /*B*/3 + /*3*/2 + /*R*/2 + /*S*/5 + /*L*/5 + 1) { uint8_t far * buf = saved_drs->cmd.ioctlrw.buffer; int len = 0; - // B = base port (2 byte) + // signature (2 bytes) + buf[len++] = 'C'; + buf[len++] = 'H'; + // B = base port (2 bytes) buf[len++] = 'B'; _fmemcpy(&buf[len], &ch375_dev.io_base, sizeof(ch375_dev.io_base)); len += sizeof(ch375_dev.io_base); @@ -615,6 +618,10 @@ void interrupt_routine() buf[len++] = 'S'; _fmemcpy(&buf[len], &data.unit[saved_drs->unit].start_sector, sizeof(uint32_t)); len += sizeof(uint32_t); + // L = partition len (4 bytes) + buf[len++] = 'L'; + _fmemcpy(&buf[len], &data.unit[saved_drs->unit].sectors, sizeof(uint32_t)); + len += sizeof(uint32_t); buf[len++] = '\0'; saved_drs->cmd.ioctlrw.len = len; } else { @@ -632,7 +639,14 @@ void interrupt_routine() if (saved_drs->cmd.ioctlrw.len >= 2) { uint8_t far * buf = saved_drs->cmd.ioctlrw.buffer; int i = 0; - do { + if (buf[i] != 'C' || buf[i+1] != 'H') { + dprintf(" invalid signature\n"); + saved_drs->cmd.ioctlrw.len = 0; + saved_drs->status = DOS_DD_ERR_UNKNOWN_COMMAND | DOS_DD_STATUS_ERROR_DONE; + return; + } + i += 2; + while (i < saved_drs->cmd.ioctlrw.len) { char c = buf[i++]; switch (c) { case 'S': // Partition start (5 bytes) @@ -659,7 +673,7 @@ void interrupt_routine() saved_drs->status = DOS_DD_ERR_WRITE_FAULT | DOS_DD_STATUS_ERROR_DONE; return; } - } while (i < saved_drs->cmd.ioctlrw.len); + } } else { saved_drs->cmd.ioctlrw.len = 0; saved_drs->status = DOS_DD_ERR_WRITE_FAULT | DOS_DD_STATUS_ERROR_DONE; diff --git a/dos/chudisk.h b/dos/chudisk.h index 1d2fbe4..bc7f12d 100644 --- a/dos/chudisk.h +++ b/dos/chudisk.h @@ -54,7 +54,7 @@ extern struct chudisk_data struct chudisk_unit { /** Whether the partition exists (start_sector points to it) */ bool exists; - /** Note in theory may be zero (superfloppy) */ + /** Start sector of partition. Note in theory may be zero (superfloppy) */ uint32_t start_sector; /** Number of sectors for this partition. */ uint32_t sectors; @@ -78,15 +78,21 @@ extern uint8_t wait_for_ch375_result(unsigned int max_ticks); // TODO Not sure we can really happily add custom minors here, // but then again DOS outright refuses to accept any other major enum CHUDISK_IOCTL_DISK_MINOR { + /** Read an absolute disk sector. + * This ignores any configured partition on this unit. */ CHUDISK_IOCTL_DISK_READ_ABS_SECTOR = 0xC1 }; typedef _Packed union CHUDISK_IOCTL_DISK_DATA { + /* @see CHUDISK_IOCTL_DISK_READ_ABS_SECTOR */ struct CHUDISK_RWABSSECTOR { - uint32_t sector; - uint8_t sectors; - void far * buffer; + /** Absolute starting sector. */ + uint32_t sector; + /** Number of sectors to read. */ + uint8_t sectors; + /** Buffer to read data into. */ + void far * buffer; } rwabs; } CHUDISK_IOCTL_DISK_DATA; diff --git a/dos/inc/dosapi.h b/dos/inc/dosapi.h index 18dbde0..8295660 100644 --- a/dos/inc/dosapi.h +++ b/dos/inc/dosapi.h @@ -57,7 +57,9 @@ enum dos_error { DOS_ERROR_SEEK = 25, DOS_ERROR_NOT_DOS_DISK = 26, DOS_ERROR_SECTOR_NOT_FOUND = 27, - + DOS_ERROR_OUT_OF_PAPER = 28, + DOS_ERROR_WRITE_FAULT = 29, + DOS_ERROR_READ_FAULT = 30, DOS_ERROR_GEN_FAILURE = 31, DOS_ERROR_HANDLE_EOF = 38, diff --git a/dos/utest.c b/dos/utest.c index 7aa8750..b4ce7f3 100644 --- a/dos/utest.c +++ b/dos/utest.c @@ -1,5 +1,6 @@ #include <stdlib.h> #include <stdio.h> +#include <string.h> #include <time.h> #include <dos.h> @@ -108,6 +109,35 @@ void chip_sleep() ch375_enter_sleep(&ch375_dev); } +void chip_version() +{ + printf("IC Version: 0x%hx\n", ch375_get_version(&ch375_dev)); +} + +void chip_reg(const char *arg_reg, const char *arg_value) +{ + int reg = arg_reg ? strtoul(arg_reg, NULL, 16) : -1; + int value = arg_value ? strtoul(arg_value, NULL, 16) : -1; + + if (reg >= 0) { + if (value >= 0) { + ch375_write_reg(&ch375_dev, reg, value); + printf("Reg[%2x] = %2x\n", reg, ch375_read_reg(&ch375_dev, reg)); + } else { + printf("Reg[%2x] = %2x\n", reg, ch375_read_reg(&ch375_dev, reg)); + } + } else { + for (reg = 0; reg < 0xFF; ) { + int max = reg + 16; + printf("Regs[%2x..%2x] =", reg, max-1); + for (; reg < max; reg++) { + printf(" %2x", ch375_read_reg(&ch375_dev, reg)); + } + printf("\n"); + } + } +} + void usb_host_off() { printf("Set usb mode disabled...\n"); @@ -251,13 +281,9 @@ int disk() int i = 0; if (ready) { - printf("Disk ready\n"); + printf("Disk already ready\n"); } else { - printf("Disk not ready\n"); - - if (!usb_host_connect()) { - return EXIT_FAILURE; - } + printf("Disk not ready, so trying to init\n"); if (!init_disk()) { return EXIT_FAILURE; @@ -328,6 +354,35 @@ int disk_read(uint32_t lba) return EXIT_SUCCESS; } +static void disk_reads(const char *arg) +{ + unsigned long lba = 0; + if (arg) { + lba = strtoul(arg, NULL, 10); + } + disk_read(lba); +} + +int disk_set_lun(int lun) +{ + uint8_t max_lun = ch375_read_reg(&ch375_dev, CH375_REG_DISK_MAX_LUN); + uint8_t cur_lun = ch375_read_reg(&ch375_dev, CH375_REG_DISK_LUN); + + printf("Disk max LUNs = %u , cur LUN = %u\n", max_lun, cur_lun); + + if (lun >= 0) { + ch375_write_reg(&ch375_dev, CH375_REG_DISK_LUN, lun); + printf("Set cur LUN to %u\n", lun); + } + + return EXIT_SUCCESS; +} + +void disk_set_luns(const char *luns) +{ + disk_set_lun(luns ? atoi(luns) : -1); +} + int autou() { uint8_t status; @@ -374,7 +429,7 @@ int autou() return EXIT_SUCCESS; } -int host() +int host_descr() { usb_device_descriptor *dev_descr; int n; @@ -437,63 +492,102 @@ int host() return EXIT_SUCCESS; } +typedef void (*cmd_func)(); +typedef void (*cmd_func1)(const char *arg1); +typedef void (*cmd_func2)(const char *arg1, const char *arg2); + +struct cmd { + const char *opt; + cmd_func func; + const char *arg1; + const char *arg2; +} cmds[] = { + {"disk", (cmd_func) disk}, + {"dread", (cmd_func)disk_reads, "[sector]"}, + {"dlun", (cmd_func)disk_set_luns, "[lun]"}, + {"dsize", (cmd_func)disk_size}, + {"dready", (cmd_func)disk_ready}, + + {"auto", (cmd_func)autou}, + {"host", (cmd_func)usb_host_on}, + {"hdescr", (cmd_func)host_descr}, + {"hconn", (cmd_func)usb_host_connect}, + {"hoff", (cmd_func)usb_host_off}, + {"hreset", (cmd_func)usb_host_reset}, + + {"reg", (cmd_func)chip_reg, "[reg]", "[value]"}, + + {"sleep", (cmd_func)chip_sleep}, + {"reset", (cmd_func)chip_reset}, + {"int", (cmd_func)dump_int_status}, + {"vers", (cmd_func)chip_version}, +}; + +#define NUM_COMMANDS (sizeof(cmds)/sizeof(struct cmd)) + +static void usage() +{ + int i, j; + printf("Usage: utest <cmd> <args>\n"); + printf("Supported commands: \n"); + for (i = 0; i < NUM_COMMANDS; i++) { + struct cmd *cmd = &cmds[i]; + printf(" %s", cmd->opt); + if (cmd->arg1) printf(" %s", cmd->arg1); + if (cmd->arg2) printf(" %s", cmd->arg2); + printf("\n"); + } + printf("To change IO port, set CH375_PORT env var\n"); +} + +static struct cmd * find_cmd(const char *arg) +{ + int i; + for (i = 0; i < NUM_COMMANDS; i++) { + struct cmd *cmd = &cmds[i]; + if (stricmp(cmd->opt, arg) == 0) { + return cmd; + } + } + return NULL; +} + int main(int argc, const char *argv[]) { - char mode = '?'; + const char *mode = argc > 1 ? argv[1] : 0; char *port = getenv("CH375_PORT"); + int rc; + struct cmd *cmd; if (port) { unsigned long lport = strtoul(port, NULL, 16); ch375_dev.io_base = lport; } - if (argc > 1) { - mode = argv[1][0]; + if (!mode || stricmp(mode, "help") == 0 || stricmp(mode, "?") == 0) { + usage(); + return EXIT_FAILURE; + } + + + cmd = find_cmd(mode); + if (!cmd) { + printf("Unrecognized command: %s\n", mode); + return EXIT_FAILURE; } - printf("Test mode %c using IO port 0x%x\n", mode, ch375_dev.io_base); + printf("\"%s\", using IO port 0x%x\n", cmd->opt, ch375_dev.io_base); dump_int_status(); - switch (mode) { - case 'd': - return disk(); - case 'e': - return disk_read(0); - case 'a': - return autou(); - case 'm': - return host(); - case 'h': - usb_host_on(); - break; - case 'c': - usb_host_connect(); - break; - case 'o': - usb_host_off(); - break; - case 'b': - usb_host_reset(); - break; - case 's': - chip_sleep(); - break; - case 'r': - chip_reset(); - break; - case 'i': - dump_int_status(); - break; - case 'v': - printf("IC Version: 0x%hx\n", ch375_get_version(&ch375_dev)); - break; - case '?': - printf("test modes: d e a m h c o b s r i v\n"); - break; - default: - printf("Unknown mode %c\n", mode); - return EXIT_FAILURE; + if (!cmd->arg1) { + cmd->func(); + } else if (cmd->arg1 && !cmd->arg2) { + cmd_func1 func = (cmd_func1) cmd->func; + func(argc > 2 ? argv[2] : 0); + } else if (cmd->arg1 && cmd->arg2) { + cmd_func2 func = (cmd_func2) cmd->func; + func(argc > 2 ? argv[2] : 0, argc > 3 ? argv[3] : 0); } return EXIT_SUCCESS; |
