hidapi icon indicating copy to clipboard operation
hidapi copied to clipboard

Open a specific interface on OS X

Open sduensin opened this issue 9 years ago • 24 comments

I know interfaces aren't supported on OS X. The work-around to check the usage to be sure you have the correct one is fine... except then what? I can either hid_open or hid_open_path. Both end up using the path to the device - which could be either interface in my case.

If I call hid_open_path twice with the same path, will I get each one? Or can it open whatever it finds first more than once? I wrote some test code to check this case and it seems it just opens whatever it wants.

I really need to get a handle to each interface on this device in OS X. Ideas?

sduensin avatar Oct 16 '14 23:10 sduensin

Bit more info:

I wrote some test code to try and open the path more than twice. The third time fails, so this is good. It appears that I'm opening each interface.

When I enumerate devices, I see one interface on usage 0 and one on 5. I wrote some code to take these handles and query IOKit for what it thinks the usages are. I either get two zeros or two fives. This doesn't make any sense to me.

sduensin avatar Oct 16 '14 23:10 sduensin

Okay. Much test code later I've learned that my prior test of opening the same path multiple times to get the different interfaces was bad. It does open the same one every time. So sometimes you get what you want as the first one opened, sometimes not.

I ended up modifying make_path() to include the usage so I could later hid_open_path() the exact one I wanted...

res = snprintf(buf, len, "%s_%04hx_%04hx_%x_%02d",
                   transport, vid, pid, location,
                   get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey)));

sduensin avatar Oct 17 '14 18:10 sduensin

A "device" as reported by hid_enumerate() is really a USB interface. The path points to an interface. This is the same on all platforms.

signal11 avatar Oct 30 '14 18:10 signal11

I get the same path for both interfaces on the Razer Hydra on OS X. There was no way for me to open a particular one without the above modification. Am I missing something?

sduensin avatar Oct 30 '14 19:10 sduensin

hmm, so there are two "devices" (interfaces) with the same "path." We need something in the constructed path to differentiate them. Usage is not good enough because they could both have the same usage. Is there any other property (maybe one with the interface number in it) which would be better?

signal11 avatar Oct 30 '14 19:10 signal11

Using the 'usage' was a hack for this particular case. I don't really know a proper solution. Perhaps another open method that can take a device handle from hid_enumerate? Then we don't care if the path is the same.

I'm using hidapi because I don't know enough to do it myself. :-P You're the expert! :-D

sduensin avatar Oct 30 '14 21:10 sduensin

Perhaps another open method that can take a device handle from hid_enumerate?

It seems like I used to use the handle (pointer) as part of the constructed path. Have a look at the git log to see why I may have taken that out. I can't remember what the story was there. If there's no good reason not to, maybe we should do that.

Then we don't care if the path is the same.

If we used the handle as part of the path, then the paths won't be the same.

signal11 avatar Oct 31 '14 14:10 signal11

If it's consistent, that'd be great. OS X seems to just return devices in whatever order it feels like at that particular moment. Would you have to open it before you free'd the list returned by hid_enumerate()?

sduensin avatar Oct 31 '14 14:10 sduensin

All true. Maybe the enumerate -> store path -> free enumeration -> open use case was the problem. Check the git log on mac/hid.c

signal11 avatar Oct 31 '14 14:10 signal11

That's how I was using it, too. :-)

sduensin avatar Oct 31 '14 15:10 sduensin

I made a branch/pull request long ago to use real IOKit paths instead of constructing paths.

The resulting paths look like: IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/EHC1@1D,7/ AppleUSBEHCI/PLAYSTATION(R)3 Controller@fd12000/IOUSBInterface@0/IOUSBHIDDriver

I haven't tested multiple interfaces but maybe it would have IOUSBInterface@1, etc.

https://github.com/signal11/hidapi/pull/40

mrpippy avatar Oct 31 '14 17:10 mrpippy

Hi Brendan,

I'm sorry. I forgot all about this. Are there any glaring drawbacks to your method? I'm sure you probably don't have 10.4, but do you know whether it should work on 10.4? You mention testing on 10.5. It may be ok to not work on 10.4. It's pretty old at this point. Maybe it already doesn't work on 10.4. I don't remember.

I'm happy to get this in.

  1. Rebase with the latest HIDAPI.
  2. Move patch #2 to first (weak link against 10.5)
  3. Combine the other two patches.

The idea is that each commit needs to compile and operate properly.

Thanks bud,

Alan.

signal11 avatar Nov 03 '14 13:11 signal11

This sounds fantastic. Thanks gang!

sduensin avatar Nov 03 '14 17:11 sduensin

Hey Alan,

I rebased on the latest master and ended up squashing it all into one commit. The "-mmacosx-version-min=10.5" part isn't a big patch and it's only needed for IOHIDDeviceGetService(). I can split it out if you want though.

HIDAPI doesn't work on 10.4 anyway, the HID Manager didn't exist until 10.5 :stuck_out_tongue:

My app has been shipping for at least a year/year and a half with this patch, so I think the basic functionality (enumeration, etc) should be solid. The only drawback I can see is that it is a significant change, and there always could be new bugs / HID Manager fragility exposed.

Also I found a very easy way to get the USB bInterfaceNumber for a HID device, just want to test and see what happens with a non-USB HID device connected. I'll make a separate pull request for that.

Brendan

mrpippy avatar Nov 06 '14 05:11 mrpippy

This patch is a godsend when working with HID devices that have multiple interfaces on OS X. Thank you kindly, @mrpippy.

travisgoodspeed avatar Nov 19 '14 17:11 travisgoodspeed

Is this patch available for download from the git hub?

hallidayts avatar Feb 04 '15 23:02 hallidayts

@hallidayts It's available from @mrpippy's fork: https://github.com/mrpippy/hidapi/tree/iokit_path

Works great for me! I'm using it from node-hid, which I forked from another fork to make it work with Node 0.11.x and to use mrpippy's fork of hidapi. Enough forks, I need a spoon.

joakim avatar Feb 14 '15 19:02 joakim

Here is your spoon: https://www.youtube.com/watch?v=dYBjVTMUQY0

Also, this patch is great, please merge it.

pepijndevos avatar Feb 21 '15 18:02 pepijndevos

Haha, thank you very much. Can't believe I hadn't heard of the technique before.

joakim avatar Feb 21 '15 19:02 joakim

Can the fix merged for https://github.com/signal11/hidapi/pull/288 be considered as fixing this issue as well? The paths for a multifunction device are now different (and, if I am not mistaken, based on @mrpippy's code.)

amadsen avatar Nov 12 '16 22:11 amadsen

@mrpippy
"Also I found a very easy way to get the USB bInterfaceNumber for a HID device, just want to test and see what happens with a non-USB HID device connected. I'll make a separate pull request for that."

Hello! I wanted to ask, if the solution for getting the bInterfaceNumber is somewhere existing? I cannot find it. I really only need this interface number and I dont care if it is not correctly handled for non-HID devices. I would be grateful if you could explain me your solution you found back then. Incredible that Apple restricts such a basic information.

Thank you!

zzyppo avatar Nov 29 '17 07:11 zzyppo

@zzyppo Try this code in hid_enumerate():

/* Interface Number */
cur_dev->interface_number = get_int_property(dev, CFSTR(kUSBInterfaceNumber));

mrpippy avatar Dec 01 '17 07:12 mrpippy

@mrpippy and @zzyppo I also had to add the following to the includes section( line 27 for me)

#include <IOKit/usb/USBSpec.h>

jschloer avatar Jan 12 '18 04:01 jschloer

I've taken the two patches posted (thanks @mrpippy and @jschloer!) and turned it into a PR.

It is not clear if the interface number returned from IOKit is valid for non-HID devices. Because of this, I have opted to simply store the interface number if and only if the USB device is an HID device.

See #380

If anybody would like to use my branch, it is at dylanmckay:mac-hid-interface-support.

dylanmckay avatar Feb 15 '18 06:02 dylanmckay