Skip to content

Commit

Permalink
USB: add hex/bcd detection to usb modalias generation
Browse files Browse the repository at this point in the history
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: Nathaniel McCallum <nathaniel@natemccallum.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Nathaniel McCallum authored and Greg Kroah-Hartman committed Dec 11, 2009
1 parent c1479a9 commit afe2dab
Showing 1 changed file with 36 additions and 12 deletions.
48 changes: 36 additions & 12 deletions scripts/mod/file2alias.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
unsigned int bcdDevice_initial, int bcdDevice_initial_digits,
unsigned char range_lo, unsigned char range_hi,
struct module *mod)
unsigned char max, struct module *mod)
{
char alias[500];
strcpy(alias, "usb:");
Expand All @@ -118,9 +118,22 @@ static void do_usb_entry(struct usb_device_id *id,
sprintf(alias + strlen(alias), "%0*X",
bcdDevice_initial_digits, bcdDevice_initial);
if (range_lo == range_hi)
sprintf(alias + strlen(alias), "%u", range_lo);
else if (range_lo > 0 || range_hi < 9)
sprintf(alias + strlen(alias), "[%u-%u]", range_lo, range_hi);
sprintf(alias + strlen(alias), "%X", range_lo);
else if (range_lo > 0 || range_hi < max) {
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))
strcat(alias, "*");

Expand Down Expand Up @@ -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)
{
unsigned int devlo, devhi;
unsigned char chi, clo;
unsigned char chi, clo, max;
int ndigits;

id->match_flags = TO_NATIVE(id->match_flags);
Expand All @@ -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 ?
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
* run-time specification that results in catch-all alias
Expand All @@ -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--) {
clo = devlo & 0xf;
chi = devhi & 0xf;
if (chi > 9) /* it's bcd not hex */
chi = 9;
if (chi > max) /* If we are in bcd mode, truncate if necessary */
chi = max;
devlo >>= 4;
devhi >>= 4;

if (devlo == devhi || !ndigits) {
do_usb_entry(id, devlo, ndigits, clo, chi, mod);
do_usb_entry(id, devlo, ndigits, clo, chi, max, mod);
break;
}

if (clo > 0)
do_usb_entry(id, devlo++, ndigits, clo, 9, mod);
if (clo > 0x0)
do_usb_entry(id, devlo++, ndigits, clo, max, max, mod);

if (chi < 9)
do_usb_entry(id, devhi--, ndigits, 0, chi, mod);
if (chi < max)
do_usb_entry(id, devhi--, ndigits, 0x0, chi, max, mod);
}
}

Expand Down

0 comments on commit afe2dab

Please sign in to comment.