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