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