pm_direct.c revision 1.9 1 /* $NetBSD: pm_direct.c,v 1.9 2000/06/08 22:10:46 tsubai 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 /* this function is MRG-Based (for testing) */
189 int pm_pmgrop_mrg __P((PMData *));
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 #if 0
906 /*
907 * MRG-based PMgrOp routine
908 */
909 int
910 pm_pmgrop_mrg(pmdata)
911 PMData *pmdata;
912 {
913 u_int32_t rval=0;
914
915 asm("
916 movl %1, a0
917 .word 0xa085
918 movl d0, %0"
919 : "=g" (rval)
920 : "g" (pmdata)
921 : "a0", "d0" );
922
923 return rval;
924 }
925 #endif
926
927
928 /*
929 * My PMgrOp routine
930 */
931 int
932 pmgrop(pmdata)
933 PMData *pmdata;
934 {
935 switch (pmHardware) {
936 case PM_HW_PB1XX:
937 return (pm_pmgrop_pm1(pmdata));
938 break;
939 case PM_HW_PB5XX:
940 return (pm_pmgrop_pm2(pmdata));
941 break;
942 default:
943 /* return (pmgrop_mrg(pmdata)); */
944 return 1;
945 }
946 }
947
948
949 /*
950 * My PM interrupt routine
951 */
952 void
953 pm_intr()
954 {
955 switch (pmHardware) {
956 case PM_HW_PB1XX:
957 pm_intr_pm1();
958 break;
959 case PM_HW_PB5XX:
960 pm_intr_pm2();
961 break;
962 default:
963 break;
964 }
965 }
966
967
968
969 /*
970 * Synchronous ADBOp routine for the Power Manager
971 */
972 int
973 pm_adb_op(buffer, compRout, data, command)
974 u_char *buffer;
975 void *compRout;
976 void *data;
977 int command;
978 {
979 int i;
980 int s;
981 int rval;
982 int delay;
983 PMData pmdata;
984 struct adbCommand packet;
985
986 if (adbWaiting == 1)
987 return 1;
988
989 s = splhigh();
990 write_via_reg(VIA1, vIER, 0x10);
991
992 adbBuffer = buffer;
993 adbCompRout = compRout;
994 adbCompData = data;
995
996 pmdata.command = 0x20;
997 pmdata.s_buf = pmdata.data;
998 pmdata.r_buf = pmdata.data;
999
1000 /* if the command is LISTEN, add number of ADB data to number of PM data */
1001 if ((command & 0xc) == 0x8) {
1002 if (buffer != (u_char *)0)
1003 pmdata.num_data = buffer[0] + 3;
1004 } else {
1005 pmdata.num_data = 3;
1006 }
1007
1008 pmdata.data[0] = (u_char)(command & 0xff);
1009 pmdata.data[1] = 0;
1010 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */
1011 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1012 pmdata.data[2] = buffer[0]; /* number of data */
1013 for (i = 0; i < buffer[0]; i++)
1014 pmdata.data[3 + i] = buffer[1 + i];
1015 } else
1016 pmdata.data[2] = 0;
1017 } else
1018 pmdata.data[2] = 0;
1019
1020 if ((command & 0xc) != 0xc) { /* if the command is not TALK */
1021 /* set up stuff for adb_pass_up */
1022 packet.data[0] = 1 + pmdata.data[2];
1023 packet.data[1] = command;
1024 for (i = 0; i < pmdata.data[2]; i++)
1025 packet.data[i+2] = pmdata.data[i+3];
1026 packet.saveBuf = adbBuffer;
1027 packet.compRout = adbCompRout;
1028 packet.compData = adbCompData;
1029 packet.cmd = command;
1030 packet.unsol = 0;
1031 packet.ack_only = 1;
1032 adb_polling = 1;
1033 adb_pass_up(&packet);
1034 adb_polling = 0;
1035 }
1036
1037 rval = pmgrop(&pmdata);
1038 if (rval != 0) {
1039 splx(s);
1040 return 1;
1041 }
1042
1043 adbWaiting = 1;
1044 adbWaitingCmd = command;
1045
1046 PM_VIA_INTR_ENABLE();
1047
1048 /* wait until the PM interrupt is occured */
1049 delay = 0x80000;
1050 while (adbWaiting == 1) {
1051 if (read_via_reg(VIA1, vIFR) & 0x14)
1052 pm_intr();
1053 #ifdef PM_GRAB_SI
1054 #if 0
1055 zshard(0); /* grab any serial interrupts */
1056 #else
1057 (void)intr_dispatch(0x70);
1058 #endif
1059 #endif
1060 if ((--delay) < 0) {
1061 splx(s);
1062 return 1;
1063 }
1064 }
1065
1066 /* this command enables the interrupt by operating ADB devices */
1067 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */
1068 pmdata.command = 0x20;
1069 pmdata.num_data = 4;
1070 pmdata.s_buf = pmdata.data;
1071 pmdata.r_buf = pmdata.data;
1072 pmdata.data[0] = 0x00;
1073 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
1074 pmdata.data[2] = 0x00;
1075 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
1076 } else { /* PB 1XX series */
1077 pmdata.command = 0x20;
1078 pmdata.num_data = 3;
1079 pmdata.s_buf = pmdata.data;
1080 pmdata.r_buf = pmdata.data;
1081 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1082 pmdata.data[1] = 0x04;
1083 pmdata.data[2] = 0x00;
1084 }
1085 rval = pmgrop(&pmdata);
1086
1087 splx(s);
1088 return rval;
1089 }
1090
1091
1092 void
1093 pm_adb_get_TALK_result(pmdata)
1094 PMData *pmdata;
1095 {
1096 int i;
1097 struct adbCommand packet;
1098
1099 /* set up data for adb_pass_up */
1100 packet.data[0] = pmdata->num_data-1;
1101 packet.data[1] = pmdata->data[3];
1102 for (i = 0; i <packet.data[0]-1; i++)
1103 packet.data[i+2] = pmdata->data[i+4];
1104
1105 packet.saveBuf = adbBuffer;
1106 packet.compRout = adbCompRout;
1107 packet.compData = adbCompData;
1108 packet.unsol = 0;
1109 packet.ack_only = 0;
1110 adb_polling = 1;
1111 adb_pass_up(&packet);
1112 adb_polling = 0;
1113
1114 adbWaiting = 0;
1115 adbBuffer = (long)0;
1116 adbCompRout = (long)0;
1117 adbCompData = (long)0;
1118 }
1119
1120
1121 void
1122 pm_adb_get_ADB_data(pmdata)
1123 PMData *pmdata;
1124 {
1125 int i;
1126 struct adbCommand packet;
1127
1128 /* set up data for adb_pass_up */
1129 packet.data[0] = pmdata->num_data-1; /* number of raw data */
1130 packet.data[1] = pmdata->data[3]; /* ADB command */
1131 for (i = 0; i <packet.data[0]-1; i++)
1132 packet.data[i+2] = pmdata->data[i+4];
1133 packet.unsol = 1;
1134 packet.ack_only = 0;
1135 adb_pass_up(&packet);
1136 }
1137
1138
1139 void
1140 pm_adb_poll_next_device_pm1(pmdata)
1141 PMData *pmdata;
1142 {
1143 int i;
1144 int ndid;
1145 u_short bendid = 0x1;
1146 int rval;
1147 PMData tmp_pmdata;
1148
1149 /* find another existent ADB device to poll */
1150 for (i = 1; i < 16; i++) {
1151 ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1152 bendid <<= ndid;
1153 if ((pm_existent_ADB_devices & bendid) != 0)
1154 break;
1155 }
1156
1157 /* poll the other device */
1158 tmp_pmdata.command = 0x20;
1159 tmp_pmdata.num_data = 3;
1160 tmp_pmdata.s_buf = tmp_pmdata.data;
1161 tmp_pmdata.r_buf = tmp_pmdata.data;
1162 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1163 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */
1164 tmp_pmdata.data[2] = 0x00;
1165 rval = pmgrop(&tmp_pmdata);
1166 }
1167
1168 void
1169 pm_adb_restart()
1170 {
1171 PMData p;
1172
1173 p.command = PMU_RESET_CPU;
1174 p.num_data = 0;
1175 p.s_buf = p.data;
1176 p.r_buf = p.data;
1177 pmgrop(&p);
1178 }
1179
1180 void
1181 pm_adb_poweroff()
1182 {
1183 PMData p;
1184
1185 p.command = PMU_POWER_OFF;
1186 p.num_data = 4;
1187 p.s_buf = p.data;
1188 p.r_buf = p.data;
1189 strcpy(p.data, "MATT");
1190 pmgrop(&p);
1191 }
1192
1193 void
1194 pm_read_date_time(time)
1195 u_long *time;
1196 {
1197 PMData p;
1198
1199 p.command = PMU_READ_RTC;
1200 p.num_data = 0;
1201 p.s_buf = p.data;
1202 p.r_buf = p.data;
1203 pmgrop(&p);
1204
1205 bcopy(p.data, time, 4);
1206 }
1207
1208 void
1209 pm_set_date_time(time)
1210 u_long time;
1211 {
1212 PMData p;
1213
1214 p.command = PMU_SET_RTC;
1215 p.num_data = 4;
1216 p.s_buf = p.r_buf = p.data;
1217 bcopy(&time, p.data, 4);
1218 pmgrop(&p);
1219 }
1220
1221 int
1222 pm_read_brightness()
1223 {
1224 PMData p;
1225
1226 p.command = PMU_READ_BRIGHTNESS;
1227 p.num_data = 1; /* XXX why 1? */
1228 p.s_buf = p.r_buf = p.data;
1229 p.data[0] = 0;
1230 pmgrop(&p);
1231
1232 return p.data[0];
1233 }
1234
1235 void
1236 pm_set_brightness(val)
1237 int val;
1238 {
1239 PMData p;
1240
1241 val = 0x7f - val / 2;
1242 if (val < 0x08)
1243 val = 0x08;
1244 if (val > 0x78)
1245 val = 0x78;
1246
1247 p.command = PMU_SET_BRIGHTNESS;
1248 p.num_data = 1;
1249 p.s_buf = p.r_buf = p.data;
1250 p.data[0] = val;
1251 pmgrop(&p);
1252 }
1253
1254 void
1255 pm_init_brightness()
1256 {
1257 int val;
1258
1259 val = pm_read_brightness();
1260 pm_set_brightness(val);
1261 }
1262
1263 void
1264 pm_eject_pcmcia(slot)
1265 int slot;
1266 {
1267 PMData p;
1268
1269 if (slot != 0 && slot != 1)
1270 return;
1271
1272 p.command = PMU_EJECT_PCMCIA;
1273 p.num_data = 1;
1274 p.s_buf = p.r_buf = p.data;
1275 p.data[0] = 5 + slot; /* XXX */
1276 pmgrop(&p);
1277 }
1278
1279 int
1280 pm_read_nvram(addr)
1281 int addr;
1282 {
1283 PMData p;
1284
1285 p.command = PMU_READ_NVRAM;
1286 p.num_data = 2;
1287 p.s_buf = p.r_buf = p.data;
1288 p.data[0] = addr >> 8;
1289 p.data[1] = addr;
1290 pmgrop(&p);
1291
1292 return p.data[0];
1293 }
1294
1295 void
1296 pm_write_nvram(addr, val)
1297 int addr, val;
1298 {
1299 PMData p;
1300
1301 p.command = PMU_WRITE_NVRAM;
1302 p.num_data = 3;
1303 p.s_buf = p.r_buf = p.data;
1304 p.data[0] = addr >> 8;
1305 p.data[1] = addr;
1306 p.data[2] = val;
1307 pmgrop(&p);
1308 }
1309