Synopsis: <Touchpad emitting keyboard events, unrecognized touchpad>
Category: <system kernel>
Environment:
  System: OpenBSD 6.2 Stable
  Details: OpenBSD laptop.home 6.2 GENERIC.MP#2 amd64
  Architecture: OpenBSD.amd64
  Machine: amd64
Description:
My laptop experienced keyboard events when touching the touchpad. The touchpad
was not recognized properly (Linux recognizes it as a Synaptics Touchpad and
FreeBSD sees it as a PS/2 mouse since it can default to this behavior) and
would not work at all (neither on Stable or Current).

On a previous release though, the touchpad worked without patching but would
emit keyboard events (I cannot remember which release sorry).

The keyboard events happen both in console and X. The touchpad could sometimes
work only for a few seconds after a fresh install but never after its first
keyboard events emitting.

So I looked for a solution in bugs@ and found two patches.

So I applied the patches described here, on Current & Stable :
https://marc.info/?l=openbsd-bugs&m=148517909028740&w=2
and here :
http://www.stoeckmann.org/patches/ps2apm.patch
from this thread:
https://marc.info/?l=openbsd-bugs&m=149539198219115&w=2
with a very small correction for it to compile. (further down this mail)

It can work on both Current and Stable but I chose to stay on Stable for now.

And it works satisfyingly enough. The touchpad is now seen as a PS/2 mouse. It
does not work when resuming from suspend and has no advanced features of course.
So a big thank you to the guys who made the patches.

I could also try to apply only the second patch to see if keyboard events
happen if that's of any use to the devs.

So I send the dmesg and other info as recommended:

dmesg:
OpenBSD 6.2-stable (GENERIC.MP) #2: Wed Nov 29 17:55:25 CET 2017
    [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
real mem = 4196806656 (4002MB)
avail mem = 4062593024 (3874MB)
mpath0 at root
scsibus0 at mpath0: 256 targets
mainbus0 at root
bios0 at mainbus0: SMBIOS rev. 2.8 @ 0xec200 (39 entries)
bios0: vendor American Megatrends Inc. version "5.6.5" date 02/10/2015
bios0: Notebook W54_55_94_95_97AU,AUQ
acpi0 at bios0: rev 2
acpi0: sleep states S0 S3 S4 S5
acpi0: tables DSDT FACP APIC FPDT FIDT MCFG HPET SSDT UEFI SSDT SSDT
ASF! SSDT SSDT TPM2 SSDT SSDT DMAR
acpi0: wakeup devices PEGP(S4) PEG0(S4) PEGP(S4) PEG1(S4) PEGP(S4)
PEG2(S4) PXSX(S4) RP01(S4) PXSX(S4) RP02(S4) PXSX(S4) RP03(S4)
PXSX(S4) RP04(S4) PXSX(S4) RP05(S4) [...]
acpitimer0 at acpi0: 3579545 Hz, 24 bits
acpimadt0 at acpi0 addr 0xfee00000: PC-AT compat
cpu0 at mainbus0: apid 0 (boot processor)
cpu0: Intel(R) Celeron(R) 3205U @ 1.50GHz, 1496.77 MHz
cpu0: 
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,SDBG,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,DEADLINE,XSAVE,RDRAND,NXE,PAGE1GB,RDTSCP,LONG,LAHF,ABM,3DNOWP,PERF,ITSC,FSGSBASE,ERMS,INVPCID,RDSEED,PT,SENSOR,ARAT
cpu0: 256KB 64b/line 8-way L2 cache
cpu0: TSC frequency 1496770360 Hz
cpu0: smt 0, core 0, package 0
mtrr: Pentium Pro MTRR support, 10 var ranges, 88 fixed ranges
cpu0: apic clock running at 99MHz
cpu0: mwait min=64, max=64, C-substates=0.2.1.2.4.1.1.1, IBE
cpu1 at mainbus0: apid 2 (application processor)
cpu1: Intel(R) Celeron(R) 3205U @ 1.50GHz, 1496.54 MHz
cpu1: 
FPU,VME,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,DS,ACPI,MMX,FXSR,SSE,SSE2,SS,HTT,TM,PBE,SSE3,PCLMUL,DTES64,MWAIT,DS-CPL,VMX,EST,TM2,SSSE3,SDBG,CX16,xTPR,PDCM,PCID,SSE4.1,SSE4.2,x2APIC,MOVBE,POPCNT,DEADLINE,XSAVE,RDRAND,NXE,PAGE1GB,RDTSCP,LONG,LAHF,ABM,3DNOWP,PERF,ITSC,FSGSBASE,ERMS,INVPCID,RDSEED,PT,SENSOR,ARAT
cpu1: 256KB 64b/line 8-way L2 cache
cpu1: smt 0, core 1, package 0
ioapic0 at mainbus0: apid 2 pa 0xfec00000, version 20, 40 pins
acpimcfg0 at acpi0 addr 0xf8000000, bus 0-63
acpihpet0 at acpi0: 14318179 Hz
acpiprt0 at acpi0: bus 0 (PCI0)
acpiprt1 at acpi0: bus -1 (PEG0)
acpiprt2 at acpi0: bus -1 (PEG1)
acpiprt3 at acpi0: bus -1 (PEG2)
acpiprt4 at acpi0: bus 1 (RP01)
acpiprt5 at acpi0: bus -1 (RP02)
acpiprt6 at acpi0: bus 2 (RP03)
acpiprt7 at acpi0: bus 3 (RP04)
acpiprt8 at acpi0: bus -1 (RP05)
acpiprt9 at acpi0: bus -1 (RP06)
acpiprt10 at acpi0: bus -1 (RP07)
acpiprt11 at acpi0: bus -1 (RP08)
acpiec0 at acpi0
acpicpu0 at acpi0: C3(200@506 mwait.1@0x60), C2(200@117 mwait.1@0x32),
C1(1000@1 mwait.1), PSS
acpicpu1 at acpi0: C3(200@506 mwait.1@0x60), C2(200@117 mwait.1@0x32),
C1(1000@1 mwait.1), PSS
acpipwrres0 at acpi0: PG00, resource for PEG0
acpipwrres1 at acpi0: PG01, resource for PEG1
acpipwrres2 at acpi0: PG02, resource for PEG2
acpitz0 at acpi0: critical temperature is 120 degC
acpipwrres3 at acpi0: FN00, resource for FAN0
acpipwrres4 at acpi0: FN01, resource for FAN1
acpipwrres5 at acpi0: FN02, resource for FAN2
acpipwrres6 at acpi0: FN03, resource for FAN3
acpipwrres7 at acpi0: FN04, resource for FAN4
acpitz1 at acpi0: critical temperature is 105 degC
acpitz2 at acpi0: critical temperature is 105 degC
"MSFT0001" at acpi0 not configured
"SYN1212" at acpi0 not configured
"INT3F0D" at acpi0 not configured
"MSFT0101" at acpi0 not configured
"PNPC000" at acpi0 not configured
acpibtn0 at acpi0: PWRB
acpibtn1 at acpi0: SLPB
acpibtn2 at acpi0: LID0
acpiac0 at acpi0: AC unit online
acpibat0 at acpi0: BAT0 model "BAT" serial 0001 type LION oem "Notebook"
"PNP0C14" at acpi0 not configured
"INT340E" at acpi0 not configured
"PNP0C0B" at acpi0 not configured
"PNP0C0B" at acpi0 not configured
"PNP0C0B" at acpi0 not configured
"PNP0C0B" at acpi0 not configured
"PNP0C0B" at acpi0 not configured
acpivideo0 at acpi0: GFX0
acpivout0 at acpivideo0: DD1F
cpu0: Enhanced SpeedStep 1496 MHz: speeds: 1501, 1500, 1400, 1300,
1200, 1100, 1000, 900, 800, 700, 600, 500 MHz
pci0 at mainbus0 bus 0
pchb0 at pci0 dev 0 function 0 "Intel Core 5G Host" rev 0x08
inteldrm0 at pci0 dev 2 function 0 "Intel HD Graphics" rev 0x08
drm0 at inteldrm0
inteldrm0: msi
inteldrm0: 1366x768, 32bpp
wsdisplay0 at inteldrm0 mux 1: console (std, vt100 emulation)
wsdisplay0: screen 1-5 added (std, vt100 emulation)
azalia0 at pci0 dev 3 function 0 "Intel Core 5G HD Audio" rev 0x08: msi
xhci0 at pci0 dev 20 function 0 "Intel 9 Series xHCI" rev 0x03: msi
usb0 at xhci0: USB revision 3.0
uhub0 at usb0 configuration 1 interface 0 "Intel xHCI root hub" rev
3.00/1.00 addr 1
"Intel 9 Series MEI" rev 0x03 at pci0 dev 22 function 0 not configured
azalia1 at pci0 dev 27 function 0 "Intel 9 Series HD Audio" rev 0x03: msi
azalia1: codecs: Realtek ALC269
audio0 at azalia1
ppb0 at pci0 dev 28 function 0 "Intel 9 Series PCIE" rev 0xe3: msi
pci1 at ppb0 bus 1
ppb1 at pci0 dev 28 function 2 "Intel 9 Series PCIE" rev 0xe3: msi
pci2 at ppb1 bus 2
iwm0 at pci2 dev 0 function 0 "Intel Dual Band Wireless AC 7260" rev 0xc3, msi
ppb2 at pci0 dev 28 function 3 "Intel 9 Series PCIE" rev 0xe3: msi
pci3 at ppb2 bus 3
rtsx0 at pci3 dev 0 function 0 "Realtek RTL8411B Card Reader" rev 0x01: msi
sdmmc0 at rtsx0: 4-bit
re0 at pci3 dev 0 function 1 "Realtek 8168" rev 0x12: RTL8411B
(0x5c80), msi, address 80:fa:5b:13:a4:89
rgephy0 at re0 phy 7: RTL8251 PHY, rev. 0
ehci0 at pci0 dev 29 function 0 "Intel 9 Series USB" rev 0x03: apic 2 int 23
usb1 at ehci0: USB revision 2.0
uhub1 at usb1 configuration 1 interface 0 "Intel EHCI root hub" rev
2.00/1.00 addr 1
pcib0 at pci0 dev 31 function 0 "Intel 9 Series LPC" rev 0x03
ahci0 at pci0 dev 31 function 2 "Intel 9 Series AHCI" rev 0x03: msi, AHCI 1.3
ahci0: port 0: 6.0Gb/s
ahci0: port 1: 1.5Gb/s
scsibus1 at ahci0: 32 targets
sd0 at scsibus1 targ 0 lun 0: <ATA, CT120BX100SSD1, MU01> SCSI3
0/direct fixed naa.500a0751f0030605
sd0: 114473MB, 512 bytes/sector, 234441648 sectors, thin
cd0 at scsibus1 targ 1 lun 0: <MATSHITA, DVD-RAM UJ8E2, 1.00> ATAPI
5/cdrom removable
ichiic0 at pci0 dev 31 function 3 "Intel 9 Series SMBus" rev 0x03: apic 2 int 18
iic0 at ichiic0
spdmem0 at iic0 addr 0x50: 4GB DDR3 SDRAM PC3-12800 SO-DIMM
isa0 at pcib0
isadma0 at isa0
pckbc0 at isa0 port 0x60/5 irq 1 irq 12 irq 12 irq 12 irq 12
pckbd0 at pckbc0 (kbd slot)
wskbd0 at pckbd0: console keyboard, using wsdisplay0
pckbc0: Active PS/2 Multiplexing, version 1.1
pms0 at pckbc0 (aux slot #1)
wsmouse0 at pms0 mux 0
pcppi0 at isa0 port 0x61
spkr0 at pcppi0
vmm0 at mainbus0: VMX/EPT
Unclaimed register detected before reading register 0x23a0
ugen0 at uhub0 port 5 "Intel product 0x07dc" rev 2.00/0.01 addr 2
uvideo0 at uhub0 port 6 configuration 1 interface 0 "Acer BisonCam, NB
Pro" rev 2.00/6.08 addr 3
video0 at uvideo0
uhub2 at uhub1 port 1 configuration 1 interface 0 "Intel Rate Matching
Hub" rev 2.00/0.03 addr 2
sdmmc0: can't enable card
vscsi0 at root
scsibus2 at vscsi0: 256 targets
softraid0 at root
scsibus3 at softraid0: 256 targets
root on sd0a (51efcee656494d34.a) swap on sd0b dump on sd0b
iwm0: hw rev 0x140, fw ver 16.242414.0, address 48:51:b7:d6:8d:ff

usbdevs:
addr 1: xHCI root hub, Intel
 addr 2: product 0x07dc, Intel
 addr 3: BisonCam, NB Pro, Acer
addr 1: EHCI root hub, Intel
 addr 2: Rate Matching Hub, Intel

pcidump:
Domain /dev/pci0:
 0:0:0: Intel Core 5G Host
 0:2:0: Intel HD Graphics
 0:3:0: Intel Core 5G HD Audio
 0:20:0: Intel 9 Series xHCI
 0:22:0: Intel 9 Series MEI
 0:27:0: Intel 9 Series HD Audio
 0:28:0: Intel 9 Series PCIE
 0:28:2: Intel 9 Series PCIE
 0:28:3: Intel 9 Series PCIE
 0:29:0: Intel 9 Series USB
 0:31:0: Intel 9 Series LPC
 0:31:2: Intel 9 Series AHCI
 0:31:3: Intel 9 Series SMBus
 2:0:0: Intel Dual Band Wireless AC 7260
 3:0:0: Realtek RTL8411B Card Reader
 3:0:1: Realtek 8168

Now comes the patch I used, which is simply the combination of the two
previously cited patches with a small correction for it to compile when
building /usr/src. (Correction is a macro added near lines 765,839
of sys/dev/ic/pckbc.c)

Best regards,

Alex C.

Index: sys/arch/hppa/gsc/gsckbc.c
===================================================================
RCS file: /cvs/src/sys/arch/hppa/gsc/gsckbc.c,v
retrieving revision 1.19
diff -u -p -r1.19 gsckbc.c
--- sys/arch/hppa/gsc/gsckbc.c 24 May 2015 10:57:47 -0000 1.19
+++ sys/arch/hppa/gsc/gsckbc.c 30 Nov 2017 16:03:11 -0000
@@ -459,7 +459,7 @@ pckbc_poll_data1(iot, ioh, ioh_c, slot,
  bus_space_tag_t iot;
  bus_space_handle_t ioh, ioh_c;
  pckbc_slot_t slot;
- int checkaux; /* ignored on hppa */
+ struct pckbc_internal *t; /* ignored on hppa */
 {
  int i;
  u_char stat;
@@ -558,7 +558,7 @@ pckbc_flush(self, slot)
 {
  struct pckbc_internal *t = self;

- pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_d, slot, 0);
+ pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_d, slot, t);
 }

 int
@@ -570,7 +570,7 @@ pckbc_poll_data(self, slot)
  struct pckbc_slotdata *q = t->t_slotdata[slot];
  int c;

- c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_d, slot, 0);
+ c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_d, slot, t);
  if (c != -1 && q && CMD_IN_QUEUE(q)) {
  /* we jumped into a running command - try to
  deliver the response */
@@ -645,7 +645,7 @@ pckbc_poll_cmd1(t, slot, cmd)
  return;
  }
  for (i = 10; i; i--) { /* 1s ??? */
- c = pckbc_poll_data1(iot, ioh, ioh, slot, 0);
+ c = pckbc_poll_data1(iot, ioh, ioh, slot, t);
  if (c != -1)
  break;
  }
@@ -686,7 +686,7 @@ pckbc_poll_cmd1(t, slot, cmd)
  else
  i = 10; /* 1s ??? */
  while (i--) {
- c = pckbc_poll_data1(iot, ioh, ioh, slot, 0);
+ c = pckbc_poll_data1(iot, ioh, ioh, slot, t);
  if (c != -1)
  break;
  }
Index: sys/dev/ic/i8042reg.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/i8042reg.h,v
retrieving revision 1.9
diff -u -p -r1.9 i8042reg.h
--- sys/dev/ic/i8042reg.h 5 May 2015 16:27:20 -0000 1.9
+++ sys/dev/ic/i8042reg.h 30 Nov 2017 16:06:19 -0000
@@ -49,3 +49,18 @@
 #define KCID_KBD1 0xAB
 #define KCID_KBD2 0x83
 #define KCID_MOUSE 0x00
+
+/*
+ * Defines for Active PS/2 Multiplexing
+ */
+
+#define KBC_APM_ENB1 0xf0
+#define KBC_APM_ENB2 0x56
+#define KBC_APM_ENB3 0xa4
+
+#define KBC_APM_DIS1 0xf0
+#define KBC_APM_DIS2 0x56
+#define KBC_APM_DIS3 0xa5
+
+#define KBC_APM_PREFIX(p) (0x90 | (p))
+
Index: sys/dev/ic/pckbc.c
===================================================================
RCS file: /cvs/src/sys/dev/ic/pckbc.c,v
retrieving revision 1.50
diff -u -p -r1.50 pckbc.c
--- sys/dev/ic/pckbc.c 11 Mar 2017 11:55:03 -0000 1.50
+++ sys/dev/ic/pckbc.c 30 Nov 2017 16:06:33 -0000
@@ -104,8 +104,20 @@ void pckbc_poll(void *);
 int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char);
 void pckbc_start(struct pckbc_internal *, pckbc_slot_t);
 int pckbcintr_internal(struct pckbc_internal *, struct pckbc_softc *);
+int pckbc_enable_apm(struct pckbc_internal *);
+int pckbc_disable_apm(struct pckbc_internal *);

-const char *pckbc_slot_names[] = { "kbd", "aux" };
+const char *pckbc_slot_names[] = {
+ "kbd slot",
+#ifdef PCKBC_APM
+ "aux slot #0",
+ "aux slot #1",
+ "aux slot #2",
+ "aux slot #3",
+#else
+ "aux slot"
+#endif
+};

 #define KBC_DEVCMD_ACK 0xfa
 #define KBC_DEVCMD_RESEND 0xfe
@@ -136,32 +148,58 @@ pckbc_send_cmd(bus_space_tag_t iot, bus_
  return (1);
 }

+/*
+ * NOTE: Active PS/2 Multiplexing behaviour is only checked if t != NULL.
+ * This behaviour is intentional.
+ */
 int
 pckbc_poll_data1(bus_space_tag_t iot, bus_space_handle_t ioh_d,
-    bus_space_handle_t ioh_c, pckbc_slot_t slot, int checkaux)
+    bus_space_handle_t ioh_c, pckbc_slot_t slot, struct pckbc_internal *t)
 {
  int i;
+ int active;
  u_char stat;

  /* polls for ~100ms */
  for (i = 100; i; i--, delay(1000)) {
  stat = bus_space_read_1(iot, ioh_c, 0);
+ /* XXX no error bit handling */
  if (stat & KBS_DIB) {
  register u_char c;

  KBD_DELAY;
  CPU_BUSY_CYCLE();
  c = bus_space_read_1(iot, ioh_d, 0);
- if (checkaux && (stat & KBS_AUXDATA)) {
- if (slot != PCKBC_AUX_SLOT) {
- DPRINTF("lost aux 0x%x\n", c);
- continue;
- }
- } else {
- if (slot == PCKBC_AUX_SLOT) {
- DPRINTF("lost kbd 0x%x\n", c);
+#ifdef PCKBC_APM
+ if (t && t->t_apmver >= 0) {
+ if (stat & KBS_AUXDATA)
+ active = PCKBC_AUX_SLOT + (stat >> 6);
+ else
+ active = PCKBC_KBD_SLOT;
+ } else
+#endif
+ active = stat & KBS_AUXDATA ?
+ PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
+
+#ifdef PCKBC_APM
+ if (active != PCKBC_KBD_SLOT &&
+    t && t->t_apmver >= 0 && (stat & KBS_WARM)) {
+ if (c >= 0xfd) {
+ /* genuine error */
+ /* XXX handle hot removal? */
  continue;
  }
+ DPRINTF("pckbc apm mode reverted?\n");
+ /* XXX schedule a switch as soon as possible */
+}
+#endif
+ if (slot != active) {
+ if ((t && t->t_haveaux) ||
+    slot != PCKBC_KBD_SLOT ||
+    active == PCKBC_KBD_SLOT)
+ DPRINTF("lost data on slot%d 0x%x\n",
+    active, c);
+ continue;
  }
  return (c);
  }
@@ -182,8 +220,7 @@ pckbc_get8042cmd(struct pckbc_internal *

  if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
  return (0);
- data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT,
- t->t_haveaux);
+ data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, t);
  if (data == -1)
  return (0);
  t->t_cmdbyte = data;
@@ -215,7 +252,15 @@ pckbc_send_devcmd(struct pckbc_internal
  bus_space_handle_t ioh_d = t->t_ioh_d;
  bus_space_handle_t ioh_c = t->t_ioh_c;

- if (slot == PCKBC_AUX_SLOT) {
+ if (slot >= PCKBC_AUX_SLOT) {
+#ifdef PCKBC_APM
+ /* send specific routing prefix if multiplexing */
+ if (t->t_apmver >= 0) {
+ if (pckbc_send_cmd(iot, ioh_c,
+    KBC_APM_PREFIX(slot - PCKBC_AUX_SLOT)) == 0)
+ return (0);
+ } else
+#endif
  if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
  return (0);
  }
@@ -311,7 +356,7 @@ pckbc_attach(struct pckbc_softc *sc, int
  }

  /* flush */
- (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+ (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, NULL);

  /* set initial cmd byte */
  if (!pckbc_put8042cmd(t)) {
@@ -335,7 +380,7 @@ pckbc_attach(struct pckbc_softc *sc, int
  */
  if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
  return;
- res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+ res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, NULL);

  /*
  * Normally, we should get a "0" here.
@@ -375,7 +420,11 @@ pckbc_attach(struct pckbc_softc *sc, int
  goto nomouse;
  }
  bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
- res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, 1);
+ res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, NULL);
+
+#if defined(__amd64__)
+  t->t_flags |= PCKBC_NEED_AUXWRITE;
+#endif

  if (ISSET(t->t_flags, PCKBC_NEED_AUXWRITE)) {
  /*
@@ -391,7 +440,7 @@ pckbc_attach(struct pckbc_softc *sc, int
  goto nomouse;
  bus_space_write_1(iot, ioh_d, 0, 0x5a);
  res = pckbc_poll_data1(iot, ioh_d, ioh_c,
-    PCKBC_AUX_SLOT, 1);
+    PCKBC_AUX_SLOT, NULL);
  DPRINTF("kbc: aux echo: %x\n", res);
  }
  }
@@ -406,8 +455,21 @@ pckbc_attach(struct pckbc_softc *sc, int
  */
  DPRINTF("kbc: aux echo: %x\n", res);
  t->t_haveaux = 1;
- if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT, 0))
+
+#ifdef PCKBC_APM
+ t->t_apmver = -1;
+ t->t_apmver = pckbc_enable_apm(t);
+ if (t->t_apmver >= 0) {
+ printf("%s: Active PS/2 Multiplexing, version %d.%d\n",
+    sc->sc_dv.dv_xname, t->t_apmver >> 4,
+    t->t_apmver & 0x0f);
  cmdbits |= KC8_MENABLE;
+ for (res = PCKBC_AUX_SLOT; res < PCKBC_NSLOTS; res++)
+ pckbc_attach_slot(sc, res, 0);
+ } else
+#endif
+ if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT, 0))
+ cmdbits |= KC8_MENABLE;
  }
 #ifdef PCKBCDEBUG
  else
@@ -438,7 +500,7 @@ pckbcprint(void *aux, const char *pnp)
  struct pckbc_attach_args *pa = aux;

  if (!pnp)
- printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]);
+ printf(" (%s)", pckbc_slot_names[pa->pa_slot]);
  return (QUIET);
 }

@@ -484,8 +546,7 @@ pckbc_flush(pckbc_tag_t self, pckbc_slot
 {
  struct pckbc_internal *t = self;

- (void) pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
-    slot, t->t_haveaux);
+ (void) pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c, slot, t);
 }

 int
@@ -495,8 +556,7 @@ pckbc_poll_data(pckbc_tag_t self, pckbc_
  struct pckbc_slotdata *q = t->t_slotdata[slot];
  int c;

- c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
-     slot, t->t_haveaux);
+ c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c, slot, t);
  if (c != -1 && q && CMD_IN_QUEUE(q)) {
  /* we jumped into a running command - try to
  deliver the response */
@@ -545,13 +605,28 @@ void
 pckbc_slot_enable(pckbc_tag_t self, pckbc_slot_t slot, int on)
 {
  struct pckbc_internal *t = (struct pckbc_internal *)self;
- struct pckbc_portcmd *cmd;
+ const struct pckbc_portcmd *cmd;
+ int rc;

+#ifdef PCKBC_APM
+ cmd = &pckbc_portcmd[slot >= PCKBC_AUX_SLOT ? PCKBC_AUX_SLOT : slot];
+#else
  cmd = &pckbc_portcmd[slot];
+#endif

- if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
-    on ? cmd->cmd_en : cmd->cmd_dis))
- printf("pckbc_slot_enable(%d) failed\n", on);
+#ifdef PCKBC_APM
+ /* send specific routing prefix if multiplexing */
+ if (t->t_apmver >= 0 && slot >= PCKBC_AUX_SLOT) {
+ rc = pckbc_send_cmd(t->t_iot, t->t_ioh_c,
+    KBC_APM_PREFIX(slot - PCKBC_AUX_SLOT));
+ } else
+#endif
+ rc = 1;
+ if (rc != 0)
+ rc = pckbc_send_cmd(t->t_iot, t->t_ioh_c,
+    on ? cmd->cmd_en : cmd->cmd_dis);
+ if (rc == 0)
+ printf("pckbc_slot_enable(%d,%d) failed\n", slot, on);

  if (slot == PCKBC_KBD_SLOT) {
  if (on)
@@ -605,8 +680,7 @@ pckbc_poll_cmd1(struct pckbc_internal *t
  return;
  }
  for (i = 10; i; i--) { /* 1s ??? */
- c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot,
-     t->t_haveaux);
+ c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot, t);
  if (c != -1)
  break;
  }
@@ -645,8 +719,7 @@ pckbc_poll_cmd1(struct pckbc_internal *t
  else
  i = 10; /* 1s ??? */
  while (i--) {
- c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot,
-     t->t_haveaux);
+ c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot, t);
  if (c != -1)
  break;
  }
@@ -709,10 +782,11 @@ pckbc_cleanqueue(struct pckbc_slotdata *
 void
 pckbc_cleanqueues(struct pckbc_internal *t)
 {
- if (t->t_slotdata[PCKBC_KBD_SLOT])
- pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]);
- if (t->t_slotdata[PCKBC_AUX_SLOT])
- pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]);
+ uint slot;
+
+ for (slot = 0; slot < PCKBC_NSLOTS; slot++)
+ if (t->t_slotdata[slot])
+ pckbc_cleanqueue(t->t_slotdata[slot]);
 }

 /*
@@ -765,11 +839,15 @@ pckbc_reset(struct pckbc_softc *sc)
  bus_space_tag_t iot = t->t_iot;
  bus_space_handle_t ioh_d = t->t_ioh_d, ioh_c = t->t_ioh_c;

- pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+ pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, NULL);
  /* KBC selftest */
  if (pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST) == 0)
  return;
- pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+ pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, NULL);
+#ifdef PCKBC_APM
+ if (t->t_apmver >= 0)
+ pckbc_enable_apm(t);
+#endif
  (void)pckbc_put8042cmd(t);
  pckbcintr_internal(t->t_sc->id, t->t_sc);
 }
@@ -995,8 +1073,16 @@ pckbcintr_internal(struct pckbc_internal

  served = 1;

- slot = (t->t_haveaux && (stat & KBS_AUXDATA)) ?
-    PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
+#ifdef PCKBC_APM
+ if (t->t_apmver >= 0) { /* implies t->t_haveaux != 0 */
+ if (stat & KBS_AUXDATA)
+ slot = PCKBC_AUX_SLOT + (stat >> 6);
+ else
+ slot = PCKBC_KBD_SLOT;
+ } else
+#endif
+ slot = (t->t_haveaux && (stat & KBS_AUXDATA)) ?
+    PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
  q = t->t_slotdata[slot];

  if (!q) {
@@ -1033,6 +1119,89 @@ pckbcintr_internal(struct pckbc_internal
  return (served);
 }

+#ifdef PCKBC_APM
+
+/*
+ * Disable Active PS/2 Multiplexing.
+ * Returns nonzero if error.
+ */
+int
+pckbc_disable_apm(struct pckbc_internal *t)
+{
+ bus_space_tag_t iot = t->t_iot;
+ bus_space_handle_t ioh_d = t->t_ioh_d, ioh_c = t->t_ioh_c;
+ int data;
+
+ /*
+ * Send the three bytes of the disable sequence
+ */
+
+ if (pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO) == 0 ||
+    pckbc_wait_output(iot, ioh_c) == 0)
+ return -1;
+ bus_space_write_1(iot, ioh_d, 0, KBC_APM_DIS1);
+ data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, NULL);
+ if (data < 0 || data != KBC_APM_DIS1)
+ return -1;
+
+ if (pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO) == 0 ||
+    pckbc_wait_output(iot, ioh_c) == 0)
+ return -1;
+ bus_space_write_1(iot, ioh_d, 0, KBC_APM_DIS2);
+ data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, NULL);
+ if (data < 0 || data != KBC_APM_DIS2)
+ return -1;
+
+ if (pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO) == 0 ||
+    pckbc_wait_output(iot, ioh_c) == 0)
+ return -1;
+ bus_space_write_1(iot, ioh_d, 0, KBC_APM_DIS3);
+ data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, NULL);
+ if (data < 0 || data != t->t_apmver)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Enable Active PS/2 Multiplexing.
+ * Returns -1 if unavailable or version supported by the controller.
+ */
+int
+pckbc_enable_apm(struct pckbc_internal *t)
+{
+ bus_space_tag_t iot = t->t_iot;
+ bus_space_handle_t ioh_d = t->t_ioh_d, ioh_c = t->t_ioh_c;
+ int data;
+
+ if (pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO) == 0 ||
+    pckbc_wait_output(iot, ioh_c) == 0)
+ return -1;
+ bus_space_write_1(iot, ioh_d, 0, KBC_APM_ENB1);
+ data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, NULL);
+ if (data < 0 || data != KBC_APM_ENB1)
+ return -1;
+
+ if (pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO) == 0 ||
+    pckbc_wait_output(iot, ioh_c) == 0)
+ return -1;
+ bus_space_write_1(iot, ioh_d, 0, KBC_APM_ENB2);
+ data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, NULL);
+ if (data < 0 || data != KBC_APM_ENB2)
+ return -1;
+
+ if (pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO) == 0 ||
+    pckbc_wait_output(iot, ioh_c) == 0)
+ return -1;
+ bus_space_write_1(iot, ioh_d, 0, KBC_APM_ENB3);
+ data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, NULL);
+ if (data < 0 || data == KBC_APM_ENB3)
+ return -1;
+
+ return data;
+}
+#endif
+
 int
 pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr, bus_size_t cmd_offset,
     int flags)
@@ -1056,7 +1225,7 @@ pckbc_cnattach(bus_space_tag_t iot, bus_
  timeout_set(&pckbc_consdata.t_poll, pckbc_poll, &pckbc_consdata);

  /* flush */
- (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+ (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, NULL);

  /* selftest? */

Index: sys/dev/ic/pckbcvar.h
===================================================================
RCS file: /cvs/src/sys/dev/ic/pckbcvar.h,v
retrieving revision 1.16
diff -u -p -r1.16 pckbcvar.h
--- sys/dev/ic/pckbcvar.h 11 Mar 2017 11:55:03 -0000 1.16
+++ sys/dev/ic/pckbcvar.h 30 Nov 2017 16:06:33 -0000
@@ -32,6 +32,14 @@

 #include <sys/timeout.h>

+/*
+ * Only compile Active PS/2 Multiplexing support on systems where it might
+ * be found.
+ */
+#if (defined(__i386__) || defined(__amd64__)) && !defined(SMALL_KERNEL)
+#define PCKBC_APM
+#endif
+
 #define PCKBCCF_SLOT            0
 #define PCKBCCF_SLOT_DEFAULT    -1

@@ -39,7 +47,11 @@ typedef void *pckbc_tag_t;
 typedef int pckbc_slot_t;
 #define PCKBC_KBD_SLOT 0
 #define PCKBC_AUX_SLOT 1
+#ifdef PCKBC_APM
+#define PCKBC_NSLOTS 5 /* 1 KBD + 4 AUX */
+#else
 #define PCKBC_NSLOTS 2
+#endif

 /*
  * external representation (pckbc_tag_t),
@@ -55,6 +67,9 @@ struct pckbc_internal {
 #define PCKBC_CANT_TRANSLATE 0x0001 /* can't translate to XT scancodes */
 #define PCKBC_NEED_AUXWRITE 0x0002 /* need auxwrite command to find aux */
  int t_haveaux; /* controller has an aux port */
+#ifdef PCKBC_APM
+ int t_apmver; /* Active PS/2 Multiplexing version */
+#endif

  struct pckbc_slotdata *t_slotdata[PCKBC_NSLOTS];

@@ -97,8 +112,8 @@ int pckbc_enqueue_cmd(pckbc_tag_t, pckbc
    int, int, u_char *);
 int pckbc_send_cmd(bus_space_tag_t, bus_space_handle_t, u_char);
 int pckbc_poll_data(pckbc_tag_t, pckbc_slot_t);
-int pckbc_poll_data1(bus_space_tag_t, bus_space_handle_t,
-  bus_space_handle_t, pckbc_slot_t, int);
+int pckbc_poll_data1(bus_space_tag_t, bus_space_handle_t, bus_space_handle_t,
+   pckbc_slot_t, struct pckbc_internal *);
 void pckbc_set_poll(pckbc_tag_t, pckbc_slot_t, int);
 int pckbc_xt_translation(pckbc_tag_t);
 void pckbc_slot_enable(pckbc_tag_t, pckbc_slot_t, int);
Index: sys/dev/isa/pckbc_isa.c
===================================================================
RCS file: /cvs/src/sys/dev/isa/pckbc_isa.c,v
retrieving revision 1.19
diff -u -p -r1.19 pckbc_isa.c
--- sys/dev/isa/pckbc_isa.c 18 Aug 2015 06:54:00 -0000 1.19
+++ sys/dev/isa/pckbc_isa.c 30 Nov 2017 16:07:01 -0000
@@ -55,6 +55,9 @@ pckbc_isa_match(struct device *parent, v
  bus_space_tag_t iot = ia->ia_iot;
  bus_space_handle_t ioh_d, ioh_c;
  int res;
+#ifdef PCKBC_APM
+ uint slot;
+#endif

  /* If values are hardwired to something that they can't be, punt. */
  if ((ia->ia_iobase != IOBASEUNK && ia->ia_iobase != IO_KBD) ||
@@ -70,12 +73,12 @@ pckbc_isa_match(struct device *parent, v
  goto fail;

  /* flush KBC */
- (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+ (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, NULL);

  /* KBC selftest */
  if (pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST) == 0)
  goto fail2;
- res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
+ res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, NULL);
  if (res != 0x55) {
  printf("kbc selftest: %x\n", res);
  goto fail2;
@@ -89,7 +92,12 @@ pckbc_isa_match(struct device *parent, v
  ia->ia_msize = 0x0;
  ia->ipa_nirq = PCKBC_NSLOTS;
  ia->ipa_irq[PCKBC_KBD_SLOT].num = 1;
+#ifdef PCKBC_APM
+ for (slot = PCKBC_AUX_SLOT; slot < PCKBC_NSLOTS; slot++)
+ ia->ipa_irq[slot].num = 12;
+#else
  ia->ipa_irq[PCKBC_AUX_SLOT].num = 12;
+#endif

  return (1);

Index: sys/dev/pckbc/pms.c
===================================================================
RCS file: /cvs/src/sys/dev/pckbc/pms.c,v
retrieving revision 1.80
diff -u -p -r1.80 pms.c
--- sys/dev/pckbc/pms.c 26 Aug 2017 18:34:04 -0000 1.80
+++ sys/dev/pckbc/pms.c 30 Nov 2017 16:12:01 -0000
@@ -150,6 +150,7 @@ struct pms_softc { /* driver status inf
  struct device sc_dev;

  pckbc_tag_t sc_kbctag;
+ int sc_slot;

  int sc_state;
 #define PMS_STATE_DISABLED 0
@@ -414,10 +415,10 @@ int
 pms_cmd(struct pms_softc *sc, u_char *cmd, int len, u_char *resp, int resplen)
 {
  if (sc->poll) {
- return pckbc_poll_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT,
+ return pckbc_poll_cmd(sc->sc_kbctag, sc->sc_slot,
     cmd, len, resplen, resp, 1);
  } else {
- return pckbc_enqueue_cmd(sc->sc_kbctag, PCKBC_AUX_SLOT,
+ return pckbc_enqueue_cmd(sc->sc_kbctag, sc->sc_slot,
     cmd, len, resplen, 1, resp);
  }
 }
@@ -638,7 +639,7 @@ pmsprobe(struct device *parent, void *ma
  u_char cmd[1], resp[2];
  int res;

- if (pa->pa_slot != PCKBC_AUX_SLOT)
+ if (pa->pa_slot < PCKBC_AUX_SLOT)
  return (0);

  /* Flush any garbage. */
@@ -666,8 +667,9 @@ pmsattach(struct device *parent, struct
  struct wsmousedev_attach_args a;

  sc->sc_kbctag = pa->pa_tag;
+ sc->sc_slot = pa->pa_slot;

- pckbc_set_inputhandler(sc->sc_kbctag, PCKBC_AUX_SLOT,
+ pckbc_set_inputhandler(sc->sc_kbctag, sc->sc_slot,
     pmsinput, sc, DEVNAME(sc));

  printf("\n");
@@ -744,10 +746,10 @@ pms_change_state(struct pms_softc *sc, i
  case PMS_STATE_ENABLED:
  sc->inputstate = 0;

- pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 1);
+ pckbc_slot_enable(sc->sc_kbctag, sc->sc_slot, 1);

  if (sc->poll)
- pckbc_flush(sc->sc_kbctag, PCKBC_AUX_SLOT);
+ pckbc_flush(sc->sc_kbctag, sc->sc_slot);

  pms_reset(sc);
  if (sc->protocol->enable != NULL &&
@@ -763,7 +765,7 @@ pms_change_state(struct pms_softc *sc, i
  if (sc->protocol->disable)
  sc->protocol->disable(sc);

- pckbc_slot_enable(sc->sc_kbctag, PCKBC_AUX_SLOT, 0);
+ pckbc_slot_enable(sc->sc_kbctag, sc->sc_slot, 0);
  break;
  }

Reply via email to