Commit afe2dab4 authored by Nathaniel McCallum's avatar Nathaniel McCallum Committed by Greg Kroah-Hartman

USB: add hex/bcd detection to usb modalias generation

The current code to generate usb modaliases from usb_device_id assumes
that the device's bcdDevice descriptor will actually be in BCD format.
While this should be a sane assumption, some devices don't follow spec
and just use plain old hex.  This causes drivers for these devices to
generate invalid modalias lines which will never actually match for the
hardware.

The following patch adds hex support for bcdDevice in file2alias.c by
detecting when a driver uses a hex formatted bcdDevice_(lo|hi) and
adjusts the output to hex format accordingly.

Drivers for devices which have bcdDevice conforming to BCD will have no
change in modalias output.  Drivers for devices which don't conform
(i.e. ibmcam) should now generate valid modaliases.

EXAMPLE OUTPUT (ibmcam; space added to highlight change)
    Old: usb:v0545p800D d030[10-9] dc*dsc*dp*ic*isc*ip*
    New: usb:v0545p800D d030a      dc*dsc*dp*ic*isc*ip*
Signed-off-by: default avatarNathaniel McCallum <nathaniel@natemccallum.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent c1479a92
...@@ -104,7 +104,7 @@ static void device_id_check(const char *modname, const char *device_id, ...@@ -104,7 +104,7 @@ static void device_id_check(const char *modname, const char *device_id,
static void do_usb_entry(struct usb_device_id *id, static void do_usb_entry(struct usb_device_id *id,
unsigned int bcdDevice_initial, int bcdDevice_initial_digits, unsigned int bcdDevice_initial, int bcdDevice_initial_digits,
unsigned char range_lo, unsigned char range_hi, unsigned char range_lo, unsigned char range_hi,
struct module *mod) unsigned char max, struct module *mod)
{ {
char alias[500]; char alias[500];
strcpy(alias, "usb:"); strcpy(alias, "usb:");
...@@ -118,9 +118,22 @@ static void do_usb_entry(struct usb_device_id *id, ...@@ -118,9 +118,22 @@ static void do_usb_entry(struct usb_device_id *id,
sprintf(alias + strlen(alias), "%0*X", sprintf(alias + strlen(alias), "%0*X",
bcdDevice_initial_digits, bcdDevice_initial); bcdDevice_initial_digits, bcdDevice_initial);
if (range_lo == range_hi) if (range_lo == range_hi)
sprintf(alias + strlen(alias), "%u", range_lo); sprintf(alias + strlen(alias), "%X", range_lo);
else if (range_lo > 0 || range_hi < 9) else if (range_lo > 0 || range_hi < max) {
sprintf(alias + strlen(alias), "[%u-%u]", range_lo, range_hi); if (range_lo > 0x9 || range_hi < 0xA)
sprintf(alias + strlen(alias),
"[%X-%X]",
range_lo,
range_hi);
else {
sprintf(alias + strlen(alias),
range_lo < 0x9 ? "[%X-9" : "[%X",
range_lo);
sprintf(alias + strlen(alias),
range_hi > 0xA ? "a-%X]" : "%X]",
range_lo);
}
}
if (bcdDevice_initial_digits < (sizeof(id->bcdDevice_lo) * 2 - 1)) if (bcdDevice_initial_digits < (sizeof(id->bcdDevice_lo) * 2 - 1))
strcat(alias, "*"); strcat(alias, "*");
...@@ -150,7 +163,7 @@ static void do_usb_entry(struct usb_device_id *id, ...@@ -150,7 +163,7 @@ static void do_usb_entry(struct usb_device_id *id,
static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)
{ {
unsigned int devlo, devhi; unsigned int devlo, devhi;
unsigned char chi, clo; unsigned char chi, clo, max;
int ndigits; int ndigits;
id->match_flags = TO_NATIVE(id->match_flags); id->match_flags = TO_NATIVE(id->match_flags);
...@@ -162,6 +175,17 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) ...@@ -162,6 +175,17 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)
devhi = id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? devhi = id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI ?
TO_NATIVE(id->bcdDevice_hi) : ~0x0U; TO_NATIVE(id->bcdDevice_hi) : ~0x0U;
/* Figure out if this entry is in bcd or hex format */
max = 0x9; /* Default to decimal format */
for (ndigits = 0 ; ndigits < sizeof(id->bcdDevice_lo) * 2 ; ndigits++) {
clo = (devlo >> (ndigits << 2)) & 0xf;
chi = ((devhi > 0x9999 ? 0x9999 : devhi) >> (ndigits << 2)) & 0xf;
if (clo > max || chi > max) {
max = 0xf;
break;
}
}
/* /*
* Some modules (visor) have empty slots as placeholder for * Some modules (visor) have empty slots as placeholder for
* run-time specification that results in catch-all alias * run-time specification that results in catch-all alias
...@@ -173,21 +197,21 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) ...@@ -173,21 +197,21 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)
for (ndigits = sizeof(id->bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) { for (ndigits = sizeof(id->bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) {
clo = devlo & 0xf; clo = devlo & 0xf;
chi = devhi & 0xf; chi = devhi & 0xf;
if (chi > 9) /* it's bcd not hex */ if (chi > max) /* If we are in bcd mode, truncate if necessary */
chi = 9; chi = max;
devlo >>= 4; devlo >>= 4;
devhi >>= 4; devhi >>= 4;
if (devlo == devhi || !ndigits) { if (devlo == devhi || !ndigits) {
do_usb_entry(id, devlo, ndigits, clo, chi, mod); do_usb_entry(id, devlo, ndigits, clo, chi, max, mod);
break; break;
} }
if (clo > 0) if (clo > 0x0)
do_usb_entry(id, devlo++, ndigits, clo, 9, mod); do_usb_entry(id, devlo++, ndigits, clo, max, max, mod);
if (chi < 9) if (chi < max)
do_usb_entry(id, devhi--, ndigits, 0, chi, mod); do_usb_entry(id, devhi--, ndigits, 0x0, chi, max, mod);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment