USB: handle bcd incrementation in usb modalias generation
This patch fixes a bug when incrementing/decrementing on a BCD formatted integer (i.e. 0x09++ should be 0x10 not 0x0A). It just adds a function for incrementing/decrementing BCD integers by converting to decimal, doing the increment/decrement and then converting back to BCD. Signed-off-by: Nathaniel McCallum <nathaniel@natemccallum.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
afe2dab4f6
commit
55f49f2682
|
@ -160,6 +160,45 @@ 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;
|
||||
|
@ -208,10 +247,16 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)
|
|||
}
|
||||
|
||||
if (clo > 0x0)
|
||||
do_usb_entry(id, devlo++, ndigits, clo, max, max, mod);
|
||||
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, devhi--, ndigits, 0x0, chi, max, mod);
|
||||
do_usb_entry(id,
|
||||
incbcd(&devhi, -1, max,
|
||||
sizeof(id->bcdDevice_lo) * 2),
|
||||
ndigits, 0x0, chi, max, mod);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue