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