Hopefully I explain this properly/get it right, since I haven't written all that much code like this myself.
For disks for example, there are some layers like:
IBM/MS-DOS (interrupt 21h) |
PC BIOS (interrupt 13h) |
Whatever interface the actual hardware provides |
Compatibility decreases the further you go down the list: If you use the DOS API/interrupts, then you software should work on any DOS machine even if it's not IBM-compatible. If you make standard IBM PC BIOS calls, then your software is compatible with fewer machines, but certainly the majority of machines people think of when they think of "DOS". If you talk directly to the hardware, your software will work with fewer machines still.
On the other hand, the closer to the hardware you get, the more you can control and the more information you can get.
If you use DOS's interface, then you might want to think about which versions to support. Whatever interface you use, you should read Ralf Brown's Interrupt List and see all the quirks of different DOS versions, different BIOSes, etc., and consider whether you want to put in the effort to work around some weird behaviour in PTS-DOS, very early IBM PC BIOSes, or whatever comes up in the particular areas you're working in.
If you think about SCSI controllers, they probably have very different low-level interfaces from an ATA/IDE controller most of us are somewhat familiar with, but they will often optionally install an interrupt 13h handler so that they can be accessed like other devices.
So there are tradeoffs to be made - either you pick some layer, stick to it, and accept the limitations, or you actually write your software to detect what is available, use it and adapt to it. In the latter case you might detect that you're running on a non-PC machine and tell your user "This machine is not IBM compatible, certain features will not be available."
In my case, I think that worrying about what other people might do with my software is probably going a bit far though, I should probably wait to see if anyone tries to use it first
I think I'll just say it only works with X and Y, may not work with Z based on what I read in Ralf Brown's Interrupt List, and please let me know if you would like it to do something else.