i2c-hid: the touchpad crash was a printf format, not the driver

The PSOGM on the ASUS TUF A15 was a page fault in cprintf, from probe(),
in the touchpad driver's own success message. cprintf had no field widths:
"%04x" printed literally and consumed no argument, so the "%s" after it
was handed the product ID as a string pointer. "%lx" misprinted the same
way -- "0x4275838976x" for 0xFEDC2000 -- on the line before.

The driver's formats are fixed, and cprintf now steps over flags and
widths and takes l/ll/z as 64-bit, so a directive it does not render can
no longer shift every argument after it. Until now any %ld or %lu printed
the number followed by a stray letter.

The touchpad on/off entry in the boot menu has served its purpose and is
gone; the verbose step trace stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-25 00:28:23 +02:00
commit 5ea03c4cf5
5 changed files with 43 additions and 45 deletions

View file

@ -119,20 +119,39 @@ vcprintf(char *fmt, va_list ap)
continue;
}
c = fmt[++i] & 0xff;
// Flags and a width are stepped over, and l/ll/z make the conversion
// 64-bit. Not because the output honours them -- it does not pad -- but
// because a conversion this function did not understand used to consume
// no argument, and every one after it then read the wrong one. "%04x"
// before a "%s" handed the %s an integer as a string, and the touchpad
// driver's first message on real hardware was a page fault in here.
while (c == '0' || c == '-' || c == '+' || c == ' ' || c == '#')
c = fmt[++i] & 0xff;
while (c >= '1' && c <= '9')
c = fmt[++i] & 0xff;
while (c >= '0' && c <= '9')
c = fmt[++i] & 0xff;
int wide = 0;
while (c == 'l' || c == 'z') {
wide = 1;
c = fmt[++i] & 0xff;
}
if (c == 0)
break;
switch(c) {
case 'd':
print_int(va_arg(ap, int), 10, 1);
case 'i':
print_int(wide ? va_arg(ap, int64) : va_arg(ap, int), 10, 1);
break;
case 'u':
print_int(va_arg(ap, uint32), 10, 0);
break;
case 'l':
print_int(va_arg(ap, int64), 10, 1);
print_int(wide ? va_arg(ap, uint64) : va_arg(ap, uint32), 10, 0);
break;
case 'x':
print_int(va_arg(ap, uint32), 16, 0);
case 'X':
print_int(wide ? va_arg(ap, uint64) : va_arg(ap, uint32), 16, 0);
break;
case 'c':
consputc(va_arg(ap, int));
break;
case 'p':
print_int(va_arg(ap, uint64), 16, 0);