1 /* $NetBSD: tctrl.c,v 1.49 2008/07/17 14:43:38 cegger Exp $ */
4 * Copyright (c) 1998, 2005, 2006 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: tctrl.c,v 1.49 2008/07/17 14:43:38 cegger Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/ioctl.h>
38 #include <sys/select.h>
44 #include <sys/kernel.h>
45 #include <sys/kthread.h>
46 #include <sys/syslog.h>
47 #include <sys/types.h>
48 #include <sys/device.h>
49 #include <sys/envsys.h>
51 #include <sys/kauth.h>
53 #include <machine/apmvar.h>
54 #include <machine/autoconf.h>
55 #include <machine/bus.h>
56 #include <machine/intr.h>
57 #include <machine/tctrl.h>
59 #include <sparc/dev/ts102reg.h>
60 #include <sparc/dev/tctrlvar.h>
61 #include <sparc/sparc/auxiotwo.h>
62 #include <sparc/sparc/auxreg.h>
64 #include <dev/sysmon/sysmonvar.h>
65 #include <dev/sysmon/sysmon_taskq.h>
67 #include "sysmon_envsys.h"
69 /*#define TCTRLDEBUG*/
73 #include <dev/scsipi/sdvar.h>
75 /* ethernet carrier */
77 #include <net/if_dl.h>
78 #include <net/if_ether.h>
79 #include <net/if_media.h>
80 #include <dev/ic/lancevar.h>
82 extern struct cfdriver tctrl_cd
;
84 dev_type_open(tctrlopen
);
85 dev_type_close(tctrlclose
);
86 dev_type_ioctl(tctrlioctl
);
87 dev_type_poll(tctrlpoll
);
88 dev_type_kqfilter(tctrlkqfilter
);
90 const struct cdevsw tctrl_cdevsw
= {
91 tctrlopen
, tctrlclose
, noread
, nowrite
, tctrlioctl
,
92 nostop
, notty
, tctrlpoll
, nommap
, tctrlkqfilter
,
95 static const char *tctrl_ext_statuses
[16] = {
96 "main power available",
97 "internal battery attached",
98 "external battery attached",
99 "external VGA attached",
100 "external keyboard attached",
101 "external mouse attached",
103 "internal battery charging",
104 "external battery charging",
105 "internal battery discharging",
106 "external battery discharging",
110 struct device sc_dev
;
111 bus_space_tag_t sc_memt
;
112 bus_space_handle_t sc_memh
;
113 unsigned int sc_junk
;
114 unsigned int sc_ext_status
;
115 unsigned int sc_flags
;
116 #define TCTRL_SEND_REQUEST 0x0001
117 #define TCTRL_APM_CTLOPEN 0x0002
118 uint32_t sc_wantdata
;
119 uint32_t sc_ext_pending
;
120 volatile uint16_t sc_lcdstate
;
121 uint16_t sc_lcdwanted
;
123 enum { TCTRL_IDLE
, TCTRL_ARGS
,
124 TCTRL_ACK
, TCTRL_DATA
} sc_state
;
125 uint8_t sc_cmdbuf
[16];
126 uint8_t sc_rspbuf
[16];
135 #define APM_NEVENTS 16
136 struct apm_event_info sc_event_list
[APM_NEVENTS
];
139 struct selinfo sc_rsel
;
142 #define ENVSYS_NUMSENSORS 3
143 struct evcnt sc_intrcnt
; /* interrupt counting */
144 struct sysmon_envsys
*sc_sme
;
145 envsys_data_t sc_sensor
[ENVSYS_NUMSENSORS
];
147 struct sysmon_pswitch sc_sm_pbutton
; /* power button */
148 struct sysmon_pswitch sc_sm_lid
; /* lid state */
149 struct sysmon_pswitch sc_sm_ac
; /* AC adaptor presence */
152 /* hardware status stuff */
153 int sc_lid
; /* 1 - open, 0 - closed */
158 * we call this when we detect connection or removal of an external
159 * monitor. 0 for no monitor, !=0 for monitor present
161 void (*sc_video_callback
)(void *, int);
162 void *sc_video_callback_cookie
;
166 lwp_t
*sc_thread
; /* event thread */
167 kmutex_t sc_requestlock
;
170 #define TCTRL_STD_DEV 0
171 #define TCTRL_APMCTL_DEV 8
173 static int tctrl_match(struct device
*, struct cfdata
*, void *);
174 static void tctrl_attach(struct device
*, struct device
*, void *);
175 static void tctrl_write(struct tctrl_softc
*, bus_size_t
, uint8_t);
176 static uint8_t tctrl_read(struct tctrl_softc
*, bus_size_t
);
177 static void tctrl_write_data(struct tctrl_softc
*, uint8_t);
178 static uint8_t tctrl_read_data(struct tctrl_softc
*);
179 static int tctrl_intr(void *);
180 static void tctrl_setup_bitport(void);
181 static void tctrl_setup_bitport_nop(void);
182 static void tctrl_read_ext_status(void);
183 static void tctrl_read_event_status(struct tctrl_softc
*);
184 static int tctrl_apm_record_event(struct tctrl_softc
*, u_int
);
185 static void tctrl_init_lcd(void);
187 static void tctrl_sensor_setup(struct tctrl_softc
*);
188 static void tctrl_refresh(struct sysmon_envsys
*, envsys_data_t
*);
190 static void tctrl_power_button_pressed(void *);
191 static void tctrl_lid_state(struct tctrl_softc
*);
192 static void tctrl_ac_state(struct tctrl_softc
*);
194 static int tctrl_powerfail(void *);
196 static void tctrl_event_thread(void *);
197 void tctrl_update_lcd(struct tctrl_softc
*);
199 static void tctrl_lock(struct tctrl_softc
*);
200 static void tctrl_unlock(struct tctrl_softc
*);
202 CFATTACH_DECL(tctrl
, sizeof(struct tctrl_softc
),
203 tctrl_match
, tctrl_attach
, NULL
, NULL
);
205 static int tadpole_request(struct tctrl_req
*, int, int);
207 /* XXX wtf is this? see i386/apm.c */
208 int tctrl_apm_evindex
;
211 tctrl_match(struct device
*parent
, struct cfdata
*cf
, void *aux
)
213 union obio_attach_args
*uoba
= aux
;
214 struct sbus_attach_args
*sa
= &uoba
->uoba_sbus
;
216 if (uoba
->uoba_isobio4
!= 0) {
220 /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
221 * (who's interface is off the TS102 PCMCIA controller but there
222 * exists a OpenProm for microcontroller interface).
224 return strcmp("uctrl", sa
->sa_name
) == 0;
228 tctrl_attach(struct device
*parent
, struct device
*self
, void *aux
)
230 struct tctrl_softc
*sc
= device_private(self
);
231 union obio_attach_args
*uoba
= aux
;
232 struct sbus_attach_args
*sa
= &uoba
->uoba_sbus
;
235 /* We're living on a sbus slot that looks like an obio that
236 * looks like an sbus slot.
238 sc
->sc_memt
= sa
->sa_bustag
;
239 if (sbus_bus_map(sc
->sc_memt
,
241 sa
->sa_offset
- TS102_REG_UCTRL_INT
,
243 BUS_SPACE_MAP_LINEAR
, &sc
->sc_memh
) != 0) {
244 printf(": can't map registers\n");
252 /* clear any pending data.
254 for (i
= 0; i
< 10000; i
++) {
255 if ((TS102_UCTRL_STS_RXNE_STA
&
256 tctrl_read(sc
, TS102_REG_UCTRL_STS
)) == 0) {
259 v
= tctrl_read(sc
, TS102_REG_UCTRL_DATA
);
260 tctrl_write(sc
, TS102_REG_UCTRL_STS
, TS102_UCTRL_STS_RXNE_STA
);
263 if (sa
->sa_nintr
!= 0) {
264 (void)bus_intr_establish(sc
->sc_memt
, sa
->sa_pri
, IPL_NONE
,
266 evcnt_attach_dynamic(&sc
->sc_intrcnt
, EVCNT_TYPE_INTR
, NULL
,
267 sc
->sc_dev
.dv_xname
, "intr");
270 /* See what the external status is */
271 sc
->sc_ext_status
= 0;
272 tctrl_read_ext_status();
273 if (sc
->sc_ext_status
!= 0) {
276 printf("%s: ", sc
->sc_dev
.dv_xname
);
277 v
= sc
->sc_ext_status
;
278 for (i
= 0, sep
= ""; v
!= 0; i
++, v
>>= 1) {
280 printf("%s%s", sep
, tctrl_ext_statuses
[i
]);
287 /* Get a current of the control bitport */
288 tctrl_setup_bitport_nop();
289 tctrl_write(sc
, TS102_REG_UCTRL_INT
,
290 TS102_UCTRL_INT_RXNE_REQ
|TS102_UCTRL_INT_RXNE_MSK
);
291 sc
->sc_lid
= (sc
->sc_ext_status
& TS102_EXT_STATUS_LID_DOWN
) == 0;
292 sc
->sc_power_state
= PWR_RESUME
;
294 sc
->sc_extvga
= (sc
->sc_ext_status
&
295 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED
) != 0;
296 sc
->sc_video_callback
= NULL
;
300 sc
->sc_event_count
= 0;
301 sc
->sc_ext_pending
= 0;
302 sc
->sc_ext_pending
= 0;
304 mutex_init(&sc
->sc_requestlock
, MUTEX_DEFAULT
, IPL_NONE
);
305 selinit(&sc
->sc_rsel
);
307 /* setup sensors and register the power button */
308 tctrl_sensor_setup(sc
);
312 /* initialize the LCD */
315 /* initialize sc_lcdstate */
317 sc
->sc_lcdwanted
= 0;
318 tadpole_set_lcd(2, 0);
320 /* fire up the LCD event thread */
323 if (kthread_create(PRI_NONE
, 0, NULL
, tctrl_event_thread
, sc
,
324 &sc
->sc_thread
, "%s", sc
->sc_dev
.dv_xname
) != 0) {
325 printf("%s: unable to create event kthread",
326 sc
->sc_dev
.dv_xname
);
331 tctrl_intr(void *arg
)
333 struct tctrl_softc
*sc
= arg
;
338 /* find out the cause(s) of the interrupt */
339 v
= tctrl_read(sc
, TS102_REG_UCTRL_STS
) & TS102_UCTRL_STS_MASK
;
341 /* clear the cause(s) of the interrupt */
342 tctrl_write(sc
, TS102_REG_UCTRL_STS
, v
);
344 v
&= ~(TS102_UCTRL_STS_RXO_STA
|TS102_UCTRL_STS_TXE_STA
);
345 if (sc
->sc_cmdoff
>= sc
->sc_cmdlen
) {
346 v
&= ~TS102_UCTRL_STS_TXNF_STA
;
347 if (tctrl_read(sc
, TS102_REG_UCTRL_INT
) &
348 TS102_UCTRL_INT_TXNF_REQ
) {
349 tctrl_write(sc
, TS102_REG_UCTRL_INT
, 0);
353 if ((v
== 0) && ((sc
->sc_flags
& TCTRL_SEND_REQUEST
) == 0 ||
354 sc
->sc_state
!= TCTRL_IDLE
)) {
360 if (v
& TS102_UCTRL_STS_RXNE_STA
) {
361 d
= tctrl_read_data(sc
);
362 switch (sc
->sc_state
) {
367 * set a flag and wakeup the event thread
369 sc
->sc_ext_pending
= 1;
371 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
372 sc
->sc_dev
.dv_xname
, sc
->sc_op
, d
);
377 printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
378 sc
->sc_dev
.dv_xname
, sc
->sc_op
, d
);
381 printf(" ack=0x%02x", d
);
385 sc
->sc_state
= sc
->sc_rsplen
? TCTRL_DATA
: TCTRL_IDLE
;
386 sc
->sc_wantdata
= sc
->sc_rsplen
? 1 : 0;
388 if (sc
->sc_rsplen
> 0) {
389 printf(" [data(%u)]", sc
->sc_rsplen
);
396 sc
->sc_rspbuf
[sc
->sc_rspoff
++] = d
;
398 printf(" [%d]=0x%02x", sc
->sc_rspoff
-1, d
);
400 if (sc
->sc_rspoff
== sc
->sc_rsplen
) {
404 sc
->sc_state
= TCTRL_IDLE
;
409 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
410 sc
->sc_dev
.dv_xname
, sc
->sc_op
, d
, sc
->sc_state
);
414 if ((sc
->sc_state
== TCTRL_IDLE
&& sc
->sc_wantdata
== 0) ||
415 sc
->sc_flags
& TCTRL_SEND_REQUEST
) {
416 if (sc
->sc_flags
& TCTRL_SEND_REQUEST
) {
417 sc
->sc_flags
&= ~TCTRL_SEND_REQUEST
;
420 if (sc
->sc_cmdlen
> 0) {
421 tctrl_write(sc
, TS102_REG_UCTRL_INT
,
422 tctrl_read(sc
, TS102_REG_UCTRL_INT
)
423 |TS102_UCTRL_INT_TXNF_MSK
424 |TS102_UCTRL_INT_TXNF_REQ
);
425 v
= tctrl_read(sc
, TS102_REG_UCTRL_STS
);
428 if ((sc
->sc_cmdoff
< sc
->sc_cmdlen
) && (v
& TS102_UCTRL_STS_TXNF_STA
)) {
429 tctrl_write_data(sc
, sc
->sc_cmdbuf
[sc
->sc_cmdoff
++]);
431 if (sc
->sc_cmdoff
== 1) {
432 printf("%s: op=0x%02x(l=%u)", sc
->sc_dev
.dv_xname
,
433 sc
->sc_cmdbuf
[0], sc
->sc_rsplen
);
435 printf(" [%d]=0x%02x", sc
->sc_cmdoff
-1,
436 sc
->sc_cmdbuf
[sc
->sc_cmdoff
-1]);
439 if (sc
->sc_cmdoff
== sc
->sc_cmdlen
) {
440 sc
->sc_state
= sc
->sc_rsplen
? TCTRL_ACK
: TCTRL_IDLE
;
442 printf(" %s", sc
->sc_rsplen
? "[ack]" : "[idle]\n");
444 if (sc
->sc_cmdoff
== 1) {
445 sc
->sc_op
= sc
->sc_cmdbuf
[0];
447 tctrl_write(sc
, TS102_REG_UCTRL_INT
,
448 tctrl_read(sc
, TS102_REG_UCTRL_INT
)
449 & (~TS102_UCTRL_INT_TXNF_MSK
450 |TS102_UCTRL_INT_TXNF_REQ
));
451 } else if (sc
->sc_state
== TCTRL_IDLE
) {
452 sc
->sc_op
= sc
->sc_cmdbuf
[0];
453 sc
->sc_state
= TCTRL_ARGS
;
463 tctrl_setup_bitport_nop(void)
465 struct tctrl_softc
*sc
;
466 struct tctrl_req req
;
469 sc
= device_lookup_private(&tctrl_cd
, TCTRL_STD_DEV
);
470 req
.cmdbuf
[0] = TS102_OP_CTL_BITPORT
;
471 req
.cmdbuf
[1] = 0xff;
472 req
.cmdbuf
[2] = 0x00;
475 tadpole_request(&req
, 1, 0);
477 sc
->sc_bitport
= (req
.rspbuf
[0] & req
.cmdbuf
[1]) ^ req
.cmdbuf
[2];
482 tctrl_setup_bitport(void)
484 struct tctrl_softc
*sc
;
485 struct tctrl_req req
;
488 sc
= device_lookup_private(&tctrl_cd
, TCTRL_STD_DEV
);
491 if ((sc
->sc_ext_status
& TS102_EXT_STATUS_LID_DOWN
)
492 || (!sc
->sc_tft_on
)) {
493 req
.cmdbuf
[2] = TS102_BITPORT_TFTPWR
;
495 req
.cmdbuf
[0] = TS102_OP_CTL_BITPORT
;
496 req
.cmdbuf
[1] = ~TS102_BITPORT_TFTPWR
;
499 tadpole_request(&req
, 1, 0);
501 sc
->sc_bitport
= (req
.rspbuf
[0] & req
.cmdbuf
[1]) ^ req
.cmdbuf
[2];
506 * The tadpole microcontroller is not preprogrammed with icon
507 * representations. The machine boots with the DC-IN light as
508 * a blank (all 0x00) and the other lights, as 4 rows of horizontal
509 * bars. The below code initializes the icons in the system to
510 * sane values. Some of these icons could be used for any purpose
511 * desired, namely the pcmcia, LAN and WAN lights. For the disk spinner,
512 * only the backslash is unprogrammed. (sigh)
514 * programming the icons is simple. It is a 5x8 matrix, which each row a
515 * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
521 struct tctrl_req req
;
523 req
.cmdbuf
[0] = TS102_OP_BLK_DEF_SPCL_CHAR
;
526 req
.cmdbuf
[1] = 0x08; /*len*/
527 req
.cmdbuf
[2] = TS102_BLK_OFF_DEF_DC_GOOD
;
528 req
.cmdbuf
[3] = 0x00; /* ..... */
529 req
.cmdbuf
[4] = 0x00; /* ..... */
530 req
.cmdbuf
[5] = 0x1f; /* XXXXX */
531 req
.cmdbuf
[6] = 0x00; /* ..... */
532 req
.cmdbuf
[7] = 0x15; /* X.X.X */
533 req
.cmdbuf
[8] = 0x00; /* ..... */
534 req
.cmdbuf
[9] = 0x00; /* ..... */
535 req
.cmdbuf
[10] = 0x00; /* ..... */
536 tadpole_request(&req
, 1, 0);
538 req
.cmdbuf
[0] = TS102_OP_BLK_DEF_SPCL_CHAR
;
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 tadpole_request(&req
, 1, 0);
553 req
.cmdbuf
[0] = TS102_OP_BLK_DEF_SPCL_CHAR
;
556 req
.cmdbuf
[1] = 0x08; /*len*/
557 req
.cmdbuf
[2] = TS102_BLK_OFF_DEF_WAN1
;
558 req
.cmdbuf
[3] = 0x0c; /* .XXX. */
559 req
.cmdbuf
[4] = 0x16; /* X.XX. */
560 req
.cmdbuf
[5] = 0x10; /* X.... */
561 req
.cmdbuf
[6] = 0x15; /* X.X.X */
562 req
.cmdbuf
[7] = 0x10; /* X.... */
563 req
.cmdbuf
[8] = 0x16; /* X.XX. */
564 req
.cmdbuf
[9] = 0x0c; /* .XXX. */
565 req
.cmdbuf
[10] = 0x00; /* ..... */
566 tadpole_request(&req
, 1, 0);
568 req
.cmdbuf
[0] = TS102_OP_BLK_DEF_SPCL_CHAR
;
571 req
.cmdbuf
[1] = 0x08; /*len*/
572 req
.cmdbuf
[2] = TS102_BLK_OFF_DEF_WAN2
;
573 req
.cmdbuf
[3] = 0x0c; /* .XXX. */
574 req
.cmdbuf
[4] = 0x0d; /* .XX.X */
575 req
.cmdbuf
[5] = 0x01; /* ....X */
576 req
.cmdbuf
[6] = 0x15; /* X.X.X */
577 req
.cmdbuf
[7] = 0x01; /* ....X */
578 req
.cmdbuf
[8] = 0x0d; /* .XX.X */
579 req
.cmdbuf
[9] = 0x0c; /* .XXX. */
580 req
.cmdbuf
[10] = 0x00; /* ..... */
581 tadpole_request(&req
, 1, 0);
583 req
.cmdbuf
[0] = TS102_OP_BLK_DEF_SPCL_CHAR
;
586 req
.cmdbuf
[1] = 0x08; /*len*/
587 req
.cmdbuf
[2] = TS102_BLK_OFF_DEF_LAN1
;
588 req
.cmdbuf
[3] = 0x00; /* ..... */
589 req
.cmdbuf
[4] = 0x04; /* ..X.. */
590 req
.cmdbuf
[5] = 0x08; /* .X... */
591 req
.cmdbuf
[6] = 0x13; /* X..XX */
592 req
.cmdbuf
[7] = 0x08; /* .X... */
593 req
.cmdbuf
[8] = 0x04; /* ..X.. */
594 req
.cmdbuf
[9] = 0x00; /* ..... */
595 req
.cmdbuf
[10] = 0x00; /* ..... */
596 tadpole_request(&req
, 1, 0);
598 req
.cmdbuf
[0] = TS102_OP_BLK_DEF_SPCL_CHAR
;
601 req
.cmdbuf
[1] = 0x08; /*len*/
602 req
.cmdbuf
[2] = TS102_BLK_OFF_DEF_LAN2
;
603 req
.cmdbuf
[3] = 0x00; /* ..... */
604 req
.cmdbuf
[4] = 0x04; /* ..X.. */
605 req
.cmdbuf
[5] = 0x02; /* ...X. */
606 req
.cmdbuf
[6] = 0x19; /* XX..X */
607 req
.cmdbuf
[7] = 0x02; /* ...X. */
608 req
.cmdbuf
[8] = 0x04; /* ..X.. */
609 req
.cmdbuf
[9] = 0x00; /* ..... */
610 req
.cmdbuf
[10] = 0x00; /* ..... */
611 tadpole_request(&req
, 1, 0);
613 req
.cmdbuf
[0] = TS102_OP_BLK_DEF_SPCL_CHAR
;
616 req
.cmdbuf
[1] = 0x08; /*len*/
617 req
.cmdbuf
[2] = TS102_BLK_OFF_DEF_PCMCIA
;
618 req
.cmdbuf
[3] = 0x00; /* ..... */
619 req
.cmdbuf
[4] = 0x0c; /* .XXX. */
620 req
.cmdbuf
[5] = 0x1f; /* XXXXX */
621 req
.cmdbuf
[6] = 0x1f; /* XXXXX */
622 req
.cmdbuf
[7] = 0x1f; /* XXXXX */
623 req
.cmdbuf
[8] = 0x1f; /* XXXXX */
624 req
.cmdbuf
[9] = 0x00; /* ..... */
625 req
.cmdbuf
[10] = 0x00; /* ..... */
626 tadpole_request(&req
, 1, 0);
629 /* sc_lcdwanted -> lcd_state */
631 tctrl_update_lcd(struct tctrl_softc
*sc
)
633 struct tctrl_req req
;
637 if (sc
->sc_lcdwanted
== sc
->sc_lcdstate
) {
641 sc
->sc_lcdstate
= sc
->sc_lcdwanted
;
645 * the mask setup on this particular command is *very* bizzare
646 * and totally undocumented.
648 req
.cmdbuf
[0] = TS102_OP_CTL_LCD
;
650 /* leave caps-lock alone */
651 req
.cmdbuf
[2] = (u_int8_t
)(sc
->sc_lcdstate
& 0xfe);
652 req
.cmdbuf
[3] = (u_int8_t
)((sc
->sc_lcdstate
& 0x100)>>8);
658 /* XXX this thing is weird.... */
662 /* below are the values one would expect but which won't work */
667 tadpole_request(&req
, 1, 0);
672 * set the blinken-lights on the lcd. what:
673 * what = 0 off, what = 1 on, what = 2 toggle
677 tadpole_set_lcd(int what
, unsigned short which
)
679 struct tctrl_softc
*sc
;
682 sc
= device_lookup_private(&tctrl_cd
, TCTRL_STD_DEV
);
687 sc
->sc_lcdwanted
&= ~which
;
690 sc
->sc_lcdwanted
|= which
;
693 sc
->sc_lcdwanted
^= which
;
700 tctrl_read_ext_status(void)
702 struct tctrl_softc
*sc
;
703 struct tctrl_req req
;
706 sc
= device_lookup_private(&tctrl_cd
, TCTRL_STD_DEV
);
707 req
.cmdbuf
[0] = TS102_OP_RD_EXT_STATUS
;
711 printf("pre read: sc->sc_ext_status = 0x%x\n", sc
->sc_ext_status
);
713 tadpole_request(&req
, 1, 0);
715 sc
->sc_ext_status
= (req
.rspbuf
[0] << 8) + req
.rspbuf
[1];
718 printf("post read: sc->sc_ext_status = 0x%x\n", sc
->sc_ext_status
);
723 * return 0 if the user will notice and handle the event,
724 * return 1 if the kernel driver should do so.
727 tctrl_apm_record_event(struct tctrl_softc
*sc
, u_int event_type
)
729 struct apm_event_info
*evp
;
731 if ((sc
->sc_flags
& TCTRL_APM_CTLOPEN
) &&
732 (sc
->sc_event_count
< APM_NEVENTS
)) {
733 evp
= &sc
->sc_event_list
[sc
->sc_event_ptr
];
734 sc
->sc_event_count
++;
736 sc
->sc_event_ptr
%= APM_NEVENTS
;
737 evp
->type
= event_type
;
738 evp
->index
= ++tctrl_apm_evindex
;
739 selnotify(&sc
->sc_rsel
, 0, 0);
740 return(sc
->sc_flags
& TCTRL_APM_CTLOPEN
) ? 0 : 1;
746 tctrl_read_event_status(struct tctrl_softc
*sc
)
748 struct tctrl_req req
;
752 req
.cmdbuf
[0] = TS102_OP_RD_EVENT_STATUS
;
755 tadpole_request(&req
, 1, 0);
757 v
= req
.rspbuf
[0] * 256 + req
.rspbuf
[1];
759 printf("event: %x\n",v
);
761 if (v
& TS102_EVENT_STATUS_POWERON_BTN_PRESSED
) {
762 printf("%s: Power button pressed\n",sc
->sc_dev
.dv_xname
);
765 if (v
& TS102_EVENT_STATUS_SHUTDOWN_REQUEST
) {
766 printf("%s: SHUTDOWN REQUEST!\n", sc
->sc_dev
.dv_xname
);
769 if (v
& TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING
) {
770 /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
771 /* according to a tadpole header, and observation */
773 printf("%s: Battery charge level change\n",
774 sc
->sc_dev
.dv_xname
);
777 if (v
& TS102_EVENT_STATUS_LOW_POWER_WARNING
) {
778 if (tctrl_apm_record_event(sc
, APM_BATTERY_LOW
))
779 printf("%s: LOW POWER WARNING!\n", sc
->sc_dev
.dv_xname
);
781 if (v
& TS102_EVENT_STATUS_DC_STATUS_CHANGE
) {
783 tctrl_read_ext_status();
786 if (tctrl_apm_record_event(sc
, APM_POWER_CHANGE
))
787 printf("%s: main power %s\n", sc
->sc_dev
.dv_xname
,
789 TS102_EXT_STATUS_MAIN_POWER_AVAILABLE
) ?
790 "restored" : "removed");
792 if (v
& TS102_EVENT_STATUS_LID_STATUS_CHANGE
) {
794 tctrl_read_ext_status();
796 tctrl_setup_bitport();
798 printf("%s: lid %s\n", sc
->sc_dev
.dv_xname
,
799 (sc
->sc_ext_status
& TS102_EXT_STATUS_LID_DOWN
)
800 ? "closed" : "opened");
802 lid
= (sc
->sc_ext_status
& TS102_EXT_STATUS_LID_DOWN
) == 0;
804 if (v
& TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE
) {
807 tctrl_read_ext_status();
808 vga
= (sc
->sc_ext_status
&
809 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED
) != 0;
810 if (vga
!= sc
->sc_extvga
) {
812 if (sc
->sc_video_callback
!= NULL
) {
813 sc
->sc_video_callback(
814 sc
->sc_video_callback_cookie
,
820 if (v
& TS102_EVENT_STATUS_EXT_MOUSE_STATUS_CHANGE
) {
822 tctrl_read_ext_status();
823 if (sc
->sc_ext_status
&
824 TS102_EXT_STATUS_EXTERNAL_MOUSE_ATTACHED
) {
825 printf("tctrl: external mouse detected\n");
829 sc
->sc_ext_pending
= 0;
834 tctrl_lock(struct tctrl_softc
*sc
)
837 mutex_enter(&sc
->sc_requestlock
);
841 tctrl_unlock(struct tctrl_softc
*sc
)
844 mutex_exit(&sc
->sc_requestlock
);
848 tadpole_request(struct tctrl_req
*req
, int spin
, int sleep
)
850 struct tctrl_softc
*sc
;
853 sc
= device_lookup_private(&tctrl_cd
, TCTRL_STD_DEV
);
863 sc
->sc_flags
|= TCTRL_SEND_REQUEST
;
864 memcpy(sc
->sc_cmdbuf
, req
->cmdbuf
, req
->cmdlen
);
866 if (sc
->sc_wantdata
!= 0) {
868 printf("tctrl: we lost the race\n");
874 sc
->sc_rsplen
= req
->rsplen
;
875 sc
->sc_cmdlen
= req
->cmdlen
;
876 sc
->sc_cmdoff
= sc
->sc_rspoff
= 0;
878 /* we spin for certain commands, like poweroffs */
880 /* for (i = 0; i < 30000; i++) {*/
882 while ((sc
->sc_wantdata
== 1) && (i
< 30000)) {
889 printf("tctrl: timeout busy waiting for micro controller request!\n");
897 int timeout
= 5 * (sc
->sc_rsplen
+ sc
->sc_cmdlen
);
900 while (((sc
->sc_rspoff
!= sc
->sc_rsplen
) ||
901 (sc
->sc_cmdoff
!= sc
->sc_cmdlen
)) &&
904 tsleep(sc
, PWAIT
, "tctrl_data", 15);
910 printf("tctrl: timeout waiting for microcontroller request\n");
919 * we give the user a reasonable amount of time for a command
920 * to complete. If it doesn't complete in time, we hand them
921 * garbage. This is here to stop things like setting the
922 * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
925 memcpy(req
->rspbuf
, sc
->sc_rspbuf
, req
->rsplen
);
933 tadpole_powerdown(void)
935 struct tctrl_req req
;
937 req
.cmdbuf
[0] = TS102_OP_ADMIN_POWER_OFF
;
940 tadpole_request(&req
, 1, 0);
944 tadpole_set_video(int enabled
)
946 struct tctrl_softc
*sc
;
947 struct tctrl_req req
;
950 sc
= device_lookup_private(&tctrl_cd
, TCTRL_STD_DEV
);
951 while (sc
->sc_wantdata
!= 0)
954 if ((sc
->sc_ext_status
& TS102_EXT_STATUS_LID_DOWN
&& !enabled
)
955 || (sc
->sc_tft_on
)) {
956 req
.cmdbuf
[2] = TS102_BITPORT_TFTPWR
;
960 req
.cmdbuf
[0] = TS102_OP_CTL_BITPORT
;
961 req
.cmdbuf
[1] = ~TS102_BITPORT_TFTPWR
;
965 if ((sc
->sc_tft_on
&& !enabled
) || (!sc
->sc_tft_on
&& enabled
)) {
966 sc
->sc_tft_on
= enabled
;
967 if (sc
->sc_ext_status
& TS102_EXT_STATUS_LID_DOWN
) {
971 tadpole_request(&req
, 1, 0);
973 (req
.rspbuf
[0] & req
.cmdbuf
[1]) ^ req
.cmdbuf
[2];
979 tctrl_write_data(struct tctrl_softc
*sc
, uint8_t v
)
983 for (i
= 0; i
< 100; i
++) {
984 if (TS102_UCTRL_STS_TXNF_STA
&
985 tctrl_read(sc
, TS102_REG_UCTRL_STS
))
988 tctrl_write(sc
, TS102_REG_UCTRL_DATA
, v
);
992 tctrl_read_data(struct tctrl_softc
*sc
)
996 for (i
= 0; i
< 100000; i
++) {
997 if (TS102_UCTRL_STS_RXNE_STA
&
998 tctrl_read(sc
, TS102_REG_UCTRL_STS
))
1003 v
= tctrl_read(sc
, TS102_REG_UCTRL_DATA
);
1004 tctrl_write(sc
, TS102_REG_UCTRL_STS
, TS102_UCTRL_STS_RXNE_STA
);
1009 tctrl_read(struct tctrl_softc
*sc
, bus_size_t off
)
1012 sc
->sc_junk
= bus_space_read_1(sc
->sc_memt
, sc
->sc_memh
, off
);
1017 tctrl_write(struct tctrl_softc
*sc
, bus_size_t off
, uint8_t v
)
1021 bus_space_write_1(sc
->sc_memt
, sc
->sc_memh
, off
, v
);
1025 tctrlopen(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
1027 int unit
= (minor(dev
)&0xf0);
1028 int ctl
= (minor(dev
)&0x0f);
1029 struct tctrl_softc
*sc
;
1031 if (unit
>= tctrl_cd
.cd_ndevs
)
1033 sc
= device_lookup_private(&tctrl_cd
, TCTRL_STD_DEV
);
1040 case TCTRL_APMCTL_DEV
:
1041 if (!(flags
& FWRITE
))
1043 if (sc
->sc_flags
& TCTRL_APM_CTLOPEN
)
1045 sc
->sc_flags
|= TCTRL_APM_CTLOPEN
;
1056 tctrlclose(dev_t dev
, int flags
, int mode
, struct lwp
*l
)
1058 int ctl
= (minor(dev
)&0x0f);
1059 struct tctrl_softc
*sc
;
1061 sc
= device_lookup_private(&tctrl_cd
, TCTRL_STD_DEV
);
1068 case TCTRL_APMCTL_DEV
:
1069 sc
->sc_flags
&= ~TCTRL_APM_CTLOPEN
;
1076 tctrlioctl(dev_t dev
, u_long cmd
, void *data
, int flags
, struct lwp
*l
)
1078 struct tctrl_req req
, *reqn
;
1079 struct tctrl_pwr
*pwrreq
;
1080 struct apm_power_info
*powerp
;
1081 struct apm_event_info
*evp
;
1082 struct tctrl_softc
*sc
;
1086 sc
= device_lookup_private(&tctrl_cd
, TCTRL_STD_DEV
);
1092 case APM_IOC_STANDBY
:
1093 /* turn off backlight and so on ? */
1095 return 0; /* for now */
1097 case APM_IOC_SUSPEND
:
1098 /* not sure what to do here - we can't really suspend */
1100 return 0; /* for now */
1102 case OAPM_IOC_GETPOWER
:
1103 case APM_IOC_GETPOWER
:
1104 powerp
= (struct apm_power_info
*)data
;
1105 req
.cmdbuf
[0] = TS102_OP_RD_INT_CHARGE_RATE
;
1108 tadpole_request(&req
, 0, l
->l_proc
? 1 : 0);
1109 if (req
.rspbuf
[0] > 0x00)
1110 powerp
->battery_state
= APM_BATT_CHARGING
;
1111 req
.cmdbuf
[0] = TS102_OP_RD_INT_CHARGE_LEVEL
;
1114 tadpole_request(&req
, 0, l
->l_proc
? 1 : 0);
1116 powerp
->battery_life
= c
;
1117 if (c
> 0x70) /* the tadpole sometimes dips below zero, and */
1118 c
= 0; /* into the 255 range. */
1119 powerp
->minutes_left
= (45 * c
) / 100; /* XXX based on 45 min */
1120 if (powerp
->battery_state
!= APM_BATT_CHARGING
) {
1122 powerp
->battery_state
= APM_BATT_CRITICAL
;
1124 powerp
->battery_state
= APM_BATT_LOW
;
1126 powerp
->battery_state
= APM_BATT_HIGH
;
1128 powerp
->battery_state
= APM_BATT_UNKNOWN
;
1131 if (sc
->sc_ext_status
& TS102_EXT_STATUS_MAIN_POWER_AVAILABLE
)
1132 powerp
->ac_state
= APM_AC_ON
;
1134 powerp
->ac_state
= APM_AC_OFF
;
1137 case APM_IOC_NEXTEVENT
:
1138 if (!sc
->sc_event_count
)
1141 evp
= (struct apm_event_info
*)data
;
1142 i
= sc
->sc_event_ptr
+ APM_NEVENTS
- sc
->sc_event_count
;
1144 *evp
= sc
->sc_event_list
[i
];
1145 sc
->sc_event_count
--;
1148 /* this ioctl assumes the caller knows exactly what he is doing */
1150 reqn
= (struct tctrl_req
*)data
;
1151 if ((i
= kauth_authorize_generic(l
->l_cred
,
1152 KAUTH_GENERIC_ISSUSER
, NULL
)) != 0 &&
1153 (reqn
->cmdbuf
[0] == TS102_OP_CTL_BITPORT
||
1154 (reqn
->cmdbuf
[0] >= TS102_OP_CTL_WATCHDOG
&&
1155 reqn
->cmdbuf
[0] <= TS102_OP_CTL_SECURITY_KEY
) ||
1156 reqn
->cmdbuf
[0] == TS102_OP_CTL_TIMEZONE
||
1157 reqn
->cmdbuf
[0] == TS102_OP_CTL_DIAGNOSTIC_MODE
||
1158 reqn
->cmdbuf
[0] == TS102_OP_CMD_SOFTWARE_RESET
||
1159 (reqn
->cmdbuf
[0] >= TS102_OP_CMD_SET_RTC
&&
1160 reqn
->cmdbuf
[0] < TS102_OP_RD_INT_CHARGE_LEVEL
) ||
1161 reqn
->cmdbuf
[0] > TS102_OP_RD_EXT_CHARGE_LEVEL
))
1163 tadpole_request(reqn
, 0, l
->l_proc
? 1 : 0);
1165 /* serial power mode (via auxiotwo) */
1166 case TCTRL_SERIAL_PWR
:
1167 pwrreq
= (struct tctrl_pwr
*)data
;
1169 pwrreq
->state
= auxiotwoserialgetapm();
1171 auxiotwoserialsetapm(pwrreq
->state
);
1174 /* modem power mode (via auxio) */
1175 case TCTRL_MODEM_PWR
:
1176 return(EOPNOTSUPP
); /* for now */
1187 tctrlpoll(dev_t dev
, int events
, struct lwp
*l
)
1189 struct tctrl_softc
*sc
= device_lookup_private(&tctrl_cd
,
1193 if (events
& (POLLIN
| POLLRDNORM
)) {
1194 if (sc
->sc_event_count
)
1195 revents
|= events
& (POLLIN
| POLLRDNORM
);
1197 selrecord(l
, &sc
->sc_rsel
);
1204 filt_tctrlrdetach(struct knote
*kn
)
1206 struct tctrl_softc
*sc
= kn
->kn_hook
;
1210 SLIST_REMOVE(&sc
->sc_rsel
.sel_klist
, kn
, knote
, kn_selnext
);
1215 filt_tctrlread(struct knote
*kn
, long hint
)
1217 struct tctrl_softc
*sc
= kn
->kn_hook
;
1219 kn
->kn_data
= sc
->sc_event_count
;
1220 return (kn
->kn_data
> 0);
1223 static const struct filterops tctrlread_filtops
=
1224 { 1, NULL
, filt_tctrlrdetach
, filt_tctrlread
};
1227 tctrlkqfilter(dev_t dev
, struct knote
*kn
)
1229 struct tctrl_softc
*sc
= device_lookup_private(&tctrl_cd
,
1231 struct klist
*klist
;
1234 switch (kn
->kn_filter
) {
1236 klist
= &sc
->sc_rsel
.sel_klist
;
1237 kn
->kn_fop
= &tctrlread_filtops
;
1247 SLIST_INSERT_HEAD(klist
, kn
, kn_selnext
);
1254 tctrl_sensor_setup(struct tctrl_softc
*sc
)
1258 sc
->sc_sme
= sysmon_envsys_create();
1260 /* case temperature */
1261 (void)strlcpy(sc
->sc_sensor
[0].desc
, "Case temperature",
1262 sizeof(sc
->sc_sensor
[0].desc
));
1263 sc
->sc_sensor
[0].units
= ENVSYS_STEMP
;
1265 /* battery voltage */
1266 (void)strlcpy(sc
->sc_sensor
[1].desc
, "Internal battery voltage",
1267 sizeof(sc
->sc_sensor
[1].desc
));
1268 sc
->sc_sensor
[1].units
= ENVSYS_SVOLTS_DC
;
1271 (void)strlcpy(sc
->sc_sensor
[2].desc
, "DC-In voltage",
1272 sizeof(sc
->sc_sensor
[2].desc
));
1273 sc
->sc_sensor
[2].units
= ENVSYS_SVOLTS_DC
;
1275 for (i
= 0; i
< ENVSYS_NUMSENSORS
; i
++) {
1276 if (sysmon_envsys_sensor_attach(sc
->sc_sme
,
1277 &sc
->sc_sensor
[i
])) {
1278 sysmon_envsys_destroy(sc
->sc_sme
);
1283 sc
->sc_sme
->sme_name
= sc
->sc_dev
.dv_xname
;
1284 sc
->sc_sme
->sme_cookie
= sc
;
1285 sc
->sc_sme
->sme_refresh
= tctrl_refresh
;
1287 if ((error
= sysmon_envsys_register(sc
->sc_sme
)) != 0) {
1288 printf("%s: couldn't register sensors (%d)\n",
1289 sc
->sc_dev
.dv_xname
, error
);
1290 sysmon_envsys_destroy(sc
->sc_sme
);
1294 /* now register the power button */
1296 sysmon_task_queue_init();
1298 sc
->sc_powerpressed
= 0;
1299 memset(&sc
->sc_sm_pbutton
, 0, sizeof(struct sysmon_pswitch
));
1300 sc
->sc_sm_pbutton
.smpsw_name
= sc
->sc_dev
.dv_xname
;
1301 sc
->sc_sm_pbutton
.smpsw_type
= PSWITCH_TYPE_POWER
;
1302 if (sysmon_pswitch_register(&sc
->sc_sm_pbutton
) != 0)
1303 printf("%s: unable to register power button with sysmon\n",
1304 sc
->sc_dev
.dv_xname
);
1306 memset(&sc
->sc_sm_lid
, 0, sizeof(struct sysmon_pswitch
));
1307 sc
->sc_sm_lid
.smpsw_name
= sc
->sc_dev
.dv_xname
;
1308 sc
->sc_sm_lid
.smpsw_type
= PSWITCH_TYPE_LID
;
1309 if (sysmon_pswitch_register(&sc
->sc_sm_lid
) != 0)
1310 printf("%s: unable to register lid switch with sysmon\n",
1311 sc
->sc_dev
.dv_xname
);
1313 memset(&sc
->sc_sm_ac
, 0, sizeof(struct sysmon_pswitch
));
1314 sc
->sc_sm_ac
.smpsw_name
= sc
->sc_dev
.dv_xname
;
1315 sc
->sc_sm_ac
.smpsw_type
= PSWITCH_TYPE_ACADAPTER
;
1316 if (sysmon_pswitch_register(&sc
->sc_sm_ac
) != 0)
1317 printf("%s: unable to register AC adaptor with sysmon\n",
1318 sc
->sc_dev
.dv_xname
);
1322 tctrl_power_button_pressed(void *arg
)
1324 struct tctrl_softc
*sc
= arg
;
1326 sysmon_pswitch_event(&sc
->sc_sm_pbutton
, PSWITCH_EVENT_PRESSED
);
1327 sc
->sc_powerpressed
= 0;
1331 tctrl_lid_state(struct tctrl_softc
*sc
)
1335 state
= (sc
->sc_ext_status
& TS102_EXT_STATUS_LID_DOWN
) ?
1336 PSWITCH_EVENT_PRESSED
: PSWITCH_EVENT_RELEASED
;
1337 sysmon_pswitch_event(&sc
->sc_sm_lid
, state
);
1341 tctrl_ac_state(struct tctrl_softc
*sc
)
1345 state
= (sc
->sc_ext_status
& TS102_EXT_STATUS_MAIN_POWER_AVAILABLE
) ?
1346 PSWITCH_EVENT_PRESSED
: PSWITCH_EVENT_RELEASED
;
1347 sysmon_pswitch_event(&sc
->sc_sm_ac
, state
);
1351 tctrl_powerfail(void *arg
)
1353 struct tctrl_softc
*sc
= (struct tctrl_softc
*)arg
;
1356 * We lost power. Queue a callback with thread context to
1357 * handle all the real work.
1359 if (sc
->sc_powerpressed
== 0) {
1360 sc
->sc_powerpressed
= 1;
1361 sysmon_task_queue_sched(0, tctrl_power_button_pressed
, sc
);
1367 tctrl_refresh(struct sysmon_envsys
*sme
, envsys_data_t
*edata
)
1369 /*struct tctrl_softc *sc = sme->sme_cookie;*/
1370 struct tctrl_req req
;
1375 sleepable
= curlwp
? 1 : 0;
1379 case 0: /* case temperature */
1380 req
.cmdbuf
[0] = TS102_OP_RD_CURRENT_TEMP
;
1383 tadpole_request(&req
, 0, sleepable
);
1384 edata
->value_cur
= /* 273160? */
1385 (uint32_t)((int)((int)req
.rspbuf
[0] - 32) * 5000000
1387 req
.cmdbuf
[0] = TS102_OP_RD_MAX_TEMP
;
1390 tadpole_request(&req
, 0, sleepable
);
1392 (uint32_t)((int)((int)req
.rspbuf
[0] - 32) * 5000000
1394 edata
->flags
|= ENVSYS_FVALID_MAX
;
1395 req
.cmdbuf
[0] = TS102_OP_RD_MIN_TEMP
;
1398 tadpole_request(&req
, 0, sleepable
);
1400 (uint32_t)((int)((int)req
.rspbuf
[0] - 32) * 5000000
1402 edata
->flags
|= ENVSYS_FVALID_MIN
;
1403 edata
->units
= ENVSYS_STEMP
;
1406 case 1: /* battery voltage */
1408 edata
->units
= ENVSYS_SVOLTS_DC
;
1409 req
.cmdbuf
[0] = TS102_OP_RD_INT_BATT_VLT
;
1412 tadpole_request(&req
, 0, sleepable
);
1413 edata
->value_cur
= (int32_t)req
.rspbuf
[0] *
1417 case 2: /* DC voltage */
1419 edata
->units
= ENVSYS_SVOLTS_DC
;
1420 req
.cmdbuf
[0] = TS102_OP_RD_DC_IN_VLT
;
1423 tadpole_request(&req
, 0, sleepable
);
1424 edata
->value_cur
= (int32_t)req
.rspbuf
[0] *
1429 edata
->state
= ENVSYS_SVALID
;
1433 tctrl_event_thread(void *v
)
1435 struct tctrl_softc
*sc
= v
;
1437 struct sd_softc
*sd
= NULL
;
1438 struct lance_softc
*le
= NULL
;
1443 while (sd
== NULL
) {
1444 dv
= device_find_by_xname("sd0");
1446 sd
= device_private(dv
);
1448 tsleep(&sc
->sc_events
, PWAIT
, "probe_disk", hz
);
1450 dv
= device_find_by_xname("le0");
1452 le
= device_private(dv
);
1453 printf("found %s\n", device_xname(sd
->sc_dev
));
1454 rcount
= sd
->sc_dk
.dk_stats
->io_rxfer
;
1455 wcount
= sd
->sc_dk
.dk_stats
->io_wxfer
;
1457 tctrl_read_event_status(sc
);
1460 tsleep(&sc
->sc_events
, PWAIT
, "tctrl_event", ticks
);
1462 if ((rcount
!= sd
->sc_dk
.dk_stats
->io_rxfer
) ||
1463 (wcount
!= sd
->sc_dk
.dk_stats
->io_wxfer
)) {
1464 rcount
= sd
->sc_dk
.dk_stats
->io_rxfer
;
1465 wcount
= sd
->sc_dk
.dk_stats
->io_wxfer
;
1466 sc
->sc_lcdwanted
|= TS102_LCD_DISK_ACTIVE
;
1468 sc
->sc_lcdwanted
&= ~TS102_LCD_DISK_ACTIVE
;
1470 if (le
->sc_havecarrier
!= 0) {
1471 sc
->sc_lcdwanted
|= TS102_LCD_LAN_ACTIVE
;
1473 sc
->sc_lcdwanted
&= ~TS102_LCD_LAN_ACTIVE
;
1476 tctrl_update_lcd(sc
);
1477 if (sc
->sc_ext_pending
)
1478 tctrl_read_event_status(sc
);
1483 tadpole_register_callback(void (*callback
)(void *, int), void *cookie
)
1485 struct tctrl_softc
*sc
;
1487 sc
= device_lookup_private(&tctrl_cd
, TCTRL_STD_DEV
);
1488 sc
->sc_video_callback
= callback
;
1489 sc
->sc_video_callback_cookie
= cookie
;
1490 if (sc
->sc_video_callback
!= NULL
) {
1491 sc
->sc_video_callback(sc
->sc_video_callback_cookie
,