As a bonus, the Market makes it easy to publish services provided by drivers through Rendezvous. In fact it can even publish services of kernel drivers that wish to participate, if the driver must be a kernel driver. There is even a Preference Pane where the user can select which devices ought to be shared with the local network.
The Market is a missing piece of Mac OS X. When developing a driver for a USB or FireWire device, the developer is faced with a choice of two paths: the IOKit kernel driver or the IOKitLib userspace driver. Kernel drivers are difficult to debug, and errors can be catastrophic. But IOKit has an arbitration system to choose the best driver for a device, and new devices are automatically matched with drivers when they appear. It is also easy to provide services to applications through a device-class protocol (e.g. standard WebCam protocol for any web cam) using IOKit's 'user client' API.
In contrast IOKitLib ties the driver for a device to the application that uses it. This means multiple drivers cannot compete for the device to find the best driver. It means that when a device is plugged in, the application must be running to do anything about it (or a daemon must be running all the time whose only purpose is to check for this). And most importantly, it means that the device is bound to that specific application - if another WebCam application wants to use the device, then it must implement a driver for the device itself - and two WebCam applications cannot access the camera at the same time. These are just some of the undesirable consequences of binding up two things which are logically (and easily!) separable.
The Market brings together all the benefits of writing a kernel driver (matching, discovery, publishing) with those of writing a userspace driver (debugging, safety, admin access not required). There are of course still reasons to go to the kernel (network card driver) or straight into an application (hardware dongle checker), but for many drivers the Market is the perfect environment. And most existing in-application drivers should really consider putting themselves onto the Market to get the free sharing via Rendezvous that it provides.
Sometimes there is a well-defined protocol for a device-class over a particular transport, that would suggest a generic driver in an application would be fine. However, usually applications do not care about the protocol - for example, iMovie did not support USB 2.0 DV cameras for a long time since it only implemented a FireWire driver, and there was no sane way for anyone to write a driver for a new device. Also, hardware devices are notorious for not sticking to specifications, are extending them in device-specific ways. Separating the application from the driver/transport-specific-protocol allows these idiosyncrasies to be accommodated.
Drivers have keys in their Info.plist that specify what kind of devices they can drive. These keys are very similar to the matching keys used in kernel IOKit drivers.
The process 'udmarket' runs all the time as background daemon. It reads the Info.plist files of any installed drivers. At startup, and whenever a new USB or FireWire device is plugged in, the daemon receives a notification and attempts to find a driver for the device. All the drivers compete, and the one that wins is matched to the device, and then owns it until it gives it up, the device goes away, or a better driver comes along (IOKit cannot do that last part in fact).
What the driver bundle does when it gets control of the device is up to it. It can just initialise the device then sit there doing nothing. It can create a new thread (of udmarket) to drive the device. It can create a new process to drive the device. And independent of any of those, it can register a service (or multiple services) with udmarket for publishing to the world.
A service is an Objective-C object that applications can use to access the functionality of the device. A service is always of some well-defined type, e.g. a WebCam service, a MMInput service, a RemoteControlReceiver service. A service type implies a protocol that defines the calls and arguments that may be made by its users. Shared memory mappings may also be specified as part of the protocol.
Services are published with Rendezvous, so that any apps on the local machine or on the network can see and use the service. Of course, it is up to the user whether or not the services provided by the drivers for their devices should be shared with the rest of the network. Rendezvous also automatically notifies everyone when a service is withdrawn (e.g. device unplugged).
When a new service is published, udmarket can optionally launch an application (or daemon) that has been identified by the user as the default app to launch for that kind of service. The driver can give a hint about what app it would prefer too. e.g. open a TV app when a TV tuner is plugged in.
Applications search for services with the normal Rendezvous methods. Rendezvous can easily restrict its searches to a local machine if the user has indicated to the application that it is only interested in devices on the local machine. There is a small helper library to extract the service object once it has been located, so the methods in its protocol may be called naturally. This library takes care of setting up shared memory mappings between processes on the same machine, or emulating them when they are on different machines.
Services may be derived from IOKit kernel drivers by creating a 'driver' for their user client. The amount of processing that happens locally in the service object in the application and the amount that happens remotely in the driver is up to the backer of the service. In the case of a service derived from an IOKit kernel driver, the local service object would talk directly to the user client if it is on the same machine - so there is no unnecessary overhead.
The Remote Control Receiver Daemon listens for all RCR services all the time. By default it only listens on the local machine, but through the preference pane you can select devices on other machines in the network. When it finds a RCR service it opens it and registers for events. When it gets events, it translates them into keypresses or mouse movements. And it sends a special 'remote control button' event through the HID event system too.
The configuration of which remote button->key mapping to use is done in the preference pane. There are a whole lot of buttons that are usually the same on all remotes. These are easily mapped. There are almost always also device-specific buttons. To make it worse, not all RCRs can receive the full button identifier information, sometimes only the last few bits are available.
The Preference Pane allows the user to match up (multiple) predefined button layouts with particular RCRs. It also allows the user to specify what action should be taken when the button is pressed, first on an application-specific level, then if there is no application-specific setting, on a system-wide level. OK there's going to be quite a few scrolling lists here! The actions can be generating key presses or mouse movement events, running applescripts, or running shell scripts. Some common operations are provided through applescripts, including launching/switching to an application, quitting an application, switching windows, changing the volume up or down, and probably some more I haven't thought of yet.
There isn't much point looking for remote devices on the network (may as well be done on that machine), so it just looks on the local machine. When the user configures a device to be used for IP over DVB, the userspace app takes care of obtaining the device (sorry, service) and tuning it to the appropriate frequency. (Other apps looking at the device will still be able to access stuff on the same multiplex.)
For getting the actual data packets into the kernel network stack, there is a kext which registers itself as a IPoverDVB linker. The daemon finds this user client and tells it the memory mapping of the driver's data buffer. This memory was quite likely originally from a PCI card driver in the kernel, but it's made a trip through a userspace application now, so that we can work with Market drivers too. So it looks like my wonderful in-kernel MMInput API will never be used after all, boo hoo :(. Then the kext pulls the packets straight out the buffer and puts the IP datagrams into the network stack.
If the first opener of a tuner goes away, then the second one wants to inherit full control. So there will have to be some unsolicited notification about this. Incredibly fortunately, distributed Objective-C provides exactly this! And it can be 'oneway' so we needn't worry about blocking there and getting our state stuffed up.
Note that the local user can always turn off sharing of the device if they want control of it themselves.