diff options
| author | Nathaniel McCallum <nathaniel@natemccallum.com> | 2009-11-18 20:15:28 -0500 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-12-11 14:55:20 -0500 |
| commit | 55f49f26821f379c451deb9fd6de8e59afb9b37e (patch) | |
| tree | c4c4cfd20a6766cd38ec25213124ccc92b48592e /scripts/mod/file2alias.c | |
| parent | afe2dab4f6d32d5650aaba42f2c7ec9c0622f4dd (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>
Diffstat (limited to 'scripts/mod/file2alias.c')
| -rw-r--r-- | scripts/mod/file2alias.c | 49 |
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, | |||
| 160 | "MODULE_ALIAS(\"%s\");\n", alias); | 160 | "MODULE_ALIAS(\"%s\");\n", alias); |
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | /* Handles increment/decrement of BCD formatted integers */ | ||
| 164 | /* Returns the previous value, so it works like i++ or i-- */ | ||
| 165 | static unsigned int incbcd(unsigned int *bcd, | ||
| 166 | int inc, | ||
| 167 | unsigned char max, | ||
| 168 | size_t chars) | ||
| 169 | { | ||
| 170 | unsigned int init = *bcd, i, j; | ||
| 171 | unsigned long long c, dec = 0; | ||
| 172 | |||
| 173 | /* If bcd is not in BCD format, just increment */ | ||
| 174 | if (max > 0x9) { | ||
| 175 | *bcd += inc; | ||
| 176 | return init; | ||
| 177 | } | ||
| 178 | |||
| 179 | /* Convert BCD to Decimal */ | ||
| 180 | for (i=0 ; i < chars ; i++) { | ||
| 181 | c = (*bcd >> (i << 2)) & 0xf; | ||
| 182 | c = c > 9 ? 9 : c; /* force to bcd just in case */ | ||
| 183 | for (j=0 ; j < i ; j++) | ||
| 184 | c = c * 10; | ||
| 185 | dec += c; | ||
| 186 | } | ||
| 187 | |||
| 188 | /* Do our increment/decrement */ | ||
| 189 | dec += inc; | ||
| 190 | *bcd = 0; | ||
| 191 | |||
| 192 | /* Convert back to BCD */ | ||
| 193 | for (i=0 ; i < chars ; i++) { | ||
| 194 | for (c=1,j=0 ; j < i ; j++) | ||
| 195 | c = c * 10; | ||
| 196 | c = (dec / c) % 10; | ||
| 197 | *bcd += c << (i << 2); | ||
| 198 | } | ||
| 199 | return init; | ||
| 200 | } | ||
| 201 | |||
| 163 | static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) | 202 | static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) |
| 164 | { | 203 | { |
| 165 | unsigned int devlo, devhi; | 204 | unsigned int devlo, devhi; |
| @@ -208,10 +247,16 @@ static void do_usb_entry_multi(struct usb_device_id *id, struct module *mod) | |||
| 208 | } | 247 | } |
| 209 | 248 | ||
| 210 | if (clo > 0x0) | 249 | if (clo > 0x0) |
| 211 | do_usb_entry(id, devlo++, ndigits, clo, max, max, mod); | 250 | do_usb_entry(id, |
| 251 | incbcd(&devlo, 1, max, | ||
| 252 | sizeof(id->bcdDevice_lo) * 2), | ||
| 253 | ndigits, clo, max, max, mod); | ||
| 212 | 254 | ||
| 213 | if (chi < max) | 255 | if (chi < max) |
| 214 | do_usb_entry(id, devhi--, ndigits, 0x0, chi, max, mod); | 256 | do_usb_entry(id, |
| 257 | incbcd(&devhi, -1, max, | ||
| 258 | sizeof(id->bcdDevice_lo) * 2), | ||
| 259 | ndigits, 0x0, chi, max, mod); | ||
| 215 | } | 260 | } |
| 216 | } | 261 | } |
| 217 | 262 | ||
