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