• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Developing drivers for a USB-based network device. . .?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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
References: 
 >Developing drivers for a USB-based network device. . .? (From: Michael Williams <email@hidden>)
 >Re: Developing drivers for a USB-based network device. . .? (From: Josh Graessley <email@hidden>)
 >Re: Developing drivers for a USB-based network device. . .? (From: Michael Williams <email@hidden>)
 >Re: Developing drivers for a USB-based network device. . .? (From: "Peter Sichel" <email@hidden>)
 >Re: Developing drivers for a USB-based network device. . .? (From: Michael Williams <email@hidden>)

  • Prev by Date: Re: UDP Broadcasts Don't Work
  • Next by Date: Re: UDP Broadcasts Don't Work
  • Previous by thread: Re: Developing drivers for a USB-based network device. . .?
  • Next by thread: Reducing the Minimum Packet Retransmit Delay on MacOS X
  • Index(es):
    • Date
    • Thread