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