Home | History | Annotate | Line # | Download | only in pckbport
      1 /* $NetBSD: alps.c,v 1.15 2021/08/02 12:56:24 andvar Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2017 Ryo ONODERA <ryo (at) tetera.org>
      5  * Copyright (c) 2008 Jared D. McNeill <jmcneill (at) invisible.ca>
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27  * POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include "opt_pms.h"
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: alps.c,v 1.15 2021/08/02 12:56:24 andvar Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/device.h>
     38 #include <sys/kernel.h>
     39 #include <sys/sysctl.h>
     40 #include <sys/bus.h>
     41 #include <sys/bitops.h>
     42 
     43 #include <dev/wscons/wsconsio.h>
     44 #include <dev/wscons/wsmousevar.h>
     45 
     46 #include <dev/pckbport/pckbportvar.h>
     47 #include <dev/pckbport/pmsreg.h>
     48 #include <dev/pckbport/pmsvar.h>
     49 #include <dev/pckbport/alpsreg.h>
     50 #include <dev/pckbport/alpsvar.h>
     51 
     52 /* #define ALPS_DEBUG */
     53 
     54 static int alps_touchpad_movement_threshold_nodenum;
     55 static int alps_touchpad_xy_unprecision_nodenum;
     56 static int alps_trackstick_xy_precision_nodenum;
     57 
     58 static int alps_touchpad_movement_threshold = 4;
     59 static int alps_touchpad_xy_unprecision = 2;
     60 static int alps_trackstick_xy_precision = 1;
     61 
     62 static void pms_alps_input_v7(void *, int);
     63 static void pms_alps_input_v2(void *, int);
     64 
     65 static int
     66 pms_sysctl_alps_verify(SYSCTLFN_ARGS)
     67 {
     68 	int error, t;
     69 	struct sysctlnode node;
     70 
     71 	node = *rnode;
     72 	t = *(int *)rnode->sysctl_data;
     73 	node.sysctl_data = &t;
     74 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
     75 	if (error || newp == NULL)
     76 		return error;
     77 
     78 	if (node.sysctl_num == alps_touchpad_xy_unprecision_nodenum ||
     79 		node.sysctl_num == alps_trackstick_xy_precision_nodenum) {
     80 		if (t < 0 || t > 7)
     81 			return EINVAL;
     82 	} else if (node.sysctl_num == alps_touchpad_movement_threshold_nodenum) {
     83 		if (t < 0)
     84 			return EINVAL;
     85 	} else
     86 		return EINVAL;
     87 
     88 	*(int *)rnode->sysctl_data = t;
     89 
     90 	return 0;
     91 
     92 }
     93 
     94 static void
     95 pms_sysctl_alps(struct sysctllog **clog)
     96 {
     97 	const struct sysctlnode *node;
     98 	int rc, root_num;
     99 
    100 	if ((rc = sysctl_createv(clog, 0, NULL, &node,
    101 		CTLFLAG_PERMANENT, CTLTYPE_NODE, "alps",
    102 		SYSCTL_DESCR("ALPS touchpad controls"),
    103 		NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0)
    104 		goto err;
    105 
    106 	root_num = node->sysctl_num;
    107 
    108 	if ((rc = sysctl_createv(clog, 0, NULL, &node,
    109 		CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
    110 		CTLTYPE_INT, "touchpad_xy_precision_shift",
    111 		SYSCTL_DESCR("Touchpad X/Y-axis precision shift value"),
    112 		pms_sysctl_alps_verify, 0,
    113 		&alps_touchpad_xy_unprecision,
    114 		0, CTL_HW, root_num, CTL_CREATE,
    115 		CTL_EOL)) != 0)
    116 			goto err;
    117 	alps_touchpad_xy_unprecision_nodenum = node->sysctl_num;
    118 
    119 	if ((rc = sysctl_createv(clog, 0, NULL, &node,
    120 		CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
    121 		CTLTYPE_INT, "trackstick_xy_precision_shift",
    122 		SYSCTL_DESCR("Trackstick X/Y-axis precision value"),
    123 		pms_sysctl_alps_verify, 0,
    124 		&alps_trackstick_xy_precision,
    125 		0, CTL_HW, root_num, CTL_CREATE,
    126 		CTL_EOL)) != 0)
    127 			goto err;
    128 	alps_trackstick_xy_precision_nodenum = node->sysctl_num;
    129 
    130 	if ((rc = sysctl_createv(clog, 0, NULL, &node,
    131 		CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
    132 		CTLTYPE_INT, "touchpad_movement_threshold",
    133 		SYSCTL_DESCR("Minimum reported movement threshold"),
    134 		pms_sysctl_alps_verify, 0,
    135 		&alps_touchpad_movement_threshold,
    136 		0, CTL_HW, root_num, CTL_CREATE,
    137 		CTL_EOL)) != 0)
    138 			goto err;
    139 	alps_touchpad_movement_threshold_nodenum = node->sysctl_num;
    140 
    141 	return;
    142 
    143 err:
    144 	aprint_error("%s: sysctl_createv failed (rc = %d)\n",
    145 		__func__, rc);
    146 }
    147 
    148 /*
    149  * Publish E6 report command and get E6 signature,
    150  * then check the signature
    151  */
    152 static int
    153 pms_alps_e6sig(struct pms_softc *psc, uint8_t *e6sig)
    154 {
    155 	uint8_t cmd[2];
    156 	int res;
    157 
    158 	e6sig[0] = 0;
    159 	cmd[0] = PMS_SET_RES; /* E8 */
    160 	cmd[1] = 0;
    161 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    162 	    cmd, 2, 0, NULL, 0)) != 0)
    163 		goto err;
    164 	cmd[0] = PMS_SET_SCALE11; /* E6 */
    165 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    166 	    cmd, 1, 0, NULL, 0)) != 0)
    167 		goto err;
    168 	cmd[0] = PMS_SET_SCALE11; /* E6 */
    169 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    170 	    cmd, 1, 0, NULL, 0)) != 0)
    171 		goto err;
    172 	cmd[0] = PMS_SET_SCALE11; /* E6 */
    173 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    174 	    cmd, 1, 0, NULL, 0)) != 0)
    175 		goto err;
    176 	e6sig[0] = e6sig[1] = e6sig[2] = 0;
    177 	/* Get E6 signature */
    178 	cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */
    179 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    180 	    cmd, 1, 3, e6sig, 0)) != 0)
    181 		goto err;
    182 
    183 	/* ALPS input device returns 00-00-64 as E6 signature */
    184 	if ((e6sig[0] & ~0x07u) != 0x00 || /* ignore buttons */
    185 	    e6sig[1] != 0x00 ||
    186 	    e6sig[2] != 0x64)
    187 	{
    188 		return ENODEV;	/* This is not an ALPS device */
    189 	}
    190 
    191 	aprint_debug_dev(psc->sc_dev,
    192 		"ALPS PS/2 E6 signature: 0x%X 0x%X 0x%X\n",
    193 		e6sig[0], e6sig[1], e6sig[2]);
    194 
    195 	return 0;
    196 err:
    197 	aprint_error_dev(psc->sc_dev, "Failed to get E6 signature.\n");
    198 	return res;
    199 }
    200 
    201 /*
    202  * Publish E7 report command and get E7 signature
    203  */
    204 static int
    205 pms_alps_e7sig(struct pms_softc *psc, uint8_t *e7sig)
    206 {
    207 	uint8_t cmd[2];
    208 	int res;
    209 
    210 	cmd[0] = PMS_SET_RES; /* E8 */
    211 	cmd[1] = 0;
    212 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    213 	    cmd, 2, 0, NULL, 0)) != 0)
    214 		goto err;
    215 	cmd[0] = PMS_SET_SCALE21; /* E7 */
    216 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    217 	    cmd, 1, 0, NULL, 0)) != 0)
    218 		goto err;
    219 	cmd[0] = PMS_SET_SCALE21; /* E7 */
    220 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    221 	    cmd, 1, 0, NULL, 0)) != 0)
    222 		goto err;
    223 	cmd[0] = PMS_SET_SCALE21; /* E7 */
    224 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    225 	    cmd, 1, 0, NULL, 0)) != 0)
    226 		goto err;
    227 	e7sig[0] = e7sig[1] = e7sig[2] = 0;
    228 	cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */
    229 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    230 	    cmd, 1, 3, e7sig, 0)) != 0)
    231 		goto err;
    232 
    233 	aprint_debug_dev(psc->sc_dev,
    234 		"ALPS PS/2 E7 signature: 0x%X 0x%X 0x%X\n",
    235 		e7sig[0], e7sig[1], e7sig[2]);
    236 
    237 	if (e7sig[0] != 0x73)
    238 		return ENODEV;	/* This is not an ALPS device */
    239 
    240 	return 0;
    241 err:
    242 	aprint_error_dev(psc->sc_dev, "Failed to get E7 signature.\n");
    243 	return res;
    244 }
    245 
    246 /*
    247  * Publish EC command and get EC signature
    248  */
    249 static int
    250 pms_alps_ecsig(struct pms_softc *psc, uint8_t *ecsig)
    251 {
    252 	uint8_t cmd[2];
    253 	int res;
    254 
    255 	cmd[0] = PMS_SET_RES; /* E8 */
    256 	cmd[1] = 0;
    257 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    258 	    cmd, 2, 0, NULL, 0)) != 0)
    259 		goto err;
    260 	cmd[0] = PMS_RESET_WRAP_MODE; /* EC */
    261 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    262 	    cmd, 1, 0, NULL, 0)) != 0)
    263 		goto err;
    264 	cmd[0] = PMS_RESET_WRAP_MODE; /* EC */
    265 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    266 	    cmd, 1, 0, NULL, 0)) != 0)
    267 		goto err;
    268 	cmd[0] = PMS_RESET_WRAP_MODE; /* EC */
    269 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    270 	    cmd, 1, 0, NULL, 0)) != 0)
    271 		goto err;
    272 	ecsig[0] = ecsig[1] = ecsig[2] = 0;
    273 	cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */
    274 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    275 	    cmd, 1, 3, ecsig, 0)) != 0)
    276 		goto err;
    277 
    278 	aprint_debug_dev(psc->sc_dev,
    279 		"ALPS PS/2 EC signature: 0x%X 0x%X 0x%X\n",
    280 		ecsig[0], ecsig[1], ecsig[2]);
    281 
    282 	return 0;
    283 
    284 err:
    285 	aprint_debug_dev(psc->sc_dev, "Failed to get EC signature.\n");
    286 	return res;
    287 }
    288 
    289 /*
    290  * Enter to command mode
    291  */
    292 static int
    293 pms_alps_start_command_mode(struct pms_softc *psc)
    294 {
    295 	uint8_t cmd[1];
    296 	uint8_t resp[3];
    297 	int res;
    298 
    299 	cmd[0] = PMS_RESET_WRAP_MODE; /* EC */
    300 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    301 	    cmd, 1, 0, NULL, 0)) != 0)
    302 		goto err;
    303 	cmd[0] = PMS_RESET_WRAP_MODE; /* EC */
    304 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    305 	    cmd, 1, 0, NULL, 0)) != 0)
    306 		goto err;
    307 	cmd[0] = PMS_RESET_WRAP_MODE; /* EC */
    308 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    309 	    cmd, 1, 0, NULL, 0)) != 0)
    310 		goto err;
    311 	resp[0] = resp[1] = resp[2] = 0;
    312 	cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */
    313 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    314 	    cmd, 1, 3, resp, 0)) != 0)
    315 		goto err;
    316 
    317 	aprint_debug_dev(psc->sc_dev, "ALPS Firmware ID: 0x%x 0x%X 0x%X\n",
    318 		resp[0], resp[1], resp[2]);
    319 
    320 	if (resp[0] != 0x88 || (resp[1] & __BITS(7, 4)) != 0xb0)
    321 		return EINVAL;
    322 
    323 	return 0;
    324 err:
    325 	aprint_error_dev(psc->sc_dev, "Failed to start command mode.\n");
    326 	return res;
    327 }
    328 
    329 /*
    330  * End command mode
    331  */
    332 static int
    333 pms_alps_end_command_mode(struct pms_softc *psc)
    334 {
    335 	int res;
    336 	uint8_t cmd[1];
    337 
    338 	cmd[0] = PMS_SET_STREAM; /* EA */
    339 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    340 	    cmd, 1, 0, NULL, 0)) != 0)
    341 		goto err;
    342 
    343 	return res;
    344 
    345 err:
    346 	aprint_error_dev(psc->sc_dev, "Failed to end command mode.\n");
    347 	return res;
    348 }
    349 
    350 /*
    351  * Write nibble (4-bit) data
    352  */
    353 static int
    354 pms_alps_cm_write_nibble(pckbport_tag_t tag, pckbport_slot_t slot, uint8_t nibble)
    355 {
    356 	uint8_t cmd[2];
    357 	uint8_t resp[3];
    358 	int sendparam;
    359 	int receive;
    360 	int res;
    361 
    362 	sendparam = alps_v7_nibble_command_data_arr[nibble].sendparam;
    363 	receive= alps_v7_nibble_command_data_arr[nibble].receive;
    364 	cmd[0] = alps_v7_nibble_command_data_arr[nibble].command;
    365 	if (receive) {
    366 		if ((res = pckbport_poll_cmd(tag, slot, cmd, 1, 3, resp, 0)) != 0) {
    367 			aprint_error("send nibble error: %d\n", res);
    368 		}
    369 	} else if (sendparam) {
    370 		cmd[1] = alps_v7_nibble_command_data_arr[nibble].data;
    371 		if ((res = pckbport_poll_cmd(tag, slot, cmd, 2, 0, NULL, 0)) != 0) {
    372 			aprint_error("send nibble error: %d\n", res);
    373 		}
    374 	} else {
    375 		if ((res = pckbport_poll_cmd(tag, slot, cmd, 1, 0, NULL, 0)) != 0) {
    376 			aprint_error("send nibble error: %d\n", res);
    377 		}
    378 	}
    379 
    380 	return res;
    381 }
    382 
    383 /*
    384  * Set an register address for read and write
    385  */
    386 static int
    387 pms_alps_set_address(pckbport_tag_t tag, pckbport_slot_t slot, uint16_t reg)
    388 {
    389 	uint8_t cmd[1];
    390 	uint8_t nibble;
    391 	int res;
    392 
    393 	cmd[0] = PMS_RESET_WRAP_MODE;
    394 	if ((res = pckbport_poll_cmd(tag, slot, cmd, 1, 0, NULL, 0)) != 0)
    395 		goto err;
    396 
    397 	/* Set address */
    398 	nibble = (reg >> 12) & __BITS(3, 0);
    399 	if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) {
    400 		goto err;
    401 	}
    402 	nibble = (reg >> 8) & __BITS(3, 0);
    403 	if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) {
    404 		goto err;
    405 	}
    406 	nibble = (reg >> 4) & __BITS(3, 0);
    407 	if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) {
    408 		goto err;
    409 	}
    410 	nibble = (reg >> 0) & __BITS(3, 0);
    411 	if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) {
    412 		goto err;
    413 	}
    414 	return res;
    415 
    416 err:
    417 	aprint_error("Failed to set address.\n");
    418 	return res;
    419 }
    420 
    421 /*
    422  * Read one byte from register
    423  */
    424 static int
    425 pms_alps_cm_read_1(pckbport_tag_t tag, pckbport_slot_t slot, uint16_t reg,
    426 	uint8_t *val)
    427 {
    428 	uint8_t cmd[1];
    429 	uint8_t resp[3];
    430 	int res;
    431 
    432 	if ((res = pms_alps_set_address(tag, slot, reg)) != 0)
    433 		goto err;
    434 
    435 	cmd[0] = PMS_SEND_DEV_STATUS;
    436 	if ((res = pckbport_poll_cmd(tag, slot,
    437 	    cmd, 1, 3, resp, 0)) != 0) {
    438 		goto err;
    439 	}
    440 
    441 	if (reg != ((resp[0] << 8) | resp[1])) {
    442 		return EINVAL;
    443 	}
    444 
    445 	*val = resp[2];
    446 	return res;
    447 
    448 err:
    449 	aprint_error("Failed to read a value.\n");
    450 	*val = 0;
    451 	return res;
    452 }
    453 
    454 /*
    455  * Write one byte to register
    456  */
    457 static int
    458 pms_alps_cm_write_1(pckbport_tag_t tag, pckbport_slot_t slot, uint16_t reg,
    459 	uint8_t val)
    460 {
    461 	uint8_t nibble;
    462 	int res;
    463 
    464 	if ((res = pms_alps_set_address(tag, slot, reg)) != 0)
    465 		goto err;
    466 
    467 	nibble = __SHIFTOUT(val, __BITS(7, 4));
    468 	if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) {
    469 		goto err;
    470 	}
    471 
    472 	nibble = __SHIFTOUT(val, __BITS(3, 0));
    473 	if ((res = pms_alps_cm_write_nibble(tag, slot, nibble)) != 0) {
    474 		goto err;
    475 	}
    476 
    477 	return res;
    478 err:
    479 	aprint_error("Failed to write a value.\n");
    480 	return res;
    481 }
    482 
    483 /*
    484  * Not used practically for initialization
    485  */
    486 static int
    487 pms_alps_get_resolution_v7(struct pms_softc *psc)
    488 {
    489 #if 0
    490 	struct alps_softc *sc = &psc->u.alps;
    491 #endif
    492 	pckbport_tag_t tag = psc->sc_kbctag;
    493 	pckbport_slot_t slot = psc->sc_kbcslot;
    494 
    495 	int res;
    496 	uint8_t ret;
    497 #if 0
    498 	uint32_t x_pitch, y_pitch;
    499 	uint32_t x_elec, y_elec;
    500 	uint32_t x_phy, y_phy;
    501 #endif
    502 	/* X/Y pitch */
    503 	if ((res = pms_alps_cm_read_1(tag, slot, 0xc397, &ret)) != 0) {
    504 		goto err;
    505 	}
    506 #if 0
    507 	/* X pitch */
    508 	x_pitch = __SHIFTOUT(ret, __BITS(7, 4)); /* Higher 4-bit */
    509 	x_pitch = x_pitch * 2 + 50; /* Unit = 0.1mm */
    510 
    511 	/* Y pitch */
    512 	y_pitch = ret & __BITS(3, 0); /* Lower 4-bit */
    513 	y_pitch = y_pitch * 2 + 36; /* Unit = 0.1mm */
    514 
    515 	/* X/Y electrode */
    516 	if ((res = pms_alps_cm_read_1(tag, slot, 0xc397 + 1, &ret)) != 0) {
    517 		goto err;
    518 	}
    519 
    520 	/* X electrode */
    521 	x_elec = __SHIFTOUT(ret, __BITS(7, 4)); /* Higher 4-bit */
    522 	x_elec = x_elec + 17;
    523 
    524 	/* Y electrode */
    525 	y_elec = ret & __BITS(3, 0); /* Lower 4-bit */
    526 	y_elec = y_elec + 13;
    527 
    528 	/* X/Y physical in unit = 0.1mm */
    529 	/* X physical */
    530 	x_phy = (x_elec - 1) * x_pitch;
    531 	y_phy = (y_elec - 1) * y_pitch;
    532 
    533 	/* X/Y resolution (unit) */
    534 	sc->res_x = 0xfff * 10 / x_phy;
    535 	sc->res_y = 0x7ff * 10 / y_phy;
    536 #endif
    537 	return res;
    538 
    539 err:
    540 	aprint_error("Failed to get resolution.\n");
    541 	return res;
    542 }
    543 
    544 /*
    545  * Enable tap mode for V2 device
    546  */
    547 static int
    548 pms_alps_enable_tap_mode_v2(struct pms_softc *psc)
    549 {
    550 	uint8_t cmd[2];
    551 	uint8_t resp[3];
    552 	int res;
    553 
    554 	resp[0] = resp[1] = resp[2] = 0;
    555 	cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */
    556 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    557 	    cmd, 1, 3, resp, 0)) != 0)
    558 		goto err;
    559 	cmd[0] = PMS_DEV_DISABLE; /* F5 */
    560 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    561 	    cmd, 1, 0, NULL, 0)) != 0)
    562 		goto err;
    563 	cmd[0] = PMS_DEV_DISABLE; /* F5 */
    564 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    565 	    cmd, 1, 0, NULL, 0)) != 0)
    566 		goto err;
    567 	cmd[0] = PMS_SET_SAMPLE;
    568 	cmd[1] = 0x0a; /* argument */
    569 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    570 	    cmd, 2, 0, NULL, 0)) != 0)
    571 		goto err;
    572 
    573 	/* Get status */
    574 	cmd[0] = PMS_DEV_DISABLE; /* F5 */
    575 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    576 	    cmd, 1, 0, NULL, 0)) != 0)
    577 		goto err;
    578 	cmd[0] = PMS_DEV_DISABLE; /* F5 */
    579 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    580 	    cmd, 1, 0, NULL, 0)) != 0)
    581 		goto err;
    582 	cmd[0] = PMS_DEV_DISABLE; /* F5 */
    583 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    584 	    cmd, 1, 0, NULL, 0)) != 0)
    585 		goto err;
    586 	resp[0] = resp[1] = resp[2] = 0;
    587 	cmd[0] = PMS_SEND_DEV_STATUS; /* E9 */
    588 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    589 	    cmd, 1, 3, resp, 0)) != 0)
    590 		goto err;
    591 
    592 	aprint_debug_dev(psc->sc_dev, "Tap mode is enabled.\n");
    593 
    594 	return 0;
    595 err:
    596 	aprint_error_dev(psc->sc_dev, "Failed to enable tap mode.\n");
    597 	return res;
    598 }
    599 
    600 static int
    601 pms_alps_init_v2(struct pms_softc *psc)
    602 {
    603 	uint8_t cmd[1];
    604 	int res;
    605 
    606 	if ((res = pms_alps_enable_tap_mode_v2(psc)) != 0)
    607 		goto err;
    608 
    609 	/* Enable absolute mode */
    610 	cmd[0] = PMS_DEV_DISABLE; /* F5 */
    611 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    612 	    cmd, 1, 0, NULL, 0)) != 0)
    613 		goto err;
    614 	cmd[0] = PMS_DEV_DISABLE; /* F5 */
    615 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    616 	    cmd, 1, 0, NULL, 0)) != 0)
    617 		goto err;
    618 	cmd[0] = PMS_DEV_DISABLE; /* F5 */
    619 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    620 	    cmd, 1, 0, NULL, 0)) != 0)
    621 		goto err;
    622 	cmd[0] = PMS_DEV_DISABLE; /* F5 */
    623 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    624 	    cmd, 1, 0, NULL, 0)) != 0)
    625 		goto err;
    626 	cmd[0] = PMS_DEV_ENABLE; /* F4 */
    627 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    628 	    cmd, 1, 0, NULL, 0)) != 0)
    629 		goto err;
    630 
    631 	/* Enable remote mode */
    632 	cmd[0] = PMS_SET_REMOTE_MODE; /* F0 */
    633 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    634 	    cmd, 1, 0, NULL, 0)) != 0)
    635 		goto err;
    636 
    637 	/* Start stream mode to get data */
    638 	cmd[0] = PMS_SET_STREAM; /* EA */
    639 	if ((res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    640 	    cmd, 1, 0, NULL, 0)) != 0)
    641 		goto err;
    642 
    643 
    644 	return 0;
    645 
    646 err:
    647 	aprint_error_dev(psc->sc_dev, "Failed to initialize V2 device.\n");
    648 	return res;
    649 }
    650 
    651 static int
    652 pms_alps_init_v7(struct pms_softc *psc)
    653 {
    654 	uint8_t val;
    655 	uint8_t nibble;
    656 	int res;
    657 
    658 	/* Start command mode */
    659 	if ((res = pms_alps_start_command_mode(psc)) != 0) {
    660 		goto err;
    661 	}
    662 	if ((res = pms_alps_cm_read_1(psc->sc_kbctag, psc->sc_kbcslot, 0xc2d9, &val)) != 0) {
    663 		goto err;
    664 	}
    665 	if ((res = pms_alps_get_resolution_v7(psc)) != 0) {
    666 		goto err;
    667 	}
    668 	if ((res = pms_alps_cm_write_1(psc->sc_kbctag, psc->sc_kbcslot, 0xc2c9, 0x64)) != 0) {
    669 		goto err;
    670 	}
    671 
    672 	/* Start absolute mode */
    673 	if ((res = pms_alps_cm_read_1(psc->sc_kbctag, psc->sc_kbcslot, 0xc2c4, &val)) != 0) {
    674 		goto err;
    675 	}
    676 	/* Do not set address before this, so do not use pms_cm_write_1() */
    677 	val = val | __BIT(1);
    678 	nibble = __SHIFTOUT(val, __BITS(7, 4));
    679 	if ((res = pms_alps_cm_write_nibble(psc->sc_kbctag, psc->sc_kbcslot, nibble)) != 0) {
    680 		goto err;
    681 	}
    682 	nibble = __SHIFTOUT(val, __BITS(3, 0));
    683 	if ((res = pms_alps_cm_write_nibble(psc->sc_kbctag, psc->sc_kbcslot, nibble)) != 0) {
    684 		goto err;
    685 	}
    686 
    687 	/* End command mode */
    688 	if ((res = pms_alps_end_command_mode(psc)) != 0)
    689 		goto err;
    690 
    691 	return res;
    692 
    693 err:
    694 	(void)pms_alps_end_command_mode(psc);
    695 	aprint_error_dev(psc->sc_dev, "Failed to initialize V7 device.\n");
    696 	return res;
    697 }
    698 
    699 int
    700 pms_alps_probe_init(void *opaque)
    701 {
    702 	struct pms_softc *psc = opaque;
    703 	struct alps_softc *sc = &psc->u.alps;
    704 	struct sysctllog *clog = NULL;
    705 	uint8_t e6sig[3];
    706 	uint8_t e7sig[3];
    707 	uint8_t ecsig[3];
    708 	int res;
    709 	u_char cmd[1];
    710 
    711 	sc->last_x1 = 0;
    712 	sc->last_y1 = 0;
    713 	sc->last_x2 = 0;
    714 	sc->last_y2 = 0;
    715 	sc->last_nfingers = 0;
    716 
    717 	pckbport_flush(psc->sc_kbctag, psc->sc_kbcslot);
    718 
    719 	if ((res = pms_alps_e6sig(psc, e6sig)) != 0)
    720 		goto err;
    721 
    722 	if ((res = pms_alps_e7sig(psc, e7sig)) != 0)
    723 		goto err;
    724 
    725 	if ((res = pms_alps_ecsig(psc, ecsig)) != 0)
    726 		goto err;
    727 
    728 	/* Determine protocol version */
    729 	if ((ecsig[0] == 0x88) && (__SHIFTOUT(ecsig[1], __BITS(7, 4)) == 0x0b)) {
    730 		/* V7 device in Toshiba dynabook R63/PS */
    731 		sc->version = ALPS_PROTO_V7;
    732 	} else if ((e7sig[0] == 0x73) && (e7sig[1] == 0x02) &&
    733 		((e7sig[2] == 0x14) || (e7sig[2] == 0x0a))) {
    734 		/* 0x14: V2 device in NEC VJ22MF-7 (VersaPro JVF-7) */
    735 		/* 0x0a: V2 devices in Toshiba dynabook satellite B551/D
    736 			 and dynabook SS RX1 */
    737 		sc->version = ALPS_PROTO_V2;
    738 	}
    739 
    740 	if (sc->version == ALPS_PROTO_V7) {
    741 		/* Initialize V7 device */
    742 		if ((res = pms_alps_init_v7(psc)) != 0)
    743 			goto err;
    744 		aprint_normal_dev(psc->sc_dev,
    745 			"ALPS PS/2 V7 pointing device\n");
    746 	} else if (sc->version == ALPS_PROTO_V2) {
    747 		/* Initialize V2 pointing device */
    748 		if ((res = pms_alps_init_v2(psc)) != 0)
    749 			goto err;
    750 		aprint_normal_dev(psc->sc_dev,
    751 			"ALPS PS/2 V2 pointing device\n");
    752 	} else {
    753 		res = EINVAL;
    754 		goto err;
    755 	}
    756 
    757 	/* From sysctl */
    758 	pms_sysctl_alps(&clog);
    759 	/* Register hundler */
    760 	if (sc->version == ALPS_PROTO_V7) {
    761 		pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot,
    762 			pms_alps_input_v7, psc, device_xname(psc->sc_dev));
    763 	} else if (sc->version == ALPS_PROTO_V2) {
    764 		pckbport_set_inputhandler(psc->sc_kbctag, psc->sc_kbcslot,
    765 			pms_alps_input_v2, psc, device_xname(psc->sc_dev));
    766 	} else {
    767 		res = EINVAL;
    768 		goto err;
    769 	}
    770 	/* Palm detection is enabled. */
    771 
    772 	return 0;
    773 
    774 err:
    775 	cmd[0] = PMS_RESET;
    776 	(void)pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot,
    777 	    cmd, 1, 2, NULL, 1);
    778 	if (res != ENODEV)
    779 		aprint_error_dev(psc->sc_dev, "Failed to initialize an ALPS device.\n");
    780 	return res;
    781 }
    782 
    783 void
    784 pms_alps_enable(void *opaque)
    785 {
    786 	struct pms_softc *psc = opaque;
    787 	struct alps_softc *sc = &psc->u.alps;
    788 
    789 	sc->initializing = true;
    790 }
    791 
    792 void
    793 pms_alps_resume(void *opaque)
    794 {
    795 	struct pms_softc *psc = opaque;
    796 	struct alps_softc *sc = &psc->u.alps;
    797 	uint8_t cmd, resp[2];
    798 	int res;
    799 
    800 	cmd = PMS_RESET;
    801 	res = pckbport_poll_cmd(psc->sc_kbctag, psc->sc_kbcslot, &cmd,
    802 		1, 2, resp, 1);
    803 	if (res)
    804 	aprint_error_dev(psc->sc_dev,
    805 		"ALPS reset on resume failed\n");
    806 	else {
    807 		if (sc->version == ALPS_PROTO_V7) {
    808 			(void)pms_alps_init_v7(psc);
    809 		} else if (sc->version == ALPS_PROTO_V2) {
    810 			(void)pms_alps_init_v2(psc);
    811 		} else {
    812 			/* Not supported */
    813 		}
    814 		pms_alps_enable(psc);
    815 	}
    816 }
    817 
    818 static void
    819 pms_alps_decode_trackstick_packet_v7(struct pms_softc *psc)
    820 {
    821 	int s;
    822 
    823 	int x, y, z;
    824 	int dx, dy, dz;
    825 	int left, middle, right;
    826 	u_int buttons;
    827 
    828 	x = (int8_t)((psc->packet[2] & 0xbf) |
    829 		((psc->packet[3] & 0x10) << 2));
    830 	y = (int8_t)((psc->packet[3] & 0x07) | (psc->packet[4] & 0xb8) |
    831 		((psc->packet[3] & 0x20) << 1));
    832 	z = (int8_t)((psc->packet[5] & 0x3f) |
    833 		((psc->packet[3] & 0x80) >> 1));
    834 
    835 	dx = x * alps_trackstick_xy_precision;
    836 	dy = y * alps_trackstick_xy_precision;
    837 	dz = z * 1;
    838 
    839 	left = psc->packet[1] & 0x01;
    840 	middle = (psc->packet[1] & 0x04) >> 2;
    841 	right = (psc->packet[1] & 0x02) >> 1;
    842 	buttons = 0;
    843 	buttons = (u_int)((left << 0) | (middle << 1) | (right << 2));
    844 
    845 	s = spltty();
    846 	wsmouse_input(psc->sc_wsmousedev,
    847 		buttons,
    848 		dx, dy, dz, 0,
    849 		WSMOUSE_INPUT_DELTA);
    850 	splx(s);
    851 }
    852 
    853 static uint8_t
    854 pms_alps_decode_packetid_v7(struct pms_softc *psc)
    855 {
    856 	if (psc->packet[4] & 0x40)
    857 		return ALPS_V7_PACKETID_TWOFINGER;
    858 	else if (psc->packet[4] & 0x01)
    859 		return ALPS_V7_PACKETID_MULTIFINGER;
    860 	else if ((psc->packet[0] & 0x10) && !(psc->packet[4] & 0x43))
    861 		return ALPS_V7_PACKETID_NEWPACKET;
    862 	else if ((psc->packet[1] == 0x00) && (psc->packet[4] == 0x00))
    863 		return ALPS_V7_PACKETID_IDLE;
    864 	else
    865 		return ALPS_V7_PACKETID_UNKNOWN;
    866 }
    867 
    868 static void
    869 pms_alps_decode_touchpad_packet_v7(struct pms_softc *psc)
    870 {
    871 	int s;
    872 	struct alps_softc *sc = &psc->u.alps;
    873 	uint8_t packetid;
    874 
    875 	uint16_t cur_x1, cur_y1;
    876 	uint16_t cur_x2, cur_y2;
    877 	int dx1, dy1;
    878 	int button;
    879 	u_int buttons;
    880 
    881 	packetid = pms_alps_decode_packetid_v7(psc);
    882 	switch (packetid) {
    883 	case ALPS_V7_PACKETID_IDLE:
    884 		/* Accept meaningful packets only */
    885 		return;
    886 	case ALPS_V7_PACKETID_UNKNOWN:
    887 		/* Accept meaningful packets only */
    888 		return;
    889 	case ALPS_V7_PACKETID_NEWPACKET:
    890 		/* Sent new packet ID to reset status and not decoded */
    891 		sc->initializing = true;
    892 		return;
    893 	}
    894 
    895 	/* Decode a number of fingers and locations */
    896 	/* X0-11 ... X0-0 */
    897 	cur_x1 = (psc->packet[2] & 0x80) << 4; /* X0-11 */
    898 	cur_x1 |= (psc->packet[2] & 0x3f) << 5; /* X0-10 ... X0-5 */
    899 	cur_x1 |= (psc->packet[3] & 0x30) >> 1; /* X0-4, X0-3 */
    900 	cur_x1 |= psc->packet[3] & 0x07; /* X0-2 ... X0-0 */
    901 
    902 	/* Y0-10 ... Y0-0 */
    903 	cur_y1 = psc->packet[1] << 3; /* Y0-10 ... Y0-3 */
    904 	cur_y1 |= psc->packet[0] & 0x07; /* Y0-2 ... Y0-0 */
    905 
    906 	/* X1-11 ... X1-3 */
    907 	cur_x2 = (psc->packet[3] & 0x80) << 4; /* X1-11 */
    908 	cur_x2 |= (psc->packet[4] & 0x80) << 3; /* X1-10 */
    909 	cur_x2 |= (psc->packet[4] & 0x3f) << 4; /* X1-9 ... X1-4 */
    910 
    911 	/* Y1-10 ... Y1-4 */
    912 	cur_y2 = (psc->packet[5] & 0x80) << 3; /* Y1-10 */
    913 	cur_y2 |= (psc->packet[5] & 0x3f) << 4; /* Y1-9 .. Y1-4 */
    914 
    915 	switch (packetid) {
    916 	case ALPS_V7_PACKETID_TWOFINGER:
    917 		cur_x2 &= ~__BITS(3, 0); /* Clear undefined locations */
    918 		cur_y2 |= __BITS(3, 0); /* Fill undefined locations */
    919 		break;
    920 	case ALPS_V7_PACKETID_MULTIFINGER:
    921 		cur_x2 &= ~__BITS(5, 0); /* Clear undefined locations */
    922 		cur_y2 &= ~__BIT(5); /* Clear duplicate locations */
    923 		cur_y2 |= (psc->packet[4] & __BIT(1)) << 4; /* Set another */
    924 		cur_y2 |= __BITS(4, 0); /* Fill undefined locations */
    925 		break;
    926 	}
    927 
    928 	cur_y1 = 0x7ff - cur_y1;
    929 	cur_y2 = 0x7ff - cur_y2;
    930 
    931 	/* Handle finger touch reported in cur_x2/y2. only */
    932 	if (cur_x1 == 0 && cur_y1 == 0 && cur_x2 != 0 && cur_y2 != 0) {
    933 		cur_x1 = cur_x2;
    934 		cur_y1 = cur_y2;
    935 		cur_x2 = 0;
    936 		cur_y2 = 0;
    937 	}
    938 
    939 	switch (packetid) {
    940 	case ALPS_V7_PACKETID_TWOFINGER:
    941 		if ((cur_x2 == 0) && (cur_y2 == 0))
    942 			sc->nfingers = 1;
    943 		else
    944 			sc->nfingers = 2;
    945 		break;
    946 	case ALPS_V7_PACKETID_MULTIFINGER:
    947 		sc->nfingers = 3 + (psc->packet[5] & 0x03);
    948 		break;
    949 	}
    950 
    951 	button = (psc->packet[0] & 0x80) >> 7;
    952 	buttons = 0;
    953 	if (sc->nfingers == 1) {
    954 		if (button && (cur_y1 > 1700) && (cur_x1 < 1700))
    955 			buttons |= button << 0; /* Left button */
    956 		else if (button && (cur_y1 > 1700)
    957 				&& (1700 <= cur_x1) && (cur_x1 <= 2700))
    958 			buttons |= button << 1; /* Middle button */
    959 		else if (button && (cur_y1 > 1700) && (2700 < cur_x1))
    960 			buttons |= button << 2; /* Right button */
    961 	} else if (sc->nfingers > 1) {
    962 		if (button && (cur_y2 > 1700) && (cur_x2 < 1700))
    963 			buttons |= button << 0; /* Left button */
    964 		else if (button && (cur_y2 > 1700)
    965 				&& (1700 <= cur_x2) && (cur_x2 <= 2700))
    966 			buttons |= button << 1; /* Middle button */
    967 		else if (button && (cur_y2 > 1700) && (2700 < cur_x2))
    968 			buttons |= button << 2; /* Right button */
    969 	}
    970 
    971 	/* New touch */
    972 	if (sc->nfingers == 0 || sc->nfingers != sc->last_nfingers)
    973 		sc->initializing = true;
    974 
    975 	if (sc->initializing == true) {
    976 		dx1 = 0;
    977 		dy1 = 0;
    978 	} else {
    979 		dx1 = (int16_t)(cur_x1 - sc->last_x1);
    980 		dy1 = (int16_t)(sc->last_y1 - cur_y1);
    981 
    982 		dx1 = dx1 >> alps_touchpad_xy_unprecision;
    983 		dy1 = dy1 >> alps_touchpad_xy_unprecision;
    984 	}
    985 
    986 	if (abs(dx1) < alps_touchpad_movement_threshold) {
    987 		dx1 = 0;
    988 	}
    989 	if (abs(dy1) < alps_touchpad_movement_threshold) {
    990 		dy1 = 0;
    991 	}
    992 
    993 	/* Allow finger detouch during drag and drop */
    994 	if ((sc->nfingers < sc->last_nfingers)
    995 		&& (cur_x2 == sc->last_x1) && (cur_y2 == sc->last_y1)) {
    996 		sc->last_x1 = sc->last_x2;
    997 		sc->last_y1 = sc->last_y2;
    998 		dx1 = 0;
    999 		dy1 = 0;
   1000 	}
   1001 
   1002 	s = spltty();
   1003 	wsmouse_input(psc->sc_wsmousedev,
   1004 		buttons,
   1005 		dx1, dy1, 0, 0,
   1006 		WSMOUSE_INPUT_DELTA);
   1007 	splx(s);
   1008 
   1009 	if (sc->initializing == true || (dx1 != 0))
   1010 		sc->last_x1 = cur_x1;
   1011 	if (sc->initializing == true || (dy1 != 0))
   1012 		sc->last_y1 = cur_y1;
   1013 
   1014 	if (sc->nfingers > 0)
   1015 		sc->initializing = false;
   1016 	sc->last_nfingers = sc->nfingers;
   1017 }
   1018 
   1019 static void
   1020 pms_alps_dispatch_packet_v7(struct pms_softc *psc)
   1021 {
   1022 	if ((psc->packet[0] == 0x48) && ((psc->packet[4] & 0x47) == 0x06))
   1023 		pms_alps_decode_trackstick_packet_v7(psc);
   1024 	else
   1025 		pms_alps_decode_touchpad_packet_v7(psc);
   1026 }
   1027 
   1028 static void
   1029 pms_alps_decode_touchpad_packet_v2(struct pms_softc *psc)
   1030 {
   1031 	int s;
   1032 	struct alps_softc *sc = &psc->u.alps;
   1033 	uint16_t cur_x, cur_y;
   1034 	int16_t dx, dy;
   1035 	u_int left, middle, right;
   1036 	u_int forward, back;
   1037 	u_int buttons;
   1038 	uint8_t ges;
   1039 
   1040 	sc->nfingers = (psc->packet[2] & 0x02) >> 1;
   1041 	if (sc->last_nfingers == 0)
   1042 		sc->initializing = true;
   1043 
   1044 	left = psc->packet[3] & 0x01;
   1045 	right = (psc->packet[3] & 0x02) >> 1;
   1046 	middle = (psc->packet[3] & 0x04) >> 2;
   1047 
   1048 	cur_x = psc->packet[1];
   1049 	cur_x |= (psc->packet[2] & 0x78) << 4;
   1050 
   1051 	cur_y = psc->packet[4];
   1052 	cur_y |= (psc->packet[3] & 0x70) << 3;
   1053 
   1054 #if 0
   1055 	cur_z = psc->packet[5];
   1056 #endif
   1057 
   1058 	forward = (psc->packet[2] & 0x04) >> 2;
   1059 	back = (psc->packet[3] & 0x04) >> 2;
   1060 	ges = psc->packet[2] & 0x01;
   1061 
   1062 	buttons = (left | ges) << 0;
   1063 	buttons |= (middle | forward | back) << 1;
   1064 	buttons |= right << 2;
   1065 
   1066 	if (sc->initializing == true) {
   1067 		dx = 0;
   1068 		dy = 0;
   1069 	} else {
   1070 		dx = (cur_x - sc->last_x1);
   1071 		dy = (sc->last_y1 - cur_y);
   1072 
   1073 		dx = dx >> alps_touchpad_xy_unprecision;
   1074 		dy = dy >> alps_touchpad_xy_unprecision;
   1075 	}
   1076 
   1077 	s = spltty();
   1078 	wsmouse_input(psc->sc_wsmousedev,
   1079 		buttons,
   1080 		dx, dy, 0, 0,
   1081 		WSMOUSE_INPUT_DELTA);
   1082 	splx(s);
   1083 
   1084 	if (sc->initializing == true || (dx != 0))
   1085 		sc->last_x1 = cur_x;
   1086 	if (sc->initializing == true || (dy != 0))
   1087 		sc->last_y1 = cur_y;
   1088 
   1089 	if (sc->nfingers > 0)
   1090 		sc->initializing = false;
   1091 	sc->last_nfingers = sc->nfingers;
   1092 }
   1093 
   1094 static void
   1095 pms_alps_input_v2(void *opaque, int data)
   1096 {
   1097 	struct pms_softc *psc = opaque;
   1098 
   1099 	if (!psc->sc_enabled)
   1100 		return;
   1101 
   1102 	psc->packet[psc->inputstate++] = data & 0xff;
   1103 	if (psc->inputstate < 6)
   1104 		return;
   1105 
   1106 	pms_alps_decode_touchpad_packet_v2(psc);
   1107 
   1108 	psc->inputstate = 0;
   1109 }
   1110 
   1111 static void
   1112 pms_alps_input_v7(void *opaque, int data)
   1113 {
   1114 	struct pms_softc *psc = opaque;
   1115 
   1116 	if (!psc->sc_enabled)
   1117 		return;
   1118 
   1119 	psc->packet[psc->inputstate++] = data & 0xff;
   1120 	if (psc->inputstate < 6)
   1121 		return;
   1122 
   1123 	pms_alps_dispatch_packet_v7(psc);
   1124 
   1125 	psc->inputstate = 0;
   1126 }
   1127