Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55f49f26 authored by Nathaniel McCallum's avatar Nathaniel McCallum Committed by Greg Kroah-Hartman
Browse files

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: default avatarNathaniel McCallum <nathaniel@natemccallum.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent afe2dab4
Loading
Loading
Loading
Loading
+47 −2
Original line number Diff line number Diff line
@@ -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);
	}
}