diff options
Diffstat (limited to 'scripts/mod/file2alias.c')
-rw-r--r-- | scripts/mod/file2alias.c | 95 |
1 files changed, 82 insertions, 13 deletions
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 62a9025cdcc7..6f426afbc522 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -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:"); @@ -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, "*"); @@ -147,10 +160,49 @@ static void do_usb_entry(struct usb_device_id *id, "MODULE_ALIAS(\"%s\");\n", alias); } +/* Handles increment/decrement of BCD formatted integers */ +/* Returns the previous value, so it works like i++ or i-- */ +static unsigned int incbcd(unsigned int *bcd, + int inc, + unsigned char max, + size_t chars) +{ + unsigned int init = *bcd, i, j; + unsigned long long c, dec = 0; + + /* If bcd is not in BCD format, just increment */ + if (max > 0x9) { + *bcd += inc; + return init; + } + + /* Convert BCD to Decimal */ + for (i=0 ; i < chars ; i++) { + c = (*bcd >> (i << 2)) & 0xf; + c = c > 9 ? 9 : c; /* force to bcd just in case */ + for (j=0 ; j < i ; j++) + c = c * 10; + dec += c; + } + + /* Do our increment/decrement */ + dec += inc; + *bcd = 0; + + /* Convert back to BCD */ + for (i=0 ; i < chars ; i++) { + for (c=1,j=0 ; j < i ; j++) + c = c * 10; + c = (dec / c) % 10; + *bcd += c << (i << 2); + } + return init; +} + 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); @@ -162,6 +214,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 @@ -173,21 +236,27 @@ 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 (chi < 9) - do_usb_entry(id, devhi--, ndigits, 0, chi, mod); + if (clo > 0x0) + do_usb_entry(id, + incbcd(&devlo, 1, max, + sizeof(id->bcdDevice_lo) * 2), + ndigits, clo, max, max, mod); + + if (chi < max) + do_usb_entry(id, + incbcd(&devhi, -1, max, + sizeof(id->bcdDevice_lo) * 2), + ndigits, 0x0, chi, max, mod); } } |