tctrl.c revision 1.4 1 /* $NetBSD: tctrl.c,v 1.4 1999/12/15 08:12:30 garbled Exp $ */
2
3 /*-
4 * Copyright (c) 1998 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/param.h>
40 #include <sys/systm.h>
41 #include <sys/ioctl.h>
42 #include <sys/select.h>
43 #include <sys/tty.h>
44 #include <sys/proc.h>
45 #include <sys/user.h>
46 #include <sys/conf.h>
47 #include <sys/file.h>
48 #include <sys/uio.h>
49 #include <sys/kernel.h>
50 #include <sys/syslog.h>
51 #include <sys/types.h>
52 #include <sys/device.h>
53 #include <sys/envsys.h>
54 #include <sys/poll.h>
55
56 #include <machine/apmvar.h>
57 #include <machine/autoconf.h>
58 #include <machine/cpu.h>
59 #include <machine/bus.h>
60 #include <machine/tctrl.h>
61
62 #include <sparc/dev/ts102reg.h>
63 #include <sparc/dev/tctrlvar.h>
64
65 cdev_decl(tctrl);
66
67 extern struct cfdriver tctrl_cd;
68
69 static const char *tctrl_ext_statuses[16] = {
70 "main power available",
71 "internal battery attached",
72 "external battery attached",
73 "external VGA attached",
74 "external keyboard attached",
75 "external mouse attached",
76 "lid down",
77 "internal battery charging",
78 "external battery charging",
79 "internal battery discharging",
80 "external battery discharging",
81 };
82
83 struct tctrl_softc {
84 struct device sc_dev;
85 bus_space_tag_t sc_memt;
86 bus_space_handle_t sc_memh;
87 unsigned int sc_junk;
88 unsigned int sc_ext_status;
89 unsigned int sc_flags;
90 #define TCTRL_SEND_REQUEST 0x0001
91 #define TCTRL_APM_CTLOPEN 0x0002
92 unsigned int sc_wantdata;
93 enum { TCTRL_IDLE, TCTRL_ARGS,
94 TCTRL_ACK, TCTRL_DATA } sc_state;
95 u_int8_t sc_cmdbuf[16];
96 u_int8_t sc_rspbuf[16];
97 u_int8_t sc_bitport;
98 u_int8_t sc_tft_on;
99 u_int8_t sc_op;
100 u_int8_t sc_cmdoff;
101 u_int8_t sc_cmdlen;
102 u_int8_t sc_rspoff;
103 u_int8_t sc_rsplen;
104 /* APM stuff */
105 #define APM_NEVENTS 16
106 struct apm_event_info sc_event_list[APM_NEVENTS];
107 int sc_event_count;
108 int sc_event_ptr;
109 struct selinfo sc_rsel;
110 /* ENVSYS stuff */
111 #define ENVSYS_NUMSENSORS 3
112 struct envsys_sensor sc_esensors[ENVSYS_NUMSENSORS];
113
114 struct evcnt sc_intrcnt; /* interrupt counting */
115 };
116
117 #define TCTRL_STD_DEV 0
118 #define TCTRL_APMCTL_DEV 8
119
120 static int tctrl_match __P((struct device *parent, struct cfdata *cf,
121 void *aux));
122 static void tctrl_attach __P((struct device *parent, struct device *self,
123 void *aux));
124 static void tctrl_write __P((struct tctrl_softc *sc, bus_size_t off,
125 u_int8_t v));
126 static u_int8_t tctrl_read __P((struct tctrl_softc *sc, bus_size_t off));
127 static void tctrl_write_data __P((struct tctrl_softc *sc, u_int8_t v));
128 static u_int8_t tctrl_read_data __P((struct tctrl_softc *sc));
129 static int tctrl_intr __P((void *arg));
130 static void tctrl_setup_bitport __P((void));
131 static void tctrl_setup_bitport_nop __P((void));
132 static void tctrl_read_ext_status __P((void));
133 static void tctrl_read_event_status __P((void *arg));
134 static int tctrl_apm_record_event __P((struct tctrl_softc *sc,
135 u_int event_type));
136
137 struct cfattach tctrl_ca = {
138 sizeof(struct tctrl_softc), tctrl_match, tctrl_attach
139 };
140
141 extern struct cfdriver tctrl_cd;
142 /* XXX wtf is this? see i386/apm.c */
143 int tctrl_apm_evindex;
144
145 static int
146 tctrl_match(parent, cf, aux)
147 struct device *parent;
148 struct cfdata *cf;
149 void *aux;
150 {
151 union obio_attach_args *uoba = aux;
152 struct sbus_attach_args *sa = &uoba->uoba_sbus;
153
154 if (uoba->uoba_isobio4 != 0) {
155 return (0);
156 }
157
158 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
159 * (who's interface is off the TS102 PCMCIA controller but there
160 * exists a OpenProm for microcontroller interface).
161 */
162 return strcmp("uctrl", sa->sa_name) == 0;
163 }
164
165 static void
166 tctrl_attach(parent, self, aux)
167 struct device *parent;
168 struct device *self;
169 void *aux;
170 {
171 struct tctrl_softc *sc = (void *)self;
172 union obio_attach_args *uoba = aux;
173 struct sbus_attach_args *sa = &uoba->uoba_sbus;
174 unsigned int i, v;
175 #if 0
176 unsigned int ack, msb, lsb;
177 #endif
178
179 /* We're living on a sbus slot that looks like an obio that
180 * looks like an sbus slot.
181 */
182 sc->sc_memt = sa->sa_bustag;
183 if (sbus_bus_map(sc->sc_memt, sa->sa_slot,
184 sa->sa_offset - TS102_REG_UCTRL_INT, sa->sa_size,
185 BUS_SPACE_MAP_LINEAR, 0,
186 &sc->sc_memh) != 0) {
187 printf(": can't map registers\n");
188 return;
189 }
190
191 printf("\n");
192
193 sc->sc_tft_on = 1;
194
195 /* clear any pending data.
196 */
197 for (i = 0; i < 10000; i++) {
198 if ((TS102_UCTRL_STS_RXNE_STA &
199 tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
200 break;
201 }
202 v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
203 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
204 }
205
206 if (sa->sa_nintr != 0) {
207 (void)bus_intr_establish(sc->sc_memt, sa->sa_pri,
208 0, tctrl_intr, sc);
209 evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);
210 }
211
212 /* See what the external status is
213 */
214
215 tctrl_read_ext_status();
216 if (sc->sc_ext_status != 0) {
217 const char *sep;
218
219 printf("%s: ", sc->sc_dev.dv_xname);
220 v = sc->sc_ext_status;
221 for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
222 if (v & 1) {
223 printf("%s%s", sep, tctrl_ext_statuses[i]);
224 sep = ", ";
225 }
226 }
227 printf("\n");
228 }
229
230 /* Get a current of the control bitport;
231 */
232 tctrl_setup_bitport_nop();
233 tctrl_write(sc, TS102_REG_UCTRL_INT,
234 TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
235
236 sc->sc_wantdata = 0;
237 sc->sc_event_count = 0;
238
239 /* prime the sensor data */
240 sprintf(sc->sc_esensors[0].desc, "%s", "Internal Unit Temperature");
241 sc->sc_esensors[0].units = ENVSYS_STEMP;
242 sprintf(sc->sc_esensors[1].desc, "%s", "Internal Battery Voltage");
243 sc->sc_esensors[1].units = ENVSYS_SVOLTS_DC;
244 sprintf(sc->sc_esensors[2].desc, "%s", "DC-In Voltage");
245 sc->sc_esensors[2].units = ENVSYS_SVOLTS_DC;
246 }
247
248 static int
249 tctrl_intr(arg)
250 void *arg;
251 {
252 struct tctrl_softc *sc = arg;
253 unsigned int v, d;
254 int progress = 0;
255
256 again:
257 /* find out the cause(s) of the interrupt */
258 v = tctrl_read(sc, TS102_REG_UCTRL_STS);
259
260 /* clear the cause(s) of the interrupt */
261 tctrl_write(sc, TS102_REG_UCTRL_STS, v);
262
263 v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
264 if (sc->sc_cmdoff >= sc->sc_cmdlen) {
265 v &= ~TS102_UCTRL_STS_TXNF_STA;
266 if (tctrl_read(sc, TS102_REG_UCTRL_INT) & TS102_UCTRL_INT_TXNF_REQ) {
267 tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
268 progress = 1;
269 }
270 }
271 if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
272 sc->sc_state != TCTRL_IDLE)) {
273 wakeup(sc);
274 return progress;
275 }
276
277 progress = 1;
278 if (v & TS102_UCTRL_STS_RXNE_STA) {
279 d = tctrl_read_data(sc);
280 switch (sc->sc_state) {
281 case TCTRL_IDLE:
282 if (d == 0xfa) {
283 /* external event */
284 timeout(tctrl_read_event_status, (void *)0, 1);
285 } else {
286 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
287 sc->sc_dev.dv_xname, sc->sc_op, d);
288 }
289 goto again;
290 case TCTRL_ACK:
291 if (d != 0xfe) {
292 printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
293 sc->sc_dev.dv_xname, sc->sc_op, d);
294 }
295 #ifdef TCTRLDEBUG
296 printf(" ack=0x%02x", d);
297 #endif
298 sc->sc_rsplen--;
299 sc->sc_rspoff = 0;
300 sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
301 sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
302 #ifdef TCTRLDEBUG
303 if (sc->sc_rsplen > 0) {
304 printf(" [data(%u)]", sc->sc_rsplen);
305 } else {
306 printf(" [idle]\n");
307 }
308 #endif
309 goto again;
310 case TCTRL_DATA:
311 sc->sc_rspbuf[sc->sc_rspoff++] = d;
312 #ifdef TCTRLDEBUG
313 printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
314 #endif
315 if (sc->sc_rspoff == sc->sc_rsplen) {
316 #ifdef TCTRLDEBUG
317 printf(" [idle]\n");
318 #endif
319 sc->sc_state = TCTRL_IDLE;
320 sc->sc_wantdata = 0;
321 }
322 goto again;
323 default:
324 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
325 sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
326 goto again;
327 }
328 }
329 if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
330 sc->sc_flags & TCTRL_SEND_REQUEST) {
331 if (sc->sc_flags & TCTRL_SEND_REQUEST) {
332 sc->sc_flags &= ~TCTRL_SEND_REQUEST;
333 sc->sc_wantdata = 1;
334 }
335 if (sc->sc_cmdlen > 0) {
336 tctrl_write(sc, TS102_REG_UCTRL_INT,
337 tctrl_read(sc, TS102_REG_UCTRL_INT)
338 |TS102_UCTRL_INT_TXNF_MSK
339 |TS102_UCTRL_INT_TXNF_REQ);
340 v = tctrl_read(sc, TS102_REG_UCTRL_STS);
341 }
342 }
343 if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
344 tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
345 #ifdef TCTRLDEBUG
346 if (sc->sc_cmdoff == 1) {
347 printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
348 sc->sc_cmdbuf[0], sc->sc_rsplen);
349 } else {
350 printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
351 sc->sc_cmdbuf[sc->sc_cmdoff-1]);
352 }
353 #endif
354 if (sc->sc_cmdoff == sc->sc_cmdlen) {
355 sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
356 #ifdef TCTRLDEBUG
357 printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
358 #endif
359 if (sc->sc_cmdoff == 1) {
360 sc->sc_op = sc->sc_cmdbuf[0];
361 }
362 tctrl_write(sc, TS102_REG_UCTRL_INT,
363 tctrl_read(sc, TS102_REG_UCTRL_INT)
364 & (~TS102_UCTRL_INT_TXNF_MSK
365 |TS102_UCTRL_INT_TXNF_REQ));
366 } else if (sc->sc_state == TCTRL_IDLE) {
367 sc->sc_op = sc->sc_cmdbuf[0];
368 sc->sc_state = TCTRL_ARGS;
369 #ifdef TCTRLDEBUG
370 printf(" [args]");
371 #endif
372 }
373 }
374 goto again;
375 }
376
377 static void
378 tctrl_setup_bitport_nop(void)
379 {
380 struct tctrl_softc *sc;
381 struct tctrl_req req;
382 int s;
383
384 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
385 req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
386 req.cmdbuf[1] = 0xff;
387 req.cmdbuf[2] = 0;
388 req.cmdlen = 3;
389 req.rsplen = 2;
390 req.p = NULL;
391 tadpole_request(&req, 1);
392 s = splts102();
393 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
394 splx(s);
395 }
396
397 static void
398 tctrl_setup_bitport(void)
399 {
400 struct tctrl_softc *sc;
401 struct tctrl_req req;
402 int s;
403
404 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
405 s = splts102();
406 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
407 || (!sc->sc_tft_on)) {
408 req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
409 } else {
410 req.cmdbuf[2] = 0;
411 }
412 req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
413 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
414 req.cmdlen = 3;
415 req.rsplen = 2;
416 req.p = NULL;
417 tadpole_request(&req, 1);
418 s = splts102();
419 sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
420 splx(s);
421 }
422
423 static void
424 tctrl_read_ext_status(void)
425 {
426 struct tctrl_softc *sc;
427 struct tctrl_req req;
428 int s;
429
430 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
431 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
432 req.cmdlen = 1;
433 req.rsplen = 3;
434 req.p = NULL;
435 #ifdef TCTRLDEBUG
436 printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
437 #endif
438 tadpole_request(&req, 1);
439 s = splts102();
440 sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1];
441 splx(s);
442 #ifdef TCTRLDEBUG
443 printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
444 #endif
445 }
446
447 /*
448 * return 0 if the user will notice and handle the event,
449 * return 1 if the kernel driver should do so.
450 */
451 static int
452 tctrl_apm_record_event(sc, event_type)
453 struct tctrl_softc *sc;
454 u_int event_type;
455 {
456 struct apm_event_info *evp;
457
458 if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
459 (sc->sc_event_count < APM_NEVENTS)) {
460 evp = &sc->sc_event_list[sc->sc_event_ptr];
461 sc->sc_event_count++;
462 sc->sc_event_ptr++;
463 sc->sc_event_ptr %= APM_NEVENTS;
464 evp->type = event_type;
465 evp->index = ++tctrl_apm_evindex;
466 selwakeup(&sc->sc_rsel);
467 return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
468 }
469 return(1);
470 }
471
472 static void
473 tctrl_read_event_status(arg)
474 void *arg;
475 {
476 struct tctrl_softc *sc;
477 struct tctrl_req req;
478 int s;
479 unsigned int v;
480
481 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
482 req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
483 req.cmdlen = 1;
484 req.rsplen = 3;
485 req.p = NULL;
486 tadpole_request(&req, 1);
487 s = splts102();
488 v = req.rspbuf[0] * 256 + req.rspbuf[1];
489 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
490 printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
491 }
492 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
493 /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
494 /* according to a tadpole header, and observation */
495 #ifdef TCTRLDEBUG
496 printf("%s: Battery charge level change\n", sc->sc_dev.dv_xname);
497 #endif
498 }
499 if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
500 if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
501 printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
502 }
503 if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
504 splx(s);
505 tctrl_read_ext_status();
506 s = splts102();
507 if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
508 printf("%s: main power %s\n", sc->sc_dev.dv_xname,
509 (sc->sc_ext_status &
510 TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
511 "restored" : "removed");
512 }
513 if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
514 splx(s);
515 tctrl_read_ext_status();
516 tctrl_setup_bitport();
517 #ifdef TCTRLDEBUG
518 printf("%s: lid %s\n", sc->sc_dev.dv_xname,
519 (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
520 ? "closed" : "opened");
521 #endif
522 }
523 splx(s);
524 }
525
526 void
527 tadpole_request(req, spin)
528 struct tctrl_req *req;
529 int spin;
530 {
531 struct tctrl_softc *sc;
532 int i, s;
533
534 if (tctrl_cd.cd_devs == NULL
535 || tctrl_cd.cd_ndevs == 0
536 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
537 return;
538 }
539
540 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
541 while (sc->sc_wantdata != 0) {
542 if (req->p != NULL)
543 tsleep(&sc->sc_wantdata, PLOCK, "tctrl_lock", 10);
544 else
545 DELAY(1);
546 }
547 if (spin)
548 s = splhigh();
549 else
550 s = splts102();
551 sc->sc_flags |= TCTRL_SEND_REQUEST;
552 memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
553 sc->sc_wantdata = 1;
554 sc->sc_rsplen = req->rsplen;
555 sc->sc_cmdlen = req->cmdlen;
556 sc->sc_cmdoff = sc->sc_rspoff = 0;
557
558 /* we spin for certain commands, like poweroffs */
559 if (spin) {
560 for (i = 0; i < 30000; i++) {
561 tctrl_intr(sc);
562 DELAY(1);
563 }
564 } else {
565 tctrl_intr(sc);
566 while ((sc->sc_rspoff != sc->sc_rsplen) ||
567 (sc->sc_cmdoff != sc->sc_cmdlen))
568 if (req->p != NULL)
569 tsleep(sc, PWAIT, "tctrl_data", 0);
570 else
571 DELAY(1);
572 }
573 memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
574 splx(s);
575 }
576
577 void
578 tadpole_powerdown(void)
579 {
580 struct tctrl_req req;
581
582 req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
583 req.cmdlen = 1;
584 req.rsplen = 1;
585 req.p = NULL;
586 tadpole_request(&req, 1);
587 }
588
589 void
590 tadpole_set_video(enabled)
591 int enabled;
592 {
593 struct tctrl_softc *sc;
594 struct tctrl_req req;
595 int s;
596
597 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
598 while (sc->sc_wantdata != 0)
599 DELAY(1);
600 s = splts102();
601 req.p = NULL;
602 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
603 || (sc->sc_tft_on)) {
604 req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
605 } else {
606 req.cmdbuf[2] = 0;
607 }
608 req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
609 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
610 req.cmdlen = 3;
611 req.rsplen = 2;
612
613 if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
614 sc->sc_tft_on = enabled;
615 if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
616 splx(s);
617 return;
618 }
619 tadpole_request(&req, 1);
620 sc->sc_bitport =
621 (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
622 }
623 splx(s);
624 }
625
626 static void
627 tctrl_write_data(sc, v)
628 struct tctrl_softc *sc;
629 u_int8_t v;
630 {
631 unsigned int i;
632
633 for (i = 0; i < 100; i++) {
634 if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
635 break;
636 }
637 tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
638 }
639
640 static u_int8_t
641 tctrl_read_data(sc)
642 struct tctrl_softc *sc;
643 {
644 unsigned int i, v;
645
646 for (i = 0; i < 100000; i++) {
647 if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
648 break;
649 DELAY(1);
650 }
651
652 v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
653 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
654 return v;
655 }
656
657 static u_int8_t
658 tctrl_read(sc, off)
659 struct tctrl_softc *sc;
660 bus_size_t off;
661 {
662
663 sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
664 return sc->sc_junk;
665 }
666
667 static void
668 tctrl_write(sc, off, v)
669 struct tctrl_softc *sc;
670 bus_size_t off;
671 u_int8_t v;
672 {
673
674 sc->sc_junk = v;
675 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
676 }
677
678 int
679 tctrlopen(dev, flags, mode, p)
680 dev_t dev;
681 int flags, mode;
682 struct proc *p;
683 {
684 int unit = (minor(dev)&0xf0);
685 int ctl = (minor(dev)&0x0f);
686 struct tctrl_softc *sc;
687
688 if (unit >= tctrl_cd.cd_ndevs)
689 return(ENXIO);
690 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
691 if (!sc)
692 return(ENXIO);
693
694 switch (ctl) {
695 case TCTRL_STD_DEV:
696 break;
697 case TCTRL_APMCTL_DEV:
698 if (!(flags & FWRITE))
699 return(EINVAL);
700 if (sc->sc_flags & TCTRL_APM_CTLOPEN)
701 return(EBUSY);
702 sc->sc_flags |= TCTRL_APM_CTLOPEN;
703 break;
704 default:
705 return(ENXIO);
706 break;
707 }
708
709 return(0);
710 }
711
712 int
713 tctrlclose(dev, flags, mode, p)
714 dev_t dev;
715 int flags, mode;
716 struct proc *p;
717 {
718 int ctl = (minor(dev)&0x0f);
719 struct tctrl_softc *sc;
720
721 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
722 if (!sc)
723 return(ENXIO);
724
725 switch (ctl) {
726 case TCTRL_STD_DEV:
727 break;
728 case TCTRL_APMCTL_DEV:
729 sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
730 break;
731 }
732 return(0);
733 }
734
735 int
736 tctrlioctl(dev, cmd, data, flags, p)
737 dev_t dev;
738 u_long cmd;
739 caddr_t data;
740 int flags;
741 struct proc *p;
742 {
743 struct tctrl_req req, *reqn;
744 envsys_range_t *envrange;
745 envsys_temp_data_t *envdata;
746 envsys_temp_info_t *envinfo;
747 struct apm_power_info *powerp;
748 struct apm_event_info *evp;
749 struct tctrl_softc *sc;
750 int i;
751 u_int j;
752 u_int16_t a;
753 u_int8_t c;
754
755 if (tctrl_cd.cd_devs == NULL
756 || tctrl_cd.cd_ndevs == 0
757 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
758 return ENXIO;
759 }
760 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
761 switch (cmd) {
762
763 case APM_IOC_STANDBY:
764 return(EOPNOTSUPP); /* for now */
765
766 case APM_IOC_SUSPEND:
767 return(EOPNOTSUPP); /* for now */
768
769 case APM_IOC_GETPOWER:
770 powerp = (struct apm_power_info *)data;
771 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
772 req.cmdlen = 1;
773 req.rsplen = 2;
774 req.p = p;
775 tadpole_request(&req, 0);
776 if (req.rspbuf[0] > 0x00)
777 powerp->battery_state = APM_BATT_CHARGING;
778 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
779 req.cmdlen = 1;
780 req.rsplen = 3;
781 req.p = p;
782 tadpole_request(&req, 0);
783 c = req.rspbuf[0];
784 powerp->battery_life = c;
785 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
786 if (powerp->battery_state != APM_BATT_CHARGING) {
787 if (c < 0x20)
788 powerp->battery_state = APM_BATT_CRITICAL;
789 else if (c < 0x40)
790 powerp->battery_state = APM_BATT_LOW;
791 else if (c < 0x66)
792 powerp->battery_state = APM_BATT_HIGH;
793 else
794 powerp->battery_state = APM_BATT_UNKNOWN;
795 }
796 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
797 req.cmdlen = 1;
798 req.rsplen = 3;
799 req.p = p;
800 tadpole_request(&req, 0);
801 a = req.rspbuf[0] * 256 + req.rspbuf[1];
802 if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
803 powerp->ac_state = APM_AC_ON;
804 else
805 powerp->ac_state = APM_AC_OFF;
806 break;
807
808 case APM_IOC_NEXTEVENT:
809 if (!sc->sc_event_count)
810 return EAGAIN;
811
812 evp = (struct apm_event_info *)data;
813 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
814 i %= APM_NEVENTS;
815 *evp = sc->sc_event_list[i];
816 sc->sc_event_count--;
817 return(0);
818
819 /* this ioctl assumes the caller knows exactly what he is doing */
820 case TCTRL_CMD_REQ:
821 reqn = (struct tctrl_req *)data;
822 if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 &&
823 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
824 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
825 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
826 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
827 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
828 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
829 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
830 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
831 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
832 return(i);
833 reqn->p = p;
834 tadpole_request(reqn, 0);
835 break;
836
837 case ENVSYS_VERSION:
838 *(int32_t *)data = 1000;
839 break;
840
841 case ENVSYS_GRANGE:
842 envrange = (envsys_range_t *)data;
843 i = 0;
844 envrange->high = envrange->low = 0;
845 for (j=0; j < ENVSYS_NUMSENSORS; j++) {
846 if (!i && envrange->units == sc->sc_esensors[j].units) {
847 envrange->low = j;
848 i++;
849 }
850 if (i && envrange->units == sc->sc_esensors[j].units)
851 envrange->high = j;
852 }
853 if (!i) {
854 envrange->high = 0;
855 envrange->low = 1;
856 }
857 break;
858
859 case ENVSYS_GTREDATA:
860 envdata = (envsys_temp_data_t *)data;
861 if (envdata->sensor >= ENVSYS_NUMSENSORS) {
862 envdata->validflags = 0;
863 break;
864 }
865 envdata->warnflags = ENVSYS_WARN_OK;
866 if (envdata->sensor == 0) {
867 envdata->validflags |= ENVSYS_FVALID;
868 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
869 req.cmdlen = 1;
870 req.rsplen = 2;
871 req.p = p;
872 tadpole_request(&req, 0);
873 envdata->cur.data_us = /* 273160? */
874 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
875 envdata->validflags |= ENVSYS_FCURVALID;
876 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
877 req.cmdlen = 1;
878 req.rsplen = 2;
879 req.p = p;
880 tadpole_request(&req, 0);
881 envdata->max.data_us =
882 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
883 envdata->validflags |= ENVSYS_FMAXVALID;
884 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
885 req.cmdlen = 1;
886 req.rsplen = 2;
887 req.p = p;
888 tadpole_request(&req, 0);
889 envdata->min.data_us =
890 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
891 envdata->validflags |= ENVSYS_FMINVALID;
892 envdata->units = sc->sc_esensors[envdata->sensor].units;
893 break;
894 } else if (envdata->sensor == 1 || envdata->sensor == 2) {
895 envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
896 envdata->units = sc->sc_esensors[envdata->sensor].units;
897 if (envdata->sensor == 1)
898 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
899 else
900 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
901 req.cmdlen = 1;
902 req.rsplen = 2;
903 req.p = p;
904 tadpole_request(&req, 0);
905 envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000/11;
906 break;
907 }
908 break;
909
910 case ENVSYS_GTREINFO:
911 envinfo = (envsys_temp_info_t *)data;
912 if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
913 envinfo->validflags = 0;
914 break;
915 }
916 envinfo->units = sc->sc_esensors[envinfo->sensor].units;
917 memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc,
918 sizeof(sc->sc_esensors[envinfo->sensor].desc) >
919 sizeof(envinfo->desc) ? sizeof(envinfo->desc) :
920 sizeof(sc->sc_esensors[envinfo->sensor].desc));
921 if (envinfo->units == ENVSYS_STEMP) {
922 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
923 ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
924 } else if (envinfo->units == ENVSYS_SVOLTS_DC) {
925 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
926 } else
927 envinfo->validflags = 0;
928 break;
929
930 case ENVSYS_STREINFO:
931 envinfo = (envsys_temp_info_t *)data;
932 if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
933 envinfo->validflags = 0;
934 break;
935 }
936 if (envinfo->units == sc->sc_esensors[envinfo->sensor].units)
937 memcpy(sc->sc_esensors[envinfo->sensor].desc,
938 envinfo->desc,
939 sizeof(envinfo->desc) > sizeof(char)*32 ?
940 sizeof(char)*32 : sizeof(envinfo->desc) );
941 if (envinfo->units == ENVSYS_STEMP) {
942 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
943 ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
944 } else if (envinfo->units == ENVSYS_SVOLTS_DC) {
945 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
946 } else
947 envinfo->validflags = 0;
948 break;
949
950
951 default:
952 return (ENOTTY);
953 }
954 return (0);
955 }
956
957 int
958 tctrlpoll(dev, events, p)
959 dev_t dev;
960 int events;
961 struct proc *p;
962 {
963 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
964 int revents = 0;
965
966 if (events & (POLLIN | POLLRDNORM)) {
967 if (sc->sc_event_count)
968 revents |= events & (POLLIN | POLLRDNORM);
969 else
970 selrecord(p, &sc->sc_rsel);
971 }
972
973 return (revents);
974 }
975