I am trying to get reports from a PS4 like controller for which I don't have access to firmware.
I've successfully managed to communicate with the device on Windows platform, but having trouble with MacOSX (tried MacOS 10.12).
On Windows I've used HidD_SetOutputReport()/HidD_GetInputReport() functions which means that the device expects the requests as Control Transfers. Interrupt Transfers' WriteFile()/ReadFile() don't seem to be able to send data where the device expects it.
HID API uses IOHIDDeviceSetReport() for the hid_write() function which seems to behave like Windows' WriteFile(). Also tried libusb but it fails when trying to usb_claim_interface() with "another process has device opened for exclusive access". libusb_detach_kernel_driver() is only implemented for linux. I could use the codeless kext approach but the device is a HID controller it is supposed to work without a driver.
Do you know of any ways of sending a Control Transfer on MacOS?
Related
I would like to ask for guidance on how to ideally communicate with a custom USB HID device on MacOS.
Use case
Modify a microphone volume via an external USB HID device.
Question
Can I use DriverKit (HIDDriverKit) for that or I need to use IOKit? I have read something here about audio limitation, but not sure what exactly is not supported.
DriverKit doesn’t support USB devices that manipulate audio or that
communicate wirelessly over Bluetooth or Wi-Fi. For those types of
devices, create a kernel extension using IOKit.
— Source
Would DriverKit still work in my case as I am not sending audio streams but controlling volume only?
Many thanks!
Cheers,
Tom
If I understand you correctly, you wouldn't even need to use DriverKit. (from experience: avoid it if you can!)
You can communicate with HID-compliant devices directly from user space processes. User space processes can generally also control the volume on audio devices.
So by far the easiest option would be to have a launch agent which uses IOKit matching as its launch condition so it starts up when your device is connected. Your agent can communicate with the device using the IOHIDManager API to receive events when your buttons are pressed, and then use the regular Core Audio APIs to control volume.
It doesn't have to be a launch agent, incidentally: a regular Cocoa app with a UI can do all of this as well. (And indeed, you may want to show some form of UI as feedback to the user pressing the buttons.)
I am planning to write driver for USB or Bluetooth multi-touch device similar to Apple Magic Trackpad or Logitech trackpad for Mac.
The idea is that all macOS applications can use this multi-touch device. As the newly introduced DriverKit (or HIDDriverKit) is to be bundled with apps, should I still use IOKit or should I use DriverKit?
Thanks.
DriverKit is built around IOKit - it's just yet another interface to it. So I guess your question really is whether your driver should be implemented as:
A DriverKit System Extension (dext)
A kernel extension (kext)
Something else
You won't escape IOKit either way, because USB devices are only accessible via IOKit, and the HID stack is built on it too.
Bluetooth
As far as I'm aware, there aren't Bluetooth APIs for use with DriverKit, at least not yet. (As of macOS 10.15.4)
So if your device uses a custom Bluetooth protocol which needs to be turned into a HID event source from scratch, then I don't think you'll be able to use DriverKit, at least not exclusively.
If your device already appears to the system as a HID device but your driver needs to rewrite HID reports, then I think it might be possible to implement using DriverKit - at the very least it's worth researching.
Implementing it as a kext will definitely work for all cases, the trouble is any new kexts will have a very limited shelf life at this stage.
USB
For USB, it's more straightforward, there are direct DriverKit USB APIs. USB HID drivers are one of the well-supported scenarios by DriverKit. So you should definitely not use a kext to implement a USB HID driver targeting macOS 10.15+ at this point. In fact, if you did develop a USB HID kext, your users would periodically be presented with an awful warning popup.
"Something Else?"
That brings us to the "something else" category: you may be able to write the driver (almost) entirely in regular user space as a daemon using user space bluetooth and USB APIs, and then inject the HID events produced back into the system. The best way to do this might end up being via a DriverKit driver - so you'd have a user space daemon performing most of the driver logic, and a small DriverKit driver creating a "virtual" HID device which just ferries the events produced by the daemon into the HID stack. If you need to support older OS versions, the responsibility of the dext in this approach could be taken by a kext, with the daemon needing virtually no customisation to run on all OS versions.
If your driver will be doing a lot of complicated processing on the raw input data, this might be the way forward, as implementing such logic in a dext or kext isn't ideal.
To say which approach is best I'd really need to know a lot more about the device (and that might exceed the scope of a Stack Overflow question…).
I am trying to intercept/interact with a Maschine Mikro 2 plugged into my Mac via USB. I have a IOUSBInterfaceInterface reference to the correct USB HID interface. However, whenever I try to call, USBInterfaceOpen on the interface, I always get the IOReturn value of 0x2c5, meaning another program already has exclusive access to this interface.
The only other program I could think of that would have this interface open is the Native Instruments device driver since it would need to write to this interface. However, if the driver has exclusive access to the interface, how is any other program supposed to read from it?
Does anyone have experience with the Native Instruments drivers and know how they expose the device to user-space? I would've expected a file of the form /dev/cu.* but none are created when the Mikro 2 is plugged in.
It turns out there is a daemon called NIHardwareAgent that I believe has exclusive access to the USB interface. Through reverse engineering the Maschine 2 app, I found that it communicates with the hardware agent through CFMessagePort's.
I have a digitizer that functions as a HID absolute pointing device. It functions properly in Ubuntu 14.04, but doesn't work in Chrome OS. However, if I boot the chromebook into developer mode, I can see the device showing up, and I can capture input from the USB device.
I would have assumed that since Chrome OS supports external USB mice that this digitizer should work. Does this mean that the kernel used in Chrome OS uses an altered modules for HID devices? (The device uses the stock usbhid driver)
I'm not really sure where to start with this... do I need to write a custom driver to support the device, or do I need to alter the firmware of the device to conform to Chrome OS's implementation of HID?
I have been searching through how to do gamepad and joystick support on Mac for some days and all resources that I found seems to suggest a pre-installed driver along with using Apple's HID API, which works.
The drawback about this approach is that each joystick and gamepad will require another kernel extension to be loaded, so it can be recognized by HID manager, or at least a code less Info.plist saying it conforms to the earlier installed driver. For instance, when I have an 360 Xbox driver KEXT in house, the Xbox controller from Microsoft will work, but not the Logitech one (I tried F710).
As Apple suggests the application that uses a gamepad or joystick should be able to do themselves at user space without introducing any KEXT stuff. Is there a way to do it?
The thing I had in mind was something like using IORegistry or IOUSB API to get the device when they get plugged in (USB Prober shows it at least). Then somehow get the description of the device, then use that description to register the device as a HID one. Then the whole HID manager can be used.
Am I on the right track? Or is there any other way to do this?
Since IOKit API actually provided keywords like kHIDUsage_GD_Joystick, and there's an ForceFeedback.h library, I suppose Apple designed their HID API with joystick and force feedback in mind. That's the slim hope I had that this might work.
Some reference documentation and open source project:
Colin Munro's 360 driver
HID API Documents
DDHID Project
After revisiting this, I found out the solution to be operating directly on the file descriptors of the device. libusb is an excellent library which greatly simplify your life on this and they have Mac supported.
xboxdrv link is a great example on how to operate on file socket using libusb.
In pseudo code, it should look like this:
enumerate device
detect kernel driver and detach it if possible
open device
file off a initial transfer
wait on the callback function to handle msg and error properly
start run loop or select on fd to call libusb_event_handle
Check libusb for more info link.