xfree86: Match devices based on USB ID

Sometimes the vendor and product names aren't specific enough to target
a USB device, so expose the numeric codes in the ID. A MatchUSBID entry
has been added that supports shell pattern matching when fnmatch(3) is
available. For example:

	MatchUSBID "046d:*"

The IDs are stored in lowercase hex separated by a ':' like "lsusb" or
"lspci -n".

Signed-off-by: Dan Nicholson <dbn.lists@gmail.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Dan Nicholson 2010-06-10 06:15:41 -07:00 committed by Peter Hutterer
parent 645679c152
commit 87a1507da7
10 changed files with 88 additions and 0 deletions

View File

@ -184,7 +184,24 @@ device_added(LibHalContext *hal_ctx, const char *udi)
parent = get_prop_string(hal_ctx, udi, "info.parent"); parent = get_prop_string(hal_ctx, udi, "info.parent");
if (parent) { if (parent) {
int usb_vendor, usb_product;
attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id"); attrs.pnp_id = get_prop_string(hal_ctx, parent, "pnp.id");
/* construct USB ID in lowercase - "0000:ffff" */
usb_vendor = libhal_device_get_property_int(hal_ctx, parent,
"usb.vendor_id", NULL);
LogMessageVerb(X_INFO, 10,
"config/hal: getting usb.vendor_id on %s "
"returned %04x\n", parent, usb_vendor);
usb_product = libhal_device_get_property_int(hal_ctx, parent,
"usb.product_id", NULL);
LogMessageVerb(X_INFO, 10,
"config/hal: getting usb.product_id on %s "
"returned %04x\n", parent, usb_product);
if (usb_vendor && usb_product)
attrs.usb_id = Xprintf("%04x:%04x", usb_vendor, usb_product);
free(parent); free(parent);
} }
@ -391,6 +408,7 @@ unwind:
free(attrs.vendor); free(attrs.vendor);
free(attrs.device); free(attrs.device);
free(attrs.pnp_id); free(attrs.pnp_id);
free(attrs.usb_id);
if (attrs.tags) { if (attrs.tags) {
char **tag = attrs.tags; char **tag = attrs.tags;
while (*tag) { while (*tag) {

View File

@ -28,6 +28,7 @@
#endif #endif
#include <libudev.h> #include <libudev.h>
#include <ctype.h>
#include "input.h" #include "input.h"
#include "inputstr.h" #include "inputstr.h"
@ -57,6 +58,7 @@ device_added(struct udev_device *udev_device)
char *config_info = NULL; char *config_info = NULL;
const char *syspath; const char *syspath;
const char *tags_prop; const char *tags_prop;
const char *usb_vendor = NULL, *usb_model = NULL;
const char *key, *value, *tmp; const char *key, *value, *tmp;
InputOption *options = NULL, *tmpo; InputOption *options = NULL, *tmpo;
InputAttributes attrs = {}; InputAttributes attrs = {};
@ -150,6 +152,12 @@ device_added(struct udev_device *udev_device)
} else if (!strcmp(key, "ID_VENDOR")) { } else if (!strcmp(key, "ID_VENDOR")) {
LOG_PROPERTY(path, key, value); LOG_PROPERTY(path, key, value);
attrs.vendor = value; attrs.vendor = value;
} else if (!strcmp(key, "ID_VENDOR_ID")) {
LOG_PROPERTY(path, key, value);
usb_vendor = value;
} else if (!strcmp(key, "ID_VENDOR_MODEL")) {
LOG_PROPERTY(path, key, value);
usb_model = value;
} else if (!strcmp(key, "ID_INPUT_KEY")) { } else if (!strcmp(key, "ID_INPUT_KEY")) {
LOG_PROPERTY(path, key, value); LOG_PROPERTY(path, key, value);
attrs.flags |= ATTR_KEYBOARD; attrs.flags |= ATTR_KEYBOARD;
@ -170,6 +178,17 @@ device_added(struct udev_device *udev_device)
attrs.flags |= ATTR_TOUCHSCREEN; attrs.flags |= ATTR_TOUCHSCREEN;
} }
} }
/* construct USB ID in lowercase hex - "0000:ffff" */
if (usb_vendor && usb_model) {
attrs.usb_id = Xprintf("%s:%s", usb_vendor, usb_model);
if (attrs.usb_id) {
char *cur;
for (cur = attrs.usb_id; *cur; cur++)
*cur = tolower(*cur);
}
}
LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n", LogMessage(X_INFO, "config/udev: Adding input device %s (%s)\n",
name, path); name, path);
rc = NewInputDeviceRequest(options, &attrs, &dev); rc = NewInputDeviceRequest(options, &attrs, &dev);
@ -190,6 +209,7 @@ device_added(struct udev_device *udev_device)
free(tmpo); free(tmpo);
} }
free(attrs.usb_id);
if (attrs.tags) { if (attrs.tags) {
char **tag = attrs.tags; char **tag = attrs.tags;
while (*tag) { while (*tag) {

View File

@ -359,6 +359,8 @@ DuplicateInputAttributes(InputAttributes *attrs)
goto unwind; goto unwind;
if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id))) if (attrs->pnp_id && !(new_attr->pnp_id = strdup(attrs->pnp_id)))
goto unwind; goto unwind;
if (attrs->usb_id && !(new_attr->usb_id = strdup(attrs->usb_id)))
goto unwind;
new_attr->flags = attrs->flags; new_attr->flags = attrs->flags;
@ -404,6 +406,7 @@ FreeInputAttributes(InputAttributes *attrs)
free(attrs->vendor); free(attrs->vendor);
free(attrs->device); free(attrs->device);
free(attrs->pnp_id); free(attrs->pnp_id);
free(attrs->usb_id);
if ((tags = attrs->tags)) if ((tags = attrs->tags))
while(*tags) while(*tags)

View File

@ -604,6 +604,10 @@ InputClassMatches(const XF86ConfInputClassPtr iclass,
if (!MatchAttrToken(attrs->pnp_id, iclass->match_pnpid, match_pattern)) if (!MatchAttrToken(attrs->pnp_id, iclass->match_pnpid, match_pattern))
return FALSE; return FALSE;
/* MatchUSBID pattern */
if (!MatchAttrToken(attrs->usb_id, iclass->match_usbid, match_pattern))
return FALSE;
/* /*
* MatchTag string * MatchTag string
* See if any of the device's tags match any of the MatchTag tokens. * See if any of the device's tags match any of the MatchTag tokens.

View File

@ -1101,6 +1101,15 @@ The device's Plug and Play (PnP) ID can be checked against the
shell wildcard pattern. Multiple IDs can be matched by separating arguments shell wildcard pattern. Multiple IDs can be matched by separating arguments
with a '|' character. with a '|' character.
.TP 7 .TP 7
.BI "MatchUSBID \*q" matchusb \*q
The device's USB ID can be checked against the
.RI \*q matchusb \*q
shell wildcard pattern. The ID is constructed as lowercase hexadecimal numbers
separated by a ':'. This is the same format as the
.BR lsusb (8)
program. Multiple IDs can be matched by separating arguments with a '|'
character.
.TP 7
.BI "MatchTag \*q" matchtag \*q .BI "MatchTag \*q" matchtag \*q
This entry can be used to check if tags assigned by the config backend This entry can be used to check if tags assigned by the config backend
matches the matches the

View File

@ -49,6 +49,7 @@ xf86ConfigSymTabRec InputClassTab[] =
{MATCH_DEVICE_PATH, "matchdevicepath"}, {MATCH_DEVICE_PATH, "matchdevicepath"},
{MATCH_OS, "matchos"}, {MATCH_OS, "matchos"},
{MATCH_PNPID, "matchpnpid"}, {MATCH_PNPID, "matchpnpid"},
{MATCH_USBID, "matchusbid"},
{MATCH_TAG, "matchtag"}, {MATCH_TAG, "matchtag"},
{MATCH_IS_KEYBOARD, "matchiskeyboard"}, {MATCH_IS_KEYBOARD, "matchiskeyboard"},
{MATCH_IS_POINTER, "matchispointer"}, {MATCH_IS_POINTER, "matchispointer"},
@ -120,6 +121,11 @@ xf86parseInputClassSection(void)
Error(QUOTE_MSG, "MatchPnPID"); Error(QUOTE_MSG, "MatchPnPID");
ptr->match_pnpid = xstrtokenize(val.str, TOKEN_SEP); ptr->match_pnpid = xstrtokenize(val.str, TOKEN_SEP);
break; break;
case MATCH_USBID:
if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchUSBID");
ptr->match_usbid = xstrtokenize(val.str, TOKEN_SEP);
break;
case MATCH_TAG: case MATCH_TAG:
if (xf86getSubToken(&(ptr->comment)) != STRING) if (xf86getSubToken(&(ptr->comment)) != STRING)
Error(QUOTE_MSG, "MatchTag"); Error(QUOTE_MSG, "MatchTag");
@ -245,6 +251,14 @@ xf86printInputClassSection (FILE * cf, XF86ConfInputClassPtr ptr)
*list); *list);
fprintf(cf, "\"\n"); fprintf(cf, "\"\n");
} }
if (ptr->match_usbid) {
fprintf(cf, "\tMatchUSBID \"");
for (list = ptr->match_usbid; *list; list++)
fprintf(cf, "%s%s",
list == ptr->match_usbid ? "" : TOKEN_SEP,
*list);
fprintf(cf, "\"\n");
}
if (ptr->match_tag) { if (ptr->match_tag) {
fprintf(cf, "\tMatchTag \""); fprintf(cf, "\tMatchTag \"");
for (list = ptr->match_tag; *list; list++) for (list = ptr->match_tag; *list; list++)
@ -311,6 +325,11 @@ xf86freeInputClassList (XF86ConfInputClassPtr ptr)
free(*list); free(*list);
free(ptr->match_pnpid); free(ptr->match_pnpid);
} }
if (ptr->match_usbid) {
for (list = ptr->match_usbid; *list; list++)
free(*list);
free(ptr->match_usbid);
}
if (ptr->match_tag) { if (ptr->match_tag) {
for (list = ptr->match_tag; *list; list++) for (list = ptr->match_tag; *list; list++)
free(*list); free(*list);

View File

@ -348,6 +348,7 @@ typedef struct
char **match_device; char **match_device;
char **match_os; char **match_os;
char **match_pnpid; char **match_pnpid;
char **match_usbid;
char **match_tag; char **match_tag;
xf86TriState is_keyboard; xf86TriState is_keyboard;
xf86TriState is_pointer; xf86TriState is_pointer;

View File

@ -281,6 +281,7 @@ typedef enum {
MATCH_DEVICE_PATH, MATCH_DEVICE_PATH,
MATCH_OS, MATCH_OS,
MATCH_PNPID, MATCH_PNPID,
MATCH_USBID,
MATCH_TAG, MATCH_TAG,
MATCH_IS_KEYBOARD, MATCH_IS_KEYBOARD,
MATCH_IS_POINTER, MATCH_IS_POINTER,

View File

@ -216,6 +216,7 @@ typedef struct _InputAttributes {
char *vendor; char *vendor;
char *device; char *device;
char *pnp_id; char *pnp_id;
char *usb_id;
char **tags; /* null-terminated */ char **tags; /* null-terminated */
uint32_t flags; uint32_t flags;
} InputAttributes; } InputAttributes;

View File

@ -808,6 +808,13 @@ static void cmp_attr_fields(InputAttributes *attr1,
} else } else
g_assert(attr2->pnp_id == NULL); g_assert(attr2->pnp_id == NULL);
if (attr1->usb_id != NULL)
{
g_assert(attr1->usb_id != attr2->usb_id);
g_assert(strcmp(attr1->usb_id, attr2->usb_id) == 0);
} else
g_assert(attr2->usb_id == NULL);
tags1 = attr1->tags; tags1 = attr1->tags;
tags2 = attr2->tags; tags2 = attr2->tags;
@ -878,6 +885,11 @@ static void dix_input_attributes(void)
cmp_attr_fields(&orig, new); cmp_attr_fields(&orig, new);
FreeInputAttributes(new); FreeInputAttributes(new);
orig.usb_id = "USBID";
new = DuplicateInputAttributes(&orig);
cmp_attr_fields(&orig, new);
FreeInputAttributes(new);
orig.flags = 0xF0; orig.flags = 0xF0;
new = DuplicateInputAttributes(&orig); new = DuplicateInputAttributes(&orig);
cmp_attr_fields(&orig, new); cmp_attr_fields(&orig, new);