12

So I'm confused on how exactly we as the programmers talk to devices on the computer. Now I'm not talking the big ideas. I know that there are device drivers that sit atop the hardware so that different programs can use there features.

But in general who exactly talks to the drivers? Is the programmer writing the application responsible for calling a function on the driver? Or does the programmer call a function through the operating system which then handles the call to the driver?

12

Where there's an operating system involved, programs don't talk to device drivers, at least not directly. Programs talk to abstractions that, unbeknownst to them, eventually end up talking to device drivers by way of one or more layers of abstraction.

I'm going to skip the complexities of modern operating systems and use CP/M, a microcomputer operating system developed 45 years ago, as an example. CP/M was a layer cake with three layers:

Program. The top layer is a program that does something useful (word processing, playing Space Invaders) by doing computation and I/O. Let's say that at some point the program wants to display the letter 'A' for the user to see. CP/M provides an abstraction known as the console, which is where the user interacting with the program should be looking. The conventional way to do send a character there is with a few assembly instructions:

LD C,2   ; Load 2 into register C
LD E,65  ; Load the ASCII code for 'A' into register E
CALL 5   ; Call CP/M's routine for getting things done

(If you're not familiar with them, registers can be thought of as variables that live in the processor.) We'll get to what the magic numbers 2 and 5 are all about in a minute. The takeaway here is that all the program knows is that there's a console and there's a way to write to it. It doesn't know or care about anything beyond that. This is the first of two abstractions that CP/M uses for I/O.

BDOS. The address 5 the program called is the entry point for the next layer, the Basic Disk Operating System or BDOS. The BDOS provides a whole raft of numbered functions that are like ordering by number from a restaurant menu. You tell it you'd like console output by loading the C register with the function number (2 for console output) and the E register with the character to be sent. Console output is a very simple operation, and the BDOS doesn't really have to do much with it other than call the next layer.

BIOS. The BIOS, or Basic Input/Output System is the layer where all of the hardware-specific code lives. In modern systems, this would be considered a set of device drivers. Like the BDOS, the BIOS provides calls for a standard set of very primitive operations that the BDOS uses to do its business. One of those operations is called CONOUT, which takes care of getting the character the program asked to write two layers above through to whatever hardware does it. (Unlike PCs, things weren't homogeneous back then. Everybody's system had different ways of making it happen.) Console output is a simple pass-through for the BDOS, but doing something more complex like creating a file on a disk might require many BIOS calls to manipulate the media. Again, because the BIOS has a standard, abstract interface, the BDOS always knows how to get what it wants and doesn't care how the BIOS does it.

You're probably wondering why there are two abstractions (program-to-BDOS and BDOS-to-BIOS) instead of just one. The answer is that CP/M and its BDOS could be provided in binary form to computer manufacturers, they'd write a custom BIOS with device drivers for their hardware, bolt the two together and ship it as the OS for their systems. This was a big deal because the BDOS was maintained by one organization and therefore always was a known quantity to user programs, making it possible to run the same applications on a very wide (for the time) variety of hardware. This is why operating systems exist and we don't just write programs that twiddle the hardware directly.

Everything I've described here applies to modern operating systems, too. Unix, for example, abstracts everything as files. It gives programs the same set of system calls (open(), write(), close(), etc.) to communicate whether it's a disk drive or serial port. The set of decisions and abstractions is much more complex, but it still eventually boils down to picking out what device driver code at the bottom layer needs to be run to make the operation happen.

  • I haven't really looked at CP/M code before (it's a little before my time... I've used CP/M computers but never written code for them), but I'm rather surprised by the use of call 5 here. Wouldn't rst 8 have been much more effective (it would sacrifice 3 bytes of memory at the destination address, but save 2 every time it's called...)? – Jules Jun 13 '16 at 12:54
  • @Jules: CP/M was developed for the 8080, which had only one interrupt mode where interrupting devices would put put a single-byte instruction (usually a RST) on the data bus. I can't say for sure, but It may have been that there weren't enough slots to go around to cover the needs of all of the devices plus DDT (which used them to make breakpoints happen) plus using one to enter the BDOS. – Blrfl Jun 13 '16 at 13:49
  • Ah. That makes sense, yes. My 8-bit development experience is limited to machines that only had a single interrupt source so didn't have to worry so much about such things... :) – Jules Jun 13 '16 at 14:51
  • Quick question, how does this process relate more to the windows OS and windows kernel? Or should I make a new question for that. – Jason Jun 14 '16 at 2:26
  • @Jason: Wikipedia has a page that describes the architecture and provides the answer. Everything Microsoft has produced since 1993 uses this architecture. It's much the same thing, just with more layers in the cake. – Blrfl Jun 14 '16 at 10:02
0

There are a bunch of different possibilities:

  • For commonly used devices, the OS often include an API that drivers implement and which your language's standard library adapts. Typical examples: filesystems, printers, network, MIDI instruments.
  • For more exotic devices, the device manufacturer has to provide drivers and sometimes those will also include language bindings for popular languages. At minimum there will be C bindings, and pretty much all languages have some way to call C libraries.
  • Somewhat inbetween those two cases, simple devices may just use a general-purpose connection like a serial port and the manufacturer only publishes the protocol which you can then use via the generic serial port driver.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.