xref: /openbsd-src/sys/arch/arm64/dev/apldc.c (revision df725a82ba061faad4bdfe0e5c13ca4542db9b12)
1 /*	$OpenBSD: apldc.c,v 1.12 2024/01/20 08:00:59 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/evcount.h>
22 #include <sys/malloc.h>
23 #include <sys/task.h>
24 #include <sys/timeout.h>
25 
26 #include <machine/bus.h>
27 #include <machine/fdt.h>
28 
29 #include <dev/ofw/openfirm.h>
30 #include <dev/ofw/ofw_gpio.h>
31 #include <dev/ofw/fdt.h>
32 
33 #include <dev/wscons/wsconsio.h>
34 #include <dev/wscons/wskbdvar.h>
35 #include <dev/wscons/wsksymdef.h>
36 #include <dev/wscons/wsmousevar.h>
37 
38 #include <dev/hid/hid.h>
39 #include <dev/hid/hidkbdsc.h>
40 #include <dev/hid/hidmsvar.h>
41 
42 #include <arm64/dev/rtkit.h>
43 #include <machine/simplebusvar.h>
44 
45 #include "apldc.h"
46 
47 #define DC_IRQ_MASK		0x0000
48 #define DC_IRQ_STAT		0x0004
49 
50 #define DC_CONFIG_TX_THRESH	0x0000
51 #define DC_CONFIG_RX_THRESH	0x0004
52 
53 #define DC_DATA_TX8		0x0004
54 #define DC_DATA_TX32		0x0010
55 #define DC_DATA_TX_FREE		0x0014
56 #define DC_DATA_RX8		0x001c
57 #define  DC_DATA_RX8_COUNT(d)	((d) & 0x7f)
58 #define  DC_DATA_RX8_DATA(d)	(((d) >> 8) & 0xff)
59 #define DC_DATA_RX32		0x0028
60 #define DC_DATA_RX_COUNT	0x002c
61 
62 #define APLDC_MAX_INTR		32
63 
64 #define HREAD4(sc, reg)							\
65 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
66 #define HWRITE4(sc, reg, val)						\
67 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
68 #define HSET4(sc, reg, bits)						\
69 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
70 #define HCLR4(sc, reg, bits)						\
71 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
72 
73 struct apldchidev_attach_args {
74 	const char *aa_name;
75 	void	*aa_desc;
76 	size_t	aa_desclen;
77 };
78 
79 struct intrhand {
80 	int (*ih_func)(void *);
81 	void *ih_arg;
82 	int ih_ipl;
83 	int ih_irq;
84 	int ih_level;
85 	struct evcount ih_count;
86 	char *ih_name;
87 	void *ih_sc;
88 };
89 
90 struct apldc_softc {
91 	struct simplebus_softc	sc_sbus;
92 	bus_space_tag_t		sc_iot;
93 	bus_space_handle_t	sc_ioh;
94 
95 	void			*sc_ih;
96 	struct intrhand		*sc_handlers[APLDC_MAX_INTR];
97 	struct interrupt_controller sc_ic;
98 };
99 
100 int	apldc_match(struct device *, void *, void *);
101 void	apldc_attach(struct device *, struct device *, void *);
102 
103 const struct cfattach apldc_ca = {
104 	sizeof (struct apldc_softc), apldc_match, apldc_attach
105 };
106 
107 struct cfdriver apldc_cd = {
108 	NULL, "apldc", DV_DULL
109 };
110 
111 int	apldc_intr(void *);
112 void	*apldc_intr_establish(void *, int *, int, struct cpu_info *,
113 	    int (*)(void *), void *, char *);
114 void	apldc_intr_enable(void *);
115 void	apldc_intr_disable(void *);
116 void	apldc_intr_barrier(void *);
117 
118 int
apldc_match(struct device * parent,void * match,void * aux)119 apldc_match(struct device *parent, void *match, void *aux)
120 {
121 	struct fdt_attach_args *faa = aux;
122 
123 	return OF_is_compatible(faa->fa_node, "apple,dockchannel");
124 }
125 
126 void
apldc_attach(struct device * parent,struct device * self,void * aux)127 apldc_attach(struct device *parent, struct device *self, void *aux)
128 {
129 	struct apldc_softc *sc = (struct apldc_softc *)self;
130 	struct fdt_attach_args *faa = aux;
131 
132 	if (faa->fa_nreg < 1) {
133 		printf(": no registers\n");
134 		return;
135 	}
136 
137 	sc->sc_iot = faa->fa_iot;
138 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
139 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
140 		printf(": can't map registers\n");
141 		return;
142 	}
143 
144 	/* Disable and clear all interrupts. */
145 	HWRITE4(sc, DC_IRQ_MASK, 0);
146 	HWRITE4(sc, DC_IRQ_STAT, 0xffffffff);
147 
148 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_TTY,
149 	    apldc_intr, sc, sc->sc_sbus.sc_dev.dv_xname);
150 
151 	sc->sc_ic.ic_node = faa->fa_node;
152 	sc->sc_ic.ic_cookie = sc;
153 	sc->sc_ic.ic_establish = apldc_intr_establish;
154 	sc->sc_ic.ic_enable = apldc_intr_enable;
155 	sc->sc_ic.ic_disable = apldc_intr_disable;
156 	sc->sc_ic.ic_barrier = apldc_intr_barrier;
157 	fdt_intr_register(&sc->sc_ic);
158 
159 	simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
160 }
161 
162 int
apldc_intr(void * arg)163 apldc_intr(void *arg)
164 {
165 	struct apldc_softc *sc = arg;
166 	struct intrhand *ih;
167 	uint32_t stat, pending;
168 	int irq, s;
169 
170 	stat = HREAD4(sc, DC_IRQ_STAT);
171 
172 	pending = stat;
173 	while (pending) {
174 		irq = ffs(pending) - 1;
175 		ih = sc->sc_handlers[irq];
176 		if (ih) {
177 			s = splraise(ih->ih_ipl);
178 			if (ih->ih_func(ih->ih_arg))
179 				ih->ih_count.ec_count++;
180 			splx(s);
181 		}
182 
183 		pending &= ~(1 << irq);
184 	}
185 
186 	HWRITE4(sc, DC_IRQ_STAT, stat);
187 
188 	return 1;
189 }
190 
191 void *
apldc_intr_establish(void * cookie,int * cells,int ipl,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)192 apldc_intr_establish(void *cookie, int *cells, int ipl,
193     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
194 {
195 	struct apldc_softc *sc = cookie;
196 	struct intrhand *ih;
197 	int irq = cells[0];
198 	int level = cells[1];
199 
200 	if (irq < 0 || irq >= APLDC_MAX_INTR)
201 		return NULL;
202 
203 	if (ipl != IPL_TTY)
204 		return NULL;
205 
206 	if (ci != NULL && !CPU_IS_PRIMARY(ci))
207 		return NULL;
208 
209 	if (sc->sc_handlers[irq])
210 		return NULL;
211 
212 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK);
213 	ih->ih_func = func;
214 	ih->ih_arg = arg;
215 	ih->ih_ipl = ipl & IPL_IRQMASK;
216 	ih->ih_irq = irq;
217 	ih->ih_name = name;
218 	ih->ih_level = level;
219 	ih->ih_sc = sc;
220 
221 	sc->sc_handlers[irq] = ih;
222 
223 	if (name != NULL)
224 		evcount_attach(&ih->ih_count, name, &ih->ih_irq);
225 
226 	return ih;
227 }
228 
229 void
apldc_intr_enable(void * cookie)230 apldc_intr_enable(void *cookie)
231 {
232 	struct intrhand	*ih = cookie;
233 	struct apldc_softc *sc = ih->ih_sc;
234 
235 	HSET4(sc, DC_IRQ_MASK, 1 << ih->ih_irq);
236 }
237 
238 void
apldc_intr_disable(void * cookie)239 apldc_intr_disable(void *cookie)
240 {
241 	struct intrhand	*ih = cookie;
242 	struct apldc_softc *sc = ih->ih_sc;
243 
244 	HCLR4(sc, DC_IRQ_MASK, 1 << ih->ih_irq);
245 }
246 
247 void
apldc_intr_barrier(void * cookie)248 apldc_intr_barrier(void *cookie)
249 {
250 	struct intrhand	*ih = cookie;
251 	struct apldc_softc *sc = ih->ih_sc;
252 
253 	intr_barrier(sc->sc_ih);
254 }
255 
256 #define APLDCHIDEV_DESC_MAX	512
257 #define APLDCHIDEV_PKT_MAX	1024
258 #define APLDCHIDEV_GPIO_MAX	4
259 
260 #define APLDCHIDEV_NUM_GPIOS	16
261 
262 struct apldchidev_gpio {
263 	struct apldchidev_softc	*ag_sc;
264 	uint8_t			ag_id;
265 	uint8_t			ag_iface;
266 	uint32_t		ag_gpio[APLDCHIDEV_GPIO_MAX];
267 	struct task		ag_task;
268 };
269 
270 struct apldchidev_softc {
271 	struct device		sc_dev;
272 	bus_space_tag_t		sc_iot;
273 	bus_space_handle_t	sc_cfg_ioh;
274 	bus_space_handle_t	sc_data_ioh;
275 
276 	bus_dma_tag_t		sc_dmat;
277 	int			sc_node;
278 
279 	void			*sc_rx_ih;
280 
281 	uint8_t			sc_seq_comm;
282 
283 	uint8_t			sc_iface_stm;
284 	uint8_t			sc_seq_stm;
285 	uint8_t			sc_stmdesc[APLDCHIDEV_DESC_MAX];
286 	size_t			sc_stmdesclen;
287 	int			sc_stm_ready;
288 
289 	uint8_t			sc_iface_kbd;
290 	uint8_t			sc_seq_kbd;
291 	struct device		*sc_kbd;
292 	uint8_t			sc_kbddesc[APLDCHIDEV_DESC_MAX];
293 	size_t			sc_kbddesclen;
294 	int			sc_kbd_ready;
295 
296 	uint8_t			sc_iface_mt;
297 	uint8_t			sc_seq_mt;
298 	struct device		*sc_mt;
299 	uint8_t			sc_mtdesc[APLDCHIDEV_DESC_MAX];
300 	size_t			sc_mtdesclen;
301 	int			sc_mt_ready;
302 	int			sc_x_min;
303 	int			sc_x_max;
304 	int			sc_y_min;
305 	int			sc_y_max;
306 	int			sc_h_res;
307 	int			sc_v_res;
308 
309 	struct apldchidev_gpio	sc_gpio[APLDCHIDEV_NUM_GPIOS];
310 	u_int			sc_ngpios;
311 	uint8_t			sc_gpio_cmd[APLDCHIDEV_PKT_MAX];
312 	size_t			sc_gpio_cmd_len;
313 
314 	uint8_t			sc_cmd_iface;
315 	uint8_t			sc_cmd_seq;
316 	uint8_t			sc_data[APLDCHIDEV_DESC_MAX];
317 	size_t			sc_data_len;
318 	uint32_t		sc_retcode;
319 	int			sc_busy;
320 };
321 
322 int	apldchidev_match(struct device *, void *, void *);
323 void	apldchidev_attach(struct device *, struct device *, void *);
324 
325 const struct cfattach apldchidev_ca = {
326 	sizeof(struct apldchidev_softc), apldchidev_match, apldchidev_attach
327 };
328 
329 struct cfdriver apldchidev_cd = {
330 	NULL, "apldchidev", DV_DULL
331 };
332 
333 void	apldchidev_attachhook(struct device *);
334 void	apldchidev_cmd(struct apldchidev_softc *, uint8_t, uint8_t,
335 	    void *, size_t);
336 void	apldchidev_wait(struct apldchidev_softc *);
337 int	apldchidev_send_firmware(struct apldchidev_softc *, int,
338 	    void *, size_t);
339 void	apldchidev_enable(struct apldchidev_softc *, uint8_t);
340 void	apldchidev_reset(struct apldchidev_softc *, uint8_t, uint8_t);
341 int	apldchidev_rx_intr(void *);
342 void	apldchidev_gpio_task(void *);
343 
344 int
apldchidev_match(struct device * parent,void * cfdata,void * aux)345 apldchidev_match(struct device *parent, void *cfdata, void *aux)
346 {
347 	struct fdt_attach_args *faa = aux;
348 
349 	return OF_is_compatible(faa->fa_node, "apple,dockchannel-hid");
350 }
351 
352 void
apldchidev_attach(struct device * parent,struct device * self,void * aux)353 apldchidev_attach(struct device *parent, struct device *self, void *aux)
354 {
355 	struct apldchidev_softc *sc = (struct apldchidev_softc *)self;
356 	struct fdt_attach_args *faa = aux;
357 	struct apldchidev_attach_args aa;
358 	uint32_t phandle;
359 	int error, idx, retry;
360 
361 	if (faa->fa_nreg < 2) {
362 		printf(": no registers\n");
363 		return;
364 	}
365 
366 	sc->sc_iot = faa->fa_iot;
367 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
368 	    faa->fa_reg[0].size, 0, &sc->sc_cfg_ioh)) {
369 		printf(": can't map registers\n");
370 		return;
371 	}
372 	if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
373 	    faa->fa_reg[1].size, 0, &sc->sc_data_ioh)) {
374 		printf(": can't map registers\n");
375 		return;
376 	}
377 
378 	sc->sc_dmat = faa->fa_dmat;
379 	sc->sc_node = faa->fa_node;
380 
381 	idx = OF_getindex(faa->fa_node, "rx", "interrupt-names");
382 	if (idx < 0) {
383 		printf(": no rx interrupt\n");
384 		return;
385 	}
386 	sc->sc_rx_ih = fdt_intr_establish_idx(faa->fa_node, idx, IPL_TTY,
387 	    apldchidev_rx_intr, sc, sc->sc_dev.dv_xname);
388 	if (sc->sc_rx_ih == NULL) {
389 		printf(": can't establish interrupt\n");
390 		return;
391 	}
392 
393 	phandle = OF_getpropint(faa->fa_node, "apple,helper-cpu", 0);
394 	if (phandle) {
395 		error = aplrtk_start(phandle);
396 		if (error) {
397 			printf(": can't start helper CPU\n");
398 			return;
399 		}
400 	}
401 
402 	printf("\n");
403 
404 	/* Poll until we have received the STM HID descriptor. */
405 	for (retry = 10; retry > 0; retry--) {
406 		if (sc->sc_stmdesclen > 0)
407 			break;
408 		apldchidev_rx_intr(sc);
409 		delay(1000);
410 	}
411 
412 	if (sc->sc_stmdesclen > 0) {
413 		/* Enable interface. */
414 		apldchidev_enable(sc, sc->sc_iface_stm);
415 	}
416 
417 	/* Poll until we have received the keyboard HID descriptor. */
418 	for (retry = 10; retry > 0; retry--) {
419 		if (sc->sc_kbddesclen > 0)
420 			break;
421 		apldchidev_rx_intr(sc);
422 		delay(1000);
423 	}
424 
425 	if (sc->sc_kbddesclen > 0) {
426 		/* Enable interface. */
427 		apldchidev_enable(sc, sc->sc_iface_kbd);
428 
429 		aa.aa_name = "keyboard";
430 		aa.aa_desc = sc->sc_kbddesc;
431 		aa.aa_desclen = sc->sc_kbddesclen;
432 		sc->sc_kbd = config_found(self, &aa, NULL);
433 	}
434 
435 	bus_space_write_4(sc->sc_iot, sc->sc_cfg_ioh, DC_CONFIG_RX_THRESH, 8);
436 	fdt_intr_enable(sc->sc_rx_ih);
437 
438 #if NAPLDCMS > 0
439 	config_mountroot(self, apldchidev_attachhook);
440 #endif
441 }
442 
443 int
apldchidev_read(struct apldchidev_softc * sc,void * buf,size_t len,uint32_t * checksum)444 apldchidev_read(struct apldchidev_softc *sc, void *buf, size_t len,
445     uint32_t *checksum)
446 {
447 	uint8_t *dst = buf;
448 	uint32_t data;
449 	int shift = 0;
450 
451 	while (len > 0) {
452 		data = bus_space_read_4(sc->sc_iot, sc->sc_data_ioh,
453 		    DC_DATA_RX8);
454 		if (DC_DATA_RX8_COUNT(data) > 0) {
455 			*dst++ = DC_DATA_RX8_DATA(data);
456 			*checksum += (DC_DATA_RX8_DATA(data) << shift);
457 			shift += 8;
458 			if (shift > 24)
459 				shift = 0;
460 			len--;
461 		} else {
462 			delay(10);
463 		}
464 	}
465 
466 	return 0;
467 }
468 
469 int
apldchidev_write(struct apldchidev_softc * sc,const void * buf,size_t len,uint32_t * checksum)470 apldchidev_write(struct apldchidev_softc *sc, const void *buf, size_t len,
471     uint32_t *checksum)
472 {
473 	const uint8_t *src = buf;
474 	uint32_t free;
475 	int shift = 0;
476 
477 	while (len > 0) {
478 		free = bus_space_read_4(sc->sc_iot, sc->sc_data_ioh,
479 		    DC_DATA_TX_FREE);
480 		if (free > 0) {
481 			if (checksum)
482 				*checksum -= *src << shift;
483 			bus_space_write_4(sc->sc_iot, sc->sc_data_ioh,
484 			    DC_DATA_TX8, *src++);
485 			shift += 8;
486 			if (shift > 24)
487 				shift = 0;
488 			len--;
489 		} else {
490 			delay(10);
491 		}
492 	}
493 
494 	return 0;
495 }
496 
497 struct mtp_hdr {
498 	uint8_t hdr_len;
499 	uint8_t chan;
500 #define MTP_CHAN_CMD		0x11
501 #define MTP_CHAN_REPORT		0x12
502 	uint16_t pkt_len;
503 	uint8_t seq;
504 	uint8_t iface;
505 #define MTP_IFACE_COMM		0
506 	uint16_t pad;
507 } __packed;
508 
509 struct mtp_subhdr {
510 	uint8_t flags;
511 #define MTP_GROUP_SHIFT	6
512 #define MTP_GROUP(x)		((x >> 6) & 0x3)
513 #define MTP_GROUP_INPUT	0
514 #define MTP_GROUP_OUTPUT	1
515 #define MTP_GROUP_CMD		2
516 #define MTP_REQ_SHIFT		0
517 #define MTP_REQ(x)		((x >> 0) & 0x3f)
518 #define MTP_REQ_SET_REPORT	0
519 #define MTP_REQ_GET_REPORT	1
520 	uint8_t unk;
521 	uint16_t len;
522 	uint32_t retcode;
523 } __packed;
524 
525 struct mtp_init_hdr {
526 	uint8_t type;
527 #define MTP_EVENT_GPIO_CMD	0xa0
528 #define MTP_EVENT_INIT	0xf0
529 #define MTP_EVENT_READY	0xf1
530 	uint8_t unk1;
531 	uint8_t unk2;
532 	uint8_t iface;
533 	char name[16];
534 } __packed;
535 
536 struct mtp_init_block_hdr {
537 	uint16_t type;
538 #define MTP_BLOCK_DESCRIPTOR	0
539 #define MTP_BLOCK_GPIO_REQ	1
540 #define MTP_BLOCK_END		2
541 	uint16_t subtype;
542 	uint16_t len;
543 } __packed;
544 
545 struct mtp_gpio_req {
546 	uint16_t unk;
547 	uint16_t id;
548 	char name[32];
549 } __packed;
550 
551 struct mtp_gpio_cmd {
552 	uint8_t type;
553 	uint8_t iface;
554 	uint8_t id;
555 	uint8_t unk;
556 	uint8_t cmd;
557 #define MTP_GPIO_CMD_TOGGLE	0x03
558 } __packed;
559 
560 struct mtp_gpio_ack {
561 	uint8_t type;
562 	uint32_t retcode;
563 	uint8_t cmd[512];
564 } __packed;
565 
566 struct mtp_dim {
567 	uint32_t width;
568 	uint32_t height;
569 	int16_t x_min;
570 	int16_t y_min;
571 	int16_t x_max;
572 	int16_t y_max;
573 };
574 
575 #define MTP_CMD_RESET_INTERFACE	0x40
576 #define MTP_CMD_SEND_FIRMWARE		0x95
577 #define MTP_CMD_ENABLE_INTERFACE	0xb4
578 #define MTP_CMD_ACK_GPIO_CMD		0xa1
579 #define MTP_CMD_GET_DIMENSIONS		0xd9
580 
581 void
apldchidev_handle_gpio_req(struct apldchidev_softc * sc,uint8_t iface,void * buf,size_t len)582 apldchidev_handle_gpio_req(struct apldchidev_softc *sc, uint8_t iface,
583     void *buf, size_t len)
584 {
585 	struct mtp_gpio_req *req = buf;
586 	uint32_t gpio[APLDCHIDEV_GPIO_MAX];
587 	char name[64];
588 	int node = -1;
589 
590 	if (len < sizeof(*req))
591 		return;
592 
593 	if (sc->sc_ngpios >= APLDCHIDEV_NUM_GPIOS)
594 		return;
595 
596 	node = sc->sc_node;
597 	snprintf(name, sizeof(name), "apple,%s-gpios", req->name);
598 	len = OF_getproplen(node, name);
599 	if (len <= 0 || len > sizeof(gpio)) {
600 		/* XXX: older device trees store gpios in sub-nodes */
601 		if (iface == sc->sc_iface_mt)
602 			node = OF_getnodebyname(sc->sc_node, "multi-touch");
603 		else if (iface == sc->sc_iface_stm)
604 			node = OF_getnodebyname(sc->sc_node, "stm");
605 		if (node == -1)
606 			return;
607 		len = OF_getproplen(node, name);
608 		if (len <= 0 || len > sizeof(gpio))
609 			return;
610 	}
611 
612 	OF_getpropintarray(node, name, gpio, len);
613 	gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT);
614 	gpio_controller_set_pin(gpio, 0);
615 
616 	sc->sc_gpio[sc->sc_ngpios].ag_sc = sc;
617 	sc->sc_gpio[sc->sc_ngpios].ag_id = req->id;
618 	sc->sc_gpio[sc->sc_ngpios].ag_iface = iface;
619 	memcpy(sc->sc_gpio[sc->sc_ngpios].ag_gpio, gpio, len);
620 	task_set(&sc->sc_gpio[sc->sc_ngpios].ag_task,
621 	    apldchidev_gpio_task, &sc->sc_gpio[sc->sc_ngpios]);
622 	sc->sc_ngpios++;
623 }
624 
625 void
apldchidev_handle_init(struct apldchidev_softc * sc,uint8_t iface,void * buf,size_t len)626 apldchidev_handle_init(struct apldchidev_softc *sc, uint8_t iface,
627     void *buf, size_t len)
628 {
629 	struct mtp_init_block_hdr *bhdr = buf;
630 
631 	for (;;) {
632 		if (len < sizeof(*bhdr))
633 			return;
634 		len -= sizeof(*bhdr);
635 
636 		if (len < bhdr->len)
637 			return;
638 		len -= bhdr->len;
639 
640 		switch (bhdr->type) {
641 		case MTP_BLOCK_DESCRIPTOR:
642 			if (iface == sc->sc_iface_kbd &&
643 			    bhdr->len <= sizeof(sc->sc_kbddesc)) {
644 				memcpy(sc->sc_kbddesc, bhdr + 1, bhdr->len);
645 				sc->sc_kbddesclen = bhdr->len;
646 			} else if (iface == sc->sc_iface_mt &&
647 			    bhdr->len <= sizeof(sc->sc_mtdesc)) {
648 				memcpy(sc->sc_mtdesc, bhdr + 1, bhdr->len);
649 				sc->sc_mtdesclen = bhdr->len;
650 			} else if (iface == sc->sc_iface_stm &&
651 			    bhdr->len <= sizeof(sc->sc_stmdesc)) {
652 				memcpy(sc->sc_stmdesc, bhdr + 1, bhdr->len);
653 				sc->sc_stmdesclen = bhdr->len;
654 			}
655 			break;
656 		case MTP_BLOCK_GPIO_REQ:
657 			apldchidev_handle_gpio_req(sc, iface,
658 			    bhdr + 1, bhdr->len);
659 			break;
660 		case MTP_BLOCK_END:
661 			return;
662 		default:
663 			printf("%s: unhandled block type 0x%04x\n",
664 			    sc->sc_dev.dv_xname, bhdr->type);
665 			break;
666 		}
667 
668 		bhdr = (struct mtp_init_block_hdr *)
669 		    ((uint8_t *)(bhdr + 1) + bhdr->len);
670 	}
671 }
672 
673 void
apldchidev_handle_comm(struct apldchidev_softc * sc,void * buf,size_t len)674 apldchidev_handle_comm(struct apldchidev_softc *sc, void *buf, size_t len)
675 {
676 	struct mtp_init_hdr *ihdr = buf;
677 	struct mtp_gpio_cmd *cmd = buf;
678 	uint8_t iface;
679 	int i;
680 
681 	switch (ihdr->type) {
682 	case MTP_EVENT_INIT:
683 		if (strcmp(ihdr->name, "keyboard") == 0) {
684 			sc->sc_iface_kbd = ihdr->iface;
685 			apldchidev_handle_init(sc, ihdr->iface,
686 			    ihdr + 1, len - sizeof(*ihdr));
687 		}
688 		if (strcmp(ihdr->name, "multi-touch") == 0) {
689 			sc->sc_iface_mt = ihdr->iface;
690 			apldchidev_handle_init(sc, ihdr->iface,
691 			    ihdr + 1, len - sizeof(*ihdr));
692 		}
693 		if (strcmp(ihdr->name, "stm") == 0) {
694 			sc->sc_iface_stm = ihdr->iface;
695 			apldchidev_handle_init(sc, ihdr->iface,
696 			    ihdr + 1, len - sizeof(*ihdr));
697 		}
698 		break;
699 	case MTP_EVENT_READY:
700 		iface = ihdr->unk1;
701 		if (iface == sc->sc_iface_stm)
702 			sc->sc_stm_ready = 1;
703 		if (iface == sc->sc_iface_kbd)
704 			sc->sc_kbd_ready = 1;
705 		if (iface == sc->sc_iface_mt)
706 			sc->sc_mt_ready = 1;
707 		break;
708 	case MTP_EVENT_GPIO_CMD:
709 		for (i =0; i < sc->sc_ngpios; i++) {
710 			if (cmd->id == sc->sc_gpio[i].ag_id &&
711 			    cmd->iface == sc->sc_gpio[i].ag_iface &&
712 			    cmd->cmd == MTP_GPIO_CMD_TOGGLE) {
713 				/* Stash the command for the reply. */
714 				KASSERT(len < sizeof(sc->sc_gpio_cmd));
715 				memcpy(sc->sc_gpio_cmd, buf, len);
716 				sc->sc_gpio_cmd_len = len;
717 				task_add(systq, &sc->sc_gpio[i].ag_task);
718 				return;
719 			}
720 		}
721 		printf("%s: unhandled gpio id %d iface %d cmd 0x%02x\n",
722 		       sc->sc_dev.dv_xname, cmd->id, cmd->iface, cmd->cmd);
723 		break;
724 	default:
725 		printf("%s: unhandled comm event 0x%02x\n",
726 		    sc->sc_dev.dv_xname, ihdr->type);
727 		break;
728 	}
729 }
730 
731 void
apldchidev_gpio_task(void * arg)732 apldchidev_gpio_task(void *arg)
733 {
734 	struct apldchidev_gpio *ag = arg;
735 	struct apldchidev_softc *sc = ag->ag_sc;
736 	struct mtp_gpio_ack *ack;
737 	uint8_t flags;
738 	size_t len;
739 
740 	gpio_controller_set_pin(ag->ag_gpio, 1);
741 	delay(10000);
742 	gpio_controller_set_pin(ag->ag_gpio, 0);
743 
744 	len = sizeof(*ack) + sc->sc_gpio_cmd_len;
745 	ack = malloc(len, M_TEMP, M_WAITOK);
746 	ack->type = MTP_CMD_ACK_GPIO_CMD;
747 	ack->retcode = 0;
748 	memcpy(ack->cmd, sc->sc_gpio_cmd, sc->sc_gpio_cmd_len);
749 
750 	flags = MTP_GROUP_CMD << MTP_GROUP_SHIFT;
751 	flags |= MTP_REQ_SET_REPORT << MTP_REQ_SHIFT;
752 	apldchidev_cmd(sc, MTP_IFACE_COMM, flags, ack, len);
753 
754 	free(ack, M_TEMP, len);
755 }
756 
757 void apldckbd_intr(struct device *, uint8_t *, size_t);
758 void apldcms_intr(struct device *, uint8_t *, size_t);
759 
760 int
apldchidev_rx_intr(void * arg)761 apldchidev_rx_intr(void *arg)
762 {
763 	struct apldchidev_softc *sc = arg;
764 	struct mtp_hdr hdr;
765 	struct mtp_subhdr *shdr;
766 	uint32_t checksum = 0;
767 	char buf[APLDCHIDEV_PKT_MAX];
768 
769 	apldchidev_read(sc, &hdr, sizeof(hdr), &checksum);
770 	apldchidev_read(sc, buf, hdr.pkt_len + 4, &checksum);
771 	if (checksum != 0xffffffff) {
772 		printf("%s: packet checksum error\n", sc->sc_dev.dv_xname);
773 		return 1;
774 	}
775 	if (hdr.pkt_len < sizeof(*shdr)) {
776 		printf("%s: packet too small\n", sc->sc_dev.dv_xname);
777 		return 1;
778 	}
779 
780 	shdr = (struct mtp_subhdr *)buf;
781 	if (MTP_GROUP(shdr->flags) == MTP_GROUP_OUTPUT ||
782 	    MTP_GROUP(shdr->flags) == MTP_GROUP_CMD) {
783 		if (hdr.iface != sc->sc_cmd_iface) {
784 			printf("%s: got ack for unexpected iface\n",
785 			    sc->sc_dev.dv_xname);
786 		}
787 		if (hdr.seq != sc->sc_cmd_seq) {
788 			printf("%s: got ack with unexpected seq\n",
789 			    sc->sc_dev.dv_xname);
790 		}
791 		if (MTP_REQ(shdr->flags) == MTP_REQ_GET_REPORT &&
792 		    shdr->len <= sizeof(sc->sc_data)) {
793 			memcpy(sc->sc_data, (shdr + 1), shdr->len);
794 			sc->sc_data_len = shdr->len;
795 		} else {
796 			sc->sc_data_len = 0;
797 		}
798 		sc->sc_retcode = shdr->retcode;
799 		sc->sc_busy = 0;
800 		wakeup(sc);
801 		return 1;
802 	}
803 	if (MTP_GROUP(shdr->flags) != MTP_GROUP_INPUT) {
804 		printf("%s: unhandled group 0x%02x\n",
805 		    sc->sc_dev.dv_xname, shdr->flags);
806 		return 1;
807 	}
808 
809 	if (hdr.iface == MTP_IFACE_COMM)
810 		apldchidev_handle_comm(sc, shdr + 1, shdr->len);
811 	else if (hdr.iface == sc->sc_iface_kbd && sc->sc_kbd)
812 		apldckbd_intr(sc->sc_kbd, (uint8_t *)(shdr + 1), shdr->len);
813 	else if (hdr.iface == sc->sc_iface_mt && sc->sc_mt)
814 		apldcms_intr(sc->sc_mt, (uint8_t *)(shdr + 1), shdr->len);
815 	else {
816 		printf("%s: unhandled iface %d\n",
817 		    sc->sc_dev.dv_xname, hdr.iface);
818 	}
819 
820 	wakeup(sc);
821 	return 1;
822 }
823 
824 void
apldchidev_cmd(struct apldchidev_softc * sc,uint8_t iface,uint8_t flags,void * data,size_t len)825 apldchidev_cmd(struct apldchidev_softc *sc, uint8_t iface, uint8_t flags,
826     void *data, size_t len)
827 {
828 	struct mtp_hdr hdr;
829 	struct mtp_subhdr shdr;
830 	uint32_t checksum = 0xffffffff;
831 	uint8_t pad[4];
832 
833 	KASSERT(sc->sc_busy == 0);
834 	sc->sc_busy = 1;
835 
836 	memset(&hdr, 0, sizeof(hdr));
837 	hdr.hdr_len = sizeof(hdr);
838 	hdr.chan = MTP_CHAN_CMD;
839 	hdr.pkt_len = roundup(len, 4) + sizeof(shdr);
840 	if (iface == MTP_IFACE_COMM)
841 		hdr.seq = sc->sc_seq_comm++;
842 	else if (iface == sc->sc_iface_kbd)
843 		hdr.seq = sc->sc_seq_kbd++;
844 	else if (iface == sc->sc_iface_mt)
845 		hdr.seq = sc->sc_seq_mt++;
846 	else if (iface == sc->sc_iface_stm)
847 		hdr.seq = sc->sc_seq_stm++;
848 	hdr.iface = iface;
849 	sc->sc_cmd_iface = hdr.iface;
850 	sc->sc_cmd_seq = hdr.seq;
851 	memset(&shdr, 0, sizeof(shdr));
852 	shdr.flags = flags;
853 	shdr.len = len;
854 	apldchidev_write(sc, &hdr, sizeof(hdr), &checksum);
855 	apldchidev_write(sc, &shdr, sizeof(shdr), &checksum);
856 	apldchidev_write(sc, data, len & ~3, &checksum);
857 	if (len & 3) {
858 		memset(pad, 0, sizeof(pad));
859 		memcpy(pad, &data[len & ~3], len & 3);
860 		apldchidev_write(sc, pad, sizeof(pad), &checksum);
861 	}
862 	apldchidev_write(sc, &checksum, sizeof(checksum), NULL);
863 }
864 
865 void
apldchidev_wait(struct apldchidev_softc * sc)866 apldchidev_wait(struct apldchidev_softc *sc)
867 {
868 	int retry, error;
869 
870 	if (cold) {
871 		for (retry = 10; retry > 0; retry--) {
872 			if (sc->sc_busy == 0)
873 				break;
874 			apldchidev_rx_intr(sc);
875 			delay(1000);
876 		}
877 		return;
878 	}
879 
880 	while (sc->sc_busy) {
881 		error = tsleep_nsec(sc, PZERO, "apldcwt", SEC_TO_NSEC(1));
882 		if (error == EWOULDBLOCK)
883 			return;
884 	}
885 
886 	if (sc->sc_retcode) {
887 		printf("%s: command failed with error 0x%04x\n",
888 		    sc->sc_dev.dv_xname, sc->sc_retcode);
889 	}
890 }
891 
892 void
apldchidev_enable(struct apldchidev_softc * sc,uint8_t iface)893 apldchidev_enable(struct apldchidev_softc *sc, uint8_t iface)
894 {
895 	uint8_t cmd[2] = { MTP_CMD_ENABLE_INTERFACE, iface };
896 	uint8_t flags;
897 
898 	flags = MTP_GROUP_CMD << MTP_GROUP_SHIFT;
899 	flags |= MTP_REQ_SET_REPORT << MTP_REQ_SHIFT;
900 	apldchidev_cmd(sc, MTP_IFACE_COMM, flags, cmd, sizeof(cmd));
901 	apldchidev_wait(sc);
902 }
903 
904 void
apldchidev_reset(struct apldchidev_softc * sc,uint8_t iface,uint8_t state)905 apldchidev_reset(struct apldchidev_softc *sc, uint8_t iface, uint8_t state)
906 {
907 	uint8_t cmd[4] = { MTP_CMD_RESET_INTERFACE, 1, iface, state };
908 	uint8_t flags;
909 
910 	flags = MTP_GROUP_CMD << MTP_GROUP_SHIFT;
911 	flags |= MTP_REQ_SET_REPORT << MTP_REQ_SHIFT;
912 	apldchidev_cmd(sc, MTP_IFACE_COMM, flags, cmd, sizeof(cmd));
913 	apldchidev_wait(sc);
914 }
915 
916 #if NAPLDCMS > 0
917 
918 int
apldchidev_send_firmware(struct apldchidev_softc * sc,int iface,void * ucode,size_t ucode_size)919 apldchidev_send_firmware(struct apldchidev_softc *sc, int iface,
920     void *ucode, size_t ucode_size)
921 {
922 	bus_dmamap_t map;
923 	bus_dma_segment_t seg;
924 	uint8_t cmd[16] = {};
925 	uint64_t addr;
926 	uint32_t size;
927 	uint8_t flags;
928 	caddr_t buf;
929 	int nsegs;
930 	int error;
931 
932 	error = bus_dmamap_create(sc->sc_dmat, ucode_size, 1, ucode_size, 0,
933 	    BUS_DMA_WAITOK, &map);
934 	if (error)
935 		return error;
936 
937 	error = bus_dmamem_alloc(sc->sc_dmat, ucode_size, 4 * PAGE_SIZE, 0,
938 	    &seg, 1, &nsegs, BUS_DMA_WAITOK);
939 	if (error) {
940 		bus_dmamap_destroy(sc->sc_dmat, map);
941 		return error;
942 	}
943 
944 	error = bus_dmamem_map(sc->sc_dmat, &seg, 1, ucode_size, &buf,
945 	    BUS_DMA_WAITOK);
946 	if (error) {
947 		bus_dmamem_free(sc->sc_dmat, &seg, 1);
948 		bus_dmamap_destroy(sc->sc_dmat, map);
949 		return error;
950 	}
951 
952 	error = bus_dmamap_load_raw(sc->sc_dmat, map, &seg, 1,
953 	    ucode_size, BUS_DMA_WAITOK);
954 	if (error) {
955 		bus_dmamem_unmap(sc->sc_dmat, buf, ucode_size);
956 		bus_dmamem_free(sc->sc_dmat, &seg, 1);
957 		bus_dmamap_destroy(sc->sc_dmat, map);
958 		return error;
959 	}
960 
961 	memcpy(buf, ucode, ucode_size);
962 	bus_dmamap_sync(sc->sc_dmat, map, 0, ucode_size, BUS_DMASYNC_PREWRITE);
963 
964 	cmd[0] = MTP_CMD_SEND_FIRMWARE;
965 	cmd[1] = 2;
966 	cmd[2] = 0;
967 	cmd[3] = iface;
968 	addr = map->dm_segs[0].ds_addr;
969 	memcpy(&cmd[4], &addr, sizeof(addr));
970 	size = map->dm_segs[0].ds_len;
971 	memcpy(&cmd[12], &size, sizeof(size));
972 
973 	flags = MTP_GROUP_CMD << MTP_GROUP_SHIFT;
974 	flags |= MTP_REQ_SET_REPORT << MTP_REQ_SHIFT;
975 	apldchidev_cmd(sc, MTP_IFACE_COMM, flags, cmd, sizeof(cmd));
976 	apldchidev_wait(sc);
977 
978 	bus_dmamap_unload(sc->sc_dmat, map);
979 	bus_dmamem_unmap(sc->sc_dmat, buf, ucode_size);
980 	bus_dmamem_free(sc->sc_dmat, &seg, 1);
981 	bus_dmamap_destroy(sc->sc_dmat, map);
982 
983 	return 0;
984 }
985 
986 struct mtp_fwhdr {
987 	uint32_t magic;
988 #define MTP_FW_MAGIC	0x46444948
989 	uint32_t version;
990 #define MTP_FW_VERSION	1
991 	uint32_t hdr_len;
992 	uint32_t data_len;
993 	uint32_t iface_off;
994 };
995 
996 int
apldchidev_load_firmware(struct apldchidev_softc * sc,const char * name)997 apldchidev_load_firmware(struct apldchidev_softc *sc, const char *name)
998 {
999 	struct mtp_fwhdr *hdr;
1000 	uint8_t *ucode;
1001 	size_t ucode_size;
1002 	uint8_t *data;
1003 	size_t size;
1004 	int error;
1005 
1006 	error = loadfirmware(name, &ucode, &ucode_size);
1007 	if (error) {
1008 		printf("%s: error %d, could not read firmware %s\n",
1009 		    sc->sc_dev.dv_xname, error, name);
1010 		return error;
1011 	}
1012 
1013 	hdr = (struct mtp_fwhdr *)ucode;
1014 	if (sizeof(hdr) > ucode_size ||
1015 	    hdr->hdr_len + hdr->data_len > ucode_size) {
1016 		printf("%s: loaded firmware is too small\n",
1017 		    sc->sc_dev.dv_xname);
1018 		return EINVAL;
1019 	}
1020 	if (hdr->magic != MTP_FW_MAGIC) {
1021 		printf("%s: wrong firmware magic number 0x%08x\n",
1022 		    sc->sc_dev.dv_xname, hdr->magic);
1023 		return EINVAL;
1024 	}
1025 	if (hdr->version != MTP_FW_VERSION) {
1026 		printf("%s: wrong firmware version %d\n",
1027 		    sc->sc_dev.dv_xname, hdr->version);
1028 		return EINVAL;
1029 	}
1030 	data = ucode + hdr->hdr_len;
1031 	if (hdr->iface_off)
1032 		data[hdr->iface_off] = sc->sc_iface_mt;
1033 	size = hdr->data_len;
1034 
1035 	apldchidev_send_firmware(sc, sc->sc_iface_mt, data, size);
1036 	apldchidev_reset(sc, sc->sc_iface_mt, 0);
1037 	apldchidev_reset(sc, sc->sc_iface_mt, 2);
1038 
1039 	/* Wait until ready. */
1040 	while (sc->sc_mt_ready == 0) {
1041 		error = tsleep_nsec(sc, PZERO, "apldcmt", SEC_TO_NSEC(2));
1042 		if (error == EWOULDBLOCK)
1043 			return error;
1044 	}
1045 
1046 	return 0;
1047 }
1048 
1049 void
apldchidev_get_dimensions(struct apldchidev_softc * sc)1050 apldchidev_get_dimensions(struct apldchidev_softc *sc)
1051 {
1052 	uint8_t cmd[1] = { MTP_CMD_GET_DIMENSIONS };
1053 	struct mtp_dim dim;
1054 	uint8_t flags;
1055 
1056 	flags = MTP_GROUP_CMD << MTP_GROUP_SHIFT;
1057 	flags |= MTP_REQ_GET_REPORT << MTP_REQ_SHIFT;
1058 	apldchidev_cmd(sc, sc->sc_iface_mt, flags, cmd, sizeof(cmd));
1059 	apldchidev_wait(sc);
1060 
1061 	if (sc->sc_retcode == 0 && sc->sc_data_len == sizeof(dim) + 1 &&
1062 	    sc->sc_data[0] == MTP_CMD_GET_DIMENSIONS) {
1063 		memcpy(&dim, &sc->sc_data[1], sizeof(dim));
1064 		sc->sc_x_min = dim.x_min;
1065 		sc->sc_x_max = dim.x_max;
1066 		sc->sc_y_min = dim.y_min;
1067 		sc->sc_y_max = dim.y_max;
1068 		sc->sc_h_res = (100 * (dim.x_max - dim.x_min)) / dim.width;
1069 		sc->sc_v_res = (100 * (dim.y_max - dim.y_min)) / dim.height;
1070 	}
1071 }
1072 
1073 void
apldchidev_attachhook(struct device * self)1074 apldchidev_attachhook(struct device *self)
1075 {
1076 	struct apldchidev_softc *sc = (struct apldchidev_softc *)self;
1077 	struct apldchidev_attach_args aa;
1078 	char *firmware_name;
1079 	int node, len;
1080 	int retry;
1081 	int error;
1082 
1083 	/* Enable interface. */
1084 	apldchidev_enable(sc, sc->sc_iface_mt);
1085 
1086 	node = OF_getnodebyname(sc->sc_node, "multi-touch");
1087 	if (node == -1)
1088 		return;
1089 	len = OF_getproplen(node, "firmware-name");
1090 	if (len <= 0)
1091 		return;
1092 
1093 	/* Wait until we have received the multi-touch HID descriptor. */
1094 	while (sc->sc_mtdesclen == 0) {
1095 		error = tsleep_nsec(sc, PZERO, "apldcmt", SEC_TO_NSEC(1));
1096 		if (error == EWOULDBLOCK)
1097 			return;
1098 	}
1099 
1100 	firmware_name = malloc(len, M_TEMP, M_WAITOK);
1101 	OF_getprop(node, "firmware-name", firmware_name, len);
1102 
1103 	for (retry = 5; retry > 0; retry--) {
1104 		error = apldchidev_load_firmware(sc, firmware_name);
1105 		if (error != EWOULDBLOCK)
1106 			break;
1107 	}
1108 	if (error)
1109 		goto out;
1110 
1111 	apldchidev_get_dimensions(sc);
1112 
1113 	aa.aa_name = "multi-touch";
1114 	aa.aa_desc = sc->sc_mtdesc;
1115 	aa.aa_desclen = sc->sc_mtdesclen;
1116 	sc->sc_mt = config_found(self, &aa, NULL);
1117 
1118 out:
1119 	free(firmware_name, M_TEMP, len);
1120 }
1121 
1122 #endif
1123 
1124 void
apldchidev_set_leds(struct apldchidev_softc * sc,uint8_t leds)1125 apldchidev_set_leds(struct apldchidev_softc *sc, uint8_t leds)
1126 {
1127 	uint8_t report[2] = { 1, leds };
1128 	uint8_t flags;
1129 
1130 	flags = MTP_GROUP_OUTPUT << MTP_GROUP_SHIFT;
1131 	flags |= MTP_REQ_SET_REPORT << MTP_REQ_SHIFT;
1132 	apldchidev_cmd(sc, sc->sc_iface_kbd, flags, report, sizeof(report));
1133 }
1134 
1135 /* Keyboard */
1136 
1137 struct apldckbd_softc {
1138 	struct device		sc_dev;
1139 	struct apldchidev_softc	*sc_hidev;
1140 	struct hidkbd		sc_kbd;
1141 	int			sc_spl;
1142 };
1143 
1144 void	apldckbd_cngetc(void *, u_int *, int *);
1145 void	apldckbd_cnpollc(void *, int);
1146 void	apldckbd_cnbell(void *, u_int, u_int, u_int);
1147 
1148 const struct wskbd_consops apldckbd_consops = {
1149 	apldckbd_cngetc,
1150 	apldckbd_cnpollc,
1151 	apldckbd_cnbell,
1152 };
1153 
1154 int	apldckbd_enable(void *, int);
1155 void	apldckbd_set_leds(void *, int);
1156 int	apldckbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
1157 
1158 const struct wskbd_accessops apldckbd_accessops = {
1159 	.enable = apldckbd_enable,
1160 	.ioctl = apldckbd_ioctl,
1161 	.set_leds = apldckbd_set_leds,
1162 };
1163 
1164 int	 apldckbd_match(struct device *, void *, void *);
1165 void	 apldckbd_attach(struct device *, struct device *, void *);
1166 
1167 const struct cfattach apldckbd_ca = {
1168 	sizeof(struct apldckbd_softc), apldckbd_match, apldckbd_attach
1169 };
1170 
1171 struct cfdriver apldckbd_cd = {
1172 	NULL, "apldckbd", DV_DULL
1173 };
1174 
1175 int
apldckbd_match(struct device * parent,void * match,void * aux)1176 apldckbd_match(struct device *parent, void *match, void *aux)
1177 {
1178 	struct apldchidev_attach_args *aa = aux;
1179 
1180 	return strcmp(aa->aa_name, "keyboard") == 0;
1181 }
1182 
1183 void
apldckbd_attach(struct device * parent,struct device * self,void * aux)1184 apldckbd_attach(struct device *parent, struct device *self, void *aux)
1185 {
1186 	struct apldckbd_softc *sc = (struct apldckbd_softc *)self;
1187 	struct apldchidev_attach_args *aa = aux;
1188 	struct hidkbd *kbd = &sc->sc_kbd;
1189 
1190 #define APLHIDEV_KBD_DEVICE	1
1191 	sc->sc_hidev = (struct apldchidev_softc *)parent;
1192 	if (hidkbd_attach(self, kbd, 1, 0, APLHIDEV_KBD_DEVICE,
1193 	    aa->aa_desc, aa->aa_desclen))
1194 		return;
1195 
1196 	printf("\n");
1197 
1198 	if (hid_locate(aa->aa_desc, aa->aa_desclen, HID_USAGE2(HUP_APPLE, HUG_FN_KEY),
1199 	    1, hid_input, &kbd->sc_fn, NULL))
1200 		kbd->sc_munge = hidkbd_apple_munge;
1201 
1202 	if (kbd->sc_console_keyboard) {
1203 		extern struct wskbd_mapdata ukbd_keymapdata;
1204 
1205 		ukbd_keymapdata.layout = KB_US | KB_DEFAULT;
1206 		wskbd_cnattach(&apldckbd_consops, sc, &ukbd_keymapdata);
1207 		apldckbd_enable(sc, 1);
1208 	}
1209 
1210 	hidkbd_attach_wskbd(kbd, KB_US | KB_DEFAULT, &apldckbd_accessops);
1211 }
1212 
1213 void
apldckbd_intr(struct device * self,uint8_t * packet,size_t packetlen)1214 apldckbd_intr(struct device *self, uint8_t *packet, size_t packetlen)
1215 {
1216 	struct apldckbd_softc *sc = (struct apldckbd_softc *)self;
1217 	struct hidkbd *kbd = &sc->sc_kbd;
1218 
1219 	if (kbd->sc_enabled)
1220 		hidkbd_input(kbd, &packet[1], packetlen - 1);
1221 }
1222 
1223 int
apldckbd_enable(void * v,int on)1224 apldckbd_enable(void *v, int on)
1225 {
1226 	struct apldckbd_softc *sc = v;
1227 	struct hidkbd *kbd = &sc->sc_kbd;
1228 
1229 	return hidkbd_enable(kbd, on);
1230 }
1231 
1232 int
apldckbd_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)1233 apldckbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
1234 {
1235 	struct apldckbd_softc *sc = v;
1236 	struct hidkbd *kbd = &sc->sc_kbd;
1237 
1238 	switch (cmd) {
1239 	case WSKBDIO_GTYPE:
1240 		/* XXX: should we set something else? */
1241 		*(u_int *)data = WSKBD_TYPE_USB;
1242 		return 0;
1243 	case WSKBDIO_SETLEDS:
1244 		apldckbd_set_leds(v, *(int *)data);
1245 		return 0;
1246 	default:
1247 		return hidkbd_ioctl(kbd, cmd, data, flag, p);
1248 	}
1249 }
1250 
1251 void
apldckbd_set_leds(void * v,int leds)1252 apldckbd_set_leds(void *v, int leds)
1253 {
1254 	struct apldckbd_softc *sc = v;
1255 	struct hidkbd *kbd = &sc->sc_kbd;
1256 	uint8_t res;
1257 
1258 	if (hidkbd_set_leds(kbd, leds, &res))
1259 		apldchidev_set_leds(sc->sc_hidev, res);
1260 }
1261 
1262 /* Console interface. */
1263 void
apldckbd_cngetc(void * v,u_int * type,int * data)1264 apldckbd_cngetc(void *v, u_int *type, int *data)
1265 {
1266 	struct apldckbd_softc *sc = v;
1267 	struct hidkbd *kbd = &sc->sc_kbd;
1268 
1269 	kbd->sc_polling = 1;
1270 	while (kbd->sc_npollchar <= 0) {
1271 		apldchidev_rx_intr(sc->sc_dev.dv_parent);
1272 		delay(1000);
1273 	}
1274 	kbd->sc_polling = 0;
1275 	hidkbd_cngetc(kbd, type, data);
1276 }
1277 
1278 void
apldckbd_cnpollc(void * v,int on)1279 apldckbd_cnpollc(void *v, int on)
1280 {
1281 	struct apldckbd_softc *sc = v;
1282 
1283 	if (on)
1284 		sc->sc_spl = spltty();
1285 	else
1286 		splx(sc->sc_spl);
1287 }
1288 
1289 void
apldckbd_cnbell(void * v,u_int pitch,u_int period,u_int volume)1290 apldckbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
1291 {
1292 	hidkbd_bell(pitch, period, volume, 1);
1293 }
1294 
1295 #if NAPLDCMS > 0
1296 
1297 /* Touchpad */
1298 
1299 /*
1300  * The contents of the touchpad event packets is identical to those
1301  * used by the ubcmtp(4) driver.  The relevant definitions and the
1302  * code to decode the packets is replicated here.
1303  */
1304 
1305 struct ubcmtp_finger {
1306 	uint16_t	origin;
1307 	uint16_t	abs_x;
1308 	uint16_t	abs_y;
1309 	uint16_t	rel_x;
1310 	uint16_t	rel_y;
1311 	uint16_t	tool_major;
1312 	uint16_t	tool_minor;
1313 	uint16_t	orientation;
1314 	uint16_t	touch_major;
1315 	uint16_t	touch_minor;
1316 	uint16_t	unused[2];
1317 	uint16_t	pressure;
1318 	uint16_t	multi;
1319 } __packed __attribute((aligned(2)));
1320 
1321 #define UBCMTP_MAX_FINGERS	16
1322 
1323 #define UBCMTP_TYPE4_TPOFF	(20 * sizeof(uint16_t))
1324 #define UBCMTP_TYPE4_BTOFF	23
1325 #define UBCMTP_TYPE4_FINGERPAD	(1 * sizeof(uint16_t))
1326 
1327 /* Use a constant, synaptics-compatible pressure value for now. */
1328 #define DEFAULT_PRESSURE	40
1329 
1330 struct apldcms_softc {
1331 	struct device		sc_dev;
1332 	struct apldchidev_softc	*sc_hidev;
1333 	struct device		*sc_wsmousedev;
1334 
1335 	int			sc_enabled;
1336 
1337 	int			tp_offset;
1338 	int			tp_fingerpad;
1339 
1340 	struct mtpoint		frame[UBCMTP_MAX_FINGERS];
1341 	int			contacts;
1342 	int			btn;
1343 };
1344 
1345 int	apldcms_enable(void *);
1346 void	apldcms_disable(void *);
1347 int	apldcms_ioctl(void *, u_long, caddr_t, int, struct proc *);
1348 
1349 static struct wsmouse_param apldcms_wsmousecfg[] = {
1350 	{ WSMOUSECFG_MTBTN_MAXDIST, 0 }, /* 0: Compute a default value. */
1351 };
1352 
1353 const struct wsmouse_accessops apldcms_accessops = {
1354 	.enable = apldcms_enable,
1355 	.disable = apldcms_disable,
1356 	.ioctl = apldcms_ioctl,
1357 };
1358 
1359 int	 apldcms_match(struct device *, void *, void *);
1360 void	 apldcms_attach(struct device *, struct device *, void *);
1361 
1362 const struct cfattach apldcms_ca = {
1363 	sizeof(struct apldcms_softc), apldcms_match, apldcms_attach
1364 };
1365 
1366 struct cfdriver apldcms_cd = {
1367 	NULL, "apldcms", DV_DULL
1368 };
1369 
1370 int	apldcms_configure(struct apldcms_softc *);
1371 
1372 int
apldcms_match(struct device * parent,void * match,void * aux)1373 apldcms_match(struct device *parent, void *match, void *aux)
1374 {
1375 	struct apldchidev_attach_args *aa = aux;
1376 
1377 	return strcmp(aa->aa_name, "multi-touch") == 0;
1378 }
1379 
1380 void
apldcms_attach(struct device * parent,struct device * self,void * aux)1381 apldcms_attach(struct device *parent, struct device *self, void *aux)
1382 {
1383 	struct apldcms_softc *sc = (struct apldcms_softc *)self;
1384 	struct wsmousedev_attach_args aa;
1385 
1386 	sc->sc_hidev = (struct apldchidev_softc *)parent;
1387 
1388 	printf("\n");
1389 
1390 	sc->tp_offset = UBCMTP_TYPE4_TPOFF;
1391 	sc->tp_fingerpad = UBCMTP_TYPE4_FINGERPAD;
1392 
1393 	aa.accessops = &apldcms_accessops;
1394 	aa.accesscookie = sc;
1395 
1396 	sc->sc_wsmousedev = config_found(self, &aa, wsmousedevprint);
1397 	if (sc->sc_wsmousedev != NULL && apldcms_configure(sc))
1398 		apldcms_disable(sc);
1399 }
1400 
1401 int
apldcms_configure(struct apldcms_softc * sc)1402 apldcms_configure(struct apldcms_softc *sc)
1403 {
1404 	struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev);
1405 
1406 	hw->type = WSMOUSE_TYPE_TOUCHPAD;
1407 	hw->hw_type = WSMOUSEHW_CLICKPAD;
1408 	hw->x_min = sc->sc_hidev->sc_x_min;
1409 	hw->x_max = sc->sc_hidev->sc_x_max;
1410 	hw->y_min = sc->sc_hidev->sc_y_min;
1411 	hw->y_max = sc->sc_hidev->sc_y_max;
1412 	hw->h_res = sc->sc_hidev->sc_h_res;
1413 	hw->v_res = sc->sc_hidev->sc_v_res;
1414 	hw->mt_slots = UBCMTP_MAX_FINGERS;
1415 	hw->flags = WSMOUSEHW_MT_TRACKING;
1416 
1417 	return wsmouse_configure(sc->sc_wsmousedev, apldcms_wsmousecfg,
1418 	    nitems(apldcms_wsmousecfg));
1419 }
1420 
1421 void
apldcms_intr(struct device * self,uint8_t * packet,size_t packetlen)1422 apldcms_intr(struct device *self, uint8_t *packet, size_t packetlen)
1423 {
1424 	struct apldcms_softc *sc = (struct apldcms_softc *)self;
1425 	struct ubcmtp_finger *finger;
1426 	int off, s, btn, contacts;
1427 
1428 	if (!sc->sc_enabled)
1429 		return;
1430 
1431 	contacts = 0;
1432 	for (off = sc->tp_offset; off < packetlen;
1433 	    off += (sizeof(struct ubcmtp_finger) + sc->tp_fingerpad)) {
1434 		finger = (struct ubcmtp_finger *)(packet + off);
1435 
1436 		if ((int16_t)letoh16(finger->touch_major) == 0)
1437 			continue; /* finger lifted */
1438 
1439 		sc->frame[contacts].x = (int16_t)letoh16(finger->abs_x);
1440 		sc->frame[contacts].y = (int16_t)letoh16(finger->abs_y);
1441 		sc->frame[contacts].pressure = DEFAULT_PRESSURE;
1442 		contacts++;
1443 	}
1444 
1445 	btn = sc->btn;
1446 	sc->btn = !!((int16_t)letoh16(packet[UBCMTP_TYPE4_BTOFF]));
1447 
1448 	if (contacts || sc->contacts || sc->btn != btn) {
1449 		sc->contacts = contacts;
1450 		s = spltty();
1451 		wsmouse_buttons(sc->sc_wsmousedev, sc->btn);
1452 		wsmouse_mtframe(sc->sc_wsmousedev, sc->frame, contacts);
1453 		wsmouse_input_sync(sc->sc_wsmousedev);
1454 		splx(s);
1455 	}
1456 }
1457 
1458 int
apldcms_enable(void * v)1459 apldcms_enable(void *v)
1460 {
1461 	struct apldcms_softc *sc = v;
1462 
1463 	if (sc->sc_enabled)
1464 		return EBUSY;
1465 
1466 	sc->sc_enabled = 1;
1467 	return 0;
1468 }
1469 
1470 void
apldcms_disable(void * v)1471 apldcms_disable(void *v)
1472 {
1473 	struct apldcms_softc *sc = v;
1474 
1475 	sc->sc_enabled = 0;
1476 }
1477 
1478 int
apldcms_ioctl(void * v,u_long cmd,caddr_t data,int flag,struct proc * p)1479 apldcms_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
1480 {
1481 	struct apldcms_softc *sc = v;
1482 	struct wsmousehw *hw = wsmouse_get_hw(sc->sc_wsmousedev);
1483 	struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
1484 	int wsmode;
1485 
1486 	switch (cmd) {
1487 	case WSMOUSEIO_GTYPE:
1488 		*(u_int *)data = hw->type;
1489 		break;
1490 
1491 	case WSMOUSEIO_GCALIBCOORDS:
1492 		wsmc->minx = hw->x_min;
1493 		wsmc->maxx = hw->x_max;
1494 		wsmc->miny = hw->y_min;
1495 		wsmc->maxy = hw->y_max;
1496 		wsmc->swapxy = 0;
1497 		wsmc->resx = 0;
1498 		wsmc->resy = 0;
1499 		break;
1500 
1501 	case WSMOUSEIO_SETMODE:
1502 		wsmode = *(u_int *)data;
1503 		if (wsmode != WSMOUSE_COMPAT && wsmode != WSMOUSE_NATIVE) {
1504 			printf("%s: invalid mode %d\n", sc->sc_dev.dv_xname,
1505 			    wsmode);
1506 			return (EINVAL);
1507 		}
1508 		wsmouse_set_mode(sc->sc_wsmousedev, wsmode);
1509 		break;
1510 
1511 	default:
1512 		return -1;
1513 	}
1514 
1515 	return 0;
1516 }
1517 
1518 #else
1519 
1520 void
apldcms_intr(struct device * self,uint8_t * packet,size_t packetlen)1521 apldcms_intr(struct device *self, uint8_t *packet, size_t packetlen)
1522 {
1523 }
1524 
1525 #endif
1526