Would DriverKit work for custom USB device to control mic volume (no stream)? - macos

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

Related

Should I use IOKit or DriverKIt (or HIDDriverKit) to write driver for USB or Bluetooth multi-touch device in macOS?

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

Are NFC "writer" devices commercially available?

I'm looking into NFC for use with Android phones and the newest iPhones. What I'm envisioning is some kind of NFC "broadcast" device plugged in via USB cable to a computer, so that it always sends out the most up-to-date information to whatever NFC-enabled phone is within close proximity. So far I've been seeing a whole lot of NFC "tags," which I assume are rather stupid devices that are pre-programmed with essentially static content. I'm wondering if there are any USB NFC devices on the market that can be more dynamic. Do such products exist? What's the best search keyword to find such a device? (What I've been searching for thusfar hasn't been turning up a whole lot of results.)
"NFC "broadcast" device plugged in via USB cable to a computer, so that it always sends out the most up-to-date information to whatever NFC-enabled phone is within close proximity" is your requirement. As I see in market there are NFC Readers with USB plugin to computer. They are active NFC devices generating 13.56MHz and mostly used for payment purposes. However they are putting these devices to ticketing, Office ID applications. When you bring your NFC Phone within this reader's proximity, the reader will read your phone's data and shall send it to the computer as encrypted data and will be verified in your Computer. In this process, phone acts as passive device while reader is active device.
You can also control this reader using your corresponding Software in computer which you wish as dynamic writing.
I think this might help you http://www.acs.com.hk/en/products/3/acr122u-usb-nfc-reader/

How can I dynamically select audio devices?

A friend of mine and I got into a conversation and realized Windows 7 is missing a key component to its per-application audio settings. You can set volume but you can't stipulate which device each application should use.
Some applications such as ventrilo or skype allow you to select which device to use however, MOST applications simply rely on the current 'Default Audio Device.'
Is there a way to access this? What language would be best used to expose these kinds of functions? Thanks!
Ventrilo and Skype are able to choose which audio device to use because they are coded to directly specify audio output devices instead of just getting the default from the OS. For applications which are coded to use the default Windows device, you can of course change which device is the default device using the sound settings, but this will change the default for the whole system.
Setting different audio devices for separate applications which all use the default audio device isn't something that is necessarily supported by Windows, and many applications use the DirectSound API which complicates the situation further. However, some applications check which device is the default when they initialize and then output exclusively to that device. In this case, you could change the default sound device to one audio device, start a program, then change the default to another audio device, and the first program would continue to use the device which was default when it started up.
However, this is a pretty weak workaround and will only work for specific applications which have been coded in the way described above.

MacOS Virtual Input Devices

How can I create a virtual HID device in code? I'm trying to avoid writing a kernel extension to accomplish this, but it seems to be the only way. I need to be able to create virtual HID devices of all types, and have an app running in the background feed them events. Is there a way to do this in user-space, or must I venture into kernel land?
The typical way of creating HID devices is to use the IOHID* classes in IOKit. You can write a userclient that passes events in and out.
I'm not sure what a "virtual" HID device is, however, I guess. If you want to create a keyboard on the screen, that sort of thing can probably be done in userspace.

How do I reset USB devices using the Windows API?

Do you know a way to use the Windows XP API to reset the USB bus? In other words, I'd like the OS to kick out any USB devices that are currently connected, and then auto-detect everything anew.
I'm aware of devcon, and I suppose I could do system calls out to it, but I'm hoping for a direct call into the API.
From kernel mode: You can force a specific USB device to be re-connected, as if it was unplugged and replugged again, by sending an IOCTL_INTERNAL_USB_CYCLE_PORT to its PDO. (This can only be done from a kernel mode, e.g. through a helper driver.) This 'cycle' operation will cause a USB reset to occur, after which the device would be re-enumerated. For example, if the device comes back with a different USB device descriptor, a different driver may be matched for it.
From user mode: You can do this by ejecting the device through the CfgMgr API. For example, to go over all USB hubs and eject all devices:
Find all devices having device interface GUID_DEVINTERFACE_USB_HUB with SetupDiGetClassDevs(... DIGCF_DEVICEINTERFACE).
Enumerate over the returned device information set (SetupDiEnumDeviceInfo).
For each device, get the DevInst member:
Invoke CM_Get_Child(DevInst) and then CM_Get_Sibling repeatedly to go over all child nodes of the hub (i.e. the USB devices).
For each child node, call CM_Request_Device_Eject.
Well, use can use the Setup API (SetupDiXXX functions) to enumerate the USB devices in the system, and then call WinUsb_ResetPipe on each one, but I'm not sure if that's what you're looking for. It's been a while since I worked with USB devices, but as I recall, there is no standard way to reset a device (i.e. simulate a power off/power on cycle). If it's possible for a particular device, you'd have to send an appropriate IOCTL (using DeviceIOControl) to the driver. The IOCTL would vary from manufacturer to manufacturer.
It's possible to cycle the parent port on the USB hub the device is attached to, as well. This will result in, among other things, apparrent unplug/replug actions, as you will see a balloon popup when this occurs.
Much of this is poorly documented, and honestly, I've gotten the impression there are only a handful of people at Microsoft who really understand it well. The design decision I've made for future devices I design is that I intend to include watchdog functionality on both sides, as well as a device-side full reset function. That way, if the device figures out it is confused, it can just cut its own power for a second and fully reset, if the host can't communicate with it, it could do the same thing, and if the device thinks everything is fine but the host knows better, the host could order it to reset.
There are at least three APIs worth looking into for this problem: the Setup API, the Config Manager API, and various WMI extensions. However, be cautious about diving into WMI if you intend to use an Embedded XP target, as you will have to include a lot of other things in your OS image you might otherwise not need.
As far as I know, there is no way to do this - you can issue a command to have PnP rescan the bus for new devices, but that isn't the same as issuing a bus reset.
Furthermore, just because from a hardware perspective you issued a bus reset doesn't mean that Windows will remove the PDOs that represent the children of the hub and redetect them; the USB bus driver can (and does) do just what I describe (i.e. issue hardware bus resets without disturbing the device tree), and only after the device doesn't respond does it issue the surprise removal and yank it from the tree.

Resources