1

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.

pmdj
  • 22,018
  • 3
  • 52
  • 103
Jason
  • 33
  • 3
  • After reading [this project.](https://github.com/pqrs-org/Karabiner-DriverKit-VirtualHIDDevice) I think I have a misunderstanding of DriverKit. I should use IOService::Create instead of new operator. My subsequent question is how can I use IOService::Create without NewUserClient method? Do I must have an app to trigger the driver to instantiate a child service. – Jason Nov 24 '22 at 09:07

1 Answers1

1

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.)

pmdj
  • 22,018
  • 3
  • 52
  • 103
  • Thank you for the reply. This [article](https://developer.apple.com/news/?id=zk5xdwbn) said I should use IOUSBHostDevice. In my experiment, the IOUSBHostInterface can't probe my device. I'm still reading more to get a right design. I have following ideas but it may be wrong. (a)Implement NewUserClient in my IOUSBHostDevice subclass driver (b)Create an IOUserClient subclass driver. In it's Start or ExternalMethod, call another IOService::Create with a SerialDriverProperties. (c) Create an IOUserSerial subclass driver with SerialDriverProperties. Implement my serial functions there. – Jason Nov 29 '22 at 15:14
  • Whether to use the device or interface for matching depends on the layout of the device. If it's a class compliant or "multifunction" device (device class code `0x00`), you'll usually want to match on interface, otherwise you'll frequently want to use the device itself. – pmdj Nov 29 '22 at 15:30
  • `NewUserClient` is for implementing a user space app/daemon to driver communications channel. You may want to use that, but it seems orthogonal to your question, if I understand it correctly. – pmdj Nov 29 '22 at 15:31
  • @Jason I've made a major update to my question with some suggestions that are more specific to your situation. You may need to provide more information about how your hardware works (including `ioreg` subtree dump) if you're not clear what applies to your situation. – pmdj Nov 29 '22 at 16:04
  • Thanks for your update. I have postponed that project before I clarifying some concepts of DriverKit. – Jason Apr 07 '23 at 05:50