Yes, that's a pretty good description of how it works.
First, I do NOT speak for Hyperion, I'm just another developer, trying to help out where I can.
Programs that access USB devices come in two types: Self-Starting Function drivers are regular programs, usually started by the user. Auto-Starting function drivers are started by the USB stack when an appropriate device is attached to the USB connector. These Auto-Starting function drivers are structured like an Exec Library.
Auto-Starting USB function drivers are stored in Sys:devs/usb/fd.
A small text file is then put into Sys:devs/usb/fdclasses that describes the "target" USB devices that might be useful for the driver in the fd drawer.
When a new USB device is connected, the fdclasses files are scanned to determine which fd's might be interested in this device. Then the actual driver can inspect the new device to see if it wants to "own" it or not. Assuming it wants it, it gathers information on how to talk to it (like what is the maximum packet size) and then communicates to the endpoints in the device.
The fd files may be function or interface based. There is a great document that covers everything about it in SDK:Documentation/DeveloperInfo/USB/fd_devman.pdf
That document is everything you need to create (and understand) a complete USB device driver.
It was my primary reference whern I wrote the USB driver for MIDI devices a few years back.
Let's say, to open DirOpus when pluging a MassStorage USB drive.
But, IF your driver gets it before the usual massstorage.fdclass, once DirOpus is open, your program will have a Lock on the USB drive, and MassStorage.usbfd will never see it.
I would suggest that you only write drivers for USB functions that you will handle completely yourself.
Have Fun!
LyleHaze