tctrl.c revision 1.5 1 /* $NetBSD: tctrl.c,v 1.5 1999/12/17 00:32:25 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 i = 0;
567 while (((sc->sc_rspoff != sc->sc_rsplen) ||
568 (sc->sc_cmdoff != sc->sc_cmdlen)) &&
569 (i < (5 * sc->sc_rsplen + sc->sc_cmdlen)))
570 if (req->p != NULL) {
571 tsleep(sc, PWAIT, "tctrl_data", 15);
572 i++;
573 }
574 else
575 DELAY(1);
576 }
577 /*
578 * we give the user a reasonable amount of time for a command
579 * to complete. If it doesn't complete in time, we hand them
580 * garbage. This is here to stop things like setting the
581 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
582 */
583 sc->sc_wantdata = 0;
584 memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
585 splx(s);
586 }
587
588 void
589 tadpole_powerdown(void)
590 {
591 struct tctrl_req req;
592
593 req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
594 req.cmdlen = 1;
595 req.rsplen = 1;
596 req.p = NULL;
597 tadpole_request(&req, 1);
598 }
599
600 void
601 tadpole_set_video(enabled)
602 int enabled;
603 {
604 struct tctrl_softc *sc;
605 struct tctrl_req req;
606 int s;
607
608 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
609 while (sc->sc_wantdata != 0)
610 DELAY(1);
611 s = splts102();
612 req.p = NULL;
613 if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
614 || (sc->sc_tft_on)) {
615 req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
616 } else {
617 req.cmdbuf[2] = 0;
618 }
619 req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
620 req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
621 req.cmdlen = 3;
622 req.rsplen = 2;
623
624 if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
625 sc->sc_tft_on = enabled;
626 if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
627 splx(s);
628 return;
629 }
630 tadpole_request(&req, 1);
631 sc->sc_bitport =
632 (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
633 }
634 splx(s);
635 }
636
637 static void
638 tctrl_write_data(sc, v)
639 struct tctrl_softc *sc;
640 u_int8_t v;
641 {
642 unsigned int i;
643
644 for (i = 0; i < 100; i++) {
645 if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
646 break;
647 }
648 tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
649 }
650
651 static u_int8_t
652 tctrl_read_data(sc)
653 struct tctrl_softc *sc;
654 {
655 unsigned int i, v;
656
657 for (i = 0; i < 100000; i++) {
658 if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
659 break;
660 DELAY(1);
661 }
662
663 v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
664 tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
665 return v;
666 }
667
668 static u_int8_t
669 tctrl_read(sc, off)
670 struct tctrl_softc *sc;
671 bus_size_t off;
672 {
673
674 sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
675 return sc->sc_junk;
676 }
677
678 static void
679 tctrl_write(sc, off, v)
680 struct tctrl_softc *sc;
681 bus_size_t off;
682 u_int8_t v;
683 {
684
685 sc->sc_junk = v;
686 bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
687 }
688
689 int
690 tctrlopen(dev, flags, mode, p)
691 dev_t dev;
692 int flags, mode;
693 struct proc *p;
694 {
695 int unit = (minor(dev)&0xf0);
696 int ctl = (minor(dev)&0x0f);
697 struct tctrl_softc *sc;
698
699 if (unit >= tctrl_cd.cd_ndevs)
700 return(ENXIO);
701 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
702 if (!sc)
703 return(ENXIO);
704
705 switch (ctl) {
706 case TCTRL_STD_DEV:
707 break;
708 case TCTRL_APMCTL_DEV:
709 if (!(flags & FWRITE))
710 return(EINVAL);
711 if (sc->sc_flags & TCTRL_APM_CTLOPEN)
712 return(EBUSY);
713 sc->sc_flags |= TCTRL_APM_CTLOPEN;
714 break;
715 default:
716 return(ENXIO);
717 break;
718 }
719
720 return(0);
721 }
722
723 int
724 tctrlclose(dev, flags, mode, p)
725 dev_t dev;
726 int flags, mode;
727 struct proc *p;
728 {
729 int ctl = (minor(dev)&0x0f);
730 struct tctrl_softc *sc;
731
732 sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
733 if (!sc)
734 return(ENXIO);
735
736 switch (ctl) {
737 case TCTRL_STD_DEV:
738 break;
739 case TCTRL_APMCTL_DEV:
740 sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
741 break;
742 }
743 return(0);
744 }
745
746 int
747 tctrlioctl(dev, cmd, data, flags, p)
748 dev_t dev;
749 u_long cmd;
750 caddr_t data;
751 int flags;
752 struct proc *p;
753 {
754 struct tctrl_req req, *reqn;
755 envsys_range_t *envrange;
756 envsys_temp_data_t *envdata;
757 envsys_temp_info_t *envinfo;
758 struct apm_power_info *powerp;
759 struct apm_event_info *evp;
760 struct tctrl_softc *sc;
761 int i;
762 u_int j;
763 u_int16_t a;
764 u_int8_t c;
765
766 if (tctrl_cd.cd_devs == NULL
767 || tctrl_cd.cd_ndevs == 0
768 || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
769 return ENXIO;
770 }
771 sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
772 switch (cmd) {
773
774 case APM_IOC_STANDBY:
775 return(EOPNOTSUPP); /* for now */
776
777 case APM_IOC_SUSPEND:
778 return(EOPNOTSUPP); /* for now */
779
780 case APM_IOC_GETPOWER:
781 powerp = (struct apm_power_info *)data;
782 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
783 req.cmdlen = 1;
784 req.rsplen = 2;
785 req.p = p;
786 tadpole_request(&req, 0);
787 if (req.rspbuf[0] > 0x00)
788 powerp->battery_state = APM_BATT_CHARGING;
789 req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
790 req.cmdlen = 1;
791 req.rsplen = 3;
792 req.p = p;
793 tadpole_request(&req, 0);
794 c = req.rspbuf[0];
795 powerp->battery_life = c;
796 powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
797 if (powerp->battery_state != APM_BATT_CHARGING) {
798 if (c < 0x20)
799 powerp->battery_state = APM_BATT_CRITICAL;
800 else if (c < 0x40)
801 powerp->battery_state = APM_BATT_LOW;
802 else if (c < 0x66)
803 powerp->battery_state = APM_BATT_HIGH;
804 else
805 powerp->battery_state = APM_BATT_UNKNOWN;
806 }
807 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
808 req.cmdlen = 1;
809 req.rsplen = 3;
810 req.p = p;
811 tadpole_request(&req, 0);
812 a = req.rspbuf[0] * 256 + req.rspbuf[1];
813 if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
814 powerp->ac_state = APM_AC_ON;
815 else
816 powerp->ac_state = APM_AC_OFF;
817 break;
818
819 case APM_IOC_NEXTEVENT:
820 if (!sc->sc_event_count)
821 return EAGAIN;
822
823 evp = (struct apm_event_info *)data;
824 i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
825 i %= APM_NEVENTS;
826 *evp = sc->sc_event_list[i];
827 sc->sc_event_count--;
828 return(0);
829
830 /* this ioctl assumes the caller knows exactly what he is doing */
831 case TCTRL_CMD_REQ:
832 reqn = (struct tctrl_req *)data;
833 if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 &&
834 (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
835 (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
836 reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
837 reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
838 reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
839 reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
840 (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
841 reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
842 reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
843 return(i);
844 reqn->p = p;
845 tadpole_request(reqn, 0);
846 break;
847
848 case ENVSYS_VERSION:
849 *(int32_t *)data = 1000;
850 break;
851
852 case ENVSYS_GRANGE:
853 envrange = (envsys_range_t *)data;
854 i = 0;
855 envrange->high = envrange->low = 0;
856 for (j=0; j < ENVSYS_NUMSENSORS; j++) {
857 if (!i && envrange->units == sc->sc_esensors[j].units) {
858 envrange->low = j;
859 i++;
860 }
861 if (i && envrange->units == sc->sc_esensors[j].units)
862 envrange->high = j;
863 }
864 if (!i) {
865 envrange->high = 0;
866 envrange->low = 1;
867 }
868 break;
869
870 case ENVSYS_GTREDATA:
871 envdata = (envsys_temp_data_t *)data;
872 if (envdata->sensor >= ENVSYS_NUMSENSORS) {
873 envdata->validflags = 0;
874 break;
875 }
876 envdata->warnflags = ENVSYS_WARN_OK;
877 if (envdata->sensor == 0) {
878 envdata->validflags |= ENVSYS_FVALID;
879 req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
880 req.cmdlen = 1;
881 req.rsplen = 2;
882 req.p = p;
883 tadpole_request(&req, 0);
884 envdata->cur.data_us = /* 273160? */
885 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
886 envdata->validflags |= ENVSYS_FCURVALID;
887 req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
888 req.cmdlen = 1;
889 req.rsplen = 2;
890 req.p = p;
891 tadpole_request(&req, 0);
892 envdata->max.data_us =
893 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
894 envdata->validflags |= ENVSYS_FMAXVALID;
895 req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
896 req.cmdlen = 1;
897 req.rsplen = 2;
898 req.p = p;
899 tadpole_request(&req, 0);
900 envdata->min.data_us =
901 (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000/9+273000);
902 envdata->validflags |= ENVSYS_FMINVALID;
903 envdata->units = sc->sc_esensors[envdata->sensor].units;
904 break;
905 } else if (envdata->sensor == 1 || envdata->sensor == 2) {
906 envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
907 envdata->units = sc->sc_esensors[envdata->sensor].units;
908 if (envdata->sensor == 1)
909 req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
910 else
911 req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
912 req.cmdlen = 1;
913 req.rsplen = 2;
914 req.p = p;
915 tadpole_request(&req, 0);
916 envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000/11;
917 break;
918 }
919 break;
920
921 case ENVSYS_GTREINFO:
922 envinfo = (envsys_temp_info_t *)data;
923 if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
924 envinfo->validflags = 0;
925 break;
926 }
927 envinfo->units = sc->sc_esensors[envinfo->sensor].units;
928 memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc,
929 sizeof(sc->sc_esensors[envinfo->sensor].desc) >
930 sizeof(envinfo->desc) ? sizeof(envinfo->desc) :
931 sizeof(sc->sc_esensors[envinfo->sensor].desc));
932 if (envinfo->units == ENVSYS_STEMP) {
933 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
934 ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
935 } else if (envinfo->units == ENVSYS_SVOLTS_DC) {
936 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
937 } else
938 envinfo->validflags = 0;
939 break;
940
941 case ENVSYS_STREINFO:
942 envinfo = (envsys_temp_info_t *)data;
943 if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
944 envinfo->validflags = 0;
945 break;
946 }
947 if (envinfo->units == sc->sc_esensors[envinfo->sensor].units)
948 memcpy(sc->sc_esensors[envinfo->sensor].desc,
949 envinfo->desc,
950 sizeof(envinfo->desc) > sizeof(char)*32 ?
951 sizeof(char)*32 : sizeof(envinfo->desc) );
952 if (envinfo->units == ENVSYS_STEMP) {
953 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
954 ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
955 } else if (envinfo->units == ENVSYS_SVOLTS_DC) {
956 envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
957 } else
958 envinfo->validflags = 0;
959 break;
960
961
962 default:
963 return (ENOTTY);
964 }
965 return (0);
966 }
967
968 int
969 tctrlpoll(dev, events, p)
970 dev_t dev;
971 int events;
972 struct proc *p;
973 {
974 struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
975 int revents = 0;
976
977 if (events & (POLLIN | POLLRDNORM)) {
978 if (sc->sc_event_count)
979 revents |= events & (POLLIN | POLLRDNORM);
980 else
981 selrecord(p, &sc->sc_rsel);
982 }
983
984 return (revents);
985 }
986