tctrl.c revision 1.12.4.5 1 1.12.4.5 jdolecek /* $NetBSD: tctrl.c,v 1.12.4.5 2002/10/02 22:02:25 jdolecek Exp $ */
2 1.1 matt
3 1.1 matt /*-
4 1.1 matt * Copyright (c) 1998 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.1 matt
39 1.1 matt #include <sys/param.h>
40 1.1 matt #include <sys/systm.h>
41 1.8 thorpej #include <sys/callout.h>
42 1.1 matt #include <sys/ioctl.h>
43 1.1 matt #include <sys/select.h>
44 1.1 matt #include <sys/tty.h>
45 1.1 matt #include <sys/proc.h>
46 1.1 matt #include <sys/user.h>
47 1.1 matt #include <sys/conf.h>
48 1.1 matt #include <sys/file.h>
49 1.1 matt #include <sys/uio.h>
50 1.1 matt #include <sys/kernel.h>
51 1.1 matt #include <sys/syslog.h>
52 1.1 matt #include <sys/types.h>
53 1.1 matt #include <sys/device.h>
54 1.4 garbled #include <sys/envsys.h>
55 1.4 garbled #include <sys/poll.h>
56 1.1 matt
57 1.4 garbled #include <machine/apmvar.h>
58 1.1 matt #include <machine/autoconf.h>
59 1.1 matt #include <machine/bus.h>
60 1.11 pk #include <machine/intr.h>
61 1.4 garbled #include <machine/tctrl.h>
62 1.1 matt
63 1.1 matt #include <sparc/dev/ts102reg.h>
64 1.1 matt #include <sparc/dev/tctrlvar.h>
65 1.7 jdc #include <sparc/sparc/auxiotwo.h>
66 1.1 matt
67 1.4 garbled cdev_decl(tctrl);
68 1.4 garbled
69 1.4 garbled extern struct cfdriver tctrl_cd;
70 1.4 garbled
71 1.1 matt static const char *tctrl_ext_statuses[16] = {
72 1.1 matt "main power available",
73 1.1 matt "internal battery attached",
74 1.1 matt "external battery attached",
75 1.1 matt "external VGA attached",
76 1.1 matt "external keyboard attached",
77 1.1 matt "external mouse attached",
78 1.1 matt "lid down",
79 1.1 matt "internal battery charging",
80 1.1 matt "external battery charging",
81 1.1 matt "internal battery discharging",
82 1.1 matt "external battery discharging",
83 1.1 matt };
84 1.1 matt
85 1.1 matt struct tctrl_softc {
86 1.4 garbled struct device sc_dev;
87 1.4 garbled bus_space_tag_t sc_memt;
88 1.4 garbled bus_space_handle_t sc_memh;
89 1.4 garbled unsigned int sc_junk;
90 1.4 garbled unsigned int sc_ext_status;
91 1.4 garbled unsigned int sc_flags;
92 1.4 garbled #define TCTRL_SEND_REQUEST 0x0001
93 1.4 garbled #define TCTRL_APM_CTLOPEN 0x0002
94 1.4 garbled unsigned int sc_wantdata;
95 1.6 garbled volatile unsigned short sc_lcdstate;
96 1.1 matt enum { TCTRL_IDLE, TCTRL_ARGS,
97 1.1 matt TCTRL_ACK, TCTRL_DATA } sc_state;
98 1.4 garbled u_int8_t sc_cmdbuf[16];
99 1.4 garbled u_int8_t sc_rspbuf[16];
100 1.4 garbled u_int8_t sc_bitport;
101 1.4 garbled u_int8_t sc_tft_on;
102 1.4 garbled u_int8_t sc_op;
103 1.4 garbled u_int8_t sc_cmdoff;
104 1.4 garbled u_int8_t sc_cmdlen;
105 1.4 garbled u_int8_t sc_rspoff;
106 1.4 garbled u_int8_t sc_rsplen;
107 1.4 garbled /* APM stuff */
108 1.4 garbled #define APM_NEVENTS 16
109 1.4 garbled struct apm_event_info sc_event_list[APM_NEVENTS];
110 1.4 garbled int sc_event_count;
111 1.4 garbled int sc_event_ptr;
112 1.4 garbled struct selinfo sc_rsel;
113 1.4 garbled /* ENVSYS stuff */
114 1.4 garbled #define ENVSYS_NUMSENSORS 3
115 1.4 garbled struct envsys_sensor sc_esensors[ENVSYS_NUMSENSORS];
116 1.1 matt
117 1.4 garbled struct evcnt sc_intrcnt; /* interrupt counting */
118 1.1 matt };
119 1.1 matt
120 1.4 garbled #define TCTRL_STD_DEV 0
121 1.4 garbled #define TCTRL_APMCTL_DEV 8
122 1.1 matt
123 1.9 thorpej static struct callout tctrl_event_ch = CALLOUT_INITIALIZER;
124 1.8 thorpej
125 1.4 garbled static int tctrl_match __P((struct device *parent, struct cfdata *cf,
126 1.4 garbled void *aux));
127 1.4 garbled static void tctrl_attach __P((struct device *parent, struct device *self,
128 1.4 garbled void *aux));
129 1.4 garbled static void tctrl_write __P((struct tctrl_softc *sc, bus_size_t off,
130 1.4 garbled u_int8_t v));
131 1.4 garbled static u_int8_t tctrl_read __P((struct tctrl_softc *sc, bus_size_t off));
132 1.4 garbled static void tctrl_write_data __P((struct tctrl_softc *sc, u_int8_t v));
133 1.4 garbled static u_int8_t tctrl_read_data __P((struct tctrl_softc *sc));
134 1.4 garbled static int tctrl_intr __P((void *arg));
135 1.4 garbled static void tctrl_setup_bitport __P((void));
136 1.4 garbled static void tctrl_setup_bitport_nop __P((void));
137 1.4 garbled static void tctrl_read_ext_status __P((void));
138 1.4 garbled static void tctrl_read_event_status __P((void *arg));
139 1.4 garbled static int tctrl_apm_record_event __P((struct tctrl_softc *sc,
140 1.4 garbled u_int event_type));
141 1.6 garbled static void tctrl_init_lcd __P((void));
142 1.1 matt
143 1.1 matt struct cfattach tctrl_ca = {
144 1.1 matt sizeof(struct tctrl_softc), tctrl_match, tctrl_attach
145 1.1 matt };
146 1.1 matt
147 1.1 matt extern struct cfdriver tctrl_cd;
148 1.4 garbled /* XXX wtf is this? see i386/apm.c */
149 1.4 garbled int tctrl_apm_evindex;
150 1.1 matt
151 1.1 matt static int
152 1.4 garbled tctrl_match(parent, cf, aux)
153 1.4 garbled struct device *parent;
154 1.4 garbled struct cfdata *cf;
155 1.4 garbled void *aux;
156 1.1 matt {
157 1.1 matt union obio_attach_args *uoba = aux;
158 1.1 matt struct sbus_attach_args *sa = &uoba->uoba_sbus;
159 1.1 matt
160 1.1 matt if (uoba->uoba_isobio4 != 0) {
161 1.1 matt return (0);
162 1.1 matt }
163 1.1 matt
164 1.1 matt /* Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
165 1.1 matt * (who's interface is off the TS102 PCMCIA controller but there
166 1.1 matt * exists a OpenProm for microcontroller interface).
167 1.1 matt */
168 1.1 matt return strcmp("uctrl", sa->sa_name) == 0;
169 1.1 matt }
170 1.1 matt
171 1.1 matt static void
172 1.4 garbled tctrl_attach(parent, self, aux)
173 1.4 garbled struct device *parent;
174 1.4 garbled struct device *self;
175 1.4 garbled void *aux;
176 1.1 matt {
177 1.1 matt struct tctrl_softc *sc = (void *)self;
178 1.1 matt union obio_attach_args *uoba = aux;
179 1.1 matt struct sbus_attach_args *sa = &uoba->uoba_sbus;
180 1.2 matt unsigned int i, v;
181 1.2 matt #if 0
182 1.1 matt unsigned int ack, msb, lsb;
183 1.2 matt #endif
184 1.1 matt
185 1.1 matt /* We're living on a sbus slot that looks like an obio that
186 1.1 matt * looks like an sbus slot.
187 1.1 matt */
188 1.1 matt sc->sc_memt = sa->sa_bustag;
189 1.12.4.3 jdolecek if (sbus_bus_map(sc->sc_memt,
190 1.12.4.3 jdolecek sa->sa_slot,
191 1.12.4.3 jdolecek sa->sa_offset - TS102_REG_UCTRL_INT,
192 1.12.4.3 jdolecek sa->sa_size,
193 1.12.4.3 jdolecek BUS_SPACE_MAP_LINEAR, &sc->sc_memh) != 0) {
194 1.1 matt printf(": can't map registers\n");
195 1.1 matt return;
196 1.1 matt }
197 1.1 matt
198 1.2 matt printf("\n");
199 1.2 matt
200 1.1 matt sc->sc_tft_on = 1;
201 1.2 matt
202 1.1 matt /* clear any pending data.
203 1.1 matt */
204 1.1 matt for (i = 0; i < 10000; i++) {
205 1.4 garbled if ((TS102_UCTRL_STS_RXNE_STA &
206 1.4 garbled tctrl_read(sc, TS102_REG_UCTRL_STS)) == 0) {
207 1.1 matt break;
208 1.1 matt }
209 1.1 matt v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
210 1.2 matt tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
211 1.1 matt }
212 1.1 matt
213 1.3 pk if (sa->sa_nintr != 0) {
214 1.11 pk (void)bus_intr_establish(sc->sc_memt, sa->sa_pri, IPL_NONE,
215 1.4 garbled 0, tctrl_intr, sc);
216 1.10 cgd evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, NULL,
217 1.10 cgd sc->sc_dev.dv_xname, "intr");
218 1.3 pk }
219 1.2 matt
220 1.2 matt /* See what the external status is
221 1.2 matt */
222 1.1 matt
223 1.4 garbled tctrl_read_ext_status();
224 1.2 matt if (sc->sc_ext_status != 0) {
225 1.2 matt const char *sep;
226 1.1 matt
227 1.1 matt printf("%s: ", sc->sc_dev.dv_xname);
228 1.2 matt v = sc->sc_ext_status;
229 1.1 matt for (i = 0, sep = ""; v != 0; i++, v >>= 1) {
230 1.1 matt if (v & 1) {
231 1.1 matt printf("%s%s", sep, tctrl_ext_statuses[i]);
232 1.1 matt sep = ", ";
233 1.1 matt }
234 1.1 matt }
235 1.1 matt printf("\n");
236 1.1 matt }
237 1.1 matt
238 1.2 matt /* Get a current of the control bitport;
239 1.2 matt */
240 1.4 garbled tctrl_setup_bitport_nop();
241 1.2 matt tctrl_write(sc, TS102_REG_UCTRL_INT,
242 1.2 matt TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK);
243 1.1 matt
244 1.4 garbled sc->sc_wantdata = 0;
245 1.4 garbled sc->sc_event_count = 0;
246 1.4 garbled
247 1.4 garbled /* prime the sensor data */
248 1.4 garbled sprintf(sc->sc_esensors[0].desc, "%s", "Internal Unit Temperature");
249 1.4 garbled sc->sc_esensors[0].units = ENVSYS_STEMP;
250 1.4 garbled sprintf(sc->sc_esensors[1].desc, "%s", "Internal Battery Voltage");
251 1.4 garbled sc->sc_esensors[1].units = ENVSYS_SVOLTS_DC;
252 1.4 garbled sprintf(sc->sc_esensors[2].desc, "%s", "DC-In Voltage");
253 1.4 garbled sc->sc_esensors[2].units = ENVSYS_SVOLTS_DC;
254 1.6 garbled
255 1.6 garbled /* initialize the LCD */
256 1.6 garbled tctrl_init_lcd();
257 1.6 garbled
258 1.6 garbled /* initialize sc_lcdstate */
259 1.6 garbled sc->sc_lcdstate = 0;
260 1.6 garbled tctrl_set_lcd(2, 0);
261 1.1 matt }
262 1.1 matt
263 1.1 matt static int
264 1.4 garbled tctrl_intr(arg)
265 1.4 garbled void *arg;
266 1.1 matt {
267 1.1 matt struct tctrl_softc *sc = arg;
268 1.1 matt unsigned int v, d;
269 1.1 matt int progress = 0;
270 1.1 matt
271 1.1 matt again:
272 1.1 matt /* find out the cause(s) of the interrupt */
273 1.12 toddpw v = tctrl_read(sc, TS102_REG_UCTRL_STS) & TS102_UCTRL_STS_MASK;
274 1.1 matt
275 1.1 matt /* clear the cause(s) of the interrupt */
276 1.1 matt tctrl_write(sc, TS102_REG_UCTRL_STS, v);
277 1.1 matt
278 1.2 matt v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
279 1.1 matt if (sc->sc_cmdoff >= sc->sc_cmdlen) {
280 1.2 matt v &= ~TS102_UCTRL_STS_TXNF_STA;
281 1.4 garbled if (tctrl_read(sc, TS102_REG_UCTRL_INT) & TS102_UCTRL_INT_TXNF_REQ) {
282 1.4 garbled tctrl_write(sc, TS102_REG_UCTRL_INT, 0);
283 1.4 garbled progress = 1;
284 1.4 garbled }
285 1.1 matt }
286 1.4 garbled if ((v == 0) && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
287 1.4 garbled sc->sc_state != TCTRL_IDLE)) {
288 1.4 garbled wakeup(sc);
289 1.1 matt return progress;
290 1.1 matt }
291 1.1 matt
292 1.1 matt progress = 1;
293 1.2 matt if (v & TS102_UCTRL_STS_RXNE_STA) {
294 1.1 matt d = tctrl_read_data(sc);
295 1.1 matt switch (sc->sc_state) {
296 1.1 matt case TCTRL_IDLE:
297 1.2 matt if (d == 0xfa) {
298 1.4 garbled /* external event */
299 1.8 thorpej callout_reset(&tctrl_event_ch, 1,
300 1.8 thorpej tctrl_read_event_status, NULL);
301 1.2 matt } else {
302 1.2 matt printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
303 1.2 matt sc->sc_dev.dv_xname, sc->sc_op, d);
304 1.1 matt }
305 1.2 matt goto again;
306 1.1 matt case TCTRL_ACK:
307 1.1 matt if (d != 0xfe) {
308 1.2 matt printf("%s: (op=0x%02x): unexpected ack value (0x%02x)\n",
309 1.1 matt sc->sc_dev.dv_xname, sc->sc_op, d);
310 1.1 matt }
311 1.4 garbled #ifdef TCTRLDEBUG
312 1.2 matt printf(" ack=0x%02x", d);
313 1.2 matt #endif
314 1.2 matt sc->sc_rsplen--;
315 1.2 matt sc->sc_rspoff = 0;
316 1.1 matt sc->sc_state = sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
317 1.4 garbled sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
318 1.4 garbled #ifdef TCTRLDEBUG
319 1.2 matt if (sc->sc_rsplen > 0) {
320 1.2 matt printf(" [data(%u)]", sc->sc_rsplen);
321 1.2 matt } else {
322 1.2 matt printf(" [idle]\n");
323 1.2 matt }
324 1.2 matt #endif
325 1.2 matt goto again;
326 1.1 matt case TCTRL_DATA:
327 1.1 matt sc->sc_rspbuf[sc->sc_rspoff++] = d;
328 1.4 garbled #ifdef TCTRLDEBUG
329 1.2 matt printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
330 1.2 matt #endif
331 1.1 matt if (sc->sc_rspoff == sc->sc_rsplen) {
332 1.4 garbled #ifdef TCTRLDEBUG
333 1.2 matt printf(" [idle]\n");
334 1.2 matt #endif
335 1.1 matt sc->sc_state = TCTRL_IDLE;
336 1.4 garbled sc->sc_wantdata = 0;
337 1.1 matt }
338 1.2 matt goto again;
339 1.1 matt default:
340 1.1 matt printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
341 1.1 matt sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
342 1.2 matt goto again;
343 1.1 matt }
344 1.1 matt }
345 1.4 garbled if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
346 1.4 garbled sc->sc_flags & TCTRL_SEND_REQUEST) {
347 1.4 garbled if (sc->sc_flags & TCTRL_SEND_REQUEST) {
348 1.4 garbled sc->sc_flags &= ~TCTRL_SEND_REQUEST;
349 1.4 garbled sc->sc_wantdata = 1;
350 1.4 garbled }
351 1.1 matt if (sc->sc_cmdlen > 0) {
352 1.1 matt tctrl_write(sc, TS102_REG_UCTRL_INT,
353 1.1 matt tctrl_read(sc, TS102_REG_UCTRL_INT)
354 1.1 matt |TS102_UCTRL_INT_TXNF_MSK
355 1.1 matt |TS102_UCTRL_INT_TXNF_REQ);
356 1.1 matt v = tctrl_read(sc, TS102_REG_UCTRL_STS);
357 1.1 matt }
358 1.1 matt }
359 1.2 matt if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
360 1.1 matt tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
361 1.4 garbled #ifdef TCTRLDEBUG
362 1.2 matt if (sc->sc_cmdoff == 1) {
363 1.2 matt printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
364 1.2 matt sc->sc_cmdbuf[0], sc->sc_rsplen);
365 1.2 matt } else {
366 1.2 matt printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
367 1.2 matt sc->sc_cmdbuf[sc->sc_cmdoff-1]);
368 1.2 matt }
369 1.2 matt #endif
370 1.1 matt if (sc->sc_cmdoff == sc->sc_cmdlen) {
371 1.1 matt sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
372 1.4 garbled #ifdef TCTRLDEBUG
373 1.2 matt printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
374 1.2 matt #endif
375 1.2 matt if (sc->sc_cmdoff == 1) {
376 1.2 matt sc->sc_op = sc->sc_cmdbuf[0];
377 1.2 matt }
378 1.1 matt tctrl_write(sc, TS102_REG_UCTRL_INT,
379 1.1 matt tctrl_read(sc, TS102_REG_UCTRL_INT)
380 1.1 matt & (~TS102_UCTRL_INT_TXNF_MSK
381 1.1 matt |TS102_UCTRL_INT_TXNF_REQ));
382 1.1 matt } else if (sc->sc_state == TCTRL_IDLE) {
383 1.1 matt sc->sc_op = sc->sc_cmdbuf[0];
384 1.1 matt sc->sc_state = TCTRL_ARGS;
385 1.4 garbled #ifdef TCTRLDEBUG
386 1.2 matt printf(" [args]");
387 1.2 matt #endif
388 1.1 matt }
389 1.1 matt }
390 1.1 matt goto again;
391 1.1 matt }
392 1.1 matt
393 1.1 matt static void
394 1.4 garbled tctrl_setup_bitport_nop(void)
395 1.4 garbled {
396 1.4 garbled struct tctrl_softc *sc;
397 1.4 garbled struct tctrl_req req;
398 1.4 garbled int s;
399 1.4 garbled
400 1.4 garbled sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
401 1.4 garbled req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
402 1.4 garbled req.cmdbuf[1] = 0xff;
403 1.4 garbled req.cmdbuf[2] = 0;
404 1.4 garbled req.cmdlen = 3;
405 1.4 garbled req.rsplen = 2;
406 1.4 garbled req.p = NULL;
407 1.4 garbled tadpole_request(&req, 1);
408 1.4 garbled s = splts102();
409 1.4 garbled sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
410 1.4 garbled splx(s);
411 1.4 garbled }
412 1.4 garbled
413 1.4 garbled static void
414 1.4 garbled tctrl_setup_bitport(void)
415 1.1 matt {
416 1.4 garbled struct tctrl_softc *sc;
417 1.4 garbled struct tctrl_req req;
418 1.4 garbled int s;
419 1.4 garbled
420 1.4 garbled sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
421 1.4 garbled s = splts102();
422 1.4 garbled if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
423 1.4 garbled || (!sc->sc_tft_on)) {
424 1.4 garbled req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
425 1.1 matt } else {
426 1.4 garbled req.cmdbuf[2] = 0;
427 1.4 garbled }
428 1.4 garbled req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
429 1.4 garbled req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
430 1.4 garbled req.cmdlen = 3;
431 1.4 garbled req.rsplen = 2;
432 1.4 garbled req.p = NULL;
433 1.4 garbled tadpole_request(&req, 1);
434 1.4 garbled s = splts102();
435 1.4 garbled sc->sc_bitport = (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
436 1.4 garbled splx(s);
437 1.4 garbled }
438 1.4 garbled
439 1.6 garbled /*
440 1.6 garbled * The tadpole microcontroller is not preprogrammed with icon
441 1.6 garbled * representations. The machine boots with the DC-IN light as
442 1.6 garbled * a blank (all 0x00) and the other lights, as 4 rows of horizontal
443 1.6 garbled * bars. The below code initializes the icons in the system to
444 1.6 garbled * sane values. Some of these icons could be used for any purpose
445 1.6 garbled * desired, namely the pcmcia, LAN and WAN lights. For the disk spinner,
446 1.6 garbled * only the backslash is unprogrammed. (sigh)
447 1.6 garbled *
448 1.6 garbled * programming the icons is simple. It is a 5x8 matrix, which each row a
449 1.6 garbled * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
450 1.6 garbled */
451 1.6 garbled
452 1.6 garbled static void
453 1.6 garbled tctrl_init_lcd(void)
454 1.6 garbled {
455 1.6 garbled struct tctrl_req req;
456 1.6 garbled
457 1.6 garbled req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
458 1.6 garbled req.cmdlen = 11;
459 1.6 garbled req.rsplen = 1;
460 1.6 garbled req.cmdbuf[1] = 0x08; /*len*/
461 1.6 garbled req.cmdbuf[2] = TS102_BLK_OFF_DEF_DC_GOOD;
462 1.6 garbled req.cmdbuf[3] = 0x00; /* ..... */
463 1.6 garbled req.cmdbuf[4] = 0x00; /* ..... */
464 1.6 garbled req.cmdbuf[5] = 0x1f; /* XXXXX */
465 1.6 garbled req.cmdbuf[6] = 0x00; /* ..... */
466 1.6 garbled req.cmdbuf[7] = 0x15; /* X.X.X */
467 1.6 garbled req.cmdbuf[8] = 0x00; /* ..... */
468 1.6 garbled req.cmdbuf[9] = 0x00; /* ..... */
469 1.6 garbled req.cmdbuf[10] = 0x00; /* ..... */
470 1.6 garbled req.p = NULL;
471 1.6 garbled tadpole_request(&req, 1);
472 1.6 garbled
473 1.6 garbled req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
474 1.6 garbled req.cmdlen = 11;
475 1.6 garbled req.rsplen = 1;
476 1.6 garbled req.cmdbuf[1] = 0x08; /*len*/
477 1.6 garbled req.cmdbuf[2] = TS102_BLK_OFF_DEF_BACKSLASH;
478 1.6 garbled req.cmdbuf[3] = 0x00; /* ..... */
479 1.6 garbled req.cmdbuf[4] = 0x10; /* X.... */
480 1.6 garbled req.cmdbuf[5] = 0x08; /* .X... */
481 1.6 garbled req.cmdbuf[6] = 0x04; /* ..X.. */
482 1.6 garbled req.cmdbuf[7] = 0x02; /* ...X. */
483 1.6 garbled req.cmdbuf[8] = 0x01; /* ....X */
484 1.6 garbled req.cmdbuf[9] = 0x00; /* ..... */
485 1.6 garbled req.cmdbuf[10] = 0x00; /* ..... */
486 1.6 garbled req.p = NULL;
487 1.6 garbled tadpole_request(&req, 1);
488 1.6 garbled
489 1.6 garbled req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
490 1.6 garbled req.cmdlen = 11;
491 1.6 garbled req.rsplen = 1;
492 1.6 garbled req.cmdbuf[1] = 0x08; /*len*/
493 1.6 garbled req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN1;
494 1.6 garbled req.cmdbuf[3] = 0x0c; /* .XXX. */
495 1.6 garbled req.cmdbuf[4] = 0x16; /* X.XX. */
496 1.6 garbled req.cmdbuf[5] = 0x10; /* X.... */
497 1.6 garbled req.cmdbuf[6] = 0x15; /* X.X.X */
498 1.6 garbled req.cmdbuf[7] = 0x10; /* X.... */
499 1.6 garbled req.cmdbuf[8] = 0x16; /* X.XX. */
500 1.6 garbled req.cmdbuf[9] = 0x0c; /* .XXX. */
501 1.6 garbled req.cmdbuf[10] = 0x00; /* ..... */
502 1.6 garbled req.p = NULL;
503 1.6 garbled tadpole_request(&req, 1);
504 1.6 garbled
505 1.6 garbled req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
506 1.6 garbled req.cmdlen = 11;
507 1.6 garbled req.rsplen = 1;
508 1.6 garbled req.cmdbuf[1] = 0x08; /*len*/
509 1.6 garbled req.cmdbuf[2] = TS102_BLK_OFF_DEF_WAN2;
510 1.6 garbled req.cmdbuf[3] = 0x0c; /* .XXX. */
511 1.6 garbled req.cmdbuf[4] = 0x0d; /* .XX.X */
512 1.6 garbled req.cmdbuf[5] = 0x01; /* ....X */
513 1.6 garbled req.cmdbuf[6] = 0x15; /* X.X.X */
514 1.6 garbled req.cmdbuf[7] = 0x01; /* ....X */
515 1.6 garbled req.cmdbuf[8] = 0x0d; /* .XX.X */
516 1.6 garbled req.cmdbuf[9] = 0x0c; /* .XXX. */
517 1.6 garbled req.cmdbuf[10] = 0x00; /* ..... */
518 1.6 garbled req.p = NULL;
519 1.6 garbled tadpole_request(&req, 1);
520 1.6 garbled
521 1.6 garbled req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
522 1.6 garbled req.cmdlen = 11;
523 1.6 garbled req.rsplen = 1;
524 1.6 garbled req.cmdbuf[1] = 0x08; /*len*/
525 1.6 garbled req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN1;
526 1.6 garbled req.cmdbuf[3] = 0x00; /* ..... */
527 1.6 garbled req.cmdbuf[4] = 0x04; /* ..X.. */
528 1.6 garbled req.cmdbuf[5] = 0x08; /* .X... */
529 1.6 garbled req.cmdbuf[6] = 0x13; /* X..XX */
530 1.6 garbled req.cmdbuf[7] = 0x08; /* .X... */
531 1.6 garbled req.cmdbuf[8] = 0x04; /* ..X.. */
532 1.6 garbled req.cmdbuf[9] = 0x00; /* ..... */
533 1.6 garbled req.cmdbuf[10] = 0x00; /* ..... */
534 1.6 garbled req.p = NULL;
535 1.6 garbled tadpole_request(&req, 1);
536 1.6 garbled
537 1.6 garbled req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
538 1.6 garbled req.cmdlen = 11;
539 1.6 garbled req.rsplen = 1;
540 1.6 garbled req.cmdbuf[1] = 0x08; /*len*/
541 1.6 garbled req.cmdbuf[2] = TS102_BLK_OFF_DEF_LAN2;
542 1.6 garbled req.cmdbuf[3] = 0x00; /* ..... */
543 1.6 garbled req.cmdbuf[4] = 0x04; /* ..X.. */
544 1.6 garbled req.cmdbuf[5] = 0x02; /* ...X. */
545 1.6 garbled req.cmdbuf[6] = 0x19; /* XX..X */
546 1.6 garbled req.cmdbuf[7] = 0x02; /* ...X. */
547 1.6 garbled req.cmdbuf[8] = 0x04; /* ..X.. */
548 1.6 garbled req.cmdbuf[9] = 0x00; /* ..... */
549 1.6 garbled req.cmdbuf[10] = 0x00; /* ..... */
550 1.6 garbled req.p = NULL;
551 1.6 garbled tadpole_request(&req, 1);
552 1.6 garbled
553 1.6 garbled req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
554 1.6 garbled req.cmdlen = 11;
555 1.6 garbled req.rsplen = 1;
556 1.6 garbled req.cmdbuf[1] = 0x08; /*len*/
557 1.6 garbled req.cmdbuf[2] = TS102_BLK_OFF_DEF_PCMCIA;
558 1.6 garbled req.cmdbuf[3] = 0x00; /* ..... */
559 1.6 garbled req.cmdbuf[4] = 0x0c; /* .XXX. */
560 1.6 garbled req.cmdbuf[5] = 0x1f; /* XXXXX */
561 1.6 garbled req.cmdbuf[6] = 0x1f; /* XXXXX */
562 1.6 garbled req.cmdbuf[7] = 0x1f; /* XXXXX */
563 1.6 garbled req.cmdbuf[8] = 0x1f; /* XXXXX */
564 1.6 garbled req.cmdbuf[9] = 0x00; /* ..... */
565 1.6 garbled req.cmdbuf[10] = 0x00; /* ..... */
566 1.6 garbled req.p = NULL;
567 1.6 garbled tadpole_request(&req, 1);
568 1.6 garbled }
569 1.6 garbled
570 1.6 garbled
571 1.6 garbled
572 1.6 garbled /*
573 1.6 garbled * set the blinken-lights on the lcd. what:
574 1.6 garbled * what = 0 off, what = 1 on, what = 2 toggle
575 1.6 garbled */
576 1.6 garbled
577 1.6 garbled void
578 1.6 garbled tctrl_set_lcd(what, which)
579 1.6 garbled int what;
580 1.6 garbled unsigned short which;
581 1.6 garbled {
582 1.6 garbled struct tctrl_softc *sc;
583 1.6 garbled struct tctrl_req req;
584 1.6 garbled int s;
585 1.6 garbled
586 1.6 garbled sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
587 1.6 garbled s = splts102();
588 1.6 garbled
589 1.6 garbled /* provide a quick exit to save cpu time */
590 1.6 garbled if ((what == 1 && sc->sc_lcdstate & which) ||
591 1.6 garbled (what == 0 && !(sc->sc_lcdstate & which))) {
592 1.6 garbled splx(s);
593 1.6 garbled return;
594 1.6 garbled }
595 1.6 garbled /*
596 1.6 garbled * the mask setup on this particular command is *very* bizzare
597 1.6 garbled * and totally undocumented.
598 1.6 garbled */
599 1.6 garbled if ((what == 1) || (what == 2 && !(sc->sc_lcdstate & which))) {
600 1.6 garbled req.cmdbuf[2] = (u_int8_t)(which&0xff);
601 1.6 garbled req.cmdbuf[3] = (u_int8_t)(which>>8);
602 1.6 garbled } else {
603 1.6 garbled req.cmdbuf[2] = 0;
604 1.6 garbled req.cmdbuf[3] = 0;
605 1.6 garbled }
606 1.6 garbled req.cmdbuf[0] = TS102_OP_CTL_LCD;
607 1.6 garbled req.cmdbuf[4] = (u_int8_t)(~which>>8);
608 1.6 garbled req.cmdbuf[1] = (u_int8_t)(~which&0xff);
609 1.6 garbled
610 1.12.4.1 thorpej /* XXX this thing is weird.... */
611 1.6 garbled req.cmdlen = 3;
612 1.6 garbled req.rsplen = 2;
613 1.6 garbled #if 0
614 1.6 garbled req.cmdlen = 5;
615 1.6 garbled req.rsplen = 4;
616 1.6 garbled #endif
617 1.6 garbled req.p = NULL;
618 1.6 garbled tadpole_request(&req, 1);
619 1.6 garbled s = splts102();
620 1.6 garbled sc->sc_lcdstate = (unsigned short)req.rspbuf[0];
621 1.6 garbled splx(s);
622 1.6 garbled }
623 1.6 garbled
624 1.4 garbled static void
625 1.4 garbled tctrl_read_ext_status(void)
626 1.4 garbled {
627 1.4 garbled struct tctrl_softc *sc;
628 1.4 garbled struct tctrl_req req;
629 1.4 garbled int s;
630 1.4 garbled
631 1.4 garbled sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
632 1.4 garbled req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
633 1.4 garbled req.cmdlen = 1;
634 1.4 garbled req.rsplen = 3;
635 1.4 garbled req.p = NULL;
636 1.4 garbled #ifdef TCTRLDEBUG
637 1.4 garbled printf("pre read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
638 1.4 garbled #endif
639 1.4 garbled tadpole_request(&req, 1);
640 1.4 garbled s = splts102();
641 1.4 garbled sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1];
642 1.4 garbled splx(s);
643 1.4 garbled #ifdef TCTRLDEBUG
644 1.4 garbled printf("post read: sc->sc_ext_status = 0x%x\n", sc->sc_ext_status);
645 1.4 garbled #endif
646 1.4 garbled }
647 1.4 garbled
648 1.4 garbled /*
649 1.4 garbled * return 0 if the user will notice and handle the event,
650 1.4 garbled * return 1 if the kernel driver should do so.
651 1.4 garbled */
652 1.4 garbled static int
653 1.4 garbled tctrl_apm_record_event(sc, event_type)
654 1.4 garbled struct tctrl_softc *sc;
655 1.4 garbled u_int event_type;
656 1.4 garbled {
657 1.4 garbled struct apm_event_info *evp;
658 1.4 garbled
659 1.4 garbled if ((sc->sc_flags & TCTRL_APM_CTLOPEN) &&
660 1.4 garbled (sc->sc_event_count < APM_NEVENTS)) {
661 1.4 garbled evp = &sc->sc_event_list[sc->sc_event_ptr];
662 1.4 garbled sc->sc_event_count++;
663 1.4 garbled sc->sc_event_ptr++;
664 1.4 garbled sc->sc_event_ptr %= APM_NEVENTS;
665 1.4 garbled evp->type = event_type;
666 1.4 garbled evp->index = ++tctrl_apm_evindex;
667 1.12.4.2 thorpej selnotify(&sc->sc_rsel, 0);
668 1.4 garbled return(sc->sc_flags & TCTRL_APM_CTLOPEN) ? 0 : 1;
669 1.1 matt }
670 1.4 garbled return(1);
671 1.1 matt }
672 1.1 matt
673 1.1 matt static void
674 1.4 garbled tctrl_read_event_status(arg)
675 1.4 garbled void *arg;
676 1.1 matt {
677 1.4 garbled struct tctrl_softc *sc;
678 1.4 garbled struct tctrl_req req;
679 1.4 garbled int s;
680 1.4 garbled unsigned int v;
681 1.4 garbled
682 1.4 garbled sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
683 1.4 garbled req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
684 1.4 garbled req.cmdlen = 1;
685 1.4 garbled req.rsplen = 3;
686 1.4 garbled req.p = NULL;
687 1.4 garbled tadpole_request(&req, 1);
688 1.4 garbled s = splts102();
689 1.4 garbled v = req.rspbuf[0] * 256 + req.rspbuf[1];
690 1.4 garbled if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
691 1.4 garbled printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
692 1.4 garbled }
693 1.4 garbled if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
694 1.4 garbled /*printf("%s: VERY LOW POWER WARNING!\n", sc->sc_dev.dv_xname);*/
695 1.4 garbled /* according to a tadpole header, and observation */
696 1.4 garbled #ifdef TCTRLDEBUG
697 1.4 garbled printf("%s: Battery charge level change\n", sc->sc_dev.dv_xname);
698 1.4 garbled #endif
699 1.1 matt }
700 1.4 garbled if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
701 1.4 garbled if (tctrl_apm_record_event(sc, APM_BATTERY_LOW))
702 1.1 matt printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
703 1.4 garbled }
704 1.4 garbled if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
705 1.4 garbled splx(s);
706 1.4 garbled tctrl_read_ext_status();
707 1.4 garbled s = splts102();
708 1.4 garbled if (tctrl_apm_record_event(sc, APM_POWER_CHANGE))
709 1.1 matt printf("%s: main power %s\n", sc->sc_dev.dv_xname,
710 1.4 garbled (sc->sc_ext_status &
711 1.4 garbled TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
712 1.4 garbled "restored" : "removed");
713 1.4 garbled }
714 1.4 garbled if (v & TS102_EVENT_STATUS_LID_STATUS_CHANGE) {
715 1.4 garbled splx(s);
716 1.4 garbled tctrl_read_ext_status();
717 1.4 garbled tctrl_setup_bitport();
718 1.4 garbled #ifdef TCTRLDEBUG
719 1.4 garbled printf("%s: lid %s\n", sc->sc_dev.dv_xname,
720 1.4 garbled (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN)
721 1.4 garbled ? "closed" : "opened");
722 1.2 matt #endif
723 1.1 matt }
724 1.4 garbled splx(s);
725 1.1 matt }
726 1.1 matt
727 1.1 matt void
728 1.4 garbled tadpole_request(req, spin)
729 1.4 garbled struct tctrl_req *req;
730 1.4 garbled int spin;
731 1.1 matt {
732 1.1 matt struct tctrl_softc *sc;
733 1.1 matt int i, s;
734 1.1 matt
735 1.1 matt if (tctrl_cd.cd_devs == NULL
736 1.1 matt || tctrl_cd.cd_ndevs == 0
737 1.4 garbled || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
738 1.1 matt return;
739 1.1 matt }
740 1.1 matt
741 1.4 garbled sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
742 1.4 garbled while (sc->sc_wantdata != 0) {
743 1.4 garbled if (req->p != NULL)
744 1.4 garbled tsleep(&sc->sc_wantdata, PLOCK, "tctrl_lock", 10);
745 1.4 garbled else
746 1.4 garbled DELAY(1);
747 1.4 garbled }
748 1.4 garbled if (spin)
749 1.4 garbled s = splhigh();
750 1.4 garbled else
751 1.4 garbled s = splts102();
752 1.4 garbled sc->sc_flags |= TCTRL_SEND_REQUEST;
753 1.4 garbled memcpy(sc->sc_cmdbuf, req->cmdbuf, req->cmdlen);
754 1.4 garbled sc->sc_wantdata = 1;
755 1.4 garbled sc->sc_rsplen = req->rsplen;
756 1.4 garbled sc->sc_cmdlen = req->cmdlen;
757 1.4 garbled sc->sc_cmdoff = sc->sc_rspoff = 0;
758 1.4 garbled
759 1.4 garbled /* we spin for certain commands, like poweroffs */
760 1.4 garbled if (spin) {
761 1.6 garbled /* for (i = 0; i < 30000; i++) {*/
762 1.6 garbled while (sc->sc_wantdata == 1) {
763 1.4 garbled tctrl_intr(sc);
764 1.4 garbled DELAY(1);
765 1.4 garbled }
766 1.4 garbled } else {
767 1.1 matt tctrl_intr(sc);
768 1.5 garbled i = 0;
769 1.5 garbled while (((sc->sc_rspoff != sc->sc_rsplen) ||
770 1.5 garbled (sc->sc_cmdoff != sc->sc_cmdlen)) &&
771 1.5 garbled (i < (5 * sc->sc_rsplen + sc->sc_cmdlen)))
772 1.5 garbled if (req->p != NULL) {
773 1.5 garbled tsleep(sc, PWAIT, "tctrl_data", 15);
774 1.5 garbled i++;
775 1.5 garbled }
776 1.4 garbled else
777 1.4 garbled DELAY(1);
778 1.1 matt }
779 1.5 garbled /*
780 1.5 garbled * we give the user a reasonable amount of time for a command
781 1.5 garbled * to complete. If it doesn't complete in time, we hand them
782 1.5 garbled * garbage. This is here to stop things like setting the
783 1.5 garbled * rsplen too long, and sleeping forever in a CMD_REQ ioctl.
784 1.5 garbled */
785 1.5 garbled sc->sc_wantdata = 0;
786 1.4 garbled memcpy(req->rspbuf, sc->sc_rspbuf, req->rsplen);
787 1.1 matt splx(s);
788 1.1 matt }
789 1.1 matt
790 1.1 matt void
791 1.4 garbled tadpole_powerdown(void)
792 1.4 garbled {
793 1.4 garbled struct tctrl_req req;
794 1.4 garbled
795 1.4 garbled req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
796 1.4 garbled req.cmdlen = 1;
797 1.4 garbled req.rsplen = 1;
798 1.4 garbled req.p = NULL;
799 1.4 garbled tadpole_request(&req, 1);
800 1.4 garbled }
801 1.4 garbled
802 1.4 garbled void
803 1.4 garbled tadpole_set_video(enabled)
804 1.4 garbled int enabled;
805 1.1 matt {
806 1.1 matt struct tctrl_softc *sc;
807 1.4 garbled struct tctrl_req req;
808 1.1 matt int s;
809 1.1 matt
810 1.4 garbled sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
811 1.4 garbled while (sc->sc_wantdata != 0)
812 1.4 garbled DELAY(1);
813 1.4 garbled s = splts102();
814 1.4 garbled req.p = NULL;
815 1.4 garbled if ((sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN && !enabled)
816 1.4 garbled || (sc->sc_tft_on)) {
817 1.4 garbled req.cmdbuf[2] = TS102_BITPORT_TFTPWR;
818 1.4 garbled } else {
819 1.4 garbled req.cmdbuf[2] = 0;
820 1.1 matt }
821 1.4 garbled req.cmdbuf[0] = TS102_OP_CTL_BITPORT;
822 1.4 garbled req.cmdbuf[1] = ~TS102_BITPORT_TFTPWR;
823 1.4 garbled req.cmdlen = 3;
824 1.4 garbled req.rsplen = 2;
825 1.1 matt
826 1.1 matt if ((sc->sc_tft_on && !enabled) || (!sc->sc_tft_on && enabled)) {
827 1.1 matt sc->sc_tft_on = enabled;
828 1.1 matt if (sc->sc_ext_status & TS102_EXT_STATUS_LID_DOWN) {
829 1.1 matt splx(s);
830 1.1 matt return;
831 1.1 matt }
832 1.4 garbled tadpole_request(&req, 1);
833 1.4 garbled sc->sc_bitport =
834 1.4 garbled (req.rspbuf[0] & req.cmdbuf[1]) ^ req.cmdbuf[2];
835 1.1 matt }
836 1.1 matt splx(s);
837 1.1 matt }
838 1.1 matt
839 1.1 matt static void
840 1.4 garbled tctrl_write_data(sc, v)
841 1.4 garbled struct tctrl_softc *sc;
842 1.4 garbled u_int8_t v;
843 1.1 matt {
844 1.1 matt unsigned int i;
845 1.4 garbled
846 1.1 matt for (i = 0; i < 100; i++) {
847 1.2 matt if (TS102_UCTRL_STS_TXNF_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
848 1.1 matt break;
849 1.1 matt }
850 1.1 matt tctrl_write(sc, TS102_REG_UCTRL_DATA, v);
851 1.1 matt }
852 1.1 matt
853 1.1 matt static u_int8_t
854 1.4 garbled tctrl_read_data(sc)
855 1.4 garbled struct tctrl_softc *sc;
856 1.4 garbled {
857 1.1 matt unsigned int i, v;
858 1.1 matt
859 1.1 matt for (i = 0; i < 100000; i++) {
860 1.2 matt if (TS102_UCTRL_STS_RXNE_STA & tctrl_read(sc, TS102_REG_UCTRL_STS))
861 1.1 matt break;
862 1.1 matt DELAY(1);
863 1.1 matt }
864 1.1 matt
865 1.1 matt v = tctrl_read(sc, TS102_REG_UCTRL_DATA);
866 1.2 matt tctrl_write(sc, TS102_REG_UCTRL_STS, TS102_UCTRL_STS_RXNE_STA);
867 1.1 matt return v;
868 1.1 matt }
869 1.1 matt
870 1.1 matt static u_int8_t
871 1.4 garbled tctrl_read(sc, off)
872 1.4 garbled struct tctrl_softc *sc;
873 1.4 garbled bus_size_t off;
874 1.1 matt {
875 1.4 garbled
876 1.2 matt sc->sc_junk = bus_space_read_1(sc->sc_memt, sc->sc_memh, off);
877 1.1 matt return sc->sc_junk;
878 1.1 matt }
879 1.1 matt
880 1.1 matt static void
881 1.4 garbled tctrl_write(sc, off, v)
882 1.4 garbled struct tctrl_softc *sc;
883 1.4 garbled bus_size_t off;
884 1.4 garbled u_int8_t v;
885 1.1 matt {
886 1.4 garbled
887 1.1 matt sc->sc_junk = v;
888 1.2 matt bus_space_write_1(sc->sc_memt, sc->sc_memh, off, v);
889 1.4 garbled }
890 1.4 garbled
891 1.4 garbled int
892 1.4 garbled tctrlopen(dev, flags, mode, p)
893 1.4 garbled dev_t dev;
894 1.4 garbled int flags, mode;
895 1.4 garbled struct proc *p;
896 1.4 garbled {
897 1.4 garbled int unit = (minor(dev)&0xf0);
898 1.4 garbled int ctl = (minor(dev)&0x0f);
899 1.4 garbled struct tctrl_softc *sc;
900 1.4 garbled
901 1.4 garbled if (unit >= tctrl_cd.cd_ndevs)
902 1.4 garbled return(ENXIO);
903 1.4 garbled sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
904 1.4 garbled if (!sc)
905 1.4 garbled return(ENXIO);
906 1.4 garbled
907 1.4 garbled switch (ctl) {
908 1.4 garbled case TCTRL_STD_DEV:
909 1.4 garbled break;
910 1.4 garbled case TCTRL_APMCTL_DEV:
911 1.4 garbled if (!(flags & FWRITE))
912 1.4 garbled return(EINVAL);
913 1.4 garbled if (sc->sc_flags & TCTRL_APM_CTLOPEN)
914 1.4 garbled return(EBUSY);
915 1.4 garbled sc->sc_flags |= TCTRL_APM_CTLOPEN;
916 1.4 garbled break;
917 1.4 garbled default:
918 1.4 garbled return(ENXIO);
919 1.4 garbled break;
920 1.4 garbled }
921 1.4 garbled
922 1.4 garbled return(0);
923 1.4 garbled }
924 1.4 garbled
925 1.4 garbled int
926 1.4 garbled tctrlclose(dev, flags, mode, p)
927 1.4 garbled dev_t dev;
928 1.4 garbled int flags, mode;
929 1.4 garbled struct proc *p;
930 1.4 garbled {
931 1.4 garbled int ctl = (minor(dev)&0x0f);
932 1.4 garbled struct tctrl_softc *sc;
933 1.4 garbled
934 1.4 garbled sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
935 1.4 garbled if (!sc)
936 1.4 garbled return(ENXIO);
937 1.4 garbled
938 1.4 garbled switch (ctl) {
939 1.4 garbled case TCTRL_STD_DEV:
940 1.4 garbled break;
941 1.4 garbled case TCTRL_APMCTL_DEV:
942 1.4 garbled sc->sc_flags &= ~TCTRL_APM_CTLOPEN;
943 1.4 garbled break;
944 1.4 garbled }
945 1.4 garbled return(0);
946 1.4 garbled }
947 1.4 garbled
948 1.4 garbled int
949 1.4 garbled tctrlioctl(dev, cmd, data, flags, p)
950 1.4 garbled dev_t dev;
951 1.4 garbled u_long cmd;
952 1.4 garbled caddr_t data;
953 1.4 garbled int flags;
954 1.4 garbled struct proc *p;
955 1.4 garbled {
956 1.4 garbled struct tctrl_req req, *reqn;
957 1.7 jdc struct tctrl_pwr *pwrreq;
958 1.4 garbled envsys_range_t *envrange;
959 1.4 garbled envsys_temp_data_t *envdata;
960 1.4 garbled envsys_temp_info_t *envinfo;
961 1.4 garbled struct apm_power_info *powerp;
962 1.4 garbled struct apm_event_info *evp;
963 1.4 garbled struct tctrl_softc *sc;
964 1.4 garbled int i;
965 1.4 garbled u_int j;
966 1.4 garbled u_int16_t a;
967 1.4 garbled u_int8_t c;
968 1.4 garbled
969 1.4 garbled if (tctrl_cd.cd_devs == NULL
970 1.4 garbled || tctrl_cd.cd_ndevs == 0
971 1.4 garbled || tctrl_cd.cd_devs[TCTRL_STD_DEV] == NULL) {
972 1.4 garbled return ENXIO;
973 1.4 garbled }
974 1.4 garbled sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
975 1.4 garbled switch (cmd) {
976 1.4 garbled
977 1.4 garbled case APM_IOC_STANDBY:
978 1.4 garbled return(EOPNOTSUPP); /* for now */
979 1.4 garbled
980 1.4 garbled case APM_IOC_SUSPEND:
981 1.4 garbled return(EOPNOTSUPP); /* for now */
982 1.4 garbled
983 1.4 garbled case APM_IOC_GETPOWER:
984 1.4 garbled powerp = (struct apm_power_info *)data;
985 1.4 garbled req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_RATE;
986 1.4 garbled req.cmdlen = 1;
987 1.4 garbled req.rsplen = 2;
988 1.4 garbled req.p = p;
989 1.4 garbled tadpole_request(&req, 0);
990 1.4 garbled if (req.rspbuf[0] > 0x00)
991 1.4 garbled powerp->battery_state = APM_BATT_CHARGING;
992 1.4 garbled req.cmdbuf[0] = TS102_OP_RD_INT_CHARGE_LEVEL;
993 1.4 garbled req.cmdlen = 1;
994 1.4 garbled req.rsplen = 3;
995 1.4 garbled req.p = p;
996 1.4 garbled tadpole_request(&req, 0);
997 1.4 garbled c = req.rspbuf[0];
998 1.4 garbled powerp->battery_life = c;
999 1.6 garbled if (c > 0x70) /* the tadpole sometimes dips below zero, and */
1000 1.6 garbled c = 0; /* into the 255 range. */
1001 1.4 garbled powerp->minutes_left = (45 * c) / 100; /* XXX based on 45 min */
1002 1.4 garbled if (powerp->battery_state != APM_BATT_CHARGING) {
1003 1.4 garbled if (c < 0x20)
1004 1.4 garbled powerp->battery_state = APM_BATT_CRITICAL;
1005 1.4 garbled else if (c < 0x40)
1006 1.4 garbled powerp->battery_state = APM_BATT_LOW;
1007 1.4 garbled else if (c < 0x66)
1008 1.4 garbled powerp->battery_state = APM_BATT_HIGH;
1009 1.4 garbled else
1010 1.4 garbled powerp->battery_state = APM_BATT_UNKNOWN;
1011 1.4 garbled }
1012 1.4 garbled req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
1013 1.4 garbled req.cmdlen = 1;
1014 1.4 garbled req.rsplen = 3;
1015 1.4 garbled req.p = p;
1016 1.4 garbled tadpole_request(&req, 0);
1017 1.4 garbled a = req.rspbuf[0] * 256 + req.rspbuf[1];
1018 1.4 garbled if (a & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE)
1019 1.4 garbled powerp->ac_state = APM_AC_ON;
1020 1.4 garbled else
1021 1.4 garbled powerp->ac_state = APM_AC_OFF;
1022 1.4 garbled break;
1023 1.4 garbled
1024 1.4 garbled case APM_IOC_NEXTEVENT:
1025 1.4 garbled if (!sc->sc_event_count)
1026 1.4 garbled return EAGAIN;
1027 1.4 garbled
1028 1.4 garbled evp = (struct apm_event_info *)data;
1029 1.4 garbled i = sc->sc_event_ptr + APM_NEVENTS - sc->sc_event_count;
1030 1.4 garbled i %= APM_NEVENTS;
1031 1.4 garbled *evp = sc->sc_event_list[i];
1032 1.4 garbled sc->sc_event_count--;
1033 1.4 garbled return(0);
1034 1.4 garbled
1035 1.4 garbled /* this ioctl assumes the caller knows exactly what he is doing */
1036 1.4 garbled case TCTRL_CMD_REQ:
1037 1.4 garbled reqn = (struct tctrl_req *)data;
1038 1.4 garbled if ((i = suser(p->p_ucred, &p->p_acflag)) != 0 &&
1039 1.4 garbled (reqn->cmdbuf[0] == TS102_OP_CTL_BITPORT ||
1040 1.4 garbled (reqn->cmdbuf[0] >= TS102_OP_CTL_WATCHDOG &&
1041 1.4 garbled reqn->cmdbuf[0] <= TS102_OP_CTL_SECURITY_KEY) ||
1042 1.4 garbled reqn->cmdbuf[0] == TS102_OP_CTL_TIMEZONE ||
1043 1.4 garbled reqn->cmdbuf[0] == TS102_OP_CTL_DIAGNOSTIC_MODE ||
1044 1.4 garbled reqn->cmdbuf[0] == TS102_OP_CMD_SOFTWARE_RESET ||
1045 1.4 garbled (reqn->cmdbuf[0] >= TS102_OP_CMD_SET_RTC &&
1046 1.4 garbled reqn->cmdbuf[0] < TS102_OP_RD_INT_CHARGE_LEVEL) ||
1047 1.4 garbled reqn->cmdbuf[0] > TS102_OP_RD_EXT_CHARGE_LEVEL))
1048 1.4 garbled return(i);
1049 1.4 garbled reqn->p = p;
1050 1.4 garbled tadpole_request(reqn, 0);
1051 1.4 garbled break;
1052 1.4 garbled
1053 1.4 garbled case ENVSYS_VERSION:
1054 1.4 garbled *(int32_t *)data = 1000;
1055 1.4 garbled break;
1056 1.4 garbled
1057 1.4 garbled case ENVSYS_GRANGE:
1058 1.4 garbled envrange = (envsys_range_t *)data;
1059 1.4 garbled i = 0;
1060 1.4 garbled envrange->high = envrange->low = 0;
1061 1.4 garbled for (j=0; j < ENVSYS_NUMSENSORS; j++) {
1062 1.4 garbled if (!i && envrange->units == sc->sc_esensors[j].units) {
1063 1.4 garbled envrange->low = j;
1064 1.4 garbled i++;
1065 1.4 garbled }
1066 1.4 garbled if (i && envrange->units == sc->sc_esensors[j].units)
1067 1.4 garbled envrange->high = j;
1068 1.4 garbled }
1069 1.4 garbled if (!i) {
1070 1.4 garbled envrange->high = 0;
1071 1.4 garbled envrange->low = 1;
1072 1.4 garbled }
1073 1.4 garbled break;
1074 1.4 garbled
1075 1.4 garbled case ENVSYS_GTREDATA:
1076 1.4 garbled envdata = (envsys_temp_data_t *)data;
1077 1.4 garbled if (envdata->sensor >= ENVSYS_NUMSENSORS) {
1078 1.4 garbled envdata->validflags = 0;
1079 1.4 garbled break;
1080 1.4 garbled }
1081 1.4 garbled envdata->warnflags = ENVSYS_WARN_OK;
1082 1.4 garbled if (envdata->sensor == 0) {
1083 1.4 garbled envdata->validflags |= ENVSYS_FVALID;
1084 1.4 garbled req.cmdbuf[0] = TS102_OP_RD_CURRENT_TEMP;
1085 1.4 garbled req.cmdlen = 1;
1086 1.4 garbled req.rsplen = 2;
1087 1.4 garbled req.p = p;
1088 1.4 garbled tadpole_request(&req, 0);
1089 1.4 garbled envdata->cur.data_us = /* 273160? */
1090 1.6 garbled (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
1091 1.4 garbled envdata->validflags |= ENVSYS_FCURVALID;
1092 1.4 garbled req.cmdbuf[0] = TS102_OP_RD_MAX_TEMP;
1093 1.4 garbled req.cmdlen = 1;
1094 1.4 garbled req.rsplen = 2;
1095 1.4 garbled req.p = p;
1096 1.4 garbled tadpole_request(&req, 0);
1097 1.4 garbled envdata->max.data_us =
1098 1.6 garbled (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
1099 1.4 garbled envdata->validflags |= ENVSYS_FMAXVALID;
1100 1.4 garbled req.cmdbuf[0] = TS102_OP_RD_MIN_TEMP;
1101 1.4 garbled req.cmdlen = 1;
1102 1.4 garbled req.rsplen = 2;
1103 1.4 garbled req.p = p;
1104 1.4 garbled tadpole_request(&req, 0);
1105 1.4 garbled envdata->min.data_us =
1106 1.6 garbled (u_int32_t)((int)((int)req.rspbuf[0]-32)*5000000/9+273150000);
1107 1.4 garbled envdata->validflags |= ENVSYS_FMINVALID;
1108 1.4 garbled envdata->units = sc->sc_esensors[envdata->sensor].units;
1109 1.4 garbled break;
1110 1.4 garbled } else if (envdata->sensor == 1 || envdata->sensor == 2) {
1111 1.4 garbled envdata->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
1112 1.4 garbled envdata->units = sc->sc_esensors[envdata->sensor].units;
1113 1.4 garbled if (envdata->sensor == 1)
1114 1.4 garbled req.cmdbuf[0] = TS102_OP_RD_INT_BATT_VLT;
1115 1.4 garbled else
1116 1.4 garbled req.cmdbuf[0] = TS102_OP_RD_DC_IN_VLT;
1117 1.4 garbled req.cmdlen = 1;
1118 1.4 garbled req.rsplen = 2;
1119 1.4 garbled req.p = p;
1120 1.4 garbled tadpole_request(&req, 0);
1121 1.6 garbled envdata->cur.data_s = (int32_t)req.rspbuf[0]*1000000/11;
1122 1.4 garbled break;
1123 1.4 garbled }
1124 1.4 garbled break;
1125 1.4 garbled
1126 1.4 garbled case ENVSYS_GTREINFO:
1127 1.4 garbled envinfo = (envsys_temp_info_t *)data;
1128 1.4 garbled if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
1129 1.4 garbled envinfo->validflags = 0;
1130 1.4 garbled break;
1131 1.4 garbled }
1132 1.4 garbled envinfo->units = sc->sc_esensors[envinfo->sensor].units;
1133 1.4 garbled memcpy(envinfo->desc, sc->sc_esensors[envinfo->sensor].desc,
1134 1.4 garbled sizeof(sc->sc_esensors[envinfo->sensor].desc) >
1135 1.4 garbled sizeof(envinfo->desc) ? sizeof(envinfo->desc) :
1136 1.4 garbled sizeof(sc->sc_esensors[envinfo->sensor].desc));
1137 1.4 garbled if (envinfo->units == ENVSYS_STEMP) {
1138 1.4 garbled envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
1139 1.4 garbled ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
1140 1.4 garbled } else if (envinfo->units == ENVSYS_SVOLTS_DC) {
1141 1.4 garbled envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
1142 1.4 garbled } else
1143 1.4 garbled envinfo->validflags = 0;
1144 1.4 garbled break;
1145 1.4 garbled
1146 1.4 garbled case ENVSYS_STREINFO:
1147 1.4 garbled envinfo = (envsys_temp_info_t *)data;
1148 1.4 garbled if (envinfo->sensor >= ENVSYS_NUMSENSORS) {
1149 1.4 garbled envinfo->validflags = 0;
1150 1.4 garbled break;
1151 1.4 garbled }
1152 1.4 garbled if (envinfo->units == sc->sc_esensors[envinfo->sensor].units)
1153 1.4 garbled memcpy(sc->sc_esensors[envinfo->sensor].desc,
1154 1.4 garbled envinfo->desc,
1155 1.4 garbled sizeof(envinfo->desc) > sizeof(char)*32 ?
1156 1.4 garbled sizeof(char)*32 : sizeof(envinfo->desc) );
1157 1.4 garbled if (envinfo->units == ENVSYS_STEMP) {
1158 1.4 garbled envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID|
1159 1.4 garbled ENVSYS_FMINVALID|ENVSYS_FMAXVALID;
1160 1.4 garbled } else if (envinfo->units == ENVSYS_SVOLTS_DC) {
1161 1.4 garbled envinfo->validflags = ENVSYS_FVALID|ENVSYS_FCURVALID;
1162 1.4 garbled } else
1163 1.4 garbled envinfo->validflags = 0;
1164 1.4 garbled break;
1165 1.7 jdc
1166 1.7 jdc /* serial power mode (via auxiotwo) */
1167 1.7 jdc case TCTRL_SERIAL_PWR:
1168 1.7 jdc pwrreq = (struct tctrl_pwr *)data;
1169 1.7 jdc if (pwrreq->rw)
1170 1.7 jdc pwrreq->state = auxiotwoserialgetapm();
1171 1.7 jdc else
1172 1.7 jdc auxiotwoserialsetapm(pwrreq->state);
1173 1.7 jdc break;
1174 1.7 jdc
1175 1.7 jdc /* modem power mode (via auxio) */
1176 1.7 jdc case TCTRL_MODEM_PWR:
1177 1.7 jdc return(EOPNOTSUPP); /* for now */
1178 1.7 jdc break;
1179 1.4 garbled
1180 1.4 garbled
1181 1.4 garbled default:
1182 1.4 garbled return (ENOTTY);
1183 1.4 garbled }
1184 1.4 garbled return (0);
1185 1.4 garbled }
1186 1.4 garbled
1187 1.4 garbled int
1188 1.4 garbled tctrlpoll(dev, events, p)
1189 1.4 garbled dev_t dev;
1190 1.4 garbled int events;
1191 1.4 garbled struct proc *p;
1192 1.4 garbled {
1193 1.4 garbled struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1194 1.4 garbled int revents = 0;
1195 1.4 garbled
1196 1.4 garbled if (events & (POLLIN | POLLRDNORM)) {
1197 1.4 garbled if (sc->sc_event_count)
1198 1.4 garbled revents |= events & (POLLIN | POLLRDNORM);
1199 1.4 garbled else
1200 1.4 garbled selrecord(p, &sc->sc_rsel);
1201 1.4 garbled }
1202 1.4 garbled
1203 1.4 garbled return (revents);
1204 1.1 matt }
1205 1.12.4.2 thorpej
1206 1.12.4.2 thorpej static void
1207 1.12.4.2 thorpej filt_tctrlrdetach(struct knote *kn)
1208 1.12.4.2 thorpej {
1209 1.12.4.5 jdolecek struct tctrl_softc *sc = kn->kn_hook;
1210 1.12.4.2 thorpej int s;
1211 1.12.4.2 thorpej
1212 1.12.4.2 thorpej s = splts102();
1213 1.12.4.2 thorpej SLIST_REMOVE(&sc->sc_rsel.si_klist, kn, knote, kn_selnext);
1214 1.12.4.2 thorpej splx(s);
1215 1.12.4.2 thorpej }
1216 1.12.4.2 thorpej
1217 1.12.4.4 jdolecek static int
1218 1.12.4.2 thorpej filt_tctrlread(struct knote *kn, long hint)
1219 1.12.4.2 thorpej {
1220 1.12.4.5 jdolecek struct tctrl_softc *sc = kn->kn_hook;
1221 1.12.4.2 thorpej
1222 1.12.4.2 thorpej kn->kn_data = sc->sc_event_count;
1223 1.12.4.2 thorpej return (kn->kn_data > 0);
1224 1.12.4.2 thorpej }
1225 1.12.4.2 thorpej
1226 1.12.4.2 thorpej static const struct filterops tctrlread_filtops =
1227 1.12.4.2 thorpej { 1, NULL, filt_tctrlrdetach, filt_tctrlread };
1228 1.12.4.2 thorpej
1229 1.12.4.2 thorpej int
1230 1.12.4.2 thorpej tctrlkqfilter(dev_t dev, struct knote *kn)
1231 1.12.4.2 thorpej {
1232 1.12.4.2 thorpej struct tctrl_softc *sc = tctrl_cd.cd_devs[TCTRL_STD_DEV];
1233 1.12.4.4 jdolecek struct klist *klist;
1234 1.12.4.2 thorpej int s;
1235 1.12.4.2 thorpej
1236 1.12.4.2 thorpej switch (kn->kn_filter) {
1237 1.12.4.2 thorpej case EVFILT_READ:
1238 1.12.4.2 thorpej klist = &sc->sc_rsel.si_klist;
1239 1.12.4.2 thorpej kn->kn_fop = &tctrlread_filtops;
1240 1.12.4.2 thorpej break;
1241 1.12.4.2 thorpej
1242 1.12.4.2 thorpej default:
1243 1.12.4.2 thorpej return (1);
1244 1.12.4.2 thorpej }
1245 1.12.4.2 thorpej
1246 1.12.4.5 jdolecek kn->kn_hook = sc;
1247 1.12.4.2 thorpej
1248 1.12.4.2 thorpej s = splts102();
1249 1.12.4.2 thorpej SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1250 1.12.4.2 thorpej splx(s);
1251 1.12.4.2 thorpej
1252 1.12.4.2 thorpej return (0);
1253 1.12.4.2 thorpej }
1254 1.12.4.2 thorpej
1255 1.6 garbled /* DO NOT SET THIS OPTION */
1256 1.6 garbled #ifdef TADPOLE_BLINK
1257 1.6 garbled void
1258 1.6 garbled cpu_disk_unbusy(busy)
1259 1.6 garbled int busy;
1260 1.6 garbled {
1261 1.6 garbled static struct timeval tctrl_ds_timestamp;
1262 1.6 garbled struct timeval dv_time, diff_time;
1263 1.6 garbled struct tctrl_softc *sc;
1264 1.6 garbled
1265 1.6 garbled sc = (struct tctrl_softc *) tctrl_cd.cd_devs[TCTRL_STD_DEV];
1266 1.6 garbled
1267 1.6 garbled /* quickly bail */
1268 1.6 garbled if (!(sc->sc_lcdstate & TS102_LCD_DISK_ACTIVE) || busy > 0)
1269 1.6 garbled return;
1270 1.6 garbled
1271 1.6 garbled /* we aren't terribly concerned with precision here */
1272 1.6 garbled dv_time = mono_time;
1273 1.6 garbled timersub(&dv_time, &tctrl_ds_timestamp, &diff_time);
1274 1.6 garbled
1275 1.6 garbled if (diff_time.tv_sec > 0) {
1276 1.6 garbled tctrl_set_lcd(0, TS102_LCD_DISK_ACTIVE);
1277 1.6 garbled tctrl_ds_timestamp = mono_time;
1278 1.6 garbled }
1279 1.6 garbled }
1280 1.6 garbled #endif
1281