Jason
Jason

Reputation: 33

The DriverKit problems to develop multiple serial USB device

I am developing a DriverKit driver for a USB device which has multiple serial UARTs connected. Each UART will represent a cu.USBX port on Mac. My driver inherits IOUSBHostDevice class and it matches device ID well. Now, I am going to crate a new class inherits IOUserSerial to implement serial port. However, compiler said no new operator on base class. It seems the base OSObject class prevent to new the subclass as I did in IOKit driver. Since the similar IOUserSerial/IOUserUSBSerial examples are hard to find, I would like to ask if anyone can help me to solve this problem. Any feedback and clue is appreciated. Following are some snippets to show my situation.

My original IOKit port driver inherits IORS232SerialStreamSync.

class KextSerial : public IORS232SerialStreamSync
{
    OSDeclareDefaultStructors( KextSerial )   ;    // Constructor & Destructor stuff
     :
}

My USB driver could create new KextSerials and initiate them as well.

KextSerial * newSerial = new KextSerial;
   
if( !newSerial->init(0, 0) ){
    goto FailExit;
}

However, in my DriverKit port driver inherits IOUserSerial.

class DextSerial : public IOUserSerial
{
      :
}

While I try to new the DextSerial as following.

DextSerial * newSerial = new DextSerial;

The compiler said "No matching function for call to 'operator new'"

Maybe I can't do this in DriverKit but I can't find documents from Apple's developing website.

Parallelly I have tried IOUserUSBSerial and OSObject, I got the same error message.

Upvotes: 1

Views: 650

Answers (1)

pmdj
pmdj

Reputation: 23438

Your question isn't especially clear, but I'll do my best to go through the various options.

  • An instance of your main driver class is created by the system when your driver matches its provider device.
  • Creating instances explicitly in code mainly happens for user client objects if you're implementing NewUserClient yourself, or if you want to create client objects to attach below your main driver object instance.

Main driver object

When it comes to creating your main driver instance, this is where I/O Kit matching comes in, and it's all defined in the dext's Info.plist file. This part is very similar to kexts, apart from some changed/new IOKitPersonalities keys:

Key Value Type Description (dext) Description (dext)
IOClass string DriverKit kernel-side IOService subclass, e.g. IOUserService, IOUserSCSIParallelInterfaceController, … The driver's own IOService (or deeper) subclass
IOUserClass string Dext-side name of the driver's IOService (or deeper) subclass N/A
CFBundleIdentifier string Bundle identifier of the dext Bundle identifier of the kext
CFBundleIdentifierKernel string Bundle identifier of the kext hosting the DriverKit kernel-side class (IOClass), e.g. com.apple.kpi.iokit, com.apple.iokit.IOSCSIParallelFamily, … N/A
IOUserServerName string Bundle identifier of the dext N/A

Beyond that, the IOKitPersonalities dictionaries take the same form as for kexts.

So if your driver's main class is called KextSerial, you would put that as the value for IOUserClass.

Subordinate objects:

If you really need to create IOService object instances explicitly, you use IOService::Create(). The reason you can't just use standard C++ syntax is that the object needs to be mirrored in the kernel's view of the I/O Kit registry. So as with the main driver object, you need to specify the kernel and DriverKit side classes to instantiate.

The way Apple expects you to do this is by providing a dictionary property in your driver's IOKit personality, so this becomes a property on your main driver object instance. In the Create call you merely specify the property's name, the dictionary is specified in the Info.plist and looks something like this:

<key>MyDriverSubService</key>
<dict>
    <key>IOClass</key>
    <string>IOUserUserClient</string>
    <key>IOUserClass</key>
    <string>MyDriverSubService</string>
</dict>

The keys and values have the same meanings as for the main personality.

My suggestion

My understanding of your situation is the following: you have a USB device which implements more than 1 serial port. How to proceed depends on the layout of the USB device I think.

1 USB Interface per serial port

If your device exposes 1 interface for each serial port it implements in its descriptor table, and their respective endpoints can be driven independently, then I'd directly subclass IOUserUSBSerial for one port, matching any of the interfaces. The system will create an instance of your driver for each port, and your driver just needs to worry about one port at a time.

If your device's interfaces aren't automatically enumerated by the system (e.g. if device class is 0xff), you may need an "umbrella" driver class and IOKit personality which matches the device itself and configures it, prompting the interfaces to be enumerated.

No 1:1 mapping between USB interfaces and serial ports.

If there isn't a 1:1 correspondence between USB interfaces and serial ports, for example just one interface ferrying the traffic from all serial ports, you'll want to have a main driver class which merely subclasses IOService.

This creates child objects, which will be instances of subclasses of IOUserSerial or IOUserUSBSerial. Depending on whether the SerialDriverKit permits multiple instances of these or not in one driver instance, you can either create these using IOService::Create, or you will need to run each port in its own driver instance, communicating with the USB device via an API you've defined on the main driver class. This is achieved by either directly matching your main driver class, or by creating instances of "nub" child objects in the main driver class and then matching those in the per-port personality. (The latter has the advantage of allowing the driver to dynamically enumerate the number of ports; when matching the main driver object directly, you'll need to use match categories to define the number of ports, and to disambiguate which instance is which.)

For example, see this question and answer about how to create a driver for a network adapter with multiple ports, as registering multiple IOUserNetworkEthernet objects from the same instance does not appear to work as you might expect. I do not know if SerialDriverKit has the same limitation, you'll have to try and find out.

Final notes

This may just be a misuse of terminology in your question, but: you do not want to inherit (subclass) from IOUSBHostDevice, you want to match existing instances of it representing the device to drive. (Use it or IOUSBHostInterface as the IOProviderClass.)

Upvotes: 1

Related Questions