summary refs log tree commit diff
path: root/scripts
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 /scripts
parentafe2dab4f6d32d5650aaba42f2c7ec9c0622f4dd (diff)
downloadlinux-55f49f26821f379c451deb9fd6de8e59afb9b37e.tar.gz
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>

Diffstat (limited to 'scripts')
-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);
 	}
 }