xref: /openbsd/sys/arch/arm64/dev/aplhidev.c (revision 3082766e)
1 /*	$OpenBSD: aplhidev.c,v 1.13 2024/01/15 13:27:20 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
4  * Copyright (c) 2013-2014 joshua stein <jcs@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/kernel.h>
22 #include <sys/device.h>
23 #include <sys/malloc.h>
24 #include <sys/timeout.h>
25 
26 #include <lib/libkern/crc16.h>
27 
28 #include <machine/fdt.h>
29 
30 #include <dev/spi/spivar.h>
31 
32 #include <dev/ofw/openfirm.h>
33 #include <dev/ofw/ofw_gpio.h>
34 #include <dev/ofw/ofw_pinctrl.h>
35 
36 #include <dev/usb/usbdevs.h>
37 
38 #include <dev/wscons/wsconsio.h>
39 #include <dev/wscons/wskbdvar.h>
40 #include <dev/wscons/wsksymdef.h>
41 #include <dev/wscons/wsmousevar.h>
42 
43 #include <dev/hid/hid.h>
44 #include <dev/hid/hidkbdsc.h>
45 #include <dev/hid/hidmsvar.h>
46 
47 #include "aplhidev.h"
48 
49 #define APLHIDEV_READ_PACKET	0x20
50 #define APLHIDEV_WRITE_PACKET	0x40
51 
52 #define APLHIDEV_KBD_DEVICE	1
53 #define APLHIDEV_TP_DEVICE	2
54 #define APLHIDEV_INFO_DEVICE	208
55 
56 #define APLHIDEV_GET_INFO	0x0120
57 #define APLHIDEV_GET_DESCRIPTOR	0x1020
58 #define  APLHIDEV_DESC_MAX	512
59 #define APLHIDEV_KBD_REPORT	0x0110
60 #define APLHIDEV_TP_REPORT	0x0210
61 #define APLHIDEV_SET_LEDS	0x0151
62 #define APLHIDEV_SET_MODE	0x0252
63 #define  APLHIDEV_MODE_HID	0x00
64 #define  APLHIDEV_MODE_RAW	0x01
65 #define APLHIDEV_GET_DIMENSIONS	0xd932
66 
67 struct aplhidev_dim {
68 	uint32_t width;
69 	uint32_t height;
70 	int16_t x_min;
71 	int16_t y_min;
72 	int16_t x_max;
73 	int16_t y_max;
74 };
75 
76 struct aplhidev_attach_args {
77 	uint8_t	aa_reportid;
78 	void	*aa_desc;
79 	size_t	aa_desclen;
80 };
81 
82 struct aplhidev_spi_packet {
83 	uint8_t		flags;
84 	uint8_t		device;
85 	uint16_t	offset;
86 	uint16_t	remaining;
87 	uint16_t	len;
88 	uint8_t		data[246];
89 	uint16_t	crc;
90 };
91 
92 struct aplhidev_spi_status {
93 	uint8_t		status[4];
94 };
95 
96 struct aplhidev_msghdr {
97 	uint16_t	type;
98 	uint8_t		device;
99 	uint8_t		msgid;
100 	uint16_t	rsplen;
101 	uint16_t	cmdlen;
102 };
103 
104 struct aplhidev_info_hdr {
105 	uint16_t	unknown[2];
106 	uint16_t	num_devices;
107 	uint16_t	vendor;
108 	uint16_t	product;
109 	uint16_t	version;
110 	uint16_t	vendor_str[2];
111 	uint16_t	product_str[2];
112 	uint16_t	serial_str[2];
113 };
114 
115 struct aplhidev_get_desc {
116 	struct aplhidev_msghdr	hdr;
117 	uint16_t		crc;
118 };
119 
120 struct aplhidev_set_leds {
121 	struct aplhidev_msghdr	hdr;
122 	uint8_t			reportid;
123 	uint8_t			leds;
124 	uint16_t		crc;
125 };
126 
127 struct aplhidev_set_mode {
128 	struct aplhidev_msghdr	hdr;
129 	uint8_t			reportid;
130 	uint8_t			mode;
131 	uint16_t		crc;
132 };
133 
134 struct aplhidev_softc {
135 	struct device		sc_dev;
136 	int			sc_node;
137 
138 	spi_tag_t		sc_spi_tag;
139 	struct spi_config	sc_spi_conf;
140 
141 	uint8_t			sc_msgid;
142 
143 	uint32_t		*sc_gpio;
144 	int			sc_gpiolen;
145 
146 	uint8_t			sc_mode;
147 	uint16_t		sc_vendor;
148 	uint16_t		sc_product;
149 
150 	struct device 		*sc_kbd;
151 	uint8_t			sc_kbddesc[APLHIDEV_DESC_MAX];
152 	size_t			sc_kbddesclen;
153 
154 	struct device		*sc_ms;
155 	uint8_t			sc_tpdesc[APLHIDEV_DESC_MAX];
156 	size_t			sc_tpdesclen;
157 	uint8_t			sc_dimdesc[APLHIDEV_DESC_MAX];
158 	size_t			sc_dimdesclen;
159 	int			sc_x_min;
160 	int			sc_x_max;
161 	int			sc_y_min;
162 	int			sc_y_max;
163 	int			sc_h_res;
164 	int			sc_v_res;
165 };
166 
167 int	 aplhidev_match(struct device *, void *, void *);
168 void	 aplhidev_attach(struct device *, struct device *, void *);
169 
170 const struct cfattach aplhidev_ca = {
171 	sizeof(struct aplhidev_softc), aplhidev_match, aplhidev_attach
172 };
173 
174 struct cfdriver aplhidev_cd = {
175 	NULL, "aplhidev", DV_DULL
176 };
177 
178 void	aplhidev_get_info(struct aplhidev_softc *);
179 void	aplhidev_get_descriptor(struct aplhidev_softc *, uint8_t);
180 void	aplhidev_set_leds(struct aplhidev_softc *, uint8_t);
181 void	aplhidev_set_mode(struct aplhidev_softc *, uint8_t);
182 void	aplhidev_get_dimensions(struct aplhidev_softc *);
183 
184 int	aplhidev_intr(void *);
185 void	aplkbd_intr(struct device *, uint8_t *, size_t);
186 void	aplms_intr(struct device *, uint8_t *, size_t);
187 
188 int
aplhidev_match(struct device * parent,void * match,void * aux)189 aplhidev_match(struct device *parent, void *match, void *aux)
190 {
191 	struct spi_attach_args *sa = aux;
192 
193 	if (strcmp(sa->sa_name, "apple,spi-hid-transport") == 0)
194 		return 1;
195 
196 	return 0;
197 }
198 
199 void
aplhidev_attach(struct device * parent,struct device * self,void * aux)200 aplhidev_attach(struct device *parent, struct device *self, void *aux)
201 {
202 	struct aplhidev_softc *sc = (struct aplhidev_softc *)self;
203 	struct spi_attach_args *sa = aux;
204 	struct aplhidev_attach_args aa;
205 	struct aplhidev_dim dim;
206 	int retry;
207 
208 	sc->sc_spi_tag = sa->sa_tag;
209 	sc->sc_node = *(int *)sa->sa_cookie;
210 
211 	sc->sc_gpiolen = OF_getproplen(sc->sc_node, "spien-gpios");
212 	if (sc->sc_gpiolen > 0) {
213 		sc->sc_gpio = malloc(sc->sc_gpiolen, M_TEMP, M_WAITOK);
214 		OF_getpropintarray(sc->sc_node, "spien-gpios",
215 		    sc->sc_gpio, sc->sc_gpiolen);
216 		gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_OUTPUT);
217 
218 		/* Reset */
219 		gpio_controller_set_pin(sc->sc_gpio, 1);
220 		delay(5000);
221 		gpio_controller_set_pin(sc->sc_gpio, 0);
222 		delay(5000);
223 
224 		/* Enable. */
225 		gpio_controller_set_pin(sc->sc_gpio, 1);
226 		delay(50000);
227 	}
228 
229 	sc->sc_spi_conf.sc_bpw = 8;
230 	sc->sc_spi_conf.sc_freq = OF_getpropint(sc->sc_node,
231 	    "spi-max-frequency", 0);
232 	sc->sc_spi_conf.sc_cs = OF_getpropint(sc->sc_node, "reg", 0);
233 	sc->sc_spi_conf.sc_cs_delay = 100;
234 
235 	fdt_intr_establish(sc->sc_node, IPL_TTY,
236 	    aplhidev_intr, sc, sc->sc_dev.dv_xname);
237 
238 	aplhidev_get_info(sc);
239 	for (retry = 10; retry > 0; retry--) {
240 		aplhidev_intr(sc);
241 		delay(1000);
242 		if (sc->sc_vendor != 0 && sc->sc_product != 0)
243 			break;
244 	}
245 
246 	aplhidev_get_descriptor(sc, APLHIDEV_KBD_DEVICE);
247 	for (retry = 10; retry > 0; retry--) {
248 		aplhidev_intr(sc);
249 		delay(1000);
250 		if (sc->sc_kbddesclen > 0)
251 			break;
252 	}
253 
254 	aplhidev_get_descriptor(sc, APLHIDEV_TP_DEVICE);
255 	for (retry = 10; retry > 0; retry--) {
256 		aplhidev_intr(sc);
257 		delay(1000);
258 		if (sc->sc_tpdesclen > 0)
259 			break;
260 	}
261 
262 	sc->sc_mode = APLHIDEV_MODE_HID;
263 	aplhidev_set_mode(sc, APLHIDEV_MODE_RAW);
264 	for (retry = 10; retry > 0; retry--) {
265 		aplhidev_intr(sc);
266 		delay(1000);
267 		if (sc->sc_mode == APLHIDEV_MODE_RAW)
268 			break;
269 	}
270 
271 	aplhidev_get_dimensions(sc);
272 	for (retry = 10; retry > 0; retry--) {
273 		aplhidev_intr(sc);
274 		delay(1000);
275 		if (sc->sc_dimdesclen > 0)
276 			break;
277 	}
278 
279 	printf("\n");
280 
281 	if (sc->sc_dimdesclen == sizeof(dim) + 1) {
282 		memcpy(&dim, &sc->sc_dimdesc[1], sizeof(dim));
283 		sc->sc_x_min = dim.x_min;
284 		sc->sc_x_max = dim.x_max;
285 		sc->sc_y_min = dim.y_min;
286 		sc->sc_y_max = dim.y_max;
287 		sc->sc_h_res = (100 * (dim.x_max - dim.x_min)) / dim.width;
288 		sc->sc_v_res = (100 * (dim.y_max - dim.y_min)) / dim.height;
289 	}
290 
291 	if (sc->sc_kbddesclen > 0) {
292 		aa.aa_reportid = APLHIDEV_KBD_DEVICE;
293 		aa.aa_desc = sc->sc_kbddesc;
294 		aa.aa_desclen = sc->sc_kbddesclen;
295 		sc->sc_kbd = config_found(self, &aa, NULL);
296 	}
297 
298 	if (sc->sc_tpdesclen > 0) {
299 		aa.aa_reportid = APLHIDEV_TP_DEVICE;
300 		aa.aa_desc = sc->sc_tpdesc;
301 		aa.aa_desclen = sc->sc_tpdesclen;
302 		sc->sc_ms = config_found(self, &aa, NULL);
303 	}
304 }
305 
306 void
aplhidev_get_info(struct aplhidev_softc * sc)307 aplhidev_get_info(struct aplhidev_softc *sc)
308 {
309 	struct aplhidev_spi_packet packet;
310 	struct aplhidev_get_desc *msg;
311 	struct aplhidev_spi_status status;
312 
313 	memset(&packet, 0, sizeof(packet));
314 	packet.flags = APLHIDEV_WRITE_PACKET;
315 	packet.device = APLHIDEV_INFO_DEVICE;
316 	packet.len = sizeof(*msg);
317 
318 	msg = (void *)&packet.data[0];
319 	msg->hdr.type = APLHIDEV_GET_INFO;
320 	msg->hdr.device = APLHIDEV_INFO_DEVICE;
321 	msg->hdr.msgid = sc->sc_msgid++;
322 	msg->hdr.cmdlen = 0;
323 	msg->hdr.rsplen = APLHIDEV_DESC_MAX;
324 	msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2);
325 
326 	packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2);
327 
328 	spi_acquire_bus(sc->sc_spi_tag, 0);
329 	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
330 	spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet),
331 	    SPI_KEEP_CS);
332 	delay(100);
333 	spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status));
334 	spi_release_bus(sc->sc_spi_tag, 0);
335 
336 	delay(1000);
337 }
338 
339 void
aplhidev_get_descriptor(struct aplhidev_softc * sc,uint8_t device)340 aplhidev_get_descriptor(struct aplhidev_softc *sc, uint8_t device)
341 {
342 	struct aplhidev_spi_packet packet;
343 	struct aplhidev_get_desc *msg;
344 	struct aplhidev_spi_status status;
345 
346 	memset(&packet, 0, sizeof(packet));
347 	packet.flags = APLHIDEV_WRITE_PACKET;
348 	packet.device = APLHIDEV_INFO_DEVICE;
349 	packet.len = sizeof(*msg);
350 
351 	msg = (void *)&packet.data[0];
352 	msg->hdr.type = APLHIDEV_GET_DESCRIPTOR;
353 	msg->hdr.device = device;
354 	msg->hdr.msgid = sc->sc_msgid++;
355 	msg->hdr.cmdlen = 0;
356 	msg->hdr.rsplen = APLHIDEV_DESC_MAX;
357 	msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2);
358 
359 	packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2);
360 
361 	spi_acquire_bus(sc->sc_spi_tag, 0);
362 	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
363 	spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet),
364 	    SPI_KEEP_CS);
365 	delay(100);
366 	spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status));
367 	spi_release_bus(sc->sc_spi_tag, 0);
368 
369 	delay(1000);
370 }
371 
372 void
aplhidev_set_leds(struct aplhidev_softc * sc,uint8_t leds)373 aplhidev_set_leds(struct aplhidev_softc *sc, uint8_t leds)
374 {
375 	struct aplhidev_spi_packet packet;
376 	struct aplhidev_set_leds *msg;
377 	struct aplhidev_spi_status status;
378 
379 	memset(&packet, 0, sizeof(packet));
380 	packet.flags = APLHIDEV_WRITE_PACKET;
381 	packet.device = APLHIDEV_KBD_DEVICE;
382 	packet.len = sizeof(*msg);
383 
384 	msg = (void *)&packet.data[0];
385 	msg->hdr.type = APLHIDEV_SET_LEDS;
386 	msg->hdr.device = APLHIDEV_KBD_DEVICE;
387 	msg->hdr.msgid = sc->sc_msgid++;
388 	msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2;
389 	msg->hdr.rsplen = msg->hdr.cmdlen;
390 	msg->reportid = APLHIDEV_KBD_DEVICE;
391 	msg->leds = leds;
392 	msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2);
393 
394 	packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2);
395 
396 	/*
397 	 * XXX Without a delay here, the command will fail.  Does the
398 	 * controller need a bit of time between sending us a keypress
399 	 * event and accepting a new command from us?
400 	 */
401 	delay(250);
402 
403 	spi_acquire_bus(sc->sc_spi_tag, 0);
404 	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
405 	spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet),
406 	    SPI_KEEP_CS);
407 	delay(100);
408 	spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status));
409 	spi_release_bus(sc->sc_spi_tag, 0);
410 }
411 
412 void
aplhidev_set_mode(struct aplhidev_softc * sc,uint8_t mode)413 aplhidev_set_mode(struct aplhidev_softc *sc, uint8_t mode)
414 {
415 	struct aplhidev_spi_packet packet;
416 	struct aplhidev_set_mode *msg;
417 	struct aplhidev_spi_status status;
418 
419 	memset(&packet, 0, sizeof(packet));
420 	packet.flags = APLHIDEV_WRITE_PACKET;
421 	packet.device = APLHIDEV_TP_DEVICE;
422 	packet.len = sizeof(*msg);
423 
424 	msg = (void *)&packet.data[0];
425 	msg->hdr.type = APLHIDEV_SET_MODE;
426 	msg->hdr.device = APLHIDEV_TP_DEVICE;
427 	msg->hdr.msgid = sc->sc_msgid++;
428 	msg->hdr.cmdlen = sizeof(*msg) - sizeof(struct aplhidev_msghdr) - 2;
429 	msg->hdr.rsplen = msg->hdr.cmdlen;
430 	msg->reportid = APLHIDEV_TP_DEVICE;
431 	msg->mode = mode;
432 	msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2);
433 
434 	packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2);
435 
436 	spi_acquire_bus(sc->sc_spi_tag, 0);
437 	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
438 	spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet),
439 	    SPI_KEEP_CS);
440 	delay(100);
441 	spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status));
442 	spi_release_bus(sc->sc_spi_tag, 0);
443 
444 	delay(1000);
445 }
446 
447 void
aplhidev_get_dimensions(struct aplhidev_softc * sc)448 aplhidev_get_dimensions(struct aplhidev_softc *sc)
449 {
450 	struct aplhidev_spi_packet packet;
451 	struct aplhidev_get_desc *msg;
452 	struct aplhidev_spi_status status;
453 
454 	memset(&packet, 0, sizeof(packet));
455 	packet.flags = APLHIDEV_WRITE_PACKET;
456 	packet.device = APLHIDEV_TP_DEVICE;
457 	packet.len = sizeof(*msg);
458 
459 	msg = (void *)&packet.data[0];
460 	msg->hdr.type = APLHIDEV_GET_DIMENSIONS;
461 	msg->hdr.device = 0;
462 	msg->hdr.msgid = sc->sc_msgid++;
463 	msg->hdr.cmdlen = 0;
464 	msg->hdr.rsplen = APLHIDEV_DESC_MAX;
465 	msg->crc = crc16(0, (void *)msg, sizeof(*msg) - 2);
466 
467 	packet.crc = crc16(0, (void *)&packet, sizeof(packet) - 2);
468 
469 	spi_acquire_bus(sc->sc_spi_tag, 0);
470 	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
471 	spi_transfer(sc->sc_spi_tag, (char *)&packet, NULL, sizeof(packet),
472 	    SPI_KEEP_CS);
473 	delay(100);
474 	spi_read(sc->sc_spi_tag, (char *)&status, sizeof(status));
475 	spi_release_bus(sc->sc_spi_tag, 0);
476 
477 	delay(1000);
478 }
479 
480 int
aplhidev_intr(void * arg)481 aplhidev_intr(void *arg)
482 {
483 	struct aplhidev_softc *sc = arg;
484 	struct aplhidev_spi_packet packet;
485 	struct aplhidev_msghdr *hdr = (struct aplhidev_msghdr *)&packet.data[0];
486 
487 	memset(&packet, 0, sizeof(packet));
488 	spi_acquire_bus(sc->sc_spi_tag, 0);
489 	spi_config(sc->sc_spi_tag, &sc->sc_spi_conf);
490 	spi_read(sc->sc_spi_tag, (char *)&packet, sizeof(packet));
491 	spi_release_bus(sc->sc_spi_tag, 0);
492 
493 	/* Treat empty packets as spurious interrupts. */
494 	if (packet.flags == 0 && packet.device == 0 && packet.crc == 0)
495 		return 0;
496 
497 	if (crc16(0, (uint8_t *)&packet, sizeof(packet)))
498 		return 1;
499 
500 	/* Keyboard input. */
501 	if (packet.flags == APLHIDEV_READ_PACKET &&
502 	    packet.device == APLHIDEV_KBD_DEVICE &&
503 	    hdr->type == APLHIDEV_KBD_REPORT) {
504 		if (sc->sc_kbd)
505 			aplkbd_intr(sc->sc_kbd, &packet.data[8], hdr->cmdlen);
506 		return 1;
507 	}
508 
509 	/* Touchpad input. */
510 	if (packet.flags == APLHIDEV_READ_PACKET &&
511 	    packet.device == APLHIDEV_TP_DEVICE &&
512 	    hdr->type == APLHIDEV_TP_REPORT) {
513 		if (sc->sc_ms)
514 			aplms_intr(sc->sc_ms, &packet.data[8], hdr->cmdlen);
515 		return 1;
516 	}
517 
518 	/* Replies to commands we sent. */
519 	if (packet.flags == APLHIDEV_WRITE_PACKET &&
520 	    packet.device == APLHIDEV_INFO_DEVICE &&
521 	    hdr->type == APLHIDEV_GET_INFO) {
522 		struct aplhidev_info_hdr *info =
523 		    (struct aplhidev_info_hdr *)&packet.data[8];
524 		sc->sc_vendor = info->vendor;
525 		sc->sc_product = info->product;
526 		return 1;
527 	}
528 	if (packet.flags == APLHIDEV_WRITE_PACKET &&
529 	    packet.device == APLHIDEV_INFO_DEVICE &&
530 	    hdr->type == APLHIDEV_GET_DESCRIPTOR) {
531 		switch (hdr->device) {
532 		case APLHIDEV_KBD_DEVICE:
533 			memcpy(sc->sc_kbddesc, &packet.data[8], hdr->cmdlen);
534 			sc->sc_kbddesclen = hdr->cmdlen;
535 			break;
536 		case APLHIDEV_TP_DEVICE:
537 			memcpy(sc->sc_tpdesc, &packet.data[8], hdr->cmdlen);
538 			sc->sc_tpdesclen = hdr->cmdlen;
539 			break;
540 		}
541 
542 		return 1;
543 	}
544 	if (packet.flags == APLHIDEV_WRITE_PACKET &&
545 	    packet.device == APLHIDEV_TP_DEVICE &&
546 	    hdr->type == APLHIDEV_SET_MODE) {
547 		sc->sc_mode = APLHIDEV_MODE_RAW;
548 		return 1;
549 	}
550 	if (packet.flags == APLHIDEV_WRITE_PACKET &&
551 	    packet.device == APLHIDEV_TP_DEVICE &&
552 	    hdr->type == APLHIDEV_GET_DIMENSIONS) {
553 		memcpy(sc->sc_dimdesc, &packet.data[8], hdr->cmdlen);
554 		sc->sc_dimdesclen = hdr->cmdlen;
555 		return 1;
556 	}
557 
558 	/* Valid, but unrecognized packet; ignore for now. */
559 	return 1;
560 }
561 
562 /* Keyboard */
563 
564 struct aplkbd_softc {
565 	struct device		sc_dev;
566 	struct aplhidev_softc	*sc_hidev;
567 	struct hidkbd		sc_kbd;
568 	int			sc_spl;
569 };
570 
571 void	aplkbd_cngetc(void *, u_int *, int *);
572 void	aplkbd_cnpollc(void *, int);
573 void	aplkbd_cnbell(void *, u_int, u_int, u_int);
574 
575 const struct wskbd_consops aplkbd_consops = {
576 	aplkbd_cngetc,
577 	aplkbd_cnpollc,
578 	aplkbd_cnbell,
579 };
580 
581 int	aplkbd_enable(void *, int);
582 void	aplkbd_set_leds(void *, int);
583 int	aplkbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
584 
585 const struct wskbd_accessops aplkbd_accessops = {
586 	.enable = aplkbd_enable,
587 	.ioctl = aplkbd_ioctl,
588 	.set_leds = aplkbd_set_leds,
589 };
590 
591 int	 aplkbd_match(struct device *, void *, void *);
592 void	 aplkbd_attach(struct device *, struct device *, void *);
593 
594 const struct cfattach aplkbd_ca = {
595 	sizeof(struct aplkbd_softc), aplkbd_match, aplkbd_attach
596 };
597 
598 struct cfdriver aplkbd_cd = {
599 	NULL, "aplkbd", DV_DULL
600 };
601 
602 int
aplkbd_match(struct device * parent,void * match,void * aux)603 aplkbd_match(struct device *parent, void *match, void *aux)
604 {
605 	struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux;
606 
607 	return (aa->aa_reportid == APLHIDEV_KBD_DEVICE);
608 }
609 
610 void
aplkbd_attach(struct device * parent,struct device * self,void * aux)611 aplkbd_attach(struct device *parent, struct device *self, void *aux)
612 {
613 	struct aplkbd_softc *sc = (struct aplkbd_softc *)self;
614 	struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux;
615 	struct hidkbd *kbd = &sc->sc_kbd;
616 
617 	sc->sc_hidev = (struct aplhidev_softc *)parent;
618 	if (hidkbd_attach(self, kbd, 1, 0, APLHIDEV_KBD_DEVICE,
619 	    aa->aa_desc, aa->aa_desclen))
620 		return;
621 
622 	printf("\n");
623 
624 	if (hid_locate(aa->aa_desc, aa->aa_desclen, HID_USAGE2(HUP_APPLE, HUG_FN_KEY),
625 	    1, hid_input, &kbd->sc_fn, NULL)) {
626 		switch (sc->sc_hidev->sc_product) {
627 		case USB_PRODUCT_APPLE_WELLSPRINGM1_J293:
628 			kbd->sc_munge = hidkbd_apple_tb_munge;
629 			break;
630 		default:
631 			kbd->sc_munge = hidkbd_apple_munge;
632 			break;
633 		}
634 	}
635 
636 	if (kbd->sc_console_keyboard) {
637 		extern struct wskbd_mapdata ukbd_keymapdata;
638 
639 		ukbd_keymapdata.layout = KB_US | KB_DEFAULT;
640 		wskbd_cnattach(&aplkbd_consops, sc, &ukbd_keymapdata);
641 		aplkbd_enable(sc, 1);
642 	}
643 
644 	hidkbd_attach_wskbd(kbd, KB_US | KB_DEFAULT, &aplkbd_accessops);
645 }
646 
647 void
aplkbd_intr(struct device * self,uint8_t * packet,size_t packetlen)648 aplkbd_intr(struct device *self, uint8_t *packet, size_t packetlen)
649 {
650 	struct aplkbd_softc *sc = (struct aplkbd_softc *)self;
651 	struct hidkbd *kbd = &sc->sc_kbd;
652 
653 	if (kbd->sc_enabled)
654 		hidkbd_input(kbd, &packet[1], packetlen - 1);
655 }
656 
657 int
aplkbd_enable(void * v,int on)658 aplkbd_enable(void *v, int on)
659 {
660 	struct aplkbd_softc *sc = v;
661 	struct hidkbd *kbd = &sc->sc_kbd;
662 
663 	return hidkbd_enable(kbd, on);
664 }
665 
666 int
aplkbd_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)667 aplkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
668 {
669 	struct aplkbd_softc *sc = v;
670 	struct hidkbd *kbd = &sc->sc_kbd;
671 
672 	switch (cmd) {
673 	case WSKBDIO_GTYPE:
674 		/* XXX: should we set something else? */
675 		*(u_int *)data = WSKBD_TYPE_USB;
676 		return 0;
677 	case WSKBDIO_SETLEDS:
678 		aplkbd_set_leds(v, *(int *)data);
679 		return 0;
680 	default:
681 		return hidkbd_ioctl(kbd, cmd, data, flag, p);
682 	}
683 }
684 
685 void
aplkbd_set_leds(void * v,int leds)686 aplkbd_set_leds(void *v, int leds)
687 {
688 	struct aplkbd_softc *sc = v;
689 	struct hidkbd *kbd = &sc->sc_kbd;
690 	uint8_t res;
691 
692 	if (hidkbd_set_leds(kbd, leds, &res))
693 		aplhidev_set_leds(sc->sc_hidev, res);
694 }
695 
696 /* Console interface. */
697 void
aplkbd_cngetc(void * v,u_int * type,int * data)698 aplkbd_cngetc(void *v, u_int *type, int *data)
699 {
700 	struct aplkbd_softc *sc = v;
701 	struct hidkbd *kbd = &sc->sc_kbd;
702 
703 	kbd->sc_polling = 1;
704 	while (kbd->sc_npollchar <= 0) {
705 		aplhidev_intr(sc->sc_dev.dv_parent);
706 		delay(1000);
707 	}
708 	kbd->sc_polling = 0;
709 	hidkbd_cngetc(kbd, type, data);
710 }
711 
712 void
aplkbd_cnpollc(void * v,int on)713 aplkbd_cnpollc(void *v, int on)
714 {
715 	struct aplkbd_softc *sc = v;
716 
717 	if (on)
718 		sc->sc_spl = spltty();
719 	else
720 		splx(sc->sc_spl);
721 }
722 
723 void
aplkbd_cnbell(void * v,u_int pitch,u_int period,u_int volume)724 aplkbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
725 {
726 	hidkbd_bell(pitch, period, volume, 1);
727 }
728 
729 #if NAPLMS > 0
730 
731 /* Touchpad */
732 
733 /*
734  * The contents of the touchpad event packets is identical to those
735  * used by the ubcmtp(4) driver.  The relevant definitions and the
736  * code to decode the packets is replicated here.
737  */
738 
739 struct ubcmtp_finger {
740 	uint16_t	origin;
741 	uint16_t	abs_x;
742 	uint16_t	abs_y;
743 	uint16_t	rel_x;
744 	uint16_t	rel_y;
745 	uint16_t	tool_major;
746 	uint16_t	tool_minor;
747 	uint16_t	orientation;
748 	uint16_t	touch_major;
749 	uint16_t	touch_minor;
750 	uint16_t	unused[2];
751 	uint16_t	pressure;
752 	uint16_t	multi;
753 } __packed __attribute((aligned(2)));
754 
755 #define UBCMTP_MAX_FINGERS	16
756 
757 #define UBCMTP_TYPE4_TPOFF	(24 * sizeof(uint16_t))
758 #define UBCMTP_TYPE4_BTOFF	31
759 #define UBCMTP_TYPE4_FINGERPAD	(1 * sizeof(uint16_t))
760 
761 /* Use a constant, synaptics-compatible pressure value for now. */
762 #define DEFAULT_PRESSURE	40
763 
764 static struct wsmouse_param aplms_wsmousecfg[] = {
765 	{ WSMOUSECFG_MTBTN_MAXDIST, 0 }, /* 0: Compute a default value. */
766 };
767 
768 struct aplms_softc {
769 	struct device		sc_dev;
770 	struct aplhidev_softc	*sc_hidev;
771 	struct device		*sc_wsmousedev;
772 
773 	int			sc_enabled;
774 
775 	int			tp_offset;
776 	int			tp_fingerpad;
777 
778 	struct mtpoint		frame[UBCMTP_MAX_FINGERS];
779 	int			contacts;
780 	int			btn;
781 };
782 
783 int	aplms_enable(void *);
784 void	aplms_disable(void *);
785 int	aplms_ioctl(void *, u_long, caddr_t, int, struct proc *);
786 
787 const struct wsmouse_accessops aplms_accessops = {
788 	.enable = aplms_enable,
789 	.disable = aplms_disable,
790 	.ioctl = aplms_ioctl,
791 };
792 
793 int	 aplms_match(struct device *, void *, void *);
794 void	 aplms_attach(struct device *, struct device *, void *);
795 
796 const struct cfattach aplms_ca = {
797 	sizeof(struct aplms_softc), aplms_match, aplms_attach
798 };
799 
800 struct cfdriver aplms_cd = {
801 	NULL, "aplms", DV_DULL
802 };
803 
804 int	aplms_configure(struct aplms_softc *);
805 
806 int
aplms_match(struct device * parent,void * match,void * aux)807 aplms_match(struct device *parent, void *match, void *aux)
808 {
809 	struct aplhidev_attach_args *aa = (struct aplhidev_attach_args *)aux;
810 
811 	return (aa->aa_reportid == APLHIDEV_TP_DEVICE);
812 }
813 
814 void
aplms_attach(struct device * parent,struct device * self,void * aux)815 aplms_attach(struct device *parent, struct device *self, void *aux)
816 {
817 	struct aplms_softc *sc = (struct aplms_softc *)self;
818 	struct wsmousedev_attach_args aa;
819 
820 	sc->sc_hidev = (struct aplhidev_softc *)parent;
821 
822 	printf("\n");
823 
824 	sc->tp_offset = UBCMTP_TYPE4_TPOFF;
825 	sc->tp_fingerpad = UBCMTP_TYPE4_FINGERPAD;
826 
827 	aa.accessops = &aplms_accessops;
828 	aa.accesscookie = sc;
829 
830 	sc->sc_wsmousedev = config_found(self, &aa, wsmousedevprint);
831 	if (sc->sc_wsmousedev != NULL && aplms_configure(sc))
832 		aplms_disable(sc);
833 }
834 
835 int
aplms_configure(struct aplms_softc * sc)836 aplms_configure(struct aplms_softc *sc)
837 {
838 	struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev);
839 
840 	hw->type = WSMOUSE_TYPE_TOUCHPAD;
841 	hw->hw_type = WSMOUSEHW_CLICKPAD;
842 	hw->x_min = sc->sc_hidev->sc_x_min;
843 	hw->x_max = sc->sc_hidev->sc_x_max;
844 	hw->y_min = sc->sc_hidev->sc_y_min;
845 	hw->y_max = sc->sc_hidev->sc_y_max;
846 	hw->h_res = sc->sc_hidev->sc_h_res;
847 	hw->v_res = sc->sc_hidev->sc_v_res;
848 	hw->mt_slots = UBCMTP_MAX_FINGERS;
849 	hw->flags = WSMOUSEHW_MT_TRACKING;
850 
851 	return wsmouse_configure(sc->sc_wsmousedev,
852 	    aplms_wsmousecfg, nitems(aplms_wsmousecfg));
853 }
854 
855 void
aplms_intr(struct device * self,uint8_t * packet,size_t packetlen)856 aplms_intr(struct device *self, uint8_t *packet, size_t packetlen)
857 {
858 	struct aplms_softc *sc = (struct aplms_softc *)self;
859 	struct ubcmtp_finger *finger;
860 	int off, s, btn, contacts;
861 
862 	if (!sc->sc_enabled)
863 		return;
864 
865 	contacts = 0;
866 	for (off = sc->tp_offset; off < packetlen;
867 	    off += (sizeof(struct ubcmtp_finger) + sc->tp_fingerpad)) {
868 		finger = (struct ubcmtp_finger *)(packet + off);
869 
870 		if ((int16_t)letoh16(finger->touch_major) == 0)
871 			continue; /* finger lifted */
872 
873 		sc->frame[contacts].x = (int16_t)letoh16(finger->abs_x);
874 		sc->frame[contacts].y = (int16_t)letoh16(finger->abs_y);
875 		sc->frame[contacts].pressure = DEFAULT_PRESSURE;
876 		contacts++;
877 	}
878 
879 	btn = sc->btn;
880 	sc->btn = !!((int16_t)letoh16(packet[UBCMTP_TYPE4_BTOFF]));
881 
882 	if (contacts || sc->contacts || sc->btn != btn) {
883 		sc->contacts = contacts;
884 		s = spltty();
885 		wsmouse_buttons(sc->sc_wsmousedev, sc->btn);
886 		wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts);
887 		wsmouse_input_sync(sc->sc_wsmousedev);
888 		splx(s);
889 	}
890 }
891 
892 int
aplms_enable(void * v)893 aplms_enable(void *v)
894 {
895 	struct aplms_softc *sc = v;
896 
897 	if (sc->sc_enabled)
898 		return EBUSY;
899 
900 	sc->sc_enabled = 1;
901 	return 0;
902 }
903 
904 void
aplms_disable(void * v)905 aplms_disable(void *v)
906 {
907 	struct aplms_softc *sc = v;
908 
909 	sc->sc_enabled = 0;
910 }
911 
912 int
aplms_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)913 aplms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
914 {
915 	struct aplms_softc *sc = v;
916 	struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev);
917 	struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
918 	int wsmode;
919 
920 	switch (cmd) {
921 	case WSMOUSEIO_GTYPE:
922 		*(u_int *)data = hw->type;
923 		break;
924 
925 	case WSMOUSEIO_GCALIBCOORDS:
926 		wsmc->minx = hw->x_min;
927 		wsmc->maxx = hw->x_max;
928 		wsmc->miny = hw->y_min;
929 		wsmc->maxy = hw->y_max;
930 		wsmc->swapxy = 0;
931 		wsmc->resx = hw->h_res;
932 		wsmc->resy = hw->v_res;
933 		break;
934 
935 	case WSMOUSEIO_SETMODE:
936 		wsmode = *(u_int *)data;
937 		if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) {
938 			printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname,
939 			    wsmode);
940 			return (EINVAL);
941 		}
942 		wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
943 		break;
944 
945 	default:
946 		return -1;
947 	}
948 
949 	return 0;
950 }
951 
952 #else
953 
954 void
aplms_intr(struct device * self,uint8_t * packet,size_t packetlen)955 aplms_intr(struct device *self, uint8_t *packet, size_t packetlen)
956 {
957 }
958 
959 #endif
960