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