tctrl.c revision 1.65 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