From 53caec7569635649af12829f214ad9fa4adea936 Mon Sep 17 00:00:00 2001 From: Matthieu Bucchianeri <69611560+mbucchia@users.noreply.github.com> Date: Fri, 3 Jan 2025 18:40:38 -0800 Subject: [PATCH] Improvements to the SDPP driver. (#30) * Mask unimplemented IOCTL message. * Add build for 286+. * Optimized IO for 8086. * Adding pre-build drivers. --- XTMax/Drivers/SD.SYS | Bin 7906 -> 7902 bytes XTMax/Drivers/SD286.SYS | Bin 0 -> 7717 bytes XTMax/Drivers/SDPP/.gitignore | 1 + XTMax/Drivers/SDPP/.vscode/tasks.json | 2 +- XTMax/Drivers/SDPP/DRIVER.C | 12 +++++-- XTMax/Drivers/SDPP/HEADER.ASM | 2 +- XTMax/Drivers/SDPP/MAKEFILE | 28 +++++++++------ XTMax/Drivers/SDPP/SD.SYS | Bin 7906 -> 0 bytes XTMax/Drivers/SDPP/SDMM.C | 49 +++++++++++++++----------- 9 files changed, 57 insertions(+), 37 deletions(-) create mode 100644 XTMax/Drivers/SD286.SYS delete mode 100644 XTMax/Drivers/SDPP/SD.SYS diff --git a/XTMax/Drivers/SD.SYS b/XTMax/Drivers/SD.SYS index ebeab06cc5db5e9b8d95f9e42da2eb12a8ab1d60..9e70e2ef0f80ba8e40984305756157b5efaf356a 100644 GIT binary patch delta 1585 zcmZuxe{2(V6#ss&z1y+=Sg+7_V_oTj>m*AN?berTm%p~l z`gF;T8RRTwBR^A4<$|&Wjvl?DfhKR#OkIF&V(ekd2HM`mY@)AP7=HE2Rdt><7|85nE$VAFH5T zO$^`ZR`N-d6H2I6ms^$H3h}uP=N5L&InXK59y`U9NT{L~`Eom)QN~^Aqr}OvOOHr( zhx03`4qSJU^(d>C8<;`$4%s*>PWkf3AxQlha>iKysK zX1|My?P9_%MQE=A`DkH65}TvDfu;j{Y2;IW>!PXH9&lh{Z-Zn*ds*bmi*+#(V<%u! zxYi)5A}+SiWkM+IGDO=UHa8Xkn<^Frsfq0anb+qcQFRrzl0o%se32M6rFa!_YOc)i zL{_j7qZ3)K_?4fG42(}}Sl7EIGE|qPnM9j%=-j|~&U#X8#lCr$_@d|P+FG4XBq+a(den1ZCYH%It*OlX)M910j zC|S(a<6-h1Hy>K`BRAjB#6kn%f<|Eyf>dhBpPSr4Ec&zmYx$h?>tDc4J?6gXRbK zVSmEzu~6F>YF(J|&E*9X)Nz8$Gj(7y`OM^_)c47(`~n;y?);WHg?Aw){i;B_hV?Cn zs{6nUTR=eoNbpjYsp}KH9kdV7Zh@hXfq1w(#NN(Pd`ar z!OWtXzd{N2amHt!WMt5VCFEqmg7%r*lLL28G%(;q#Zly!(8GeATW|hhm(HX($IoduT{01Svk5bBFXz zeX6vXjr=L^F7O^9U%^K?m@6OErKNBP9KRlc?htLENnNDilP5>Kx4*%{>ts%0Y1JYi zwt-pwXv$lGSUckV&qAz#nPnD&7D5W~7;HOqO86MuXOZKD#Y>vmE~bU;E{K;{u6V|; z6;I1#%$FR^tmJ5c7L7~(lyDIOZViVLxtUcn#t~f!W!?q)JA%!&b`CyD$A`U=LyrV2 z=!b{B-slwhF7p5e0ZI-75~>0C(l(Q9TMw{Nw&f$?4FFylOhrNnz_PTXS#~@IutK&K zA>mU1WiptCgi8RXzbK<(B-{XGltBrS9Mh3-3kVu2XC%iAU`mm2517#*nJELtj)YvA uPyXJMG@CJe1ZWFC$x4e0JKd>M+em|DE?o)ca&pvC#ojU;Gn_DdVE7lHiEds1 delta 1619 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 VwjFBVFTn+Cmc3K>Vc{o*{{t$^+baM7 literal 0 HcmV?d00001 diff --git a/XTMax/Drivers/SDPP/.gitignore b/XTMax/Drivers/SDPP/.gitignore index 37ebf5e..8b3e801 100644 --- a/XTMax/Drivers/SDPP/.gitignore +++ b/XTMax/Drivers/SDPP/.gitignore @@ -1,3 +1,4 @@ *.obj *.map +*.sys log.txt diff --git a/XTMax/Drivers/SDPP/.vscode/tasks.json b/XTMax/Drivers/SDPP/.vscode/tasks.json index b9c2cd2..568385c 100644 --- a/XTMax/Drivers/SDPP/.vscode/tasks.json +++ b/XTMax/Drivers/SDPP/.vscode/tasks.json @@ -6,7 +6,7 @@ { "label": "Build in DOSBox", "type": "shell", - "command": "..\\Driver_Build_Tools\\DOSBox\\DOSBox.exe -conf Build.conf", + "command": "..\\Driver_Build_Tools\\DOSBox\\DOSBox.exe -conf Build.conf && copy *.sys ..\\", "options": { "cwd": "${workspaceFolder}" }, diff --git a/XTMax/Drivers/SDPP/DRIVER.C b/XTMax/Drivers/SDPP/DRIVER.C index 0e27393..dddd357 100644 --- a/XTMax/Drivers/SDPP/DRIVER.C +++ b/XTMax/Drivers/SDPP/DRIVER.C @@ -256,13 +256,13 @@ PUBLIC void GenericIOCTL (rh_generic_ioctl_t far *rh) case GET_ACCESS: ((access_flag_t far *) (rh->packet))->allowed = 1; rh->rh.status = DONE; return; + case GET_MEDIA_ID: case SET_MEDIA_ID: case SET_ACCESS: case SET_PARAMETERS: case FORMAT_TRACK: rh->rh.status = DONE; return; - case GET_MEDIA_ID: default: ; } cdprintf("SD: unimplemented IOCTL - unit=%d, major=0x%2x, minor=0x%2x\n", @@ -367,8 +367,14 @@ PUBLIC void Initialize (rh_init_t far *rh) WORD brkadr, reboot[2]; int status, i; /* The version number is sneakily stored in the device header! */ - cdprintf("SD Card driver for XTMax\n based on SD pport device driver V%c.%c (C) 2014 by Dan Marks\n based on TU58 by Robert Armstrong\n", - header.name[6], header.name[7]); + cdprintf("SD Card driver V%c.%c for XTMax (%s)\n based on SD pport device driver (C) 2014 by Dan Marks\n based on TU58 by Robert Armstrong\n", + header.name[6], header.name[7], +#ifdef USE286 + "80286+" +#else + "8086" +#endif + ); /* Parse the options from the CONFIG.SYS file, if any... */ if (!parse_options((char far *) rh->bpbtbl)) { diff --git a/XTMax/Drivers/SDPP/HEADER.ASM b/XTMax/Drivers/SDPP/HEADER.ASM index 585c20e..42925f6 100644 --- a/XTMax/Drivers/SDPP/HEADER.ASM +++ b/XTMax/Drivers/SDPP/HEADER.ASM @@ -129,7 +129,7 @@ _header DD -1 ; link to the next device DW DGROUP:STRATEGY ; address of the strategy routine DW DGROUP:INTERRUPT; " " " interrupt " DB 1 ; number of drives - DB 'SDCDv11' ; DOS doesn't really use these bytes + DB 'SDCDv12' ; DOS doesn't really use these bytes ; The geometry (sectors/track, tracks/cylinder) defined in the BPB is rather ; arbitrary in the case of the TU58, but there are things to watch out for. diff --git a/XTMax/Drivers/SDPP/MAKEFILE b/XTMax/Drivers/SDPP/MAKEFILE index af3ce4b..37ed1c3 100644 --- a/XTMax/Drivers/SDPP/MAKEFILE +++ b/XTMax/Drivers/SDPP/MAKEFILE @@ -3,24 +3,30 @@ CC=bcc -c -ms -Z -O -Ol -Oe ASM=tasm -mx -.c.obj: - $(CC) $< +DEPS=cprint.c driver.c sd.c sdmm.c cprint.h diskio.h driver.h integer.h sd.h standard.h + +all: sd.sys sd286.sys .asm.obj: $(ASM) $* -sd.sys: header.obj cprint.obj sd.obj sdmm.obj driver.obj - tlink -t -m -s -n header cprint sd sdmm driver, sd.sys +sd.sys: header.obj $(DEPS) + $(CC) cprint.c + $(CC) sd.c + $(CC) sdmm.c + $(CC) driver.c + tlink -t -m -s -n header cprint sd sdmm driver, $@ -sd.com: header.obj cprint.obj sd.obj sdmm.obj driver.obj - tlink -t -m -s -n header cprint sd sdmm driver, sd.sys - rename sd.sys sd.com +sd286.sys: header.obj $(DEPS) + $(CC) -1 -DUSE286 cprint.c + $(CC) -1 -DUSE286 sd.c + $(CC) -1 -DUSE286 sdmm.c + $(CC) -1 -DUSE286 driver.c + tlink -t -m -s -n header cprint sd sdmm driver, $@ clean: del *.obj - del sd.sys + del *.map + del *.sys -driver.obj: cprint.c sdmm.c driver.c cprint.c cprint.h standard.h driver.h sd.h -sd.obj: sd.c sd.h standard.h driver.h -sdmm.obj: sdmm.c diskio.h integer.h header.obj: header.asm diff --git a/XTMax/Drivers/SDPP/SD.SYS b/XTMax/Drivers/SDPP/SD.SYS deleted file mode 100644 index ebeab06cc5db5e9b8d95f9e42da2eb12a8ab1d60..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7906 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 Wv*2oEM=u}|jn6tZ>+M