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