Writing a (working) USB driver for OS X

This post is part of USB Programming on Mac series. More posts in this series can be found here.

For some time I was struggling with an ambitious project, to write a Mac driver for my Agilent DSO-X 2002A oscilloscope (see here). The reason behind this is SCPI and the opportunity to reach fresh perspectives in computer–measurement instruments’ integration. However, it was not an easy way. More of a reverse–engineering project, was very time–consuming and complicated. And even dangerous (kernel panics). At times I was so frustrated that I wanted to call the entire thing off and the only thing that kept the flame burning was my innate stubbornness and repulsion to failure. To make things more difficult and complicated, the official documentation it is at least misleading sometimes and marginally useful almost all the time. It is not flawed overall, but there are some minor omissions that make the difference between a working driver or a sheer kernel panic. Moreover, debugging — when writing code for kernel — should be done on two computers. I have only one. It was pure luck the fact that I was able to reach some results without too many panics, system freezes or possibly any other more severe hardware failure.

I’ll start this series today, around a topic I’ve been particularly interested: USB communication with a Mac. To make things more interesting, I’ll focus on something practical. How to create an USB driver (or kernel extension), from scratch, for OS X 10.9 for a custom FTDI USB interface. There is no ambition to cover this subject in one post. Instead, we will take it slowly, one step at a time. At the end we will have a working solution.

Some preparations

After one year of doing this, I really believe that writing kernel extensions is a dark art. One one hand, it requires more programming skills than any other coding endeavour, especially C and C++. One the other hand — as I was to discover — it requires much more patience and discipline than any other coding endeavour. Finally, but not the least, it requires a huge dose of optimism and, as I said, stubbornness. Combine these and you have to fit into a very tight profile. But it is doable.

All these examples are coded under OS X 10.9 (Mavericks), on XCode 5.1.x. Normally they should be backward compatible to at least OS X 10.6 (Snow Leopard), but I cannot guarantee. And you need some tools:

  • USBProber; lately Apple distributes USBProber wrapped within the debugging version of IOUSBFamily kext (IOUSBFamilyLog release). It is available as dmg bundle from Apple’s Developer portal. See the image below. You need to install it and continue with a hard reboot because it replaces the default IOUSBFamily kernel extension. Tracing USB events is not possible without this logging version of the kext so this is of paramount importance if you want to get any meaningful information from the system console.

IOUSBFamilyLog

Further reading

Getting Started with Hardware and Drivers is a pretty good starting point. A list of possible reading materials are provided on this page, but I will outline them here too (most comments below are from Apple’s documentation):

  • Coding in the Kernel — If you are thinking of writing code for the kernel environment, think carefully. Programming in the kernel can be a difficult and dangerous task. And often there is a way to accomplish what you want to do without touching the kernel. This explains the pros and cons of developing in-kernel code.
  • Introduction to I/O Kit Fundamentals — This document explains the terminology, concepts, architecture, and basic mechanisms of the I/O Kit, Apple’s object-oriented framework for developing device drivers for OS X. It contains essential background information for anyone wanting to create device drivers for this platform.
  • What Is the I/O Kit? in I/O Kit Fundamentals provides an overview of the OS X driver development environment. The I/O Kit is a collection of system frameworks, libraries, tools, and other resources for creating device drivers in OS X. It is based on an object-oriented programming model implemented in a restricted form of C++ that omits features unsuitable for use within a multithreaded kernel. By modelling the hardware connected to an OS X system and abstracting common functionality for devices in particular categories, the I/O Kit streamlines the process of device-driver development.This chapter talks about the inherent capabilities of the I/O Kit (and of the drivers developed with it), about the decisions informing its design, and about the I/O Kit when considered as a product. It also offers some caveats and guidelines for those considering developing kernel software such as device drivers.
  • The Darwin and Core Technologies article in Mac Technology Overview describes Darwin (the UNIX-based foundation of OS X) and other low-level technologies.
  • I/O Kit Family Device-Access Support in Accessing Hardware From Applications provides guidance about what device access is available from user-space applications.
  • I/O Kit Family Reference in I/O Kit Fundamentals provides additional details for some device types.
  • Network Kernel Extensions Programming Guide explains how to write kernel extensions that work with network packets.

That’s it for today. We’ll get back on this awesome topic.

 
 

Leave a Reply

Your email address will not be published. Required fields are marked *