pm_direct.c revision 1.20 1 /* $NetBSD: pm_direct.c,v 1.20 2003/07/15 02:43:30 lukem Exp $ */
2
3 /*
4 * Copyright (C) 1997 Takashi Hamada
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Takashi Hamada
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /* From: pm_direct.c 1.3 03/18/98 Takashi Hamada */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: pm_direct.c,v 1.20 2003/07/15 02:43:30 lukem Exp $");
36
37 #ifdef DEBUG
38 #ifndef ADB_DEBUG
39 #define ADB_DEBUG
40 #endif
41 #endif
42
43 /* #define PM_GRAB_SI 1 */
44
45 #include <sys/param.h>
46 #include <sys/cdefs.h>
47 #include <sys/device.h>
48 #include <sys/systm.h>
49
50 #include <machine/adbsys.h>
51 #include <machine/cpu.h>
52
53 #include <macppc/dev/adbvar.h>
54 #include <macppc/dev/pm_direct.h>
55 #include <macppc/dev/viareg.h>
56
57 extern int adb_polling; /* Are we polling? (Debugger mode) */
58
59 /* hardware dependent values */
60 #define ADBDelay 100 /* XXX */
61 #define HwCfgFlags3 0x20000 /* XXX */
62
63 /* define the types of the Power Manager */
64 #define PM_HW_UNKNOWN 0x00 /* don't know */
65 #define PM_HW_PB1XX 0x01 /* PowerBook 1XX series */
66 #define PM_HW_PB5XX 0x02 /* PowerBook Duo and 5XX series */
67
68 /* useful macros */
69 #define PM_SR() read_via_reg(VIA1, vSR)
70 #define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90)
71 #define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10)
72 #define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90)
73 #if 0
74 #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x04)
75 #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x04)
76 #define PM_IS_ON (0x02 == (read_via_reg(VIA2, vBufB) & 0x02))
77 #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x02))
78 #else
79 #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10)
80 #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10)
81 #define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08))
82 #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08))
83 #endif
84
85 /*
86 * Variables for internal use
87 */
88 int pmHardware = PM_HW_UNKNOWN;
89 u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */
90 u_int pm_LCD_brightness = 0x0;
91 u_int pm_LCD_contrast = 0x0;
92 u_int pm_counter = 0; /* clock count */
93
94 /* these values shows that number of data returned after 'send' cmd is sent */
95 signed char pm_send_cmd_type[] = {
96 -1, -1, -1, -1, -1, -1, -1, -1,
97 -1, -1, -1, -1, -1, -1, -1, -1,
98 0x01, 0x01, -1, -1, -1, -1, -1, -1,
99 0x00, 0x00, -1, -1, -1, -1, -1, 0x00,
100 -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1,
101 0x00, -1, -1, -1, -1, -1, -1, -1,
102 0x04, 0x14, -1, 0x03, -1, -1, -1, -1,
103 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1,
104 0x01, 0x01, -1, -1, -1, -1, -1, -1,
105 0x00, 0x00, -1, -1, 0x01, -1, -1, -1,
106 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01,
107 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1,
108 0x02, -1, -1, -1, -1, -1, -1, -1,
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1,
110 0x01, 0x01, 0x01, -1, -1, -1, -1, -1,
111 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04,
112 0x04, -1, 0x00, -1, -1, -1, -1, -1,
113 0x00, -1, -1, -1, -1, -1, -1, -1,
114 0x01, 0x02, -1, -1, -1, -1, -1, -1,
115 0x00, 0x00, -1, -1, -1, -1, -1, -1,
116 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1,
117 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1,
118 -1, -1, -1, -1, -1, -1, -1, -1,
119 -1, -1, -1, -1, -1, -1, -1, -1,
120 -1, -1, -1, -1, -1, -1, -1, -1,
121 -1, -1, -1, -1, -1, -1, -1, -1,
122 0x00, -1, -1, -1, -1, -1, -1, -1,
123 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1,
124 -1, 0x04, 0x00, -1, -1, -1, -1, -1,
125 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00,
126 -1, -1, -1, -1, -1, -1, -1, -1,
127 -1, -1, -1, -1, -1, -1, -1, -1
128 };
129
130 /* these values shows that number of data returned after 'receive' cmd is sent */
131 signed char pm_receive_cmd_type[] = {
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 -1, -1, -1, -1, -1, -1, -1, -1,
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 0x02, 0x02, -1, -1, -1, -1, -1, 0x00,
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137 -1, -1, -1, -1, -1, -1, -1, -1,
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 0x05, 0x15, -1, 0x02, -1, -1, -1, -1,
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141 0x02, 0x02, -1, -1, -1, -1, -1, -1,
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1,
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147 -1, -1, -1, -1, -1, -1, 0x01, 0x01,
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149 0x06, -1, -1, -1, -1, -1, -1, -1,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151 0x02, 0x02, -1, -1, -1, -1, -1, -1,
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1,
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155 -1, -1, -1, -1, -1, -1, -1, -1,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 -1, -1, -1, -1, -1, -1, -1, -1,
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159 0x02, 0x02, -1, -1, 0x02, -1, -1, -1,
160 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
161 -1, -1, 0x02, -1, -1, -1, -1, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
163 -1, -1, -1, -1, -1, -1, -1, -1,
164 };
165
166
167 /*
168 * Define the private functions
169 */
170
171 /* for debugging */
172 #ifdef ADB_DEBUG
173 void pm_printerr __P((char *, int, int, char *));
174 #endif
175
176 int pm_wait_busy __P((int));
177 int pm_wait_free __P((int));
178
179 /* these functions are for the PB1XX series */
180 int pm_receive_pm1 __P((u_char *));
181 int pm_send_pm1 __P((u_char,int));
182 int pm_pmgrop_pm1 __P((PMData *));
183 void pm_intr_pm1 __P((void));
184
185 /* these functions are for the PB Duo series and the PB 5XX series */
186 int pm_receive_pm2 __P((u_char *));
187 int pm_send_pm2 __P((u_char));
188 int pm_pmgrop_pm2 __P((PMData *));
189 void pm_intr_pm2 __P((void));
190
191 /* these functions are called from adb_direct.c */
192 void pm_setup_adb __P((void));
193 void pm_check_adb_devices __P((int));
194 void pm_intr __P((void));
195 int pm_adb_op __P((u_char *, void *, void *, int));
196
197 /* these functions also use the variables of adb_direct.c */
198 void pm_adb_get_TALK_result __P((PMData *));
199 void pm_adb_get_ADB_data __P((PMData *));
200 void pm_adb_poll_next_device_pm1 __P((PMData *));
201
202
203 /*
204 * These variables are in adb_direct.c.
205 */
206 extern u_char *adbBuffer; /* pointer to user data area */
207 extern void *adbCompRout; /* pointer to the completion routine */
208 extern void *adbCompData; /* pointer to the completion routine data */
209 extern int adbWaiting; /* waiting for return data from the device */
210 extern int adbWaitingCmd; /* ADB command we are waiting for */
211 extern int adbStarting; /* doing ADB reinit, so do "polling" differently */
212
213 #define ADB_MAX_MSG_LENGTH 16
214 #define ADB_MAX_HDR_LENGTH 8
215 struct adbCommand {
216 u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */
217 u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */
218 u_char *saveBuf; /* where to save result */
219 u_char *compRout; /* completion routine pointer */
220 u_char *compData; /* completion routine data pointer */
221 u_int cmd; /* the original command for this data */
222 u_int unsol; /* 1 if packet was unsolicited */
223 u_int ack_only; /* 1 for no special processing */
224 };
225 extern void adb_pass_up __P((struct adbCommand *));
226
227 #if 0
228 /*
229 * Define the external functions
230 */
231 extern int zshard __P((int)); /* from zs.c */
232 #endif
233
234 #ifdef ADB_DEBUG
235 /*
236 * This function dumps contents of the PMData
237 */
238 void
239 pm_printerr(ttl, rval, num, data)
240 char *ttl;
241 int rval;
242 int num;
243 char *data;
244 {
245 int i;
246
247 printf("pm: %s:%04x %02x ", ttl, rval, num);
248 for (i = 0; i < num; i++)
249 printf("%02x ", data[i]);
250 printf("\n");
251 }
252 #endif
253
254
255
256 /*
257 * Check the hardware type of the Power Manager
258 */
259 void
260 pm_setup_adb()
261 {
262 pmHardware = PM_HW_PB5XX; /* XXX */
263 }
264
265
266 /*
267 * Check the existent ADB devices
268 */
269 void
270 pm_check_adb_devices(id)
271 int id;
272 {
273 u_short ed = 0x1;
274
275 ed <<= id;
276 pm_existent_ADB_devices |= ed;
277 }
278
279
280 /*
281 * Wait until PM IC is busy
282 */
283 int
284 pm_wait_busy(delay)
285 int delay;
286 {
287 while (PM_IS_ON) {
288 #ifdef PM_GRAB_SI
289 #if 0
290 zshard(0); /* grab any serial interrupts */
291 #else
292 (void)intr_dispatch(0x70);
293 #endif
294 #endif
295 if ((--delay) < 0)
296 return 1; /* timeout */
297 }
298 return 0;
299 }
300
301
302 /*
303 * Wait until PM IC is free
304 */
305 int
306 pm_wait_free(delay)
307 int delay;
308 {
309 while (PM_IS_OFF) {
310 #ifdef PM_GRAB_SI
311 #if 0
312 zshard(0); /* grab any serial interrupts */
313 #else
314 (void)intr_dispatch(0x70);
315 #endif
316 #endif
317 if ((--delay) < 0)
318 return 0; /* timeout */
319 }
320 return 1;
321 }
322
323
324
325 /*
326 * Functions for the PB1XX series
327 */
328
329 /*
330 * Receive data from PM for the PB1XX series
331 */
332 int
333 pm_receive_pm1(data)
334 u_char *data;
335 {
336 #if 0
337 int rval = 0xffffcd34;
338
339 via_reg(VIA2, vDirA) = 0x00;
340
341 switch (1) {
342 default:
343 if (pm_wait_busy(0x40) != 0)
344 break; /* timeout */
345
346 PM_SET_STATE_ACKOFF();
347 *data = via_reg(VIA2, 0x200);
348
349 rval = 0xffffcd33;
350 if (pm_wait_free(0x40) == 0)
351 break; /* timeout */
352
353 rval = 0x00;
354 break;
355 }
356
357 PM_SET_STATE_ACKON();
358 via_reg(VIA2, vDirA) = 0x00;
359
360 return rval;
361 #else
362 panic("pm_receive_pm1");
363 #endif
364 }
365
366
367
368 /*
369 * Send data to PM for the PB1XX series
370 */
371 int
372 pm_send_pm1(data, delay)
373 u_char data;
374 int delay;
375 {
376 #if 0
377 int rval;
378
379 via_reg(VIA2, vDirA) = 0xff;
380 via_reg(VIA2, 0x200) = data;
381
382 PM_SET_STATE_ACKOFF();
383 if (pm_wait_busy(0x400) != 0) {
384 PM_SET_STATE_ACKON();
385 via_reg(VIA2, vDirA) = 0x00;
386
387 return 0xffffcd36;
388 }
389
390 rval = 0x0;
391 PM_SET_STATE_ACKON();
392 if (pm_wait_free(0x40) == 0)
393 rval = 0xffffcd35;
394
395 PM_SET_STATE_ACKON();
396 via_reg(VIA2, vDirA) = 0x00;
397
398 return rval;
399 #else
400 panic("pm_send_pm1");
401 #endif
402 }
403
404
405 /*
406 * My PMgrOp routine for the PB1XX series
407 */
408 int
409 pm_pmgrop_pm1(pmdata)
410 PMData *pmdata;
411 {
412 #if 0
413 int i;
414 int s = 0x81815963;
415 u_char via1_vIER, via1_vDirA;
416 int rval = 0;
417 int num_pm_data = 0;
418 u_char pm_cmd;
419 u_char pm_data;
420 u_char *pm_buf;
421
422 /* disable all inetrrupts but PM */
423 via1_vIER = via_reg(VIA1, vIER);
424 PM_VIA_INTR_DISABLE();
425
426 via1_vDirA = via_reg(VIA1, vDirA);
427
428 switch (pmdata->command) {
429 default:
430 for (i = 0; i < 7; i++) {
431 via_reg(VIA2, vDirA) = 0x00;
432
433 /* wait until PM is free */
434 if (pm_wait_free(ADBDelay) == 0) { /* timeout */
435 via_reg(VIA2, vDirA) = 0x00;
436 /* restore formar value */
437 via_reg(VIA1, vDirA) = via1_vDirA;
438 via_reg(VIA1, vIER) = via1_vIER;
439 return 0xffffcd38;
440 }
441
442 switch (mac68k_machine.machineid) {
443 case MACH_MACPB160:
444 case MACH_MACPB165:
445 case MACH_MACPB165C:
446 case MACH_MACPB180:
447 case MACH_MACPB180C:
448 {
449 int delay = ADBDelay * 16;
450
451 via_reg(VIA2, vDirA) = 0x00;
452 while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
453 delay--;
454
455 if (delay < 0) { /* timeout */
456 via_reg(VIA2, vDirA) = 0x00;
457 /* restore formar value */
458 via_reg(VIA1, vIER) = via1_vIER;
459 return 0xffffcd38;
460 }
461 }
462 } /* end switch */
463
464 s = splhigh();
465
466 via1_vDirA = via_reg(VIA1, vDirA);
467 via_reg(VIA1, vDirA) &= 0x7f;
468
469 pm_cmd = (u_char)(pmdata->command & 0xff);
470 if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
471 break; /* send command succeeded */
472
473 via_reg(VIA1, vDirA) = via1_vDirA;
474 splx(s);
475 } /* end for */
476
477 /* failed to send a command */
478 if (i == 7) {
479 via_reg(VIA2, vDirA) = 0x00;
480 /* restore formar value */
481 via_reg(VIA1, vDirA) = via1_vDirA;
482 via_reg(VIA1, vIER) = via1_vIER;
483 if (s != 0x81815963)
484 splx(s);
485 return 0xffffcd38;
486 }
487
488 /* send # of PM data */
489 num_pm_data = pmdata->num_data;
490 if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
491 break; /* timeout */
492
493 /* send PM data */
494 pm_buf = (u_char *)pmdata->s_buf;
495 for (i = 0; i < num_pm_data; i++)
496 if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
497 break; /* timeout */
498 if ((i != num_pm_data) && (num_pm_data != 0))
499 break; /* timeout */
500
501 /* Will PM IC return data? */
502 if ((pm_cmd & 0x08) == 0) {
503 rval = 0;
504 break; /* no returned data */
505 }
506
507 rval = 0xffffcd37;
508 if (pm_wait_busy(ADBDelay) != 0)
509 break; /* timeout */
510
511 /* receive PM command */
512 if ((rval = pm_receive_pm1(&pm_data)) != 0)
513 break;
514
515 pmdata->command = pm_data;
516
517 /* receive number of PM data */
518 if ((rval = pm_receive_pm1(&pm_data)) != 0)
519 break; /* timeout */
520 num_pm_data = pm_data;
521 pmdata->num_data = num_pm_data;
522
523 /* receive PM data */
524 pm_buf = (u_char *)pmdata->r_buf;
525 for (i = 0; i < num_pm_data; i++) {
526 if ((rval = pm_receive_pm1(&pm_data)) != 0)
527 break; /* timeout */
528 pm_buf[i] = pm_data;
529 }
530
531 rval = 0;
532 }
533
534 via_reg(VIA2, vDirA) = 0x00;
535
536 /* restore formar value */
537 via_reg(VIA1, vDirA) = via1_vDirA;
538 via_reg(VIA1, vIER) = via1_vIER;
539 if (s != 0x81815963)
540 splx(s);
541
542 return rval;
543 #else
544 panic("pm_pmgrop_pm1");
545 #endif
546 }
547
548
549 /*
550 * My PM interrupt routine for PB1XX series
551 */
552 void
553 pm_intr_pm1()
554 {
555 #if 0
556 int s;
557 int rval;
558 PMData pmdata;
559
560 s = splhigh();
561
562 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
563
564 /* ask PM what happend */
565 pmdata.command = 0x78;
566 pmdata.num_data = 0;
567 pmdata.data[0] = pmdata.data[1] = 0;
568 pmdata.s_buf = &pmdata.data[2];
569 pmdata.r_buf = &pmdata.data[2];
570 rval = pm_pmgrop_pm1(&pmdata);
571 if (rval != 0) {
572 #ifdef ADB_DEBUG
573 if (adb_debug)
574 printf("pm: PM is not ready. error code=%08x\n", rval);
575 #endif
576 splx(s);
577 }
578
579 if ((pmdata.data[2] & 0x10) == 0x10) {
580 if ((pmdata.data[2] & 0x0f) == 0) {
581 /* ADB data that were requested by TALK command */
582 pm_adb_get_TALK_result(&pmdata);
583 } else if ((pmdata.data[2] & 0x08) == 0x8) {
584 /* PM is requesting to poll */
585 pm_adb_poll_next_device_pm1(&pmdata);
586 } else if ((pmdata.data[2] & 0x04) == 0x4) {
587 /* ADB device event */
588 pm_adb_get_ADB_data(&pmdata);
589 }
590 } else {
591 #ifdef ADB_DEBUG
592 if (adb_debug)
593 pm_printerr("driver does not supported this event.",
594 rval, pmdata.num_data, pmdata.data);
595 #endif
596 }
597
598 splx(s);
599 #else
600 panic("pm_intr_pm1");
601 #endif
602 }
603
604
605
606 /*
607 * Functions for the PB Duo series and the PB 5XX series
608 */
609
610 /*
611 * Receive data from PM for the PB Duo series and the PB 5XX series
612 */
613 int
614 pm_receive_pm2(data)
615 u_char *data;
616 {
617 int i;
618 int rval;
619
620 rval = 0xffffcd34;
621
622 switch (1) {
623 default:
624 /* set VIA SR to input mode */
625 via_reg_or(VIA1, vACR, 0x0c);
626 via_reg_and(VIA1, vACR, ~0x10);
627 i = PM_SR();
628
629 PM_SET_STATE_ACKOFF();
630 if (pm_wait_busy((int)ADBDelay*32) != 0)
631 break; /* timeout */
632
633 PM_SET_STATE_ACKON();
634 rval = 0xffffcd33;
635 if (pm_wait_free((int)ADBDelay*32) == 0)
636 break; /* timeout */
637
638 *data = PM_SR();
639 rval = 0;
640
641 break;
642 }
643
644 PM_SET_STATE_ACKON();
645 via_reg_or(VIA1, vACR, 0x1c);
646
647 return rval;
648 }
649
650
651
652 /*
653 * Send data to PM for the PB Duo series and the PB 5XX series
654 */
655 int
656 pm_send_pm2(data)
657 u_char data;
658 {
659 int rval;
660
661 via_reg_or(VIA1, vACR, 0x1c);
662 write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */
663
664 PM_SET_STATE_ACKOFF();
665 rval = 0xffffcd36;
666 if (pm_wait_busy((int)ADBDelay*32) != 0) {
667 PM_SET_STATE_ACKON();
668
669 via_reg_or(VIA1, vACR, 0x1c);
670
671 return rval;
672 }
673
674 PM_SET_STATE_ACKON();
675 rval = 0xffffcd35;
676 if (pm_wait_free((int)ADBDelay*32) != 0)
677 rval = 0;
678
679 PM_SET_STATE_ACKON();
680 via_reg_or(VIA1, vACR, 0x1c);
681
682 return rval;
683 }
684
685
686
687 /*
688 * My PMgrOp routine for the PB Duo series and the PB 5XX series
689 */
690 int
691 pm_pmgrop_pm2(pmdata)
692 PMData *pmdata;
693 {
694 int i;
695 int s;
696 u_char via1_vIER;
697 int rval = 0;
698 int num_pm_data = 0;
699 u_char pm_cmd;
700 short pm_num_rx_data;
701 u_char pm_data;
702 u_char *pm_buf;
703
704 s = splhigh();
705
706 /* disable all inetrrupts but PM */
707 via1_vIER = 0x10;
708 via1_vIER &= read_via_reg(VIA1, vIER);
709 write_via_reg(VIA1, vIER, via1_vIER);
710 if (via1_vIER != 0x0)
711 via1_vIER |= 0x80;
712
713 switch (pmdata->command) {
714 default:
715 /* wait until PM is free */
716 pm_cmd = (u_char)(pmdata->command & 0xff);
717 rval = 0xcd38;
718 if (pm_wait_free(ADBDelay * 4) == 0)
719 break; /* timeout */
720
721 if (HwCfgFlags3 & 0x00200000) {
722 /* PB 160, PB 165(c), PB 180(c)? */
723 int delay = ADBDelay * 16;
724
725 write_via_reg(VIA2, vDirA, 0x00);
726 while ((read_via_reg(VIA2, 0x200) == 0x07) &&
727 (delay >= 0))
728 delay--;
729
730 if (delay < 0) {
731 rval = 0xffffcd38;
732 break; /* timeout */
733 }
734 }
735
736 /* send PM command */
737 if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
738 break; /* timeout */
739
740 /* send number of PM data */
741 num_pm_data = pmdata->num_data;
742 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
743 if (pm_send_cmd_type[pm_cmd] < 0) {
744 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
745 break; /* timeout */
746 pmdata->command = 0;
747 }
748 } else { /* PB 1XX series ? */
749 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
750 break; /* timeout */
751 }
752 /* send PM data */
753 pm_buf = (u_char *)pmdata->s_buf;
754 for (i = 0 ; i < num_pm_data; i++)
755 if ((rval = pm_send_pm2(pm_buf[i])) != 0)
756 break; /* timeout */
757 if (i != num_pm_data)
758 break; /* timeout */
759
760
761 /* check if PM will send me data */
762 pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
763 pmdata->num_data = pm_num_rx_data;
764 if (pm_num_rx_data == 0) {
765 rval = 0;
766 break; /* no return data */
767 }
768
769 /* receive PM command */
770 pm_data = pmdata->command;
771 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
772 pm_num_rx_data--;
773 if (pm_num_rx_data == 0)
774 if ((rval = pm_receive_pm2(&pm_data)) != 0) {
775 rval = 0xffffcd37;
776 break;
777 }
778 pmdata->command = pm_data;
779 } else { /* PB 1XX series ? */
780 if ((rval = pm_receive_pm2(&pm_data)) != 0) {
781 rval = 0xffffcd37;
782 break;
783 }
784 pmdata->command = pm_data;
785 }
786
787 /* receive number of PM data */
788 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
789 if (pm_num_rx_data < 0) {
790 if ((rval = pm_receive_pm2(&pm_data)) != 0)
791 break; /* timeout */
792 num_pm_data = pm_data;
793 } else
794 num_pm_data = pm_num_rx_data;
795 pmdata->num_data = num_pm_data;
796 } else { /* PB 1XX serias ? */
797 if ((rval = pm_receive_pm2(&pm_data)) != 0)
798 break; /* timeout */
799 num_pm_data = pm_data;
800 pmdata->num_data = num_pm_data;
801 }
802
803 /* receive PM data */
804 pm_buf = (u_char *)pmdata->r_buf;
805 for (i = 0; i < num_pm_data; i++) {
806 if ((rval = pm_receive_pm2(&pm_data)) != 0)
807 break; /* timeout */
808 pm_buf[i] = pm_data;
809 }
810
811 rval = 0;
812 }
813
814 /* restore former value */
815 write_via_reg(VIA1, vIER, via1_vIER);
816 splx(s);
817
818 return rval;
819 }
820
821
822 /*
823 * My PM interrupt routine for the PB Duo series and the PB 5XX series
824 */
825 void
826 pm_intr_pm2()
827 {
828 int s;
829 int rval;
830 PMData pmdata;
831
832 s = splhigh();
833
834 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
835 /* ask PM what happend */
836 pmdata.command = 0x78;
837 pmdata.num_data = 0;
838 pmdata.s_buf = &pmdata.data[2];
839 pmdata.r_buf = &pmdata.data[2];
840 rval = pm_pmgrop_pm2(&pmdata);
841 if (rval != 0) {
842 #ifdef ADB_DEBUG
843 if (adb_debug)
844 printf("pm: PM is not ready. error code: %08x\n", rval);
845 #endif
846 splx(s);
847 }
848
849 switch ((u_int)(pmdata.data[2] & 0xff)) {
850 case 0x00: /* 1 sec interrupt? */
851 break;
852 case 0x80: /* 1 sec interrupt? */
853 pm_counter++;
854 break;
855 case 0x08: /* Brightness/Contrast button on LCD panel */
856 /* get brightness and contrast of the LCD */
857 pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
858 pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
859 /*
860 pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
861 pmdata.command = 0x33;
862 pmdata.num_data = 1;
863 pmdata.s_buf = pmdata.data;
864 pmdata.r_buf = pmdata.data;
865 pmdata.data[0] = pm_LCD_contrast;
866 rval = pm_pmgrop_pm2(&pmdata);
867 pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
868 */
869 /* this is an experimental code */
870 pmdata.command = 0x41;
871 pmdata.num_data = 1;
872 pmdata.s_buf = pmdata.data;
873 pmdata.r_buf = pmdata.data;
874 pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
875 if (pm_LCD_brightness < 0x08)
876 pm_LCD_brightness = 0x08;
877 if (pm_LCD_brightness > 0x78)
878 pm_LCD_brightness = 0x78;
879 pmdata.data[0] = pm_LCD_brightness;
880 rval = pm_pmgrop_pm2(&pmdata);
881 break;
882 case 0x10: /* ADB data that were requested by TALK command */
883 case 0x14:
884 pm_adb_get_TALK_result(&pmdata);
885 break;
886 case 0x16: /* ADB device event */
887 case 0x18:
888 case 0x1e:
889 pm_adb_get_ADB_data(&pmdata);
890 break;
891 default:
892 #ifdef ADB_DEBUG
893 if (adb_debug)
894 pm_printerr("driver does not supported this event.",
895 pmdata.data[2], pmdata.num_data,
896 pmdata.data);
897 #endif
898 break;
899 }
900
901 splx(s);
902 }
903
904
905 /*
906 * My PMgrOp routine
907 */
908 int
909 pmgrop(pmdata)
910 PMData *pmdata;
911 {
912 switch (pmHardware) {
913 case PM_HW_PB1XX:
914 return (pm_pmgrop_pm1(pmdata));
915 break;
916 case PM_HW_PB5XX:
917 return (pm_pmgrop_pm2(pmdata));
918 break;
919 default:
920 /* return (pmgrop_mrg(pmdata)); */
921 return 1;
922 }
923 }
924
925
926 /*
927 * My PM interrupt routine
928 */
929 void
930 pm_intr()
931 {
932 switch (pmHardware) {
933 case PM_HW_PB1XX:
934 pm_intr_pm1();
935 break;
936 case PM_HW_PB5XX:
937 pm_intr_pm2();
938 break;
939 default:
940 break;
941 }
942 }
943
944
945
946 /*
947 * Synchronous ADBOp routine for the Power Manager
948 */
949 int
950 pm_adb_op(buffer, compRout, data, command)
951 u_char *buffer;
952 void *compRout;
953 void *data;
954 int command;
955 {
956 int i;
957 int s;
958 int rval;
959 int timo;
960 PMData pmdata;
961 struct adbCommand packet;
962
963 if (adbWaiting == 1)
964 return 1;
965
966 s = splhigh();
967 write_via_reg(VIA1, vIER, 0x10);
968
969 adbBuffer = buffer;
970 adbCompRout = compRout;
971 adbCompData = data;
972
973 pmdata.command = 0x20;
974 pmdata.s_buf = pmdata.data;
975 pmdata.r_buf = pmdata.data;
976
977 /* if the command is LISTEN, add number of ADB data to number of PM data */
978 if ((command & 0xc) == 0x8) {
979 if (buffer != (u_char *)0)
980 pmdata.num_data = buffer[0] + 3;
981 } else {
982 pmdata.num_data = 3;
983 }
984
985 pmdata.data[0] = (u_char)(command & 0xff);
986 pmdata.data[1] = 0;
987 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */
988 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
989 pmdata.data[2] = buffer[0]; /* number of data */
990 for (i = 0; i < buffer[0]; i++)
991 pmdata.data[3 + i] = buffer[1 + i];
992 } else
993 pmdata.data[2] = 0;
994 } else
995 pmdata.data[2] = 0;
996
997 if ((command & 0xc) != 0xc) { /* if the command is not TALK */
998 /* set up stuff for adb_pass_up */
999 packet.data[0] = 1 + pmdata.data[2];
1000 packet.data[1] = command;
1001 for (i = 0; i < pmdata.data[2]; i++)
1002 packet.data[i+2] = pmdata.data[i+3];
1003 packet.saveBuf = adbBuffer;
1004 packet.compRout = adbCompRout;
1005 packet.compData = adbCompData;
1006 packet.cmd = command;
1007 packet.unsol = 0;
1008 packet.ack_only = 1;
1009 adb_polling = 1;
1010 adb_pass_up(&packet);
1011 adb_polling = 0;
1012 }
1013
1014 rval = pmgrop(&pmdata);
1015 if (rval != 0) {
1016 splx(s);
1017 return 1;
1018 }
1019
1020 delay(10000);
1021
1022 adbWaiting = 1;
1023 adbWaitingCmd = command;
1024
1025 PM_VIA_INTR_ENABLE();
1026
1027 /* wait until the PM interrupt has occurred */
1028 timo = 0x80000;
1029 while (adbWaiting == 1) {
1030 if (read_via_reg(VIA1, vIFR) & 0x14)
1031 pm_intr();
1032 #ifdef PM_GRAB_SI
1033 #if 0
1034 zshard(0); /* grab any serial interrupts */
1035 #else
1036 (void)intr_dispatch(0x70);
1037 #endif
1038 #endif
1039 if ((--timo) < 0) {
1040 /* Try to take an interrupt anyway, just in case.
1041 * This has been observed to happen on my ibook
1042 * when i press a key after boot and before adb
1043 * is attached; For example, when booting with -d.
1044 */
1045 pm_intr();
1046 if (adbWaiting) {
1047 printf("pm_adb_op: timeout. command = 0x%x\n",command);
1048 splx(s);
1049 return 1;
1050 }
1051 #ifdef ADB_DEBUG
1052 else {
1053 printf("pm_adb_op: missed interrupt. cmd=0x%x\n",command);
1054 }
1055 #endif
1056 }
1057 }
1058
1059 /* this command enables the interrupt by operating ADB devices */
1060 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */
1061 pmdata.command = 0x20;
1062 pmdata.num_data = 4;
1063 pmdata.s_buf = pmdata.data;
1064 pmdata.r_buf = pmdata.data;
1065 pmdata.data[0] = 0x00;
1066 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
1067 pmdata.data[2] = 0x00;
1068 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
1069 } else { /* PB 1XX series */
1070 pmdata.command = 0x20;
1071 pmdata.num_data = 3;
1072 pmdata.s_buf = pmdata.data;
1073 pmdata.r_buf = pmdata.data;
1074 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1075 pmdata.data[1] = 0x04;
1076 pmdata.data[2] = 0x00;
1077 }
1078 rval = pmgrop(&pmdata);
1079
1080 splx(s);
1081 return rval;
1082 }
1083
1084
1085 void
1086 pm_adb_get_TALK_result(pmdata)
1087 PMData *pmdata;
1088 {
1089 int i;
1090 struct adbCommand packet;
1091
1092 /* set up data for adb_pass_up */
1093 packet.data[0] = pmdata->num_data-1;
1094 packet.data[1] = pmdata->data[3];
1095 for (i = 0; i <packet.data[0]-1; i++)
1096 packet.data[i+2] = pmdata->data[i+4];
1097
1098 packet.saveBuf = adbBuffer;
1099 packet.compRout = adbCompRout;
1100 packet.compData = adbCompData;
1101 packet.unsol = 0;
1102 packet.ack_only = 0;
1103 adb_polling = 1;
1104 adb_pass_up(&packet);
1105 adb_polling = 0;
1106
1107 adbWaiting = 0;
1108 adbBuffer = (long)0;
1109 adbCompRout = (long)0;
1110 adbCompData = (long)0;
1111 }
1112
1113
1114 void
1115 pm_adb_get_ADB_data(pmdata)
1116 PMData *pmdata;
1117 {
1118 int i;
1119 struct adbCommand packet;
1120
1121 /* set up data for adb_pass_up */
1122 packet.data[0] = pmdata->num_data-1; /* number of raw data */
1123 packet.data[1] = pmdata->data[3]; /* ADB command */
1124 for (i = 0; i <packet.data[0]-1; i++)
1125 packet.data[i+2] = pmdata->data[i+4];
1126 packet.unsol = 1;
1127 packet.ack_only = 0;
1128 adb_pass_up(&packet);
1129 }
1130
1131
1132 void
1133 pm_adb_poll_next_device_pm1(pmdata)
1134 PMData *pmdata;
1135 {
1136 int i;
1137 int ndid;
1138 u_short bendid = 0x1;
1139 int rval;
1140 PMData tmp_pmdata;
1141
1142 /* find another existent ADB device to poll */
1143 for (i = 1; i < 16; i++) {
1144 ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1145 bendid <<= ndid;
1146 if ((pm_existent_ADB_devices & bendid) != 0)
1147 break;
1148 }
1149
1150 /* poll the other device */
1151 tmp_pmdata.command = 0x20;
1152 tmp_pmdata.num_data = 3;
1153 tmp_pmdata.s_buf = tmp_pmdata.data;
1154 tmp_pmdata.r_buf = tmp_pmdata.data;
1155 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1156 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */
1157 tmp_pmdata.data[2] = 0x00;
1158 rval = pmgrop(&tmp_pmdata);
1159 }
1160
1161 void
1162 pm_adb_restart()
1163 {
1164 PMData p;
1165
1166 p.command = PMU_RESET_CPU;
1167 p.num_data = 0;
1168 p.s_buf = p.data;
1169 p.r_buf = p.data;
1170 pmgrop(&p);
1171 }
1172
1173 void
1174 pm_adb_poweroff()
1175 {
1176 PMData p;
1177
1178 p.command = PMU_POWER_OFF;
1179 p.num_data = 4;
1180 p.s_buf = p.data;
1181 p.r_buf = p.data;
1182 strcpy(p.data, "MATT");
1183 pmgrop(&p);
1184 }
1185
1186 void
1187 pm_read_date_time(time)
1188 u_long *time;
1189 {
1190 PMData p;
1191
1192 p.command = PMU_READ_RTC;
1193 p.num_data = 0;
1194 p.s_buf = p.data;
1195 p.r_buf = p.data;
1196 pmgrop(&p);
1197
1198 memcpy(time, p.data, 4);
1199 }
1200
1201 void
1202 pm_set_date_time(time)
1203 u_long time;
1204 {
1205 PMData p;
1206
1207 p.command = PMU_SET_RTC;
1208 p.num_data = 4;
1209 p.s_buf = p.r_buf = p.data;
1210 memcpy(p.data, &time, 4);
1211 pmgrop(&p);
1212 }
1213
1214 int
1215 pm_read_brightness()
1216 {
1217 PMData p;
1218
1219 p.command = PMU_READ_BRIGHTNESS;
1220 p.num_data = 1; /* XXX why 1? */
1221 p.s_buf = p.r_buf = p.data;
1222 p.data[0] = 0;
1223 pmgrop(&p);
1224
1225 return p.data[0];
1226 }
1227
1228 void
1229 pm_set_brightness(val)
1230 int val;
1231 {
1232 PMData p;
1233
1234 val = 0x7f - val / 2;
1235 if (val < 0x08)
1236 val = 0x08;
1237 if (val > 0x78)
1238 val = 0x78;
1239
1240 p.command = PMU_SET_BRIGHTNESS;
1241 p.num_data = 1;
1242 p.s_buf = p.r_buf = p.data;
1243 p.data[0] = val;
1244 pmgrop(&p);
1245 }
1246
1247 void
1248 pm_init_brightness()
1249 {
1250 int val;
1251
1252 val = pm_read_brightness();
1253 pm_set_brightness(val);
1254 }
1255
1256 void
1257 pm_eject_pcmcia(slot)
1258 int slot;
1259 {
1260 PMData p;
1261
1262 if (slot != 0 && slot != 1)
1263 return;
1264
1265 p.command = PMU_EJECT_PCMCIA;
1266 p.num_data = 1;
1267 p.s_buf = p.r_buf = p.data;
1268 p.data[0] = 5 + slot; /* XXX */
1269 pmgrop(&p);
1270 }
1271
1272 /*
1273 * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation
1274 * for a clear description of the PMU results.
1275 */
1276 int
1277 pm_battery_info(int battery, struct pmu_battery_info *info)
1278 {
1279 PMData p;
1280
1281 p.command = PMU_SMART_BATTERY_STATE;
1282 p.num_data = 1;
1283 p.s_buf = p.r_buf = p.data;
1284 p.data[0] = battery + 1;
1285 pmgrop(&p);
1286
1287 info->flags = p.data[1];
1288
1289 switch (p.data[0]) {
1290 case 3:
1291 case 4:
1292 info->cur_charge = p.data[2];
1293 info->max_charge = p.data[3];
1294 info->draw = *((signed char *)&p.data[4]);
1295 info->voltage = p.data[5];
1296 break;
1297 case 5:
1298 info->cur_charge = ((p.data[2] << 8) | (p.data[3]));
1299 info->max_charge = ((p.data[4] << 8) | (p.data[5]));
1300 info->draw = *((signed short *)&p.data[6]);
1301 info->voltage = ((p.data[8] << 8) | (p.data[7]));
1302 break;
1303 default:
1304 /* XXX - Error condition */
1305 info->cur_charge = 0;
1306 info->max_charge = 0;
1307 info->draw = 0;
1308 info->voltage = 0;
1309 break;
1310 }
1311
1312 return 1;
1313 }
1314
1315 int
1316 pm_read_nvram(addr)
1317 int addr;
1318 {
1319 PMData p;
1320
1321 p.command = PMU_READ_NVRAM;
1322 p.num_data = 2;
1323 p.s_buf = p.r_buf = p.data;
1324 p.data[0] = addr >> 8;
1325 p.data[1] = addr;
1326 pmgrop(&p);
1327
1328 return p.data[0];
1329 }
1330
1331 void
1332 pm_write_nvram(addr, val)
1333 int addr, val;
1334 {
1335 PMData p;
1336
1337 p.command = PMU_WRITE_NVRAM;
1338 p.num_data = 3;
1339 p.s_buf = p.r_buf = p.data;
1340 p.data[0] = addr >> 8;
1341 p.data[1] = addr;
1342 p.data[2] = val;
1343 pmgrop(&p);
1344 }
1345