I'm having a difficult time understanding when device drivers are needed, and when its fine to just talk directly to a port controller via the OS-provided serial/parallel/USB/etc. driver.

For instance, Example 1: let's take OpenBCI, an open source hardware BCI that allows you to read EEG + EKG ("brainwave") readings. The OpenBCI headset sends RF signals to a USB drive plugged into your machine, and then you can write your own software to read the data coming into that port; thus, allowing you to read your own brainwaves and interpret brainwave data at the app layer. Pretty cool. To read your "streaming" brainwave data, you need to not only read from your serial port (using the serial driver provided by the OS), but you need to interpret the data in according with the OpenBCI specs. So the stack looks like this:

enter image description here

But nowhere here do we have a "device driver" specific to the OpenBCI headset. Just the serial driver necessary to read bytes of data from, and then you need to interpret what those bytes mean from inside your app. So for instance, if I wanted a Java app to interpret brainwave data, I might use JSerialComm to read the data off my local COM port (or whatever USB is on the local system). It would then be up to my app to interpet that data per the specs listed above.

Now, Example 2: a Logitech USB webcam like this one. Here, you need to install the webcam's device drivers on your machine so that you can use it. I'm wondering why. Let's pretend (just push the "I believe!" button for a moment) that the pinout for this webcam was stupid simple:

PIN #       Meaning
1           Power
2           Ground
3           Send data (if 1 then the camera will start "streaming" its video data over data pins)
4           Data pin 1
5           Data pin 2

This is a USB device, just like the OpenBCI. So why couldn't I write an app (in any language) that also just reads/writes directly to the USB/serial port (again, perhaps using JSerialComm or similar)? When I want the app to start capturing webcam video data, I send bytes to the serial port (again via JSerialComm, etc.) that turn Pin #3 high/on, and that subsequently start reading the video data from Pins 4 and 5.

I guess I don't understand why OpenBCI doesn't have or need a device driver, whereas the webcam (or any other standard USB device like a printer, mouse, keyboard, etc.) does. Thanks in advance!

8 Answers 8


There are several reasons you might want/need to write a device driver.

  1. you are making a device that fits into a generic category. A printer, a scanner, a webcam, a storage controller etc. You want to write a device driver so that generic applications can talk to your device without having to modify the applications.

  2. you want to have a device be usable by multiple applications running at the same time. The device driver needs to arbitrate usage of the device among the applications. That typically means having a higher level of understanding of the device than "stream of bytes".

  3. The hardware and/or operating system design may simply force you to. Windows needs some kind of driver bound to a USB device for it to work at all, you can abuse the hid driver but only if the hardware is set up to claim to be a HID device. You can possiblly use an existing USB to serial device driver but only if your device presents and interface that looks like a serial port. If your device is on a memory mapped bus with direct DMA then you need your driver to be in the kernel to correctly set up the DMA transactions.

Equally though there are reaons to want to avoid writing a device driver, especially a kernel mode device driver.

  1. Writing kernel mode code is tricky/specialist and if you screw it up you bring down the whole system, not just your program. Even if the OS offers the ability to write your driver in user-mode it may mean programming in an unfamiliar language and environment.

  2. Deployment is much more of a pain. On the windows side MS has been ratcheting up the driver signing requirements recently. On the Linux side the userland interfaces are far more stable than the kernel-side ones and kernel modules pretty much have to be rebuilt for every new kernel version.

  3. If your code is split into an application and a driver you have to worry about the situation of mixed application/driver versions.

It then comes down to a balancing act of which reasons are more compelling for a particular device.

  • Thanks @Peter Green (+1) - everything you said makes perfect sense, except one thing. In your first bullet you say "You want to write a device driver so that generic applications can talk to your device." But couldn't those generic applications just read/write directly to the USB/serial port (via a serial comm library like JSerialComm)? This is what I've done successfully with OpenBCI and Java. Thanks again!
    – smeeb
    Mar 28, 2017 at 18:45
  • Imagine you have a hundred different applications that want to print and a hundred different printers. Back before operating systems had printer drivers someone would have had to write printing code for every combination of application and printer. That's ten thousand chunks of code. Mar 28, 2017 at 19:01
  • On the other hand with an OS having a printer driver framework each application only needs one chunk of printing code and each printer only needs one driver. Mar 28, 2017 at 19:03

Device drivers are an abstraction layer. They allow you to talk to the device without knowing low-level operating system mechanics or device-specific idiosyncrasies. They also provide a well-known, high-level interface to the operating system, an interface that is exactly the same for similar devices.

Without a device driver, you would essentially need to write one yourself, and that device driver would be completely different for every device model. Instead, the manufacturer typically provides a device driver for you which translates from the hardware-specific interface of that specific device to the well-known, high-level interface for the operating system.

This arrangement provides several benefits:

  1. Software written for these devices will all work with any device in the device class (e.g. webcams), if it is written against the same common, high-level interface.

  2. Device-specific characteristics like timing, signal handling and data protocols are abstracted away from the user.

  3. Device drivers provide a layer of safety. While the device driver typically operates in the kernel (where problems can crash the OS), the user application typically communicates with the device driver in the user space, where a problem will merely crash the application.

  4. Device drivers have access to management tools like Control Panel.

Sometimes, you can align your device with an API like the HID (Human Interface Device) specification, and you don't even need to install another device driver.

I haven't looked at the OpenBCI software in detail, but I suspect that it actually is or has a device driver. Most modern operating systems won't even allow you to talk to ports directly; you must go through the operating system.

  • Thanks @Rober Harvey (+1) - everything you say makes sense. However I have successfully read OpenBCI data off my COM port (I have a Macbook Pro) using JSerialComm directly. I'm not saying that device drivers weren't somehow magically installed somewhere, but I never had to do anything other than integrate my Java app with JSerialComm and then plug my OpenBCI's USB stick in.
    – smeeb
    Mar 28, 2017 at 18:48
  • 1
    @smeeb In a way, JSerialComm is acting like a driver for your own code.
    – Andres F.
    Mar 28, 2017 at 20:05
  • Thanks @AndresF. (+1) thats sort of what I was driving at with all my followup Qs :-)
    – smeeb
    Mar 28, 2017 at 20:35

The reason you need to install the driver for your webcam, is because your webcam is possibly newer than your OS, or its drivers aren't included with your OS. Many webcams do not require you to install drivers, as many webcams use platforms that have been around for a long time, and drivers for them come with your OS. Find a 15 year old logitech webcam and plug it in, and you have a good chance of finding that you can use it without installing anything*

Serial ports almost always have drivers included with your OS, because the hardware for serial ports has been essentially the same thing for 20 years.

The two types of drivers however provide programmatic access to different abstractions of different hardware. That's why you can't, in userspace, talk to a webcam via streams of bytes in and out. Instead, the webcam "speaks" DirectShow or Video4Linux or whatever video abstraction your OS is using*

The reverse is true again, the serial port only 'speaks' streams of bytes, so you cannot request video frames and get them from the driver.

*Some drivers require you to install special drivers, regardless of age, to fully use the device as sometimes devices have capabilities that aren't supported in DirectShow/etc, such as webcams that can pan, tilt and zoom, or do facial recognition, or other stuff. But don't think too hard about that as those are special cases.


Several of the other answers have very good points on the benefits of separating your application from the device interface and of abstraction but there are two points that hasn't been mentioned - performance and access privileges.


Device drivers often sit waiting for an input or an interrupt to tell them to read an input so when you are writing your own code you will need to do one of:

  • Polling the device the rest of your code has to make sure that this happens often enough
  • Handling interrupts this is a specialist skill and what if you need to talk to more than one device
  • Multi-threading or Multi-processing again specialist skills, not all languages have good support and if you are going to split your device handler into a separate thread you are most of the way to a device driver

Access Privileges

On many Operating Systems, and even in some assembly level bare metal targets the access to hardware and absolute memory locations requires elevated privileges super user, root, admin rights - It is not a good practice for your Application, and its user, to require such rights but if it implements its own device interfaces it will have to have them.


When your software is only intended to work with one specific piece of hardware then you do not need an additional device driver. However, if there were other brainwave reader hardware with different interfaces that you wanted to support, then an additional device driver would be useful. It all depends on the scope of your project. For hobbyist usage there is no need to make an extra device driver.


Basically the answer is, when you're not talking to a device driver, your program IS the device driver.

Device drivers make talking to hardware easier, but they're also restrictive: you can only do the things the device driver offers.

But in general: If you need total freedom you talk to a port directly. This often makes your software intertwined with the hardware as in: it will only work for the specific device you made it for.

If there isn't a device driver available, you obviously need to talk directly to your hardware.

If the device drivers available aren't good enough you talk directly to your hardware.

Basically in all other cases you use a device driver. (but remember, even if you don't use a device driver your still use it, you just made it yourself)


Actually, you are missing a couple of important blocks in the diagram. The"RF receiver (USB stick)" doesn't send the data to "serial/USB port". First, there is no "USB port". The RF dongle sends USB data into "USB pipe" in response to host requests. Host generates request via host controller USB driver, ehci.sys, or something. The host driver forms USB packets and obeys USB protocol.

The packet content for host controller, however, is initiated by a generic COM-class driver, another layer of software (also a OS default). This is the "device driver", which emulates a standard COM port and maps/converts the port reads/writes into USB requests in accord with class definitions/formats. The Java library piece, JSerialComm, is just a stream-like (buffered) interface to this emulated, virtual COM port.

As one can see, there is nothing like "talking directly to your hardware", or "direct write to COM port", there are several layers of virtual ports. It is impossible to generate a single toggle on USB bus without setting huge, very specific and complicated data structures (device/slot context, transfer ring buffers, command ring, event ring, etc.) in main memory and configuring USB host controller for linked list processing, and then ringing a doorbell register to start a USB transaction. All this is accomplished with two layers of drivers, host controller, and device, with many thousands lines of code and half-dozen of years of development and debug. For better understanding and appreciation of this hidden layer of services, check with Microsoft.


The interface to export data from kernel space to user space is not very expressive. In particular, it is untyped. You get a sequence of bytes and your user space program then has to convert those bytes into something with semantic meaning. So device drivers are usually paired with user space libraries.

If you added a kernel space OpenBCI device driver on top of the generic serial driver, that would basically give you the ability to convert one way to sequence the bytes into a different way to sequence the bytes. If you could do this, what different sequence would you choose? If a different sequence would be better, why didn't you just build that better sequence into the OpenBCI firmware in the first place?

You might have performance reasons to write a device-specific kernel mode driver, or you might need to translate to conform to an existing interface, but otherwise you're going to get a lot more value out of making an expressive user space library like OpenBCI_Python than making what would amount to a very anemic kernel mode driver.

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