Re: Developing drivers for a USB-based network device. . .?
Re: Developing drivers for a USB-based network device. . .?
- Subject: Re: Developing drivers for a USB-based network device. . .?
- From: Quinn <email@hidden>
- Date: Tue, 21 Aug 2007 11:20:04 +0100
At 14:00 -0400 19/8/07, Michael Williams wrote:
So I've read an amazing amount of material about the ins and outs of
the OS, etc.; I've done a few of the tutorials on writing
IOKit/Kernel Extensions, and you guys have been amazing with your
feedback. However, I'm still a bit stumped as to where to truly
begin. I'm developing a driver for a USB-based wireless network
device, and I'm still not sure where to begin. Should I begin
writing the code to handle the network connection, or should I focus
on getting the USB portion handled first? Or, is this a process
where I'll need to work on both in tandem correcting one for the
other?
I never saw your response to the question "Does this thing look like
Ethernet or serial?" Your starting place really depends on that
answer because the architecture to support these two classes of
networking devices is very different.
For the moment I'm going to assume it's an Ethernet-like device.
That's the side of things that I know best. However, before I start
I want to follow-up on one of Peter's points:
At 11:28 -0400 18/8/07, Peter Sichel wrote:
I'd say it's easier to develop and test a single UB and it will help you
to write better platform independent code. A bigger issue is whether
you need to support Mac OS X 10.3 (Panther), or can live with 10.4 or
later only.
I agree that starting with a universal binary is the best idea. This
is particularly true for I/O Kit device drivers because there are
some nasty gotchas when setting up your project to build a universal
I/O Kit driver. See DTS Technote 2163 "Building Universal I/O Kit
Drivers" for the details.
<http://developer.apple.com/technotes/tn2006/tn2163.html>
OK, back to the question of how to build an Ethernet driver. There
are two key classes involved in any I/O Kit driver:
o the one you subclass -- This controls what your devices looks like
to the rest of the system. For an Ethernet-style networking device,
you would subclass IOEthernetController.
o your provider -- Real hardware drivers don't existing in a vacuum.
Rather, a driver typically depends on the presence of some hardware.
And you rarely talk to hardware directly. Rather, you call into some
system service to talk to the actual hardware. This service is your
"provider", and its class is your "provider class".
So, you want to set up your project so that you driver subclasses
IOEthernetController and your "Info.plist" lists the providers you're
interested in. If you were writing a driver for a PCI Ethernet
device, you would list IOPCIDevice as your provider. Then, when your
driver wanted to map or unmap PCI registers, it would call down into
its provider, which is actually responsible for mucking around with
the PCI bridge on the logic board.
To continue this example, let's look at the driver for the built-in
Ethernet on my main computer ("Yukon").
guy-smiley$ cat
/System/Library/Extensions/IONetworkingFamily.kext/Contents/PlugIns/\
AppleYukon2.kext/Contents/Info.plist
[...]
<dict>
[...]
<key>CFBundleIdentifier</key>
<string>com.apple.iokit.AppleYukon2</string>
[...]
<key>IOKitPersonalities</key>
<dict>
<key>SK-9E21</key>
<dict>
<key>IOProviderClass</key>
<string>IOPCIDevice</string>
<key>IOPCIPrimaryMatch</key>
<string>0x9E001148</string>
<key>IOPCISecondaryMatch</key>
<string>0x21001148</string>
[...]
<key>IOClass</key>
<string>yukon2osx</string>
<key>CFBundleIdentifier</key>
<string>com.apple.iokit.AppleYukon2</string>
[...]
</dict>
[...]
</dict>
[...]
</dict>
[...]
The most critical structure is IOKitPersonalities. This is a
dictionary of dictionaries. Each dictionary specifies a particular
type of hardware that the driver supports. The critical key is
"IOProviderClass". A value of "IOPCIDevice" indicates that this
driver should match on IOPCIDevice services. Beyond that, the
"IOPCIPrimaryMatch" and "IOPCISecondaryMatch" specify some PCI magic
numbers to further refine the match.
The second group of keys specify the class to instantiate for this
driver ("IOClass") and the bundle identifier of the bundle where
you'll find the binary that implements this class
("CFBundleIdentifier"). In this case the binary for the class is
within this bundle itself, so this matches the "CFBundleIdentifier"
of the bundle itself. This is the typical approach for a
straightforward third party driver.
Now let's look at how to adapt this for your USB device [1]. The
first thing to keep in mind is that the top half of your driver
doesn't change. You want to look to the system like an Ethernet
device, so you subclass IOEthernetController. OTOH your bottom half,
your provider, changes a lot.
Let's look at the I/O Kit personality for the AppleUSBCDCEEM driver [2]:
$ cat /System/Library/Extensions/IOUSBFamily.kext/Contents/PlugIns/\
AppleUSBCDCEEM.kext/Contents/Info.plist
[...]
<dict>
<key>CFBundleIdentifier</key>
<string>com.apple.driver.AppleUSBCDCEEM</string>
[...]
<key>IOKitPersonalities</key>
<dict>
<key>AppleUSBCDCEEM</key>
<dict>
<key>IOProviderClass</key>
<string>IOUSBInterface</string>
<key>bInterfaceClass</key>
<integer>2</integer>
<key>bInterfaceSubClass</key>
<integer>12</integer>
[...]
<key>CFBundleIdentifier</key>
<string>com.apple.driver.AppleUSBCDCEEM</string>
<key>IOClass</key>
<string>AppleUSBCDCEEM</string>
</dict>
</dict>
[...]
</dict>
[...]
You can see that "IOProviderClass" has changed to "IOUSBInterface".
This says that the driver wants to be loaded on top of a USB
interface (in the USB sense of that word). The "bInterfaceClass" and
"bInterfaceSubClass" specify the particular type of USB interface
that it supports.
So, when someone plugs in a CDC EEM device (that is, a USB device
with an interface of class 2 and subclass 12), the system will
instantiate an IOUSBInterface nub for that device and then go looking
for a driver for this nub. It will find this personality, verify
that the provider and the other keys match, then go looking for a
class called AppleUSBCDCEEM in the binary within the bundle with
identifier "com.apple.driver.AppleUSBCDCEEM". Assuming that this
driver wins the matching process, it will load and run the driver.
To adapt this to your device you should plug in your device, look in
the I/O Registry for the keys that identify your device, and change
the properties in I/O Kit personality to match. This should get your
driver /loaded/. Then you have to actually implement its
functionality (-:
If you look at the IOEthernetController documentation, you'll see
that a subclass is only required to implement limited functionality
for sending and receiving packets on your particular hardware. Your
superclass, and the rest of the system, take care of all the common
work. For example, once you publish your nub (by calling
IOEthernetController::attachInterface), the system will take care of
all the high-level stuff (like assigning your interface an name
("enXXX"), connecting it to the BSD networking stack, and thence to
user space networking components ("configd" and the
SystemConfiguration framework).
As you write the code you might want to look at the source for the
AppleCDCEEM driver, which is available in Darwin.
<http://www.opensource.apple.com/darwinsource/Current/AppleUSBCDCDriver-319.4.1/AppleUSBCDCEEM/Classes/AppleUSBCDCEEM.cpp>
[This link requires an APSL <http://www.opensource.apple.com/apsl/>
account.]
Share and Enjoy
--
Quinn "The Eskimo!" <http://www.apple.com/developer/>
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
[1] This is where I start to handwave because I'm not a USB expert.
For the USB side of things you might want to ask follow-up questions
on the USB mailing list <http://lists.apple.com/mailman/listinfo/usb>
or the darwin-drivers mailing list
<http://lists.apple.com/mailman/listinfo/darwin-drivers>.
[2] This is the driver for the USB Ethernet Emulation Model
<http://www.usb.org/developers/devclass_docs/CDC_EEM10.pdf>.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Macnetworkprog mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden