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