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