3

I'm working on a virtual USB bus driver for MacOSX (Windows already running) connected via network with a linux box. It works fine under 10.6 and 10.7 with a mass storage device and HID devices like mice or keyboards.

But removing devices (unplugging) or more simple unload the kext fails for HID devices under 10.7(.5) because of one remaining instance (retain count does not go down to zero after detach). My 10.6 and 10.7 test environments are identically MacBooksPro 8.2 i7.

Sometimes after a while (5-50minutes) the kext becomes free without an action from my side. It seems not to depend an changing power mode.

Yes, I have USBFamily logging lib and a lot of output, but between working (kextunload ok) and not working run I find no difference in the loggings, even with logging level 7.

Because of mass storage devices seem to work well, I guess the problem is inside die HID driver stack especially under 10.7?

Are there any known differences to remove an USB HID device driver stack between 10.6 and 10.7?

My kext is a (virtual) ControllerV3 derivated class establishing/creating an USBDevice for any real plugged (at the remote linux box) USB device. Using XCode 4.4.1.

Thanks in advance for any idea or hint, regards Markus

PS: Looks a little bit odd to me that under 10.7 so many HID objects are on top of the driver stack. After kextunload (with failure "..VirDevice has 1 instance") they seem still alive. But this in 100% the same a local plugged and unplugged Logitech mouse.

From me are only the lowest both objects MsVirBus (virtual USB bus, derivated from IOUSBControllerV3 ) and the Mouse@xaffe003f with is an IOUSBDevice derivated object.

Driver Stack after kextunload

tshepang
  • 12,111
  • 21
  • 91
  • 136

1 Answers1

2

I don't have deep experience with the HID stack, but I can give you some general IOKit/kext advice on how to track down the source of this kind of problem.

kextunload calls terminate() on all your objects in the I/O registry. This means there are two cases why you might end up unable to unload the kext:

  1. terminate() fails or fails to remove all child objects

  2. The remaining live objects are all not in the I/O registry

Check with the ioreg command whether any of your objects remain in the I/O registry. Also check what clients they have, as those will typically prevent removal.

If the registry is clear of your objects, you've most likely got a retain/release mismatch. I gave some suggestions on tracking these down in this answer so I won't repeat that here. It also doesn't seem likely as your kext eventually does unload and works on 10.6.

If you have objects left in the I/O registry, you'll need to track down why those are still there. If you aren't already overriding terminate() in your classes, add dummy overrides which just forward the call to the base class implementation. But wrap that forwarding call with logging output, and output whether the call succeeds. If you're already overriding terminate, add similar logging. You may also want to add similar logging for didTerminate(), as termination can be asynchronous.

You should be passing terminate() down the device tree to your clients when a USB device is unplugged. I'd check in the equivalent part of the EHCI controller code to see whether any special arguments etc. are required for this.

Community
  • 1
  • 1
pmdj
  • 22,018
  • 3
  • 52
  • 103
  • Many thanks for your constructive suggestions! It seems that the registry is cleaned up. There are still a lot of funny HID Objects on the top of driver stack, but that looks identically to a local plugged and unplugged mouse (I use a optical wired Logitech mouse, simple standard). I don't know how to add pictures here, maybe it would be of interest to see the stack after kextunload. – Markus Steinmann Dec 07 '12 at 15:14
  • To override the taggedRetain/Release method is a great idea, I will try it Monday and add e feedback asap. Other odd thing is that after unload with error "...has 1 instance" I can load the kext again and it works well. After unloading second time is the identically error with instant count "1". – Markus Steinmann Dec 07 '12 at 15:37
  • Hello, before I've called for help here I've already added some getRetainCount() infos in my logs, but the way by overloading you proposed is much smarter. So far the backtrace doesn't work, system hangs with busy mouse pointer (rotating coloured ball) but because I use the USBLogger there is a little more to do for OSDebug I guess. The result of the counter is as expected: goes down to 0 for 10.6 and to 1 for error case with 10.7. The RetainCounter seems to differ after USBDevice::start after successful matching and establishing the driver stack.... – Markus Steinmann Dec 10 '12 at 16:37
  • ...I see a lot of these overloaded tagged functions but nothing else, so I still don't know who is unlucky with my virtual USBDevice and who doesn't decrease the counter. Next I have to try to get the backtrace running for hopeful more information what goes wrong. Thanks so far. – Markus Steinmann Dec 10 '12 at 16:39