pm_direct.c revision 1.16 1 /* $NetBSD: pm_direct.c,v 1.16 2001/09/16 16:40:44 wiz 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 splx(s);
1038 return 1;
1039 }
1040 }
1041
1042 /* this command enables the interrupt by operating ADB devices */
1043 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */
1044 pmdata.command = 0x20;
1045 pmdata.num_data = 4;
1046 pmdata.s_buf = pmdata.data;
1047 pmdata.r_buf = pmdata.data;
1048 pmdata.data[0] = 0x00;
1049 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
1050 pmdata.data[2] = 0x00;
1051 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
1052 } else { /* PB 1XX series */
1053 pmdata.command = 0x20;
1054 pmdata.num_data = 3;
1055 pmdata.s_buf = pmdata.data;
1056 pmdata.r_buf = pmdata.data;
1057 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1058 pmdata.data[1] = 0x04;
1059 pmdata.data[2] = 0x00;
1060 }
1061 rval = pmgrop(&pmdata);
1062
1063 splx(s);
1064 return rval;
1065 }
1066
1067
1068 void
1069 pm_adb_get_TALK_result(pmdata)
1070 PMData *pmdata;
1071 {
1072 int i;
1073 struct adbCommand packet;
1074
1075 /* set up data for adb_pass_up */
1076 packet.data[0] = pmdata->num_data-1;
1077 packet.data[1] = pmdata->data[3];
1078 for (i = 0; i <packet.data[0]-1; i++)
1079 packet.data[i+2] = pmdata->data[i+4];
1080
1081 packet.saveBuf = adbBuffer;
1082 packet.compRout = adbCompRout;
1083 packet.compData = adbCompData;
1084 packet.unsol = 0;
1085 packet.ack_only = 0;
1086 adb_polling = 1;
1087 adb_pass_up(&packet);
1088 adb_polling = 0;
1089
1090 adbWaiting = 0;
1091 adbBuffer = (long)0;
1092 adbCompRout = (long)0;
1093 adbCompData = (long)0;
1094 }
1095
1096
1097 void
1098 pm_adb_get_ADB_data(pmdata)
1099 PMData *pmdata;
1100 {
1101 int i;
1102 struct adbCommand packet;
1103
1104 /* set up data for adb_pass_up */
1105 packet.data[0] = pmdata->num_data-1; /* number of raw data */
1106 packet.data[1] = pmdata->data[3]; /* ADB command */
1107 for (i = 0; i <packet.data[0]-1; i++)
1108 packet.data[i+2] = pmdata->data[i+4];
1109 packet.unsol = 1;
1110 packet.ack_only = 0;
1111 adb_pass_up(&packet);
1112 }
1113
1114
1115 void
1116 pm_adb_poll_next_device_pm1(pmdata)
1117 PMData *pmdata;
1118 {
1119 int i;
1120 int ndid;
1121 u_short bendid = 0x1;
1122 int rval;
1123 PMData tmp_pmdata;
1124
1125 /* find another existent ADB device to poll */
1126 for (i = 1; i < 16; i++) {
1127 ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1128 bendid <<= ndid;
1129 if ((pm_existent_ADB_devices & bendid) != 0)
1130 break;
1131 }
1132
1133 /* poll the other device */
1134 tmp_pmdata.command = 0x20;
1135 tmp_pmdata.num_data = 3;
1136 tmp_pmdata.s_buf = tmp_pmdata.data;
1137 tmp_pmdata.r_buf = tmp_pmdata.data;
1138 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1139 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */
1140 tmp_pmdata.data[2] = 0x00;
1141 rval = pmgrop(&tmp_pmdata);
1142 }
1143
1144 void
1145 pm_adb_restart()
1146 {
1147 PMData p;
1148
1149 p.command = PMU_RESET_CPU;
1150 p.num_data = 0;
1151 p.s_buf = p.data;
1152 p.r_buf = p.data;
1153 pmgrop(&p);
1154 }
1155
1156 void
1157 pm_adb_poweroff()
1158 {
1159 PMData p;
1160
1161 p.command = PMU_POWER_OFF;
1162 p.num_data = 4;
1163 p.s_buf = p.data;
1164 p.r_buf = p.data;
1165 strcpy(p.data, "MATT");
1166 pmgrop(&p);
1167 }
1168
1169 void
1170 pm_read_date_time(time)
1171 u_long *time;
1172 {
1173 PMData p;
1174
1175 p.command = PMU_READ_RTC;
1176 p.num_data = 0;
1177 p.s_buf = p.data;
1178 p.r_buf = p.data;
1179 pmgrop(&p);
1180
1181 memcpy(time, p.data, 4);
1182 }
1183
1184 void
1185 pm_set_date_time(time)
1186 u_long time;
1187 {
1188 PMData p;
1189
1190 p.command = PMU_SET_RTC;
1191 p.num_data = 4;
1192 p.s_buf = p.r_buf = p.data;
1193 memcpy(p.data, &time, 4);
1194 pmgrop(&p);
1195 }
1196
1197 int
1198 pm_read_brightness()
1199 {
1200 PMData p;
1201
1202 p.command = PMU_READ_BRIGHTNESS;
1203 p.num_data = 1; /* XXX why 1? */
1204 p.s_buf = p.r_buf = p.data;
1205 p.data[0] = 0;
1206 pmgrop(&p);
1207
1208 return p.data[0];
1209 }
1210
1211 void
1212 pm_set_brightness(val)
1213 int val;
1214 {
1215 PMData p;
1216
1217 val = 0x7f - val / 2;
1218 if (val < 0x08)
1219 val = 0x08;
1220 if (val > 0x78)
1221 val = 0x78;
1222
1223 p.command = PMU_SET_BRIGHTNESS;
1224 p.num_data = 1;
1225 p.s_buf = p.r_buf = p.data;
1226 p.data[0] = val;
1227 pmgrop(&p);
1228 }
1229
1230 void
1231 pm_init_brightness()
1232 {
1233 int val;
1234
1235 val = pm_read_brightness();
1236 pm_set_brightness(val);
1237 }
1238
1239 void
1240 pm_eject_pcmcia(slot)
1241 int slot;
1242 {
1243 PMData p;
1244
1245 if (slot != 0 && slot != 1)
1246 return;
1247
1248 p.command = PMU_EJECT_PCMCIA;
1249 p.num_data = 1;
1250 p.s_buf = p.r_buf = p.data;
1251 p.data[0] = 5 + slot; /* XXX */
1252 pmgrop(&p);
1253 }
1254
1255 int
1256 pm_read_nvram(addr)
1257 int addr;
1258 {
1259 PMData p;
1260
1261 p.command = PMU_READ_NVRAM;
1262 p.num_data = 2;
1263 p.s_buf = p.r_buf = p.data;
1264 p.data[0] = addr >> 8;
1265 p.data[1] = addr;
1266 pmgrop(&p);
1267
1268 return p.data[0];
1269 }
1270
1271 void
1272 pm_write_nvram(addr, val)
1273 int addr, val;
1274 {
1275 PMData p;
1276
1277 p.command = PMU_WRITE_NVRAM;
1278 p.num_data = 3;
1279 p.s_buf = p.r_buf = p.data;
1280 p.data[0] = addr >> 8;
1281 p.data[1] = addr;
1282 p.data[2] = val;
1283 pmgrop(&p);
1284 }
1285