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