The USB matching rules in the configuration files tell the USB launcher service how to process specific types of devices when they're attached through a USB port.
The matching rules specify device properties (for instance, vendor ID, device ID, USB class) that the service compares against the device descriptors provided by the USB stack. When the service finds a rule with properties matching those of a newly attached device, it executes the commands listed in the rule.
Matching rules are expressed in a hierarchy that defines different levels at which to match device descriptors. Each level of depth is more specific than the last, meaning that its rules match a more restricted set of devices. Here are the five levels of device specification rules:
When an outer (more general) rule matches a device, the USB launcher service compares the inner (more specific) rules in a depth-first search order. You can omit some or all of the inner rules if you don't need to match any descriptors at that level. For rules at the same level, USB launcher applies the rule listed earliest. You can verify the search order by calling show_config() at the end of your configuration file.
Level | Descriptors matched | Rule syntax |
---|---|---|
device | Vendor ID, device ID, earliest revision, latest revision |
device(vid, did, rev_low, rev_high) device(vid, did, rev_low) device(vid, did) device() |
product
(same as device rule except you can specify a range of device IDs) |
Vendor ID, lowest device ID, highest device ID |
product(vid, did_low, did_high) product(vid, did_low) product(vid) product() |
configuration | Configuration number |
configuration(num) configuration() |
interface | Interface number or range indicated by lowest and highest numbers |
interface(num_low, num_high) interface(num) interface() |
class | Interface class, subclass, and protocol |
class(class, subclass, protocol) class(class, subclass) class(class) class() |
ms_desc | Microsoft descriptor |
ms_desc(compatibleID, subcompatibleID, vendorID) ms_desc(compatibleID, subcompatibleID) ms_desc(compatibleID) ms_desc() |
The device specification below shows three levels of matching rules. The driver command line is enclosed in double quotes and prefixed with the driver keyword. The names of macro variables in the driver command line are the same as the attribute names in PPS device objects.
device(vid, did, rev_low, rev_high) { configuration(1) { class(class, subclass, protocol) { driver"io-fs-media -dxxx,\z device=$(busno):$(devno):$(interface)"; }; }; };
You can define variables to store values and use those values in matching rules listed later in the configuration file. Here are some sample definitions:
-- definitions of common USB properties USB_CLASS_AUDIO = 0x01 USB_AUDIO_SUBCLASS_CONTROL = 0x01 USB_AUDIO_SUBCLASS_STREAMING = 0x02 USB_AUDIO_PROTOCOL_1_0 = 0x00 USB_AUDIO_PROTOCOL_2_0 = 0x20 USB_CLASS_PHYSICAL = 0x05 USB_CLASS_IMAGING = 0x06 USB_IMAGING_SUBCLASS_STILL = 0x01 USB_IMAGING_STILL_PROTOCOL_PTP = 0x01 USB_CLASS_PRINTER = 0x07 USB_CLASS_MASS_STORAGE = 0x08
The matching rule shown below demonstrates the use of variables. This specification matches any device that has a mass-storage class:
-- generic mass storage rule device() { class(USB_CLASS_MASS_STORAGE) { DISK_OPTS = "blk cache=1m,vnode=384,\z auto=none,delwri=2:2,rmvto=none,noatime \z disk name=umass cdrom name=umasscd"; UMASS_OPTS = "umass priority=21"; driver"devb-umass $(DISK_OPTS) $(UMASS_OPTS),\z vid=$(vendor_id),did=$(product_id),\z busno=$(busno),devno=$(devno),\z interface=$(interface),ign_remove"; }; };
Notice that variables can be defined in the scope of a rule and used in the driver command. When searching for variable definitions, the USB launcher service searches from the innermost to the outermost scope.
You can place flags in a rule to change the range of devices matched and to change the actions performed after matching a device.
Ignore flag
At the device level, the Ignore flag instructs the USB launcher service to ignore the device by not attaching to it and reading its descriptors. In this case, no PPS objects are published and no driver is launched.
Consider the following example:
device(0x0e0f, 0x0003) { Ignore; -- don't even attach to this device }
Because it performs the Ignore check before attaching to the device, the USB launcher service doesn't have any device descriptors to match against. As a result, it can look at only the vendor ID and device ID supplied by the stack when the device was physically attached to the target system. Therefore, the device rule can't be made more specific about ignoring devices with certain revisions.
For rules at inner levels, the USB launcher service performs the Ignore check after retrieving device descriptors, allowing you to make these rules more specific. At any inner level, the Ignore flag stops the service from launching a driver and from matching the device with any subsequent rules.
product(0x05AC) { class(USB_CLASS_AUDIO, USB_AUDIO_SUBCLASS_CONTROL) { driver"io-audio -dipod busno=$(busno),devno=$(devno),\z cap_name=ipod-$(busno)-$(devno)"; }; class(USB_CLASS_HID) { driver"io-fs-media -dipod,$(IPOD_OPTS)"; }; class(USB_CLASS_MASS_STORAGE) { Ignore; }; };
Default flag
You can include the Default flag in a configuration rule to limit driver matching to the device's default configuration, as shown here:
configuration(1) { Default; driver"io-fs-media -dipod,$(IPOD_OPTS)"; }
Never flag
The Never flag means no device is matched, which lets you temporarily disable a rule. The device can match another rule specified later in the configuration file and have an alternative driver launched.
Always flag
The Always flag means any device is matched (if it hasn't been matched with another rule already). For example, although the class rule in the following device specification indicates an interface class of 8, the rule actually matches devices of any class:
device() { class(8) { Always; start"echo this is busno=$(busno) devno=$(devno) inserted"; }; };
You can specify multiple interface classes for one device or product rule, as in the iPod device specification in the following example:
-- iPod product(0x05AC, 0x1200, 0x12FF) { class(USB_CLASS_AUDIO, USB_AUDIO_SUBCLASS_CONTROL) { driver"io-audio -dipod busno=$(busno),devno=$(devno),\z cap_name=ipod-$(busno)-$(devno)"; }; class(USB_CLASS_HID) { driver"io-fs-media -dipod,transport=usb:busno=$(busno):\z devno=$(devno):\z audio=/dev/snd/ipod-$(busno)-$(devno),\z darates=+8000:11025:12000:16000:22050:24000,\z playback,acp=i2c:addr=0x11:path=/dev/i2c99,\z fnames=short,config=/etc/mm/ipod.cfg"; }; class(USB_CLASS_MASS_STORAGE) { Never; }; };
With the foreach rule, you can launch a particular driver for any device in a given list of devices. This rule saves you from having to specify many device (or product) rules that differ only by their device or vendor IDs, as shown in this example:
char_devices = { device(0x0557, 0x2008); -- ATEN_232A/GUC_232A device(0x2478, 0x2008); -- TRIPP LITE U2009-000-R device(0x9710, 0x7720); -- MOSCHIP 7720 device(0x0403, 0x6001); -- FTDI 8U232AM device(0x1199, 0x0120); -- Sierra AirCard U595 device(0x0681, 0x0040); -- Siemens HC25 device(0x1bc7, 0x1003); -- Telit UC864E device(0x067b, 0x2303); -- Prolific } foreach (char_devices) { driver" devc-serusb -d vid=$(vendor_id),did=$(product_id),\z busno=$(busno),devno=$(devno)"; }
The foreach rule also works with rules of inner scopes such as configuration or interface.
You can specify a driver with either of the driver or start functions. The difference is that driver is used to launch programs that are expected to run as long as the device is attached. These programs are usually daemons. Consider the following rule for launching a daemon:
device() { class(USB_CLASS_MASS_STORAGE) { driver"devb-umass $(DISK_OPTS) $(UMASS_OPTS),\z vid=$(vendor_id),did=$(product_id),busno=$(busno),\z devno=$(devno),interface=$(interface)"; }; };
You can use the start function and its corresponding removal function to execute short, simple scripts that mount or unmount a network DLL. You can also use these functions to launch short-lived commands, such as the echo commands, below:
device() { class(USB_CLASS_MASS_STORAGE) { start"echo Device busno=$(busno) devno=$(devno) inserted"; removal"echo Device busno=$(busno) devno=$(devno) removed"; }; };