1 /* $NetBSD: tctrl.c,v 1.65 2021/09/26 16:36:19 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 2005, 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: tctrl.c,v 1.65 2021/09/26 16:36:19 thorpej Exp $");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/ioctl.h>
38 #include <sys/select.h>
39 #include <sys/tty.h>
40 #include <sys/proc.h>
41 #include <sys/conf.h>
42 #include <sys/file.h>
43 #include <sys/uio.h>
44 #include <sys/kernel.h>
45 #include <sys/kthread.h>
46 #include <sys/syslog.h>
47 #include <sys/types.h>
48 #include <sys/device.h>
49 #include <sys/envsys.h>
50 #include <sys/poll.h>
51 #include <sys/kauth.h>
52
53 #include <machine/apmvar.h>
54 #include <machine/autoconf.h>
55 #include <sys/bus.h>
56 #include <machine/intr.h>
57 #include <machine/tctrl.h>
58
59 #include <sparc/dev/ts102reg.h>
60 #include <sparc/dev/tctrlvar.h>
61 #include <sparc/sparc/auxiotwo.h>
62 #include <sparc/sparc/auxreg.h>
63
64 #include <dev/sysmon/sysmonvar.h>
65 #include <dev/sysmon/sysmon_taskq.h>
66
67 #include "sysmon_envsys.h"
68
69 /*#define TCTRLDEBUG*/
70
71 /* disk spinner */
72 #include <sys/disk.h>
73 #include <dev/scsipi/sdvar.h>
74
75 /* ethernet carrier */
76 #include <net/if.h>
77 #include <net/if_dl.h>
78 #include <net/if_ether.h>
79 #include <net/if_media.h>
80 #include <dev/ic/lancevar.h>
81
82 extern struct cfdriver tctrl_cd;
83
84 dev_type_open(tctrlopen);
85 dev_type_close(tctrlclose);
86 dev_type_ioctl(tctrlioctl);
87 dev_type_poll(tctrlpoll);
88 dev_type_kqfilter(tctrlkqfilter);
89
90 const struct cdevsw tctrl_cdevsw = {
91 .d_open = tctrlopen,
92 .d_close = tctrlclose,
93 .d_read = noread,
94 .d_write = nowrite,
95 .d_ioctl = tctrlioctl,
96 .d_stop = nostop,
97 .d_tty = notty,
98 .d_poll = tctrlpoll,
99 .d_mmap = nommap,
100 .d_kqfilter = tctrlkqfilter,
101 .d_discard = nodiscard,
102 .d_flag = 0
103 };
104
105 static const char *tctrl_ext_statuses[16] = {
106 "main power available",
107 "internal battery attached",
108 "external battery attached",
109 "external VGA attached",
110 "external keyboard attached",
111 "external mouse attached",
112 "lid down",
113 "internal battery charging",
114 "external battery charging",
115 "internal battery discharging",
116 "external battery discharging",
117 };
118
119 struct tctrl_softc {
120 device_t sc_dev;
121 bus_space_tag_t sc_memt;
122 bus_space_handle_t sc_memh;
123 unsigned int sc_junk;
124 unsigned int sc_ext_status;
125 unsigned int sc_flags;
126 #define TCTRL_SEND_REQUEST 0x0001
127 #define TCTRL_APM_CTLOPEN 0x0002
128 uint32_t sc_wantdata;
129 uint32_t sc_ext_pending;
130 volatile uint16_t sc_lcdstate;
131 uint16_t sc_lcdwanted;
132
133 enum { TCTRL_IDLE, TCTRL_ARGS,
134 TCTRL_ACK, TCTRL_DATA } sc_state;
135 uint8_t sc_cmdbuf[16];
136 uint8_t sc_rspbuf[16];
137 uint8_t sc_bitport;
138 uint8_t sc_tft_on;
139 uint8_t sc_op;
140 uint8_t sc_cmdoff;
141 uint8_t sc_cmdlen;
142 uint8_t sc_rspoff;
143 uint8_t sc_rsplen;
144 /* APM stuff */
145 #define APM_NEVENTS 16
146 struct apm_event_info sc_event_list[APM_NEVENTS];
147 int sc_event_count;
148 int sc_event_ptr;
149 struct selinfo sc_rsel;
150
151 /* ENVSYS stuff */
152 #define ENVSYS_NUMSENSORS 3
153 struct evcnt sc_intrcnt; /* interrupt counting */
154 struct sysmon_envsys *sc_sme;
155 envsys_data_t sc_sensor[ENVSYS_NUMSENSORS];
156
157 struct sysmon_pswitch sc_sm_pbutton; /* power button */
158 struct sysmon_pswitch sc_sm_lid; /* lid state */
159 struct sysmon_pswitch sc_sm_ac; /* AC adaptor presence */
160 int sc_powerpressed;
161
162 /* hardware status stuff */
163 int sc_lid; /* 1 - open, 0 - closed */
164 int sc_power_state;
165 int sc_spl;
166
167 /*
168 * we call this when we detect connection or removal of an external
169 * monitor. 0 for no monitor, !=0 for monitor present
170 */
171 void (*sc_video_callback)(void *, int);
172 void *sc_video_callback_cookie;
173 int sc_extvga;
174
175 uint32_t sc_events;
176 lwp_t *sc_thread; /* event thread */
177 kmutex_t sc_requestlock;
178 };
179
180 #define TCTRL_STD_DEV 0
181 #define TCTRL_APMCTL_DEV 8
182
183 static int tctrl_match(device_t, cfdata_t, void *);
184 static void tctrl_attach(device_t, device_t, void *);
185 static void tctrl_write(struct tctrl_softc *, bus_size_t, uint8_t);
186 static uint8_t tctrl_read(struct tctrl_softc *, bus_size_t);
187 static void tctrl_write_data(struct tctrl_softc *, uint8_t);
188 static uint8_t tctrl_read_data(struct tctrl_softc *);
189 static int tctrl_intr(void *);
190 static void tctrl_setup_bitport(void);
191 static void tctrl_setup_bitport_nop(void);
192 static void tctrl_read_ext_status(void);
193 static void tctrl_read_event_status(struct tctrl_softc *);
194 static int tctrl_apm_record_event(struct tctrl_softc *, u_int);
195 static void tctrl_init_lcd(void);
196
197 static void tctrl_sensor_setup(struct tctrl_softc *);
198 static void tctrl_refresh(struct sysmon_envsys *, envsys_data_t *);
199
200 static void tctrl_power_button_pressed(void *);
201 static void tctrl_lid_state(struct tctrl_softc *);
202 static void tctrl_ac_state(struct tctrl_softc *);
203
204 static int tctrl_powerfail(void *);
205
206 static void tctrl_event_thread(void *);
207 void tctrl_update_lcd(struct tctrl_softc *);
208
209 static void tctrl_lock(struct tctrl_softc *);
210 static void tctrl_unlock(struct tctrl_softc *);
211
212 CFATTACH_DECL_NEW(tctrl, sizeof(struct tctrl_softc),
213 tctrl_match, tctrl_attach, NULL, NULL);
214
215 static int tadpole_request(struct tctrl_req *, int, int);
216
217 /* XXX wtf is this? see i386/apm.c */
218 int tctrl_apm_evindex;
219
220 static int
tctrl_match(device_t parent,cfdata_t cf,void * aux)221 tctrl_match(device_t parent, cfdata_t cf, void *aux)
222 {
223 union obio_attach_args *uoba = aux;
224 struct sbus_attach_args *sa = &uoba->uoba_sbus;
225
226 if (uoba->uoba_isobio4 != 0) {
227 return (0);
228 }
229
230 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
231 * (who's interface is off the TS102 PCMCIA controller but there
232 * exists a OpenProm for microcontroller interface).
233 */
234 return strcmp("uctrl", sa->sa_name) == 0;
235 }
236
237 static void
tctrl_attach(device_t parent,device_t self,void * aux)238 tctrl_attach(device_t parent, device_t self, void *aux)
239 {
240 struct tctrl_softc *sc = device_private(self);
241 union obio_attach_args *uoba = aux;
242 struct sbus_attach_args *sa = &uoba->uoba_sbus;
243 unsigned int i, v;
244
245 /* We're living on a sbus slot that looks like an obio that
246 * looks like an sbus slot.
247 */
248 sc->sc_dev = self;
249 sc->sc_memt = sa->sa_bustag;
250 if (sbus_bus_map(sc->sc_memt,
251 sa->sa_slot,
252 sa->sa_offset - TS102_REG_UCTRL_INT,
253 sa->sa_size,
254 BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) {
255 printf(": can't map registers\n");
256 return;
257 }
258
259 printf("\n");
260
261 sc->sc_tft_on = 1;
262
263 mutex_init(&sc->sc_requestlock, MUTEX_DEFAULT, IPL_NONE);
264
265 /* clear any pending data.
266 */
267 for (i = 0; i < 10000; i++) {
268 if ((TS102_UCTRL_STS_RXNE_STA &
269 tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
270 break;
271 }
272 v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
273 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
274 }
275
276 if (sa->sa_nintr != 0) {
277 (void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE,
278 tctrl_intr, sc);
279 evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
280 device_xname(sc->sc_dev), "intr");
281 }
282
283 /* See what the external status is */
284 sc->sc_ext_status = 0;
285 tctrl_read_ext_status();
286 if (sc->sc_ext_status != 0) {
287 const char *sep;
288
289 printf("%s: ", device_xname(sc->sc_dev));
290 v = sc->sc_ext_status;
291 for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
292 if (v & 1) {
293 printf("%s%s", sep, tctrl_ext_statuses[i]);
294 sep = ", ";
295 }
296 }
297 printf("\n");
298 }
299
300 /* Get a current of the control bitport */
301 tctrl_setup_bitport_nop();
302 tctrl_write(sc, TS102_REG_UCTRL_INT,
303 TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
304 sc->sc_lid = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) == 0;
305 sc->sc_power_state = PWR_RESUME;
306
307 sc->sc_extvga = (sc->sc_ext_status &
308 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0;
309 sc->sc_video_callback = NULL;
310
311
312 sc->sc_wantdata = 0;
313 sc->sc_event_count = 0;
314 sc->sc_ext_pending = 0;
315 sc->sc_ext_pending = 0;
316
317 selinit(&sc->sc_rsel);
318
319 /* setup sensors and register the power button */
320 tctrl_sensor_setup(sc);
321 tctrl_lid_state(sc);
322 tctrl_ac_state(sc);
323
324 /* initialize the LCD */
325 tctrl_init_lcd();
326
327 /* initialize sc_lcdstate */
328 sc->sc_lcdstate = 0;
329 sc->sc_lcdwanted = 0;
330 tadpole_set_lcd(2, 0);
331
332 /* fire up the LCD event thread */
333 sc->sc_events = 0;
334
335 if (kthread_create(PRI_NONE, 0, NULL, tctrl_event_thread, sc,
336 &sc->sc_thread, "%s", device_xname(sc->sc_dev)) != 0) {
337 printf("%s: unable to create event kthread",
338 device_xname(sc->sc_dev));
339 }
340 }
341
342 static int
tctrl_intr(void * arg)343 tctrl_intr(void *arg)
344 {
345 struct tctrl_softc *sc = arg;
346 unsigned int v, d;
347 int progress = 0;
348
349 again:
350 /* find out the cause(s) of the interrupt */
351 v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK;
352
353 /* clear the cause(s) of the interrupt */
354 tctrl_write(sc, TS102_REG_UCTRL_STS, v);
355
356 v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
357 if (sc->sc_cmdoff >= sc->sc_cmdlen) {
358 v &= ~TS102_UCTRL_STS_TXNF_STA;
359 if (tctrl_read(sc, TS102_REG_UCTRL_INT) &
360 TS102_UCTRL_INT_TXNF_REQ) {
361 tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
362 progress = 1;
363 }
364 }
365 if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
366 sc->sc_state != TCTRL_IDLE)) {
367 wakeup(sc);
368 return progress;
369 }
370
371 progress = 1;
372 if (v & TS102_UCTRL_STS_RXNE_STA) {
373 d = tctrl_read_data(sc);
374 switch (sc->sc_state) {
375 case TCTRL_IDLE:
376 if (d == 0xfa) {
377 /*
378 * external event,
379 * set a flag and wakeup the event thread
380 */
381 sc->sc_ext_pending = 1;
382 } else {
383 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
384 device_xname(sc->sc_dev), sc->sc_op, d);
385 }
386 goto again;
387 case TCTRL_ACK:
388 if (d != 0xfe) {
389 printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
390 device_xname(sc->sc_dev), sc->sc_op, d);
391 }
392 #ifdef TCTRLDEBUG
393 printf(" ack=0x%02x", d);
394 #endif
395 sc->sc_rsplen--;
396 sc->sc_rspoff = 0;
397 sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
398 sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
399 #ifdef TCTRLDEBUG
400 if (sc->sc_rsplen > 0) {
401 printf(" [data(%u)]", sc->sc_rsplen);
402 } else {
403 printf(" [idle]\n");
404 }
405 #endif
406 goto again;
407 case TCTRL_DATA:
408 sc->sc_rspbuf[sc->sc_rspoff++] = d;
409 #ifdef TCTRLDEBUG
410 printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
411 #endif
412 if (sc->sc_rspoff == sc->sc_rsplen) {
413 #ifdef TCTRLDEBUG
414 printf(" [idle]\n");
415 #endif
416 sc->sc_state = TCTRL_IDLE;
417 sc->sc_wantdata = 0;
418 }
419 goto again;
420 default:
421 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
422 device_xname(sc->sc_dev), sc->sc_op, d, sc->sc_state);
423 goto again;
424 }
425 }
426 if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
427 sc->sc_flags & TCTRL_SEND_REQUEST) {
428 if (sc->sc_flags & TCTRL_SEND_REQUEST) {
429 sc->sc_flags &= ~TCTRL_SEND_REQUEST;
430 sc->sc_wantdata = 1;
431 }
432 if (sc->sc_cmdlen > 0) {
433 tctrl_write(sc, TS102_REG_UCTRL_INT,
434 tctrl_read(sc, TS102_REG_UCTRL_INT)
435 |TS102_UCTRL_INT_TXNF_MSK
436 |TS102_UCTRL_INT_TXNF_REQ);
437 v = tctrl_read(sc, TS102_REG_UCTRL_STS);
438 }
439 }
440 if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
441 tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
442 #ifdef TCTRLDEBUG
443 if (sc->sc_cmdoff == 1) {
444 printf("%s: op=0x%02x(l=%u)", device_xname(sc->sc_dev),
445 sc->sc_cmdbuf[0], sc->sc_rsplen);
446 } else {
447 printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
448 sc->sc_cmdbuf[sc->sc_cmdoff-1]);
449 }
450 #endif
451 if (sc->sc_cmdoff == sc->sc_cmdlen) {
452 sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
453 #ifdef TCTRLDEBUG
454 printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
455 #endif
456 if (sc->sc_cmdoff == 1) {
457 sc->sc_op = sc->sc_cmdbuf[0];
458 }
459 tctrl_write(sc, TS102_REG_UCTRL_INT,
460 tctrl_read(sc, TS102_REG_UCTRL_INT)
461 & (~TS102_UCTRL_INT_TXNF_MSK
462 |TS102_UCTRL_INT_TXNF_REQ));
463 } else if (sc->sc_state == TCTRL_IDLE) {
464 sc->sc_op = sc->sc_cmdbuf[0];
465 sc->sc_state = TCTRL_ARGS;
466 #ifdef TCTRLDEBUG
467 printf(" [args]");
468 #endif
469 }
470 }
471 goto again;
472 }
473
474 static void
tctrl_setup_bitport_nop(void)475 tctrl_setup_bitport_nop(void)
476 {
477 struct tctrl_softc *sc;
478 struct tctrl_req req;
479 int s;
480
481 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
482 req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
483 req.cmdbuf[1] = 0xff;
484 req.cmdbuf[2] = 0x00;
485 req.cmdlen = 3;
486 req.rsplen = 2;
487 tadpole_request(&req, 1, 0);
488 s = splts102();
489 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
490 splx(s);
491 }
492
493 static void
tctrl_setup_bitport(void)494 tctrl_setup_bitport(void)
495 {
496 struct tctrl_softc *sc;
497 struct tctrl_req req;
498 int s;
499
500 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
501 s = splts102();
502 req.cmdbuf[2] = 0;
503 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
504 || (!sc->sc_tft_on)) {
505 req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
506 }
507 req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
508 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
509 req.cmdlen = 3;
510 req.rsplen = 2;
511 tadpole_request(&req, 1, 0);
512 s = splts102();
513 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
514 splx(s);
515 }
516
517 /*
518 * The tadpole microcontroller is not preprogrammed with icon
519 * representations. The machine boots with the DC-IN light as
520 * a blank (all 0x00) and the other lights, as 4 rows of horizontal
521 * bars. The below code initializes the icons in the system to
522 * sane values. Some of these icons could be used for any purpose
523 * desired, namely the pcmcia, LAN and WAN lights. For the disk spinner,
524 * only the backslash is unprogrammed. (sigh)
525 *
526 * programming the icons is simple. It is a 5x8 matrix, which each row a
527 * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
528 */
529
530 static void
tctrl_init_lcd(void)531 tctrl_init_lcd(void)
532 {
533 struct tctrl_req req;
534
535 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
536 req.cmdlen = 11;
537 req.rsplen = 1;
538 req.cmdbuf[1] = 0x08; /*len*/
539 req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD;
540 req.cmdbuf[3] = 0x00; /* ..... */
541 req.cmdbuf[4] = 0x00; /* ..... */
542 req.cmdbuf[5] = 0x1f; /* XXXXX */
543 req.cmdbuf[6] = 0x00; /* ..... */
544 req.cmdbuf[7] = 0x15; /* X.X.X */
545 req.cmdbuf[8] = 0x00; /* ..... */
546 req.cmdbuf[9] = 0x00; /* ..... */
547 req.cmdbuf[10] = 0x00; /* ..... */
548 tadpole_request(&req, 1, 0);
549
550 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
551 req.cmdlen = 11;
552 req.rsplen = 1;
553 req.cmdbuf[1] = 0x08; /*len*/
554 req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH;
555 req.cmdbuf[3] = 0x00; /* ..... */
556 req.cmdbuf[4] = 0x10; /* X.... */
557 req.cmdbuf[5] = 0x08; /* .X... */
558 req.cmdbuf[6] = 0x04; /* ..X.. */
559 req.cmdbuf[7] = 0x02; /* ...X. */
560 req.cmdbuf[8] = 0x01; /* ....X */
561 req.cmdbuf[9] = 0x00; /* ..... */
562 req.cmdbuf[10] = 0x00; /* ..... */
563 tadpole_request(&req, 1, 0);
564
565 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
566 req.cmdlen = 11;
567 req.rsplen = 1;
568 req.cmdbuf[1] = 0x08; /*len*/
569 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1;
570 req.cmdbuf[3] = 0x0c; /* .XXX. */
571 req.cmdbuf[4] = 0x16; /* X.XX. */
572 req.cmdbuf[5] = 0x10; /* X.... */
573 req.cmdbuf[6] = 0x15; /* X.X.X */
574 req.cmdbuf[7] = 0x10; /* X.... */
575 req.cmdbuf[8] = 0x16; /* X.XX. */
576 req.cmdbuf[9] = 0x0c; /* .XXX. */
577 req.cmdbuf[10] = 0x00; /* ..... */
578 tadpole_request(&req, 1, 0);
579
580 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
581 req.cmdlen = 11;
582 req.rsplen = 1;
583 req.cmdbuf[1] = 0x08; /*len*/
584 req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2;
585 req.cmdbuf[3] = 0x0c; /* .XXX. */
586 req.cmdbuf[4] = 0x0d; /* .XX.X */
587 req.cmdbuf[5] = 0x01; /* ....X */
588 req.cmdbuf[6] = 0x15; /* X.X.X */
589 req.cmdbuf[7] = 0x01; /* ....X */
590 req.cmdbuf[8] = 0x0d; /* .XX.X */
591 req.cmdbuf[9] = 0x0c; /* .XXX. */
592 req.cmdbuf[10] = 0x00; /* ..... */
593 tadpole_request(&req, 1, 0);
594
595 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
596 req.cmdlen = 11;
597 req.rsplen = 1;
598 req.cmdbuf[1] = 0x08; /*len*/
599 req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1;
600 req.cmdbuf[3] = 0x00; /* ..... */
601 req.cmdbuf[4] = 0x04; /* ..X.. */
602 req.cmdbuf[5] = 0x08; /* .X... */
603 req.cmdbuf[6] = 0x13; /* X..XX */
604 req.cmdbuf[7] = 0x08; /* .X... */
605 req.cmdbuf[8] = 0x04; /* ..X.. */
606 req.cmdbuf[9] = 0x00; /* ..... */
607 req.cmdbuf[10] = 0x00; /* ..... */
608 tadpole_request(&req, 1, 0);
609
610 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
611 req.cmdlen = 11;
612 req.rsplen = 1;
613 req.cmdbuf[1] = 0x08; /*len*/
614 req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2;
615 req.cmdbuf[3] = 0x00; /* ..... */
616 req.cmdbuf[4] = 0x04; /* ..X.. */
617 req.cmdbuf[5] = 0x02; /* ...X. */
618 req.cmdbuf[6] = 0x19; /* XX..X */
619 req.cmdbuf[7] = 0x02; /* ...X. */
620 req.cmdbuf[8] = 0x04; /* ..X.. */
621 req.cmdbuf[9] = 0x00; /* ..... */
622 req.cmdbuf[10] = 0x00; /* ..... */
623 tadpole_request(&req, 1, 0);
624
625 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
626 req.cmdlen = 11;
627 req.rsplen = 1;
628 req.cmdbuf[1] = 0x08; /*len*/
629 req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA;
630 req.cmdbuf[3] = 0x00; /* ..... */
631 req.cmdbuf[4] = 0x0c; /* .XXX. */
632 req.cmdbuf[5] = 0x1f; /* XXXXX */
633 req.cmdbuf[6] = 0x1f; /* XXXXX */
634 req.cmdbuf[7] = 0x1f; /* XXXXX */
635 req.cmdbuf[8] = 0x1f; /* XXXXX */
636 req.cmdbuf[9] = 0x00; /* ..... */
637 req.cmdbuf[10] = 0x00; /* ..... */
638 tadpole_request(&req, 1, 0);
639 }
640
641 /* sc_lcdwanted -> lcd_state */
642 void
tctrl_update_lcd(struct tctrl_softc * sc)643 tctrl_update_lcd(struct tctrl_softc *sc)
644 {
645 struct tctrl_req req;
646 int s;
647
648 s = splhigh();
649 if (sc->sc_lcdwanted == sc->sc_lcdstate) {
650 splx(s);
651 return;
652 }
653 sc->sc_lcdstate = sc->sc_lcdwanted;
654 splx(s);
655
656 /*
657 * the mask setup on this particular command is *very* bizzare
658 * and totally undocumented.
659 */
660 req.cmdbuf[0] = TS102_OP_CTL_LCD;
661
662 /* leave caps-lock alone */
663 req.cmdbuf[2] = (u_int8_t)(sc->sc_lcdstate & 0xfe);
664 req.cmdbuf[3] = (u_int8_t)((sc->sc_lcdstate & 0x100)>>8);
665
666 req.cmdbuf[1] = 1;
667 req.cmdbuf[4] = 0;
668
669
670 /* XXX this thing is weird.... */
671 req.cmdlen = 3;
672 req.rsplen = 2;
673
674 /* below are the values one would expect but which won't work */
675 #if 0
676 req.cmdlen = 5;
677 req.rsplen = 4;
678 #endif
679 tadpole_request(&req, 1, 0);
680 }
681
682
683 /*
684 * set the blinken-lights on the lcd. what:
685 * what = 0 off, what = 1 on, what = 2 toggle
686 */
687
688 void
tadpole_set_lcd(int what,unsigned short which)689 tadpole_set_lcd(int what, unsigned short which)
690 {
691 struct tctrl_softc *sc;
692 int s;
693
694 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
695
696 s = splhigh();
697 switch (what) {
698 case 0:
699 sc->sc_lcdwanted &= ~which;
700 break;
701 case 1:
702 sc->sc_lcdwanted |= which;
703 break;
704 case 2:
705 sc->sc_lcdwanted ^= which;
706 break;
707 }
708 splx(s);
709 }
710
711 static void
tctrl_read_ext_status(void)712 tctrl_read_ext_status(void)
713 {
714 struct tctrl_softc *sc;
715 struct tctrl_req req;
716 int s;
717
718 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
719 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
720 req.cmdlen = 1;
721 req.rsplen = 3;
722 #ifdef TCTRLDEBUG
723 printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
724 #endif
725 tadpole_request(&req, 1, 0);
726 s = splts102();
727 sc->sc_ext_status = (req.rspbuf[0] << 8) + req.rspbuf[1];
728 splx(s);
729 #ifdef TCTRLDEBUG
730 printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
731 #endif
732 }
733
734 /*
735 * return 0 if the user will notice and handle the event,
736 * return 1 if the kernel driver should do so.
737 */
738 static int
tctrl_apm_record_event(struct tctrl_softc * sc,u_int event_type)739 tctrl_apm_record_event(struct tctrl_softc *sc, u_int event_type)
740 {
741 struct apm_event_info *evp;
742
743 if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
744 (sc->sc_event_count < APM_NEVENTS)) {
745 evp = &sc->sc_event_list[sc->sc_event_ptr];
746 sc->sc_event_count++;
747 sc->sc_event_ptr++;
748 sc->sc_event_ptr %= APM_NEVENTS;
749 evp->type = event_type;
750 evp->index = ++tctrl_apm_evindex;
751 selnotify(&sc->sc_rsel, 0, 0);
752 return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
753 }
754 return(1);
755 }
756
757 static void
tctrl_read_event_status(struct tctrl_softc * sc)758 tctrl_read_event_status(struct tctrl_softc *sc)
759 {
760 struct tctrl_req req;
761 int s;
762 uint32_t v;
763
764 req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
765 req.cmdlen = 1;
766 req.rsplen = 3;
767 tadpole_request(&req, 1, 0);
768 s = splts102();
769 v = req.rspbuf[0] * 256 + req.rspbuf[1];
770 #ifdef TCTRLDEBUG
771 printf("event: %x\n",v);
772 #endif
773 if (v & TS102_EVENT_STATUS_POWERON_BTN_PRESSED) {
774 printf("%s: Power button pressed\n",device_xname(sc->sc_dev));
775 tctrl_powerfail(sc);
776 }
777 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
778 printf("%s: SHUTDOWN REQUEST!\n", device_xname(sc->sc_dev));
779 tctrl_powerfail(sc);
780 }
781 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
782 /*printf("%s: VERY LOW POWER WARNING!\n", device_xname(sc->sc_dev));*/
783 /* according to a tadpole header, and observation */
784 #ifdef TCTRLDEBUG
785 printf("%s: Battery charge level change\n",
786 device_xname(sc->sc_dev));
787 #endif
788 }
789 if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
790 if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
791 printf("%s: LOW POWER WARNING!\n", device_xname(sc->sc_dev));
792 }
793 if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
794 splx(s);
795 tctrl_read_ext_status();
796 tctrl_ac_state(sc);
797 s = splts102();
798 if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
799 printf("%s: main power %s\n", device_xname(sc->sc_dev),
800 (sc->sc_ext_status &
801 TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
802 "restored" : "removed");
803 }
804 if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
805 splx(s);
806 tctrl_read_ext_status();
807 tctrl_lid_state(sc);
808 tctrl_setup_bitport();
809 #ifdef TCTRLDEBUG
810 printf("%s: lid %s\n", device_xname(sc->sc_dev),
811 (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
812 ? "closed" : "opened");
813 #endif
814 }
815 if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) {
816 int vga;
817 splx(s);
818 tctrl_read_ext_status();
819 vga = (sc->sc_ext_status &
820 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED) != 0;
821 if (vga != sc->sc_extvga) {
822 sc->sc_extvga = vga;
823 if (sc->sc_video_callback != NULL) {
824 sc->sc_video_callback(
825 sc->sc_video_callback_cookie,
826 sc->sc_extvga);
827 }
828 }
829 }
830 #ifdef DIAGNOSTIC
831 if (v & TS102_EVENT_STATUS_EXT_MOUSE_STATUS_CHANGE) {
832 splx(s);
833 tctrl_read_ext_status();
834 if (sc->sc_ext_status &
835 TS102_EXT_STATUS_EXTERNAL_MOUSE_ATTACHED) {
836 printf("tctrl: external mouse detected\n");
837 }
838 }
839 #endif
840 sc->sc_ext_pending = 0;
841 splx(s);
842 }
843
844 static void
tctrl_lock(struct tctrl_softc * sc)845 tctrl_lock(struct tctrl_softc *sc)
846 {
847
848 mutex_enter(&sc->sc_requestlock);
849 }
850
851 static void
tctrl_unlock(struct tctrl_softc * sc)852 tctrl_unlock(struct tctrl_softc *sc)
853 {
854
855 mutex_exit(&sc->sc_requestlock);
856 }
857
858 int
tadpole_request(struct tctrl_req * req,int spin,int sleep)859 tadpole_request(struct tctrl_req *req, int spin, int sleep)
860 {
861 struct tctrl_softc *sc;
862 int i, s;
863
864 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
865 if (!sc)
866 return ENODEV;
867
868 tctrl_lock(sc);
869
870 if (spin)
871 s = splhigh();
872 else
873 s = splts102();
874 sc->sc_flags |= TCTRL_SEND_REQUEST;
875 memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
876 #ifdef DIAGNOSTIC
877 if (sc->sc_wantdata != 0) {
878 splx(s);
879 printf("tctrl: we lost the race\n");
880 tctrl_unlock(sc);
881 return EAGAIN;
882 }
883 #endif
884 sc->sc_wantdata = 1;
885 sc->sc_rsplen = req->rsplen;
886 sc->sc_cmdlen = req->cmdlen;
887 sc->sc_cmdoff = sc->sc_rspoff = 0;
888
889 /* we spin for certain commands, like poweroffs */
890 if (spin) {
891 /* for (i = 0; i < 30000; i++) {*/
892 i = 0;
893 while ((sc->sc_wantdata == 1) && (i < 30000)) {
894 tctrl_intr(sc);
895 DELAY(1);
896 i++;
897 }
898 #ifdef DIAGNOSTIC
899 if (i >= 30000) {
900 printf("tctrl: timeout busy waiting for micro controller request!\n");
901 sc->sc_wantdata = 0;
902 splx(s);
903 tctrl_unlock(sc);
904 return EAGAIN;
905 }
906 #endif
907 } else {
908 int timeout = 5 * (sc->sc_rsplen + sc->sc_cmdlen);
909 tctrl_intr(sc);
910 i = 0;
911 while (((sc->sc_rspoff != sc->sc_rsplen) ||
912 (sc->sc_cmdoff != sc->sc_cmdlen)) &&
913 (i < timeout))
914 if (sleep) {
915 tsleep(sc, PWAIT, "tctrl_data", 15);
916 i++;
917 } else
918 DELAY(1);
919 #ifdef DIAGNOSTIC
920 if (i >= timeout) {
921 printf("tctrl: timeout waiting for microcontroller request\n");
922 sc->sc_wantdata = 0;
923 splx(s);
924 tctrl_unlock(sc);
925 return EAGAIN;
926 }
927 #endif
928 }
929 /*
930 * we give the user a reasonable amount of time for a command
931 * to complete. If it doesn't complete in time, we hand them
932 * garbage. This is here to stop things like setting the
933 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
934 */
935 sc->sc_wantdata = 0;
936 memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
937 splx(s);
938
939 tctrl_unlock(sc);
940 return 0;
941 }
942
943 void
tadpole_powerdown(void)944 tadpole_powerdown(void)
945 {
946 struct tctrl_req req;
947
948 req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
949 req.cmdlen = 1;
950 req.rsplen = 1;
951 tadpole_request(&req, 1, 0);
952 }
953
954 void
tadpole_set_video(int enabled)955 tadpole_set_video(int enabled)
956 {
957 struct tctrl_softc *sc;
958 struct tctrl_req req;
959 int s;
960
961 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
962 while (sc->sc_wantdata != 0)
963 DELAY(1);
964 s = splts102();
965 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
966 || (sc->sc_tft_on)) {
967 req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
968 } else {
969 req.cmdbuf[2] = 0;
970 }
971 req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
972 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
973 req.cmdlen = 3;
974 req.rsplen = 2;
975
976 if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
977 sc->sc_tft_on = enabled;
978 if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
979 splx(s);
980 return;
981 }
982 tadpole_request(&req, 1, 0);
983 sc->sc_bitport =
984 (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
985 }
986 splx(s);
987 }
988
989 static void
tctrl_write_data(struct tctrl_softc * sc,uint8_t v)990 tctrl_write_data(struct tctrl_softc *sc, uint8_t v)
991 {
992 unsigned int i;
993
994 for (i = 0; i < 100; i++) {
995 if (TS102_UCTRL_STS_TXNF_STA &
996 tctrl_read(sc, TS102_REG_UCTRL_STS))
997 break;
998 }
999 tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
1000 }
1001
1002 static uint8_t
tctrl_read_data(struct tctrl_softc * sc)1003 tctrl_read_data(struct tctrl_softc *sc)
1004 {
1005 unsigned int i, v;
1006
1007 for (i = 0; i < 100000; i++) {
1008 if (TS102_UCTRL_STS_RXNE_STA &
1009 tctrl_read(sc, TS102_REG_UCTRL_STS))
1010 break;
1011 DELAY(1);
1012 }
1013
1014 v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
1015 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
1016 return v;
1017 }
1018
1019 static uint8_t
tctrl_read(struct tctrl_softc * sc,bus_size_t off)1020 tctrl_read(struct tctrl_softc *sc, bus_size_t off)
1021 {
1022
1023 sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
1024 return sc->sc_junk;
1025 }
1026
1027 static void
tctrl_write(struct tctrl_softc * sc,bus_size_t off,uint8_t v)1028 tctrl_write(struct tctrl_softc *sc, bus_size_t off, uint8_t v)
1029 {
1030
1031 sc->sc_junk = v;
1032 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
1033 }
1034
1035 int
tctrlopen(dev_t dev,int flags,int mode,struct lwp * l)1036 tctrlopen(dev_t dev, int flags, int mode, struct lwp *l)
1037 {
1038 int unit = (minor(dev)&0xf0);
1039 int ctl = (minor(dev)&0x0f);
1040 struct tctrl_softc *sc;
1041
1042 if (unit >= tctrl_cd.cd_ndevs)
1043 return(ENXIO);
1044 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1045 if (!sc)
1046 return(ENXIO);
1047
1048 switch (ctl) {
1049 case TCTRL_STD_DEV:
1050 break;
1051 case TCTRL_APMCTL_DEV:
1052 if (!(flags & FWRITE))
1053 return(EINVAL);
1054 if (sc->sc_flags & TCTRL_APM_CTLOPEN)
1055 return(EBUSY);
1056 sc->sc_flags |= TCTRL_APM_CTLOPEN;
1057 break;
1058 default:
1059 return(ENXIO);
1060 break;
1061 }
1062
1063 return(0);
1064 }
1065
1066 int
tctrlclose(dev_t dev,int flags,int mode,struct lwp * l)1067 tctrlclose(dev_t dev, int flags, int mode, struct lwp *l)
1068 {
1069 int ctl = (minor(dev)&0x0f);
1070 struct tctrl_softc *sc;
1071
1072 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1073 if (!sc)
1074 return(ENXIO);
1075
1076 switch (ctl) {
1077 case TCTRL_STD_DEV:
1078 break;
1079 case TCTRL_APMCTL_DEV:
1080 sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
1081 break;
1082 }
1083 return(0);
1084 }
1085
1086 int
tctrlioctl(dev_t dev,u_long cmd,void * data,int flags,struct lwp * l)1087 tctrlioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
1088 {
1089 struct tctrl_req req, *reqn;
1090 struct tctrl_pwr *pwrreq;
1091 struct apm_power_info *powerp;
1092 struct apm_event_info *evp;
1093 struct tctrl_softc *sc;
1094 int i;
1095 uint8_t c;
1096
1097 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1098 if (!sc)
1099 return ENXIO;
1100
1101 switch (cmd) {
1102
1103 case APM_IOC_STANDBY:
1104 /* turn off backlight and so on ? */
1105
1106 return 0; /* for now */
1107
1108 case APM_IOC_SUSPEND:
1109 /* not sure what to do here - we can't really suspend */
1110
1111 return 0; /* for now */
1112
1113 case OAPM_IOC_GETPOWER:
1114 case APM_IOC_GETPOWER:
1115 powerp = (struct apm_power_info *)data;
1116 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
1117 req.cmdlen = 1;
1118 req.rsplen = 2;
1119 tadpole_request(&req, 0, l->l_proc ? 1 : 0);
1120 if (req.rspbuf[0] > 0x00)
1121 powerp->battery_state = APM_BATT_CHARGING;
1122 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
1123 req.cmdlen = 1;
1124 req.rsplen = 3;
1125 tadpole_request(&req, 0, l->l_proc ? 1 : 0);
1126 c = req.rspbuf[0];
1127 powerp->battery_life = c;
1128 if (c > 0x70) /* the tadpole sometimes dips below zero, and */
1129 c = 0; /* into the 255 range. */
1130 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
1131 if (powerp->battery_state != APM_BATT_CHARGING) {
1132 if (c < 0x20)
1133 powerp->battery_state = APM_BATT_CRITICAL;
1134 else if (c < 0x40)
1135 powerp->battery_state = APM_BATT_LOW;
1136 else if (c < 0x66)
1137 powerp->battery_state = APM_BATT_HIGH;
1138 else
1139 powerp->battery_state = APM_BATT_UNKNOWN;
1140 }
1141
1142 if (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
1143 powerp->ac_state = APM_AC_ON;
1144 else
1145 powerp->ac_state = APM_AC_OFF;
1146 break;
1147
1148 case APM_IOC_NEXTEVENT:
1149 if (!sc->sc_event_count)
1150 return EAGAIN;
1151
1152 evp = (struct apm_event_info *)data;
1153 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
1154 i %= APM_NEVENTS;
1155 *evp = sc->sc_event_list[i];
1156 sc->sc_event_count--;
1157 return(0);
1158
1159 /* this ioctl assumes the caller knows exactly what he is doing */
1160 case TCTRL_CMD_REQ:
1161 reqn = (struct tctrl_req *)data;
1162 if ((i = kauth_authorize_device_passthru(l->l_cred,
1163 dev, KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data)) != 0 &&
1164 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
1165 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
1166 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
1167 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
1168 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
1169 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
1170 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
1171 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
1172 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
1173 return(i);
1174 tadpole_request(reqn, 0, l->l_proc ? 1 : 0);
1175 break;
1176 /* serial power mode (via auxiotwo) */
1177 case TCTRL_SERIAL_PWR:
1178 pwrreq = (struct tctrl_pwr *)data;
1179 if (pwrreq->rw)
1180 pwrreq->state = auxiotwoserialgetapm();
1181 else
1182 auxiotwoserialsetapm(pwrreq->state);
1183 break;
1184
1185 /* modem power mode (via auxio) */
1186 case TCTRL_MODEM_PWR:
1187 return(EOPNOTSUPP); /* for now */
1188 break;
1189
1190
1191 default:
1192 return (ENOTTY);
1193 }
1194 return (0);
1195 }
1196
1197 int
tctrlpoll(dev_t dev,int events,struct lwp * l)1198 tctrlpoll(dev_t dev, int events, struct lwp *l)
1199 {
1200 struct tctrl_softc *sc = device_lookup_private(&tctrl_cd,
1201 TCTRL_STD_DEV);
1202 int revents = 0;
1203
1204 if (events & (POLLIN | POLLRDNORM)) {
1205 if (sc->sc_event_count)
1206 revents |= events & (POLLIN | POLLRDNORM);
1207 else
1208 selrecord(l, &sc->sc_rsel);
1209 }
1210
1211 return (revents);
1212 }
1213
1214 static void
filt_tctrlrdetach(struct knote * kn)1215 filt_tctrlrdetach(struct knote *kn)
1216 {
1217 struct tctrl_softc *sc = kn->kn_hook;
1218 int s;
1219
1220 s = splts102();
1221 selremove_knote(&sc->sc_rsel, kn);
1222 splx(s);
1223 }
1224
1225 static int
filt_tctrlread(struct knote * kn,long hint)1226 filt_tctrlread(struct knote *kn, long hint)
1227 {
1228 struct tctrl_softc *sc = kn->kn_hook;
1229
1230 kn->kn_data = sc->sc_event_count;
1231 return (kn->kn_data > 0);
1232 }
1233
1234 static const struct filterops tctrlread_filtops = {
1235 .f_flags = FILTEROP_ISFD,
1236 .f_attach = NULL,
1237 .f_detach = filt_tctrlrdetach,
1238 .f_event = filt_tctrlread,
1239 };
1240
1241 int
tctrlkqfilter(dev_t dev,struct knote * kn)1242 tctrlkqfilter(dev_t dev, struct knote *kn)
1243 {
1244 struct tctrl_softc *sc = device_lookup_private(&tctrl_cd,
1245 TCTRL_STD_DEV);
1246 int s;
1247
1248 switch (kn->kn_filter) {
1249 case EVFILT_READ:
1250 kn->kn_fop = &tctrlread_filtops;
1251 break;
1252
1253 default:
1254 return (EINVAL);
1255 }
1256
1257 kn->kn_hook = sc;
1258
1259 s = splts102();
1260 selrecord_knote(&sc->sc_rsel, kn);
1261 splx(s);
1262
1263 return (0);
1264 }
1265
1266 static void
tctrl_sensor_setup(struct tctrl_softc * sc)1267 tctrl_sensor_setup(struct tctrl_softc *sc)
1268 {
1269 int i, error;
1270
1271 sc->sc_sme = sysmon_envsys_create();
1272
1273 /* case temperature */
1274 (void)strlcpy(sc->sc_sensor[0].desc, "Case temperature",
1275 sizeof(sc->sc_sensor[0].desc));
1276 sc->sc_sensor[0].units = ENVSYS_STEMP;
1277 sc->sc_sensor[0].state = ENVSYS_SINVALID;
1278
1279 /* battery voltage */
1280 (void)strlcpy(sc->sc_sensor[1].desc, "Internal battery voltage",
1281 sizeof(sc->sc_sensor[1].desc));
1282 sc->sc_sensor[1].units = ENVSYS_SVOLTS_DC;
1283 sc->sc_sensor[1].state = ENVSYS_SINVALID;
1284
1285 /* DC voltage */
1286 (void)strlcpy(sc->sc_sensor[2].desc, "DC-In voltage",
1287 sizeof(sc->sc_sensor[2].desc));
1288 sc->sc_sensor[2].units = ENVSYS_SVOLTS_DC;
1289 sc->sc_sensor[2].state = ENVSYS_SINVALID;
1290
1291 for (i = 0; i < ENVSYS_NUMSENSORS; i++) {
1292 if (sysmon_envsys_sensor_attach(sc->sc_sme,
1293 &sc->sc_sensor[i])) {
1294 sysmon_envsys_destroy(sc->sc_sme);
1295 return;
1296 }
1297 }
1298
1299 sc->sc_sme->sme_name = device_xname(sc->sc_dev);
1300 sc->sc_sme->sme_cookie = sc;
1301 sc->sc_sme->sme_refresh = tctrl_refresh;
1302
1303 if ((error = sysmon_envsys_register(sc->sc_sme)) != 0) {
1304 printf("%s: couldn't register sensors (%d)\n",
1305 device_xname(sc->sc_dev), error);
1306 sysmon_envsys_destroy(sc->sc_sme);
1307 return;
1308 }
1309
1310 /* now register the power button */
1311
1312 sysmon_task_queue_init();
1313
1314 sc->sc_powerpressed = 0;
1315 memset(&sc->sc_sm_pbutton, 0, sizeof(struct sysmon_pswitch));
1316 sc->sc_sm_pbutton.smpsw_name = device_xname(sc->sc_dev);
1317 sc->sc_sm_pbutton.smpsw_type = PSWITCH_TYPE_POWER;
1318 if (sysmon_pswitch_register(&sc->sc_sm_pbutton) != 0)
1319 printf("%s: unable to register power button with sysmon\n",
1320 device_xname(sc->sc_dev));
1321
1322 memset(&sc->sc_sm_lid, 0, sizeof(struct sysmon_pswitch));
1323 sc->sc_sm_lid.smpsw_name = device_xname(sc->sc_dev);
1324 sc->sc_sm_lid.smpsw_type = PSWITCH_TYPE_LID;
1325 if (sysmon_pswitch_register(&sc->sc_sm_lid) != 0)
1326 printf("%s: unable to register lid switch with sysmon\n",
1327 device_xname(sc->sc_dev));
1328
1329 memset(&sc->sc_sm_ac, 0, sizeof(struct sysmon_pswitch));
1330 sc->sc_sm_ac.smpsw_name = device_xname(sc->sc_dev);
1331 sc->sc_sm_ac.smpsw_type = PSWITCH_TYPE_ACADAPTER;
1332 if (sysmon_pswitch_register(&sc->sc_sm_ac) != 0)
1333 printf("%s: unable to register AC adaptor with sysmon\n",
1334 device_xname(sc->sc_dev));
1335 }
1336
1337 static void
tctrl_power_button_pressed(void * arg)1338 tctrl_power_button_pressed(void *arg)
1339 {
1340 struct tctrl_softc *sc = arg;
1341
1342 sysmon_pswitch_event(&sc->sc_sm_pbutton, PSWITCH_EVENT_PRESSED);
1343 sc->sc_powerpressed = 0;
1344 }
1345
1346 static void
tctrl_lid_state(struct tctrl_softc * sc)1347 tctrl_lid_state(struct tctrl_softc *sc)
1348 {
1349 int state;
1350
1351 state = (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) ?
1352 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED;
1353 sysmon_pswitch_event(&sc->sc_sm_lid, state);
1354 }
1355
1356 static void
tctrl_ac_state(struct tctrl_softc * sc)1357 tctrl_ac_state(struct tctrl_softc *sc)
1358 {
1359 int state;
1360
1361 state = (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
1362 PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED;
1363 sysmon_pswitch_event(&sc->sc_sm_ac, state);
1364 }
1365
1366 static int
tctrl_powerfail(void * arg)1367 tctrl_powerfail(void *arg)
1368 {
1369 struct tctrl_softc *sc = (struct tctrl_softc *)arg;
1370
1371 /*
1372 * We lost power. Queue a callback with thread context to
1373 * handle all the real work.
1374 */
1375 if (sc->sc_powerpressed == 0) {
1376 sc->sc_powerpressed = 1;
1377 sysmon_task_queue_sched(0, tctrl_power_button_pressed, sc);
1378 }
1379 return (1);
1380 }
1381
1382 static void
tctrl_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)1383 tctrl_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
1384 {
1385 /*struct tctrl_softc *sc = sme->sme_cookie;*/
1386 struct tctrl_req req;
1387 int sleepable;
1388 int i;
1389
1390 i = edata->sensor;
1391 sleepable = curlwp ? 1 : 0;
1392
1393 switch (i)
1394 {
1395 case 0: /* case temperature */
1396 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
1397 req.cmdlen = 1;
1398 req.rsplen = 2;
1399 tadpole_request(&req, 0, sleepable);
1400 edata->value_cur = /* 273160? */
1401 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1402 / 9 + 273150000);
1403 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
1404 req.cmdlen = 1;
1405 req.rsplen = 2;
1406 tadpole_request(&req, 0, sleepable);
1407 edata->value_max =
1408 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1409 / 9 + 273150000);
1410 edata->flags |= ENVSYS_FVALID_MAX;
1411 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
1412 req.cmdlen = 1;
1413 req.rsplen = 2;
1414 tadpole_request(&req, 0, sleepable);
1415 edata->value_min =
1416 (uint32_t)((int)((int)req.rspbuf[0] - 32) * 5000000
1417 / 9 + 273150000);
1418 edata->flags |= ENVSYS_FVALID_MIN;
1419 edata->units = ENVSYS_STEMP;
1420 break;
1421
1422 case 1: /* battery voltage */
1423 {
1424 edata->units = ENVSYS_SVOLTS_DC;
1425 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
1426 req.cmdlen = 1;
1427 req.rsplen = 2;
1428 tadpole_request(&req, 0, sleepable);
1429 edata->value_cur = (int32_t)req.rspbuf[0] *
1430 1000000 / 11;
1431 }
1432 break;
1433 case 2: /* DC voltage */
1434 {
1435 edata->units = ENVSYS_SVOLTS_DC;
1436 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
1437 req.cmdlen = 1;
1438 req.rsplen = 2;
1439 tadpole_request(&req, 0, sleepable);
1440 edata->value_cur = (int32_t)req.rspbuf[0] *
1441 1000000 / 11;
1442 }
1443 break;
1444 }
1445 edata->state = ENVSYS_SVALID;
1446 }
1447
1448 static void
tctrl_event_thread(void * v)1449 tctrl_event_thread(void *v)
1450 {
1451 struct tctrl_softc *sc = v;
1452 device_t dv;
1453 struct sd_softc *sd;
1454
1455 for (sd = NULL; sd == NULL;) {
1456 dv = device_find_by_xname("sd0");
1457 if (dv != NULL)
1458 sd = device_private(dv);
1459 else
1460 tsleep(&sc->sc_events, PWAIT, "probe_disk", hz);
1461 }
1462
1463 dv = device_find_by_xname("le0");
1464
1465 struct lance_softc *le = dv != NULL ? device_private(dv) : NULL;
1466 struct dk_softc *dk = &sd->sc_dksc;
1467 printf("found %s\n", device_xname(dk->sc_dev));
1468
1469 struct io_stats *io = dk->sc_dkdev.dk_stats;
1470 int rcount = io->io_rxfer;
1471 int wcount = io->io_wxfer;
1472
1473 tctrl_read_event_status(sc);
1474
1475 int ticks = hz / 2;
1476 for (;;) {
1477 tsleep(&sc->sc_events, PWAIT, "tctrl_event", ticks);
1478 int s = splhigh();
1479 if ((rcount != io->io_rxfer) || (wcount != io->io_wxfer)) {
1480 rcount = io->io_rxfer;
1481 wcount = io->io_wxfer;
1482 sc->sc_lcdwanted |= TS102_LCD_DISK_ACTIVE;
1483 } else
1484 sc->sc_lcdwanted &= ~TS102_LCD_DISK_ACTIVE;
1485
1486 if (le != NULL) {
1487 if (le->sc_havecarrier != 0)
1488 sc->sc_lcdwanted |= TS102_LCD_LAN_ACTIVE;
1489 else
1490 sc->sc_lcdwanted &= ~TS102_LCD_LAN_ACTIVE;
1491 }
1492 splx(s);
1493 tctrl_update_lcd(sc);
1494 if (sc->sc_ext_pending)
1495 tctrl_read_event_status(sc);
1496 }
1497 }
1498
1499 void
tadpole_register_callback(void (* callback)(void *,int),void * cookie)1500 tadpole_register_callback(void (*callback)(void *, int), void *cookie)
1501 {
1502 struct tctrl_softc *sc;
1503
1504 sc = device_lookup_private(&tctrl_cd, TCTRL_STD_DEV);
1505 sc->sc_video_callback = callback;
1506 sc->sc_video_callback_cookie = cookie;
1507 if (sc->sc_video_callback != NULL) {
1508 sc->sc_video_callback(sc->sc_video_callback_cookie,
1509 sc->sc_extvga);
1510 }
1511 }
1512