• Please review our updated Terms and Rules here

A driver model in C (16bit DOS)

pan069

Member
Joined
Jun 4, 2019
Messages
49
Hi all.

I'm working on a little project for which I want to have a driver model. E.g. to have an external binary file (e.g. a .COM file) that can be loaded into memory and and then functions within the file to be executed.

I was wondering if anyone has an example on how to do this?

I'm using C and I am targeting 16-bit real-mode DOS.

Thanks!
 
Last edited:
There is the .SYS type DOS drivers, but I don't know anything about them.

With a program you can just hook an interrupt and TSR. Then anything that wants to use it can make an interrupt call to it.
 
Since that would be specific to your program, the system driver model would be excessive. Overlays would be easiest to implement. Design a standard interface and then load an overlay in the same place for the required device. That does have the drawback of limiting the size of the driver to what is assigned to the overlay. Loading a separate program and doing far calls into it would be more flexible but takes a lot more work. I don't know of a good sample that implements such a driver system.
 
I'm working on a little project for which I want to have a driver model. E.g. to have an external binary file (e.g. a .COM file) that can be loaded into memory and and then functions within the file to be executed.
If your "driver model" is only useful for your application, you should look into how "overlay" technologies work. Some C compilers (for example, Open Watcom) do support them. Otherwise, you may look into libraries and just link those statically into a compact-model or large-model program.

If your "driver model" is useful outside your application, then you should look into how TSRs (Terminate and Stay Resident) work. Then you can hook one or more specific interrupt vectors and use these to provide their functionality.

If your "driver model" targets something which already exists, you might also look into existing standards. For example, drives are supported by the "redirector" interface (used by network, ramdisk or CD-ROM drivers to provide drives). Network cards use the "packet interface" (or ODI) standards. Trumpet used to provide a resident DOS TCP/IP stack. These are usually implemented as TSRs (either SYS or COM/EXE files).
 
Thanks guys. I think the word "driver" might have thrown some people off in what it is that I am trying to do.

I basically just want to externalise some behaviour of my program, e.g. a sound driver. Where each driver (e.g. a .DRV file) implements the same interface but different behaviour behind that interface. This allows me to add new behaviour to my program without re-compiling it.

I actually found a disassembled source to the CT-VOICE.DRV (part of the Sound Blaster files) [1] that basically does exactly what I am looking for so I am going to spend some time with that to figure out how it works.

This is the simplest possible C code I could come up with in the meantime:
Code:
char _my_code[] = {
  0x90, // nop
  0xcb, // retf
};

void main()
{
  void (far* run_code)();

  run_code = (void(far*)())_my_code;

  run_code();
}

[1] http://www.dcee.net/Files/Programm/Sound/ (ct-voice.arj)
 
Thanks for clarifying. However, it doesn't really change the answers.

You want your drivers to be separate files, so you need to specify the interface between it and your actual application. Some C compilers support overlays and provide a lot of scaffolding, which can make life a lot easier (consult the compiler's documentation). However, it also ties you into the specific toolchain. Such systems rely on compiler and linker support. Also, it's inherently not portable.

The alternative is to do it yourself, and you cannot do it exclusively in C. There are many areas you need to think about, and a lot of them depend on your memory model and compiler specifics. Position independence requires using segmentation carefully, otherwise you need to handle relocation. Note that your C runtime can be located anywhere and its location may change, so calling any C functions reliably from your driver may be surprisingly challenging. Travelling the full path requires implementing a dynamic linker and shared libraries, or overlay schemes in a simpler system. A simpler approach is to treat the drivers as pure data files (shipped separately) and a support library built into each application.

Your code example will most likely not work if your "my_code" driver code lives externally and wants to call any functions.
 
Valid points, but what I am after is far more simplistic. If I was doing anything more serious I would certainly look into the suggestions made here. The link with the CT-VOICE.DRV I posted earlier seems to have everything I need for my purpose, so I'll go with that.

Thanks all.
 
I basically just want to externalise some behaviour of my program, e.g. a sound driver. Where each driver (e.g. a .DRV file) implements the same interface but different behaviour behind that interface. This allows me to add new behaviour to my program without re-compiling it.

There are many graceful ways to do this, but what it comes down to is whether or not you want other people to be able to extend your program without needing access to the source code. If you do, then a driver skeleton in .C or .ASM that loads itself resident and makes the locations of its functions available is typical, like sound or game drivers.

But if you will be the only person working on your program, this isn't necessary if your concern is "add new behavior without recompiling". Most decent C compilers will only compile changed code, and the linking step takes seconds, not minutes.

A third thing mentioned was the concept of an overlay; this is also built into decent compilers (Borland C, Turbo Pascal 6 or 7, others) where you can compile code into overlays that are loaded on demand to save memory. So for example you can have 200KB of code that supports 30 different sound cards, but only the actual 5K-worth of code needed by a particular sound card is loaded. Same goes for very large real-mode programs that would normally not completely fit into 640KB of RAM.
 
Back
Top