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