1 /* $OpenBSD: tctrl.c,v 1.18 2006/10/27 17:52:38 miod Exp $ */
2 /* $NetBSD: tctrl.c,v 1.2 1999/08/11 00:46:06 matt Exp $ */
3
4 /*-
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Matt Thomas.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/conf.h>
43 #include <sys/kernel.h>
44 #include <sys/device.h>
45 #include <sys/event.h>
46 #include <sys/fcntl.h>
47 #include <sys/ioctl.h>
48 #include <sys/proc.h>
49 #include <sys/timeout.h>
50
51 #include <machine/apmvar.h>
52 #include <machine/autoconf.h>
53 #include <machine/conf.h>
54 #include <machine/cpu.h>
55
56 #include <sparc/sparc/auxioreg.h>
57
58 #include <sparc/dev/ts102reg.h>
59 #include <sparc/dev/tctrlvar.h>
60
61 /*
62 * Flags to control kernel display
63 * SCFLAG_NOPRINT: do not output APM power messages due to
64 * a power change event.
65 *
66 * SCFLAG_PCTPRINT: do not output APM power messages due to
67 * to a power change event unless the battery
68 * percentage changes.
69 */
70
71 #define SCFLAG_NOPRINT 0x0008000
72 #define SCFLAG_PCTPRINT 0x0004000
73 #define SCFLAG_PRINT (SCFLAG_NOPRINT|SCFLAG_PCTPRINT)
74
75 const char *tctrl_ext_status[16] = {
76 "main power available",
77 "internal battery attached",
78 "external battery attached",
79 "external VGA attached",
80 "external keyboard attached",
81 "external mouse attached",
82 "lid down",
83 "internal battery charging",
84 "external battery charging",
85 "internal battery discharging",
86 "external battery discharging",
87 };
88
89 /* Request "packet" */
90 struct tctrl_req {
91 u_int8_t cmdbuf[16];
92 u_int cmdlen;
93 u_int8_t rspbuf[16];
94 u_int rsplen;
95 };
96
97 struct tctrl_softc {
98 struct device sc_dev;
99 struct uctrl_regs *sc_regs;
100 struct intrhand sc_ih;
101 u_int sc_ext_status;
102 u_int sc_flags;
103 #define TCTRL_SEND_REQUEST 0x0001
104 #define TCTRL_ISXT 0x0002
105 u_int sc_wantdata;
106 enum { TCTRL_IDLE, TCTRL_ARGS,
107 TCTRL_ACK, TCTRL_DATA } sc_state;
108 u_int8_t sc_cmdbuf[16];
109 u_int8_t sc_rspbuf[16];
110 u_int8_t sc_tft_on;
111 u_int8_t sc_pcmcia_on;
112 u_int8_t sc_brightness;
113 u_int8_t sc_op;
114 u_int sc_cmdoff;
115 u_int sc_cmdlen;
116 u_int sc_rspoff;
117 u_int sc_rsplen;
118 u_int sc_rspack;
119 u_int sc_bellfreq;
120 u_int sc_bellvol;
121
122 struct timeout sc_tmo;
123
124 /* /dev/apm{,ctl} fields */
125 struct klist sc_note;
126 u_int sc_apmflags;
127
128 /* external video control callback */
129 void (*sc_evcb)(void *, int);
130 void *sc_evdata;
131 };
132
133 int tctrl_match(struct device *, void *, void *);
134 void tctrl_attach(struct device *, struct device *, void *);
135
136 void tctrl_bell(struct tctrl_softc *, int, int);
137 void tctrl_brightness(struct tctrl_softc *, int, int);
138 void tctrl_init_lcd(struct tctrl_softc *);
139 int tctrl_intr(void *);
140 void tctrl_lcd(struct tctrl_softc *, int, int);
141 u_int8_t tctrl_read_data(struct tctrl_softc *);
142 void tctrl_read_event_status(void *);
143 void tctrl_read_ext_status(struct tctrl_softc *);
144 int tctrl_request(struct tctrl_softc *, struct tctrl_req *);
145 void tctrl_write_data(struct tctrl_softc *, u_int8_t);
146
147 struct cfattach tctrl_ca = {
148 sizeof(struct tctrl_softc), tctrl_match, tctrl_attach
149 };
150
151 struct cfdriver tctrl_cd = {
152 NULL, "tctrl", DV_DULL
153 };
154
155 int
tctrl_match(parent,vcf,aux)156 tctrl_match(parent, vcf, aux)
157 struct device *parent;
158 void *vcf;
159 void *aux;
160 {
161 struct confargs *ca = aux;
162 struct romaux *ra = &ca->ca_ra;
163
164 /*
165 * Tadpole 3GX/3GS uses "uctrl" for the Tadpole Microcontroller
166 * (which is really part of the TS102 PCMCIA controller, but there
167 * exists a distinct OpenProm node for the microcontroller interface).
168 */
169 if (strcmp("uctrl", ra->ra_name))
170 return (0);
171
172 return (1);
173 }
174
175 void
tctrl_attach(parent,self,aux)176 tctrl_attach(parent, self, aux)
177 struct device *parent, *self;
178 void *aux;
179 {
180 struct confargs *ca = aux;
181 struct tctrl_softc *sc = (void *)self;
182 u_int i, v;
183 int pri;
184
185 if (ca->ca_ra.ra_nintr != 1) {
186 printf(": expected 1 interrupt, got %d\n",
187 ca->ca_ra.ra_nintr);
188 return;
189 }
190 pri = ca->ca_ra.ra_intr[0].int_pri;
191
192 if (ca->ca_ra.ra_nreg != 1) {
193 printf(": expected 1 register, got %d\n",
194 ca->ca_ra.ra_nreg);
195 return;
196 }
197 sc->sc_regs = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
198 ca->ca_ra.ra_reg[0].rr_len);
199
200 printf(" pri %d\n", pri);
201
202 /*
203 * We need to check if we are running on the SPARCbook S3XT, which
204 * needs extra work to control the TFT power.
205 */
206 sc->sc_flags = 0;
207 if (strcmp(mainbus_model, "Tadpole_S3000XT") == 0)
208 sc->sc_flags |= TCTRL_ISXT;
209 sc->sc_tft_on = 1;
210
211 /* clear any pending data */
212 for (i = 0; i < 10000; i++) {
213 if ((TS102_UCTRL_STS_RXNE_STA & sc->sc_regs->stat) == 0)
214 break;
215 v = sc->sc_regs->data;
216 sc->sc_regs->stat = TS102_UCTRL_STS_RXNE_STA;
217 }
218
219 sc->sc_ih.ih_fun = tctrl_intr;
220 sc->sc_ih.ih_arg = sc;
221 intr_establish(pri, &sc->sc_ih, -1);
222
223 timeout_set(&sc->sc_tmo, tctrl_read_event_status, sc);
224
225 /* See what the external status is */
226 tctrl_read_ext_status(sc);
227 if (sc->sc_ext_status != 0) {
228 const char *sep;
229 u_int len;
230
231 v = sc->sc_ext_status;
232 len = 0;
233 sep = "";
234 for (i = 0; v != 0; i++, v >>= 1) {
235 if ((v & 1) == 0)
236 continue;
237 /* wrap to next line if necessary */
238 if (len != 0 && len + strlen(sep) +
239 strlen(tctrl_ext_status[i]) > 80) {
240 printf("\n");
241 len = 0;
242 }
243 if (len == 0) {
244 printf("%s: ", sc->sc_dev.dv_xname);
245 len = 2 + strlen(sc->sc_dev.dv_xname);
246 sep = "";
247 }
248 printf("%s%s", sep, tctrl_ext_status[i]);
249 len += strlen(sep) + strlen(tctrl_ext_status[i]);
250 sep = ", ";
251 }
252 if (len != 0)
253 printf("\n");
254 }
255
256 /* Get a few status values */
257 tctrl_bell(sc, 0xff, 0);
258 tctrl_brightness(sc, 0xff, 0);
259
260 sc->sc_regs->intr = TS102_UCTRL_INT_RXNE_REQ|TS102_UCTRL_INT_RXNE_MSK;
261
262 sc->sc_wantdata = 0;
263
264 /* Initialize the LCD icons */
265 tctrl_init_lcd(sc);
266 }
267
268 int
tctrl_intr(void * arg)269 tctrl_intr(void *arg)
270 {
271 struct tctrl_softc *sc = arg;
272 unsigned int v, d;
273 int progress = 0;
274
275 again:
276 /* find out the cause(s) of the interrupt */
277 v = sc->sc_regs->stat & TS102_UCTRL_STS_MASK;
278
279 /* clear the cause(s) of the interrupt */
280 sc->sc_regs->stat = v;
281
282 v &= ~(TS102_UCTRL_STS_RXO_STA|TS102_UCTRL_STS_TXE_STA);
283 if (sc->sc_cmdoff >= sc->sc_cmdlen) {
284 v &= ~TS102_UCTRL_STS_TXNF_STA;
285 if (sc->sc_regs->intr & TS102_UCTRL_INT_TXNF_REQ) {
286 sc->sc_regs->intr = 0;
287 progress = 1;
288 }
289 }
290 if (v == 0 && ((sc->sc_flags & TCTRL_SEND_REQUEST) == 0 ||
291 sc->sc_state != TCTRL_IDLE)) {
292 return (progress);
293 }
294
295 progress = 1;
296 if (v & TS102_UCTRL_STS_RXNE_STA) {
297 d = tctrl_read_data(sc);
298 switch (sc->sc_state) {
299 case TCTRL_IDLE:
300 if (d == TS102_UCTRL_INTR) {
301 /* external event */
302 timeout_add(&sc->sc_tmo, 1);
303 } else {
304 printf("%s: (op=0x%02x): unexpected data (0x%02x)\n",
305 sc->sc_dev.dv_xname, sc->sc_op, d);
306 }
307 goto again;
308 case TCTRL_ACK:
309 #ifdef TCTRLDEBUG
310 printf(" ack=0x%02x", d);
311 #endif
312 switch (d) {
313 case TS102_UCTRL_ACK:
314 sc->sc_rspack = 1;
315 sc->sc_rsplen--;
316 sc->sc_rspoff = 0;
317 sc->sc_state =
318 sc->sc_rsplen ? TCTRL_DATA : TCTRL_IDLE;
319 sc->sc_wantdata = sc->sc_rsplen ? 1 : 0;
320 #ifdef TCTRLDEBUG
321 if (sc->sc_rsplen > 0) {
322 printf(" [data(%u)]", sc->sc_rsplen);
323 } else {
324 printf(" [idle]\n");
325 }
326 #endif
327 goto again;
328 default:
329 printf("%s: (op=0x%02x): unexpected return value (0x%02x)\n",
330 sc->sc_dev.dv_xname, sc->sc_op, d);
331 /* FALLTHROUGH */
332 case TS102_UCTRL_NACK:
333 printf("%s: command %x failed\n",
334 sc->sc_dev.dv_xname, sc->sc_op);
335 sc->sc_rspack = 0;
336 sc->sc_wantdata = 0;
337 sc->sc_state = TCTRL_IDLE;
338 break;
339 }
340 break;
341 case TCTRL_DATA:
342 sc->sc_rspbuf[sc->sc_rspoff++] = d;
343 #ifdef TCTRLDEBUG
344 printf(" [%d]=0x%02x", sc->sc_rspoff-1, d);
345 #endif
346 if (sc->sc_rspoff == sc->sc_rsplen) {
347 #ifdef TCTRLDEBUG
348 printf(" [idle]\n");
349 #endif
350 sc->sc_state = TCTRL_IDLE;
351 sc->sc_wantdata = 0;
352 }
353 goto again;
354 default:
355 printf("%s: (op=0x%02x): unexpected data (0x%02x) in state %d\n",
356 sc->sc_dev.dv_xname, sc->sc_op, d, sc->sc_state);
357 goto again;
358 }
359 }
360 if ((sc->sc_state == TCTRL_IDLE && sc->sc_wantdata == 0) ||
361 (sc->sc_flags & TCTRL_SEND_REQUEST)) {
362 if (sc->sc_flags & TCTRL_SEND_REQUEST) {
363 sc->sc_flags &= ~TCTRL_SEND_REQUEST;
364 sc->sc_wantdata = 1;
365 }
366 if (sc->sc_cmdlen > 0) {
367 sc->sc_regs->intr =
368 sc->sc_regs->intr | TS102_UCTRL_INT_TXNF_MSK
369 |TS102_UCTRL_INT_TXNF_REQ;
370 v = sc->sc_regs->stat;
371 }
372 }
373 if ((sc->sc_cmdoff < sc->sc_cmdlen) && (v & TS102_UCTRL_STS_TXNF_STA)) {
374 tctrl_write_data(sc, sc->sc_cmdbuf[sc->sc_cmdoff++]);
375 #ifdef TCTRLDEBUG
376 if (sc->sc_cmdoff == 1) {
377 printf("%s: op=0x%02x(l=%u)", sc->sc_dev.dv_xname,
378 sc->sc_cmdbuf[0], sc->sc_rsplen);
379 } else {
380 printf(" [%d]=0x%02x", sc->sc_cmdoff-1,
381 sc->sc_cmdbuf[sc->sc_cmdoff-1]);
382 }
383 #endif
384 if (sc->sc_cmdoff == sc->sc_cmdlen) {
385 sc->sc_state = sc->sc_rsplen ? TCTRL_ACK : TCTRL_IDLE;
386 #ifdef TCTRLDEBUG
387 printf(" %s", sc->sc_rsplen ? "[ack]" : "[idle]\n");
388 #endif
389 if (sc->sc_cmdoff == 1) {
390 sc->sc_op = sc->sc_cmdbuf[0];
391 }
392 sc->sc_regs->intr =
393 sc->sc_regs->intr & (~TS102_UCTRL_INT_TXNF_MSK
394 |TS102_UCTRL_INT_TXNF_REQ);
395 } else if (sc->sc_state == TCTRL_IDLE) {
396 sc->sc_op = sc->sc_cmdbuf[0];
397 sc->sc_state = TCTRL_ARGS;
398 #ifdef TCTRLDEBUG
399 printf(" [args]");
400 #endif
401 }
402 }
403 goto again;
404 }
405
406 /*
407 * The Tadpole microcontroller is not preprogrammed with icon
408 * representations. The machine boots with the DC-IN light as
409 * a blank (all 0x00) and the other lights, as 4 rows of horizontal
410 * bars. The below code initializes the few icons the system will use
411 * to sane values.
412 *
413 * Programming the icons is simple. It is a 5x8 matrix, with each row a
414 * bitfield in the order 0x10 0x08 0x04 0x02 0x01.
415 */
416
417 static void tctrl_set_glyph(struct tctrl_softc *, u_int, const u_int8_t *);
418
419 static const u_int8_t
420 tctrl_glyph_dc[] = { 0x00, 0x00, 0x1f, 0x00, 0x15, 0x00, 0x00, 0x00 },
421 #if 0
422 tctrl_glyph_bs[] = { 0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00 },
423 tctrl_glyph_w1[] = { 0x0c, 0x16, 0x10, 0x15, 0x10, 0x16, 0x0c, 0x00 },
424 tctrl_glyph_w2[] = { 0x0c, 0x0d, 0x01, 0x15, 0x01, 0x0d, 0x0c, 0x00 },
425 tctrl_glyph_l1[] = { 0x00, 0x04, 0x08, 0x13, 0x08, 0x04, 0x00, 0x00 },
426 tctrl_glyph_l2[] = { 0x00, 0x04, 0x02, 0x19, 0x02, 0x04, 0x00, 0x00 },
427 #endif
428 tctrl_glyph_pc[] = { 0x00, 0x0e, 0x0e, 0x1f, 0x1f, 0x1f, 0x1f, 0x00 };
429
430 void
tctrl_init_lcd(struct tctrl_softc * sc)431 tctrl_init_lcd(struct tctrl_softc *sc)
432 {
433 tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_DC_GOOD, tctrl_glyph_dc);
434 #if 0
435 tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_BACKSLASH, tctrl_glyph_bs);
436 tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_WAN1, tctrl_glyph_w1);
437 tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_WAN2, tctrl_glyph_w2);
438 tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_LAN1, tctrl_glyph_l1);
439 tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_LAN2, tctrl_glyph_l2);
440 #endif
441 tctrl_set_glyph(sc, TS102_BLK_OFF_DEF_PCMCIA, tctrl_glyph_pc);
442 }
443
444 static void
tctrl_set_glyph(struct tctrl_softc * sc,u_int glyph,const u_int8_t * data)445 tctrl_set_glyph(struct tctrl_softc *sc, u_int glyph, const u_int8_t *data)
446 {
447 struct tctrl_req req;
448
449 req.cmdbuf[0] = TS102_OP_BLK_DEF_SPCL_CHAR;
450 req.cmdbuf[1] = 8;
451 req.cmdbuf[2] = glyph;
452 bcopy(data, req.cmdbuf + 3, 8);
453 req.cmdlen = 3 + 8;
454 req.rsplen = 1;
455
456 tctrl_request(sc, &req);
457 }
458
459 void
tctrl_read_event_status(void * arg)460 tctrl_read_event_status(void *arg)
461 {
462 struct tctrl_softc *sc = (struct tctrl_softc *)arg;
463 struct tctrl_req req;
464 unsigned int v;
465
466 req.cmdbuf[0] = TS102_OP_RD_EVENT_STATUS;
467 req.cmdlen = 1;
468 req.rsplen = 3;
469
470 tctrl_request(sc, &req);
471
472 v = req.rspbuf[0] * 256 + req.rspbuf[1];
473
474 /*
475 * Read the new external status value if necessary
476 */
477 if (v & (TS102_EVENT_STATUS_DC_STATUS_CHANGE |
478 TS102_EVENT_STATUS_LID_STATUS_CHANGE |
479 TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE))
480 tctrl_read_ext_status(sc);
481
482 if (v & TS102_EVENT_STATUS_SHUTDOWN_REQUEST) {
483 printf("%s: SHUTDOWN REQUEST!\n", sc->sc_dev.dv_xname);
484 }
485 #ifdef TCTRLDEBUG
486 /* Obviously status change */
487 if (v & TS102_EVENT_STATUS_VERY_LOW_POWER_WARNING) {
488 if (sc->sc_apmflags & SCFLAG_PCTPRINT)
489 printf("%s: Battery level change\n",
490 sc->sc_dev.dv_xname);
491 }
492 #endif
493 if (v & TS102_EVENT_STATUS_LOW_POWER_WARNING) {
494 if ((sc->sc_apmflags & SCFLAG_NOPRINT) == 0)
495 printf("%s: LOW POWER WARNING!\n", sc->sc_dev.dv_xname);
496 }
497 if (v & TS102_EVENT_STATUS_DC_STATUS_CHANGE) {
498 if ((sc->sc_apmflags & SCFLAG_NOPRINT) == 0)
499 printf("%s: main power %s\n", sc->sc_dev.dv_xname,
500 (sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE) ?
501 "restored" : "removed");
502 #if 0 /* automatically done for us */
503 tctrl_lcd(sc, ~TS102_LCD_DC_OK,
504 sc->sc_ext_status & TS102_EXT_STATUS_MAIN_POWER_AVAILABLE ?
505 TS102_LCD_DC_OK : 0);
506 #endif
507 }
508 if (v & TS102_EVENT_STATUS_EXTERNAL_VGA_STATUS_CHANGE) {
509 printf("%s: external vga %s\n", sc->sc_dev.dv_xname,
510 sc->sc_ext_status & TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED ?
511 "attached" : "detached");
512 #ifdef TCTRLDEBUG
513 req.cmdbuf[0] = TS102_OP_RD_EXT_VGA_PORT;
514 req.cmdlen = 1;
515 req.rsplen = 2;
516 tctrl_request(sc, &req);
517 printf("%s: vga status %x\n", sc->sc_dev.dv_xname,
518 req.rspbuf[0]);
519 #endif
520 if (sc->sc_evcb != NULL)
521 (*sc->sc_evcb)(sc->sc_evdata, sc->sc_ext_status &
522 TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED);
523 }
524 }
525
526 void
tctrl_read_ext_status(struct tctrl_softc * sc)527 tctrl_read_ext_status(struct tctrl_softc *sc)
528 {
529 struct tctrl_req req;
530
531 req.cmdbuf[0] = TS102_OP_RD_EXT_STATUS;
532 req.cmdlen = 1;
533 req.rsplen = 3;
534 #ifdef TCTRLDEBUG
535 printf("tctrl_read_ext_status: before, ext_status = %x\n",
536 sc->sc_ext_status);
537 #endif
538
539 tctrl_request(sc, &req);
540
541 sc->sc_ext_status = req.rspbuf[0] * 256 + req.rspbuf[1];
542
543 #ifdef TCTRLDEBUG
544 printf("tctrl_read_ext_status: after, ext_status = %x\n",
545 sc->sc_ext_status);
546 #endif
547 }
548
549 void
tctrl_bell(struct tctrl_softc * sc,int mask,int value)550 tctrl_bell(struct tctrl_softc *sc, int mask, int value)
551 {
552 struct tctrl_req req;
553
554 req.cmdbuf[0] = TS102_OP_CTL_SPEAKER_VOLUME;
555 req.cmdbuf[1] = mask;
556 req.cmdbuf[2] = value;
557 req.cmdlen = 3;
558 req.rsplen = 2;
559
560 tctrl_request(sc, &req);
561
562 /*
563 * Note that rspbuf[0] returns the previous value, before any
564 * adjustment happened.
565 */
566 if (mask == 0)
567 sc->sc_bellvol = value;
568 else
569 sc->sc_bellvol = req.rspbuf[0];
570 }
571
572 void
tctrl_brightness(struct tctrl_softc * sc,int mask,int value)573 tctrl_brightness(struct tctrl_softc *sc, int mask, int value)
574 {
575 struct tctrl_req req;
576
577 req.cmdbuf[0] = TS102_OP_CTL_TFT_BRIGHTNESS;
578 req.cmdbuf[1] = mask;
579 req.cmdbuf[2] = value;
580 req.cmdlen = 3;
581 req.rsplen = 2;
582
583 tctrl_request(sc, &req);
584
585 /*
586 * Note that rspbuf[0] returns the previous value, before any
587 * adjustment happened.
588 */
589 if (mask == 0)
590 sc->sc_brightness = value;
591 else
592 sc->sc_brightness = req.rspbuf[0];
593 }
594
595 void
tctrl_lcd(struct tctrl_softc * sc,int mask,int value)596 tctrl_lcd(struct tctrl_softc *sc, int mask, int value)
597 {
598 struct tctrl_req req;
599
600 req.cmdbuf[0] = TS102_OP_CTL_LCD;
601
602 /*
603 * The mask setup for this particular command is *very* bizarre
604 * and totally undocumented.
605 * One would expect the cmdlen and rsplen to be 5 and 3,
606 * respectively, as well. Though luck, they are not...
607 */
608
609 req.cmdbuf[1] = mask & 0xff;
610 req.cmdbuf[4] = (mask >> 8) & 0x01;
611
612 req.cmdbuf[2] = value & 0xff;
613 req.cmdbuf[3] = (value >> 8 & 0x01);
614
615 req.cmdlen = 3;
616 req.rsplen = 2;
617
618 tctrl_request(sc, &req);
619 }
620
621 int
tctrl_request(struct tctrl_softc * sc,struct tctrl_req * req)622 tctrl_request(struct tctrl_softc *sc, struct tctrl_req *req)
623 {
624 int s, rv;
625
626 while (sc->sc_wantdata != 0) {
627 DELAY(1);
628 }
629
630 s = splhigh();
631 sc->sc_flags |= TCTRL_SEND_REQUEST;
632 bcopy(req->cmdbuf, sc->sc_cmdbuf, req->cmdlen);
633 sc->sc_wantdata = 1;
634 sc->sc_rsplen = req->rsplen;
635 sc->sc_cmdlen = req->cmdlen;
636 sc->sc_cmdoff = sc->sc_rspoff = 0;
637
638 do {
639 tctrl_intr(sc);
640 } while (sc->sc_state != TCTRL_IDLE);
641
642 sc->sc_wantdata = 0; /* just in case... */
643
644 rv = sc->sc_rspack;
645 if (rv != 0)
646 bcopy(sc->sc_rspbuf, req->rspbuf, sc->sc_rsplen);
647 else
648 bzero(req->rspbuf, req->rsplen); /* safety */
649 splx(s);
650
651 return (rv);
652 }
653
654 void
tctrl_write_data(sc,v)655 tctrl_write_data(sc, v)
656 struct tctrl_softc *sc;
657 u_int8_t v;
658 {
659 unsigned int i;
660
661 for (i = 0; i < 100; i++) {
662 if (sc->sc_regs->stat & TS102_UCTRL_STS_TXNF_STA)
663 break;
664 }
665 sc->sc_regs->data = v;
666 }
667
668 u_int8_t
tctrl_read_data(sc)669 tctrl_read_data(sc)
670 struct tctrl_softc *sc;
671 {
672 unsigned int i, v;
673
674 for (i = 0; i < 100000; i++) {
675 if (sc->sc_regs->stat & TS102_UCTRL_STS_RXNE_STA)
676 break;
677 DELAY(1);
678 }
679
680 v = sc->sc_regs->data;
681 sc->sc_regs->stat = TS102_UCTRL_STS_RXNE_STA;
682 return v;
683 }
684
685 /*
686 * External interfaces, used by the display and pcmcia drivers, as well
687 * as the powerdown code.
688 */
689
690 void
tadpole_powerdown(void)691 tadpole_powerdown(void)
692 {
693 struct tctrl_softc *sc;
694 struct tctrl_req req;
695
696 if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
697 return;
698 }
699
700 sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
701 req.cmdbuf[0] = TS102_OP_ADMIN_POWER_OFF;
702 req.cmdlen = 1;
703 req.rsplen = 1;
704
705 tctrl_request(sc, &req);
706 }
707
708 void
tadpole_set_brightness(int value)709 tadpole_set_brightness(int value)
710 {
711 struct tctrl_softc *sc;
712
713 if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
714 return;
715 }
716
717 sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
718 if (value != sc->sc_brightness)
719 tctrl_brightness(sc, 0, value);
720 }
721
722 int
tadpole_get_brightness()723 tadpole_get_brightness()
724 {
725 struct tctrl_softc *sc;
726
727 if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
728 return 0;
729 }
730
731 sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
732 return sc->sc_brightness;
733 }
734
735 void
tadpole_set_video(int enabled)736 tadpole_set_video(int enabled)
737 {
738 struct tctrl_softc *sc;
739
740 if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
741 return;
742 }
743
744 sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
745 if (sc->sc_tft_on ^ enabled) {
746 sc->sc_tft_on = enabled;
747 }
748 }
749
750 u_int
tadpole_get_video()751 tadpole_get_video()
752 {
753 struct tctrl_softc *sc;
754 unsigned int status;
755
756 if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
757 return 0;
758 }
759
760 sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
761 status = sc->sc_tft_on ? TV_ON : 0;
762
763 return status;
764 }
765
766 void
tadpole_register_extvideo(void (* cb)(void *,int),void * data)767 tadpole_register_extvideo(void (*cb)(void *, int), void *data)
768 {
769 struct tctrl_softc *sc;
770
771 if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
772 return;
773 }
774
775 sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
776 sc->sc_evcb = cb;
777 sc->sc_evdata = data;
778
779 (*cb)(data, sc->sc_ext_status & TS102_EXT_STATUS_EXTERNAL_VGA_ATTACHED);
780 }
781
782 void
tadpole_set_pcmcia(int slot,int enabled)783 tadpole_set_pcmcia(int slot, int enabled)
784 {
785 struct tctrl_softc *sc;
786 int mask;
787
788 if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
789 return;
790 }
791
792 sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
793 mask = 1 << slot;
794 enabled = enabled ? mask : 0;
795 if ((sc->sc_pcmcia_on ^ enabled) & mask) {
796 sc->sc_pcmcia_on ^= mask;
797 tctrl_lcd(sc, ~TS102_LCD_PCMCIA_ACTIVE,
798 sc->sc_pcmcia_on ? TS102_LCD_PCMCIA_ACTIVE : 0);
799 }
800 }
801
802 int
tadpole_bell(u_int duration,u_int freq,u_int volume)803 tadpole_bell(u_int duration, u_int freq, u_int volume)
804 {
805 struct tctrl_softc *sc;
806 struct tctrl_req req;
807
808 if (tctrl_cd.cd_ndevs == 0 || tctrl_cd.cd_devs[0] == NULL) {
809 return (0);
810 }
811
812 sc = (struct tctrl_softc *)tctrl_cd.cd_devs[0];
813
814 /* Adjust frequency if necessary (first time or frequence change) */
815 if (freq > 0 && freq <= 0xffff && freq != sc->sc_bellfreq) {
816 req.cmdbuf[0] = TS102_OP_CMD_SET_BELL_FREQ;
817 req.cmdbuf[1] = (freq >> 8) & 0xff;
818 req.cmdbuf[2] = freq & 0xff;
819 req.cmdlen = 3;
820 req.rsplen = 1;
821
822 tctrl_request(sc, &req);
823
824 sc->sc_bellfreq = freq;
825 }
826
827 /* Adjust volume if necessary */
828 if (volume >= 0 && volume <= 100) {
829 volume = (volume * 255) / 100;
830 if (volume != sc->sc_bellvol)
831 tctrl_bell(sc, 0, volume);
832
833 }
834
835 req.cmdbuf[0] = TS102_OP_CMD_RING_BELL;
836 req.cmdbuf[1] = (duration >> 8) & 0xff;
837 req.cmdbuf[2] = duration & 0xff;
838 req.cmdlen = 3;
839 req.rsplen = 1;
840
841 tctrl_request(sc, &req);
842
843 return (1);
844 }
845