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