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:
Nathaniel McCallum 2009-11-18 20:15:28 -05:00 committed by Greg Kroah-Hartman
parent afe2dab4f6
commit 55f49f2682

View File

@ -160,6 +160,45 @@ static void do_usb_entry(struct usb_device_id *id,
"MODULE_ALIAS(\"%s\");\n", alias); "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) static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod)
{ {
unsigned int devlo, devhi; 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) 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) 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);
} }
} }