summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathaniel McCallum <nathaniel@natemccallum.com>2009-11-18 20:15:28 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 11:55:20 -0800
commit55f49f26821f379c451deb9fd6de8e59afb9b37e (patch)
treec4c4cfd20a6766cd38ec25213124ccc92b48592e
parentafe2dab4f6d32d5650aaba42f2c7ec9c0622f4dd (diff)
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>
-rw-r--r--scripts/mod/file2alias.c49
1 files changed, 47 insertions, 2 deletions
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index e31f03aaf294..6f426afbc522 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -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);
}
}