The USB matching rules in the main configuration file (rules.lua) provide usblauncher with commands for launching the appropriate driver with the appropriate configuration when a device is attached through a USB port.
The matching rules specify device properties (e.g., vendor ID, device ID, USB class) that usblauncher compares against the descriptors of newly attached devices; these descriptors are provided by the USB stack. When usblauncher finds a matching rule with properties matching those of a newly attached USB device, it executes the driver command specified in that 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. The five levels in device specification rules are:
When an outer (more general) rule matches a newly attached device, usblauncher 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 care about matching any descriptors at that level.
For rules at the same level, usblauncher applies the rule listed the earliest in the configuration file. You can confirm the exact search order by calling show_config() at the end of your configuration file.
The device specification that follows provides 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)"; }; }; };
The matching rules take variable numbers of arguments so that they may be as specific as necessary. The following table outlines the descriptors matched at each device specification level:
Level | Descriptors matched | Rule syntax |
---|---|---|
device | vendor ID, device ID, earliest revision, latest revision | device(<vid>, <did>, <rev_low>, <rev_high>) -- most specific device(<vid>, <did>, <rev_low>) device(<vid>, <did>) device() -- most general |
product (see 1) | vendor ID, lowest device ID, highest device ID | product(<vid>, <did_low>, <did_high>) -- most specific product(<vid>, <did_low>) product(<vid>) product() -- most general |
configuration | configuration number | configuration(<num>) -- specific configuration() -- general |
interface | interface number or range indicated by lowest and highest numbers | interface(<num_low>, <num_high>) -- most specific interface(<num>) interface() -- most general |
class | interface class, subclass, and protocol | class(<class>, <subclass>, <protocol>) -- most specific class(<class>, <subclass>) class(<class>) class() -- most general |
ms_desc | Microsoft descriptor | ms_desc(<compatibleID>, <subcompatibleID>, <vendorID>) -- most specific ms_desc(<compatibleID>, <subcompatibleID>) ms_desc(<compatibleID>) ms_desc() -- most general |
You can define variables at the top of the configuration file to hold configuration values used in the matching rules:
-- 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 rules that follow demonstrate the use of variables. The first specification matches any device that has a mass-storage class while the second specification matches a Sony Walkman device with an MTP Microsoft descriptor.
-- generic mass storage rule device() { class(USB_CLASS_MASS_STORAGE) { DISK_OPTS = "cam quiet 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"; }; }; -- Sony Walkman device(0x054c, 0x03fd) { ms_desc("MTP", "", 1) { driver"io-fs-media -dpfs,device=$(busno):\z $(devno):$(interface)"; }; };
Notice that variables can be defined in the scope of a rule and used in the driver command line. When searching for variables, usblauncher searches the definitions from the innermost to the outermost scope.
You can also place flags in a rule to change the range of devices matched as well as the actions performed after matching a device.
At the device level, the Ignore flag instructs usblauncher 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, usblauncher doesn't have any device descriptors to match against. This means that it can look at only the vendor ID and device ID supplied by the stack when the device was physically attached to the system. Therefore, the device rule can't be made more specific about ignoring certain devices.
For rules at inner levels, the Ignore check is done after retrieving device descriptors, which means that you can make these rules more specific. At any inner level, the Ignore flag stops usblauncher 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; }; };
You can include the Default flag in a configuration rule to limit driver matching to the device's default configuration, as demonstrated in the following example:
configuration(0x48E0) { Default; driver"io-fs-media -dipod,$(IPOD_OPTS)"; }
The Never flag means no device is matched. This flag lets you temporarily disable a rule. The device can match another rule specified later in the configuration file and have an alternative driver launched.
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"; }; };
These last two flags provide a helpful way to test a rule during development.
You can specify multiple interface classes for one device or product rule, as in the sample iPod device specification that follows.
-- 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 seen in the example that follows:
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 device-specification 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)"; }; };
The start function is used for launching short-lived commands, such as the echo command shown in the following example:
device() { class(USB_CLASS_MASS_STORAGE) { start"echo Device busno=$(busno) devno=$(devno) inserted"; }; };