pm_direct.c revision 1.6 1 /* $NetBSD: pm_direct.c,v 1.6 1998/08/12 05:42:44 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.3 03/18/98 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 extern void *adbCompRout; /* pointer to the completion routine */
204 extern void *adbCompData; /* pointer to the completion routine data */
205 extern int adbWaiting; /* waiting for return data from the device */
206 extern int adbWaitingCmd; /* ADB command we are waiting for */
207 extern int adbStarting; /* doing ADB reinit, so do "polling" differently */
208
209 #define ADB_MAX_MSG_LENGTH 16
210 #define ADB_MAX_HDR_LENGTH 8
211 struct adbCommand {
212 u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */
213 u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */
214 u_char *saveBuf; /* where to save result */
215 u_char *compRout; /* completion routine pointer */
216 u_char *compData; /* completion routine data pointer */
217 u_int cmd; /* the original command for this data */
218 u_int unsol; /* 1 if packet was unsolicited */
219 u_int ack_only; /* 1 for no special processing */
220 };
221 extern void adb_pass_up __P((struct adbCommand *));
222
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 switch (mac68k_machine.machineid) {
260 case MACH_MACPB140:
261 case MACH_MACPB145:
262 case MACH_MACPB150:
263 case MACH_MACPB160:
264 case MACH_MACPB165:
265 case MACH_MACPB165C:
266 case MACH_MACPB170:
267 case MACH_MACPB180:
268 case MACH_MACPB180C:
269 pmHardware = PM_HW_PB1XX;
270 break;
271 case MACH_MACPB210:
272 case MACH_MACPB230:
273 case MACH_MACPB250:
274 case MACH_MACPB270:
275 case MACH_MACPB280:
276 case MACH_MACPB280C:
277 case MACH_MACPB500:
278 pmHardware = PM_HW_PB5XX;
279 break;
280 default:
281 break;
282 }
283 }
284
285
286 /*
287 * Check the existent ADB devices
288 */
289 void
290 pm_check_adb_devices(id)
291 int id;
292 {
293 u_short ed = 0x1;
294
295 ed <<= id;
296 pm_existent_ADB_devices |= ed;
297 }
298
299
300 /*
301 * Wait until PM IC is busy
302 */
303 int
304 pm_wait_busy(delay)
305 int delay;
306 {
307 while (PM_IS_ON) {
308 #ifdef PM_GRAB_SI
309 #if 0
310 zshard(0); /* grab any serial interrupts */
311 #else
312 (void)intr_dispatch(0x70);
313 #endif
314 #endif
315 if ((--delay) < 0)
316 return 1; /* timeout */
317 }
318 return 0;
319 }
320
321
322 /*
323 * Wait until PM IC is free
324 */
325 int
326 pm_wait_free(delay)
327 int delay;
328 {
329 while (PM_IS_OFF) {
330 #ifdef PM_GRAB_SI
331 #if 0
332 zshard(0); /* grab any serial interrupts */
333 #else
334 (void)intr_dispatch(0x70);
335 #endif
336 #endif
337 if ((--delay) < 0)
338 return 0; /* timeout */
339 }
340 return 1;
341 }
342
343
344
345 /*
346 * Functions for the PB1XX series
347 */
348
349 /*
350 * Receive data from PM for the PB1XX series
351 */
352 int
353 pm_receive_pm1(data)
354 u_char *data;
355 {
356 int rval = 0xffffcd34;
357
358 via_reg(VIA2, vDirA) = 0x00;
359
360 switch (1) {
361 default:
362 if (pm_wait_busy(0x40) != 0)
363 break; /* timeout */
364
365 PM_SET_STATE_ACKOFF();
366 *data = via_reg(VIA2, 0x200);
367
368 rval = 0xffffcd33;
369 if (pm_wait_free(0x40) == 0)
370 break; /* timeout */
371
372 rval = 0x00;
373 break;
374 }
375
376 PM_SET_STATE_ACKON();
377 via_reg(VIA2, vDirA) = 0x00;
378
379 return rval;
380 }
381
382
383
384 /*
385 * Send data to PM for the PB1XX series
386 */
387 int
388 pm_send_pm1(data, delay)
389 u_char data;
390 int delay;
391 {
392 int rval;
393
394 via_reg(VIA2, vDirA) = 0xff;
395 via_reg(VIA2, 0x200) = data;
396
397 PM_SET_STATE_ACKOFF();
398 if (pm_wait_busy(0x400) != 0) {
399 PM_SET_STATE_ACKON();
400 via_reg(VIA2, vDirA) = 0x00;
401
402 return 0xffffcd36;
403 }
404
405 rval = 0x0;
406 PM_SET_STATE_ACKON();
407 if (pm_wait_free(0x40) == 0)
408 rval = 0xffffcd35;
409
410 PM_SET_STATE_ACKON();
411 via_reg(VIA2, vDirA) = 0x00;
412
413 return rval;
414 }
415
416
417 /*
418 * My PMgrOp routine for the PB1XX series
419 */
420 int
421 pm_pmgrop_pm1(pmdata)
422 PMData *pmdata;
423 {
424 int i;
425 int s = 0x81815963;
426 u_char via1_vIER, via1_vDirA;
427 int rval = 0;
428 int num_pm_data = 0;
429 u_char pm_cmd;
430 u_char pm_data;
431 u_char *pm_buf;
432
433 /* disable all inetrrupts but PM */
434 via1_vIER = via_reg(VIA1, vIER);
435 PM_VIA_INTR_DISABLE();
436
437 via1_vDirA = via_reg(VIA1, vDirA);
438
439 switch (pmdata->command) {
440 default:
441 for (i = 0; i < 7; i++) {
442 via_reg(VIA2, vDirA) = 0x00;
443
444 /* wait until PM is free */
445 if (pm_wait_free(ADBDelay) == 0) { /* timeout */
446 via_reg(VIA2, vDirA) = 0x00;
447 /* restore formar value */
448 via_reg(VIA1, vDirA) = via1_vDirA;
449 via_reg(VIA1, vIER) = via1_vIER;
450 return 0xffffcd38;
451 }
452
453 switch (mac68k_machine.machineid) {
454 case MACH_MACPB160:
455 case MACH_MACPB165:
456 case MACH_MACPB165C:
457 case MACH_MACPB180:
458 case MACH_MACPB180C:
459 {
460 int delay = ADBDelay * 16;
461
462 via_reg(VIA2, vDirA) = 0x00;
463 while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
464 delay--;
465
466 if (delay < 0) { /* timeout */
467 via_reg(VIA2, vDirA) = 0x00;
468 /* restore formar value */
469 via_reg(VIA1, vIER) = via1_vIER;
470 return 0xffffcd38;
471 }
472 }
473 } /* end switch */
474
475 s = splhigh();
476
477 via1_vDirA = via_reg(VIA1, vDirA);
478 via_reg(VIA1, vDirA) &= 0x7f;
479
480 pm_cmd = (u_char)(pmdata->command & 0xff);
481 if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
482 break; /* send command succeeded */
483
484 via_reg(VIA1, vDirA) = via1_vDirA;
485 splx(s);
486 } /* end for */
487
488 /* failed to send a command */
489 if (i == 7) {
490 via_reg(VIA2, vDirA) = 0x00;
491 /* restore formar value */
492 via_reg(VIA1, vDirA) = via1_vDirA;
493 via_reg(VIA1, vIER) = via1_vIER;
494 return 0xffffcd38;
495 }
496
497 /* send # of PM data */
498 num_pm_data = pmdata->num_data;
499 if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
500 break; /* timeout */
501
502 /* send PM data */
503 pm_buf = (u_char *)pmdata->s_buf;
504 for (i = 0; i < num_pm_data; i++)
505 if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
506 break; /* timeout */
507 if ((i != num_pm_data) && (num_pm_data != 0))
508 break; /* timeout */
509
510 /* Will PM IC return data? */
511 if ((pm_cmd & 0x08) == 0) {
512 rval = 0;
513 break; /* no returned data */
514 }
515
516 rval = 0xffffcd37;
517 if (pm_wait_busy(ADBDelay) != 0)
518 break; /* timeout */
519
520 /* receive PM command */
521 if ((rval = pm_receive_pm1(&pm_data)) != 0)
522 break;
523
524 pmdata->command = pm_data;
525
526 /* receive number of PM data */
527 if ((rval = pm_receive_pm1(&pm_data)) != 0)
528 break; /* timeout */
529 num_pm_data = pm_data;
530 pmdata->num_data = num_pm_data;
531
532 /* receive PM data */
533 pm_buf = (u_char *)pmdata->r_buf;
534 for (i = 0; i < num_pm_data; i++) {
535 if ((rval = pm_receive_pm1(&pm_data)) != 0)
536 break; /* timeout */
537 pm_buf[i] = pm_data;
538 }
539
540 rval = 0;
541 }
542
543 via_reg(VIA2, vDirA) = 0x00;
544
545 /* restore formar value */
546 via_reg(VIA1, vDirA) = via1_vDirA;
547 via_reg(VIA1, vIER) = via1_vIER;
548 if (s != 0x81815963)
549 splx(s);
550
551 return rval;
552 }
553
554
555 /*
556 * My PM interrupt routine for PB1XX series
557 */
558 void
559 pm_intr_pm1()
560 {
561 int s;
562 int rval;
563 PMData pmdata;
564
565 s = splhigh();
566
567 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
568
569 /* ask PM what happend */
570 pmdata.command = 0x78;
571 pmdata.num_data = 0;
572 pmdata.data[0] = pmdata.data[1] = 0;
573 pmdata.s_buf = &pmdata.data[2];
574 pmdata.r_buf = &pmdata.data[2];
575 rval = pm_pmgrop_pm1(&pmdata);
576 if (rval != 0) {
577 #ifdef ADB_DEBUG
578 if (adb_debug)
579 printf("pm: PM is not ready. error code=%08x\n", rval);
580 #endif
581 splx(s);
582 }
583
584 if ((pmdata.data[2] & 0x10) == 0x10) {
585 if ((pmdata.data[2] & 0x0f) == 0) {
586 /* ADB data that were requested by TALK command */
587 pm_adb_get_TALK_result(&pmdata);
588 } else if ((pmdata.data[2] & 0x08) == 0x8) {
589 /* PM is requesting to poll */
590 pm_adb_poll_next_device_pm1(&pmdata);
591 } else if ((pmdata.data[2] & 0x04) == 0x4) {
592 /* ADB device event */
593 pm_adb_get_ADB_data(&pmdata);
594 }
595 } else {
596 #ifdef ADB_DEBUG
597 if (adb_debug)
598 pm_printerr("driver does not supported this event.",
599 rval, pmdata.num_data, pmdata.data);
600 #endif
601 }
602
603 splx(s);
604 }
605
606
607
608 /*
609 * Functions for the PB Duo series and the PB 5XX series
610 */
611
612 /*
613 * Receive data from PM for the PB Duo series and the PB 5XX series
614 */
615 int
616 pm_receive_pm2(data)
617 u_char *data;
618 {
619 int i;
620 int rval;
621
622 rval = 0xffffcd34;
623
624 switch (1) {
625 default:
626 /* set VIA SR to input mode */
627 via_reg(VIA1, vACR) |= 0x0c;
628 via_reg(VIA1, vACR) &= ~0x10;
629 i = PM_SR();
630
631 PM_SET_STATE_ACKOFF();
632 if (pm_wait_busy((int)ADBDelay*32) != 0)
633 break; /* timeout */
634
635 PM_SET_STATE_ACKON();
636 rval = 0xffffcd33;
637 if (pm_wait_free((int)ADBDelay*32) == 0)
638 break; /* timeout */
639
640 *data = PM_SR();
641 rval = 0;
642
643 break;
644 }
645
646 PM_SET_STATE_ACKON();
647 via_reg(VIA1, vACR) |= 0x1c;
648
649 return rval;
650 }
651
652
653
654 /*
655 * Send data to PM for the PB Duo series and the PB 5XX series
656 */
657 int
658 pm_send_pm2(data)
659 u_char data;
660 {
661 int rval;
662
663 via_reg(VIA1, vACR) |= 0x1c;
664 PM_SR() = data;
665
666 PM_SET_STATE_ACKOFF();
667 rval = 0xffffcd36;
668 if (pm_wait_busy((int)ADBDelay*32) != 0) {
669 PM_SET_STATE_ACKON();
670
671 via_reg(VIA1, vACR) |= 0x1c;
672
673 return rval;
674 }
675
676 PM_SET_STATE_ACKON();
677 rval = 0xffffcd35;
678 if (pm_wait_free((int)ADBDelay*32) != 0)
679 rval = 0;
680
681 PM_SET_STATE_ACKON();
682 via_reg(VIA1, vACR) |= 0x1c;
683
684 return rval;
685 }
686
687
688
689 /*
690 * My PMgrOp routine for the PB Duo series and the PB 5XX series
691 */
692 int
693 pm_pmgrop_pm2(pmdata)
694 PMData *pmdata;
695 {
696 int i;
697 int s;
698 u_char via1_vIER;
699 int rval = 0;
700 int num_pm_data = 0;
701 u_char pm_cmd;
702 short pm_num_rx_data;
703 u_char pm_data;
704 u_char *pm_buf;
705
706 s = splhigh();
707
708 /* disable all inetrrupts but PM */
709 via1_vIER = 0x10;
710 via1_vIER &= via_reg(VIA1, vIER);
711 via_reg(VIA1, vIER) = via1_vIER;
712 if (via1_vIER != 0x0)
713 via1_vIER |= 0x80;
714
715 switch (pmdata->command) {
716 default:
717 /* wait until PM is free */
718 pm_cmd = (u_char)(pmdata->command & 0xff);
719 rval = 0xcd38;
720 if (pm_wait_free(ADBDelay * 4) == 0)
721 break; /* timeout */
722
723 if (HwCfgFlags3 & 0x00200000) {
724 /* PB 160, PB 165(c), PB 180(c)? */
725 int delay = ADBDelay * 16;
726
727 via_reg(VIA2, vDirA) = 0x00;
728 while ((via_reg(VIA2, 0x200) == 0x07) &&
729 (delay >= 0))
730 delay--;
731
732 if (delay < 0) {
733 rval = 0xffffcd38;
734 break; /* timeout */
735 }
736 }
737
738 /* send PM command */
739 if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
740 break; /* timeout */
741
742 /* send number of PM data */
743 num_pm_data = pmdata->num_data;
744 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
745 if (pm_send_cmd_type[pm_cmd] < 0) {
746 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
747 break; /* timeout */
748 pmdata->command = 0;
749 }
750 } else { /* PB 1XX series ? */
751 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
752 break; /* timeout */
753 }
754 /* send PM data */
755 pm_buf = (u_char *)pmdata->s_buf;
756 for (i = 0 ; i < num_pm_data; i++)
757 if ((rval = pm_send_pm2(pm_buf[i])) != 0)
758 break; /* timeout */
759 if (i != num_pm_data)
760 break; /* timeout */
761
762
763 /* check if PM will send me data */
764 pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
765 pmdata->num_data = pm_num_rx_data;
766 if (pm_num_rx_data == 0) {
767 rval = 0;
768 break; /* no return data */
769 }
770
771 /* receive PM command */
772 pm_data = pmdata->command;
773 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
774 pm_num_rx_data--;
775 if (pm_num_rx_data == 0)
776 if ((rval = pm_receive_pm2(&pm_data)) != 0) {
777 rval = 0xffffcd37;
778 break;
779 }
780 pmdata->command = pm_data;
781 } else { /* PB 1XX series ? */
782 if ((rval = pm_receive_pm2(&pm_data)) != 0) {
783 rval = 0xffffcd37;
784 break;
785 }
786 pmdata->command = pm_data;
787 }
788
789 /* receive number of PM data */
790 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
791 if (pm_num_rx_data < 0) {
792 if ((rval = pm_receive_pm2(&pm_data)) != 0)
793 break; /* timeout */
794 num_pm_data = pm_data;
795 } else
796 num_pm_data = pm_num_rx_data;
797 pmdata->num_data = num_pm_data;
798 } else { /* PB 1XX serias ? */
799 if ((rval = pm_receive_pm2(&pm_data)) != 0)
800 break; /* timeout */
801 num_pm_data = pm_data;
802 pmdata->num_data = num_pm_data;
803 }
804
805 /* receive PM data */
806 pm_buf = (u_char *)pmdata->r_buf;
807 for (i = 0; i < num_pm_data; i++) {
808 if ((rval = pm_receive_pm2(&pm_data)) != 0)
809 break; /* timeout */
810 pm_buf[i] = pm_data;
811 }
812
813 rval = 0;
814 }
815
816 /* restore former value */
817 via_reg(VIA1, vIER) = via1_vIER;
818 splx(s);
819
820 return rval;
821 }
822
823
824 /*
825 * My PM interrupt routine for the PB Duo series and the PB 5XX series
826 */
827 void
828 pm_intr_pm2()
829 {
830 int s;
831 int rval;
832 PMData pmdata;
833
834 s = splhigh();
835
836 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
837 /* ask PM what happend */
838 pmdata.command = 0x78;
839 pmdata.num_data = 0;
840 pmdata.s_buf = &pmdata.data[2];
841 pmdata.r_buf = &pmdata.data[2];
842 rval = pm_pmgrop_pm2(&pmdata);
843 if (rval != 0) {
844 #ifdef ADB_DEBUG
845 if (adb_debug)
846 printf("pm: PM is not ready. error code: %08x\n", rval);
847 #endif
848 splx(s);
849 }
850
851 switch ((u_int)(pmdata.data[2] & 0xff)) {
852 case 0x00: /* 1 sec interrupt? */
853 break;
854 case 0x80: /* 1 sec interrupt? */
855 pm_counter++;
856 break;
857 case 0x08: /* Brightness/Contrast button on LCD panel */
858 /* get brightness and contrast of the LCD */
859 pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
860 pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
861 /*
862 pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
863 pmdata.command = 0x33;
864 pmdata.num_data = 1;
865 pmdata.s_buf = pmdata.data;
866 pmdata.r_buf = pmdata.data;
867 pmdata.data[0] = pm_LCD_contrast;
868 rval = pm_pmgrop_pm2(&pmdata);
869 pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
870 */
871 /* this is an experimental code */
872 pmdata.command = 0x41;
873 pmdata.num_data = 1;
874 pmdata.s_buf = pmdata.data;
875 pmdata.r_buf = pmdata.data;
876 pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
877 if (pm_LCD_brightness < 0x25)
878 pm_LCD_brightness = 0x25;
879 if (pm_LCD_brightness > 0x5a)
880 pm_LCD_brightness = 0x7f;
881 pmdata.data[0] = pm_LCD_brightness;
882 rval = pm_pmgrop_pm2(&pmdata);
883 break;
884 case 0x10: /* ADB data that were requested by TALK command */
885 case 0x14:
886 pm_adb_get_TALK_result(&pmdata);
887 break;
888 case 0x16: /* ADB device event */
889 case 0x18:
890 case 0x1e:
891 pm_adb_get_ADB_data(&pmdata);
892 break;
893 default:
894 #ifdef ADB_DEBUG
895 if (adb_debug)
896 pm_printerr("driver does not supported this event.",
897 pmdata.data[2], pmdata.num_data,
898 pmdata.data);
899 #endif
900 break;
901 }
902
903 splx(s);
904 }
905
906
907 /*
908 * MRG-based PMgrOp routine
909 */
910 int
911 pm_pmgrop_mrg(pmdata)
912 PMData *pmdata;
913 {
914 u_int32_t rval=0;
915
916 asm("
917 movl %1, a0
918 .word 0xa085
919 movl d0, %0"
920 : "=g" (rval)
921 : "g" (pmdata)
922 : "a0", "d0" );
923
924 return rval;
925 }
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 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 ((command & 0xc) == 0x8) { /* if the command is LISTEN, add number of ADB data to number of PM data */
1001 if (buffer != (u_char *)0)
1002 pmdata.num_data = buffer[0] + 3;
1003 } else {
1004 pmdata.num_data = 3;
1005 }
1006
1007 pmdata.data[0] = (u_char)(command & 0xff);
1008 pmdata.data[1] = 0;
1009 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */
1010 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1011 pmdata.data[2] = buffer[0]; /* number of data */
1012 for (i = 0; i < buffer[0]; i++)
1013 pmdata.data[3 + i] = buffer[1 + i];
1014 } else
1015 pmdata.data[2] = 0;
1016 } else
1017 pmdata.data[2] = 0;
1018
1019 if ((command & 0xc) != 0xc) { /* if the command is not TALK */
1020 /* set up stuff for adb_pass_up */
1021 packet.data[0] = 1 + pmdata.data[2];
1022 packet.data[1] = command;
1023 for (i = 0; i < pmdata.data[2]; i++)
1024 packet.data[i+2] = pmdata.data[i+3];
1025 packet.saveBuf = adbBuffer;
1026 packet.compRout = adbCompRout;
1027 packet.compData = adbCompData;
1028 packet.cmd = command;
1029 packet.unsol = 0;
1030 packet.ack_only = 1;
1031 adb_polling = 1;
1032 adb_pass_up(&packet);
1033 adb_polling = 0;
1034 }
1035
1036 rval = pmgrop(&pmdata);
1037 if (rval != 0)
1038 return 1;
1039
1040 adbWaiting = 1;
1041 adbWaitingCmd = command;
1042
1043 PM_VIA_INTR_ENABLE();
1044
1045 /* wait until the PM interrupt is occured */
1046 delay = 0x80000;
1047 while (adbWaiting == 1) {
1048 if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
1049 pm_intr();
1050 #ifdef PM_GRAB_SI
1051 #if 0
1052 zshard(0); /* grab any serial interrupts */
1053 #else
1054 (void)intr_dispatch(0x70);
1055 #endif
1056 #endif
1057 if ((--delay) < 0)
1058 return 1;
1059 }
1060
1061 /* this command enables the interrupt by operating ADB devices */
1062 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */
1063 pmdata.command = 0x20;
1064 pmdata.num_data = 4;
1065 pmdata.s_buf = pmdata.data;
1066 pmdata.r_buf = pmdata.data;
1067 pmdata.data[0] = 0x00;
1068 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
1069 pmdata.data[2] = 0x00;
1070 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
1071 } else { /* PB 1XX series */
1072 pmdata.command = 0x20;
1073 pmdata.num_data = 3;
1074 pmdata.s_buf = pmdata.data;
1075 pmdata.r_buf = pmdata.data;
1076 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1077 pmdata.data[1] = 0x04;
1078 pmdata.data[2] = 0x00;
1079 }
1080 rval = pmgrop(&pmdata);
1081
1082 splx(s);
1083 return rval;
1084 }
1085
1086
1087 void
1088 pm_adb_get_TALK_result(pmdata)
1089 PMData *pmdata;
1090 {
1091 int i;
1092 struct adbCommand packet;
1093
1094 /* set up data for adb_pass_up */
1095 packet.data[0] = pmdata->num_data-1;
1096 packet.data[1] = pmdata->data[3];
1097 for (i = 0; i <packet.data[0]-1; i++)
1098 packet.data[i+2] = pmdata->data[i+4];
1099
1100 packet.saveBuf = adbBuffer;
1101 packet.compRout = adbCompRout;
1102 packet.compData = adbCompData;
1103 packet.unsol = 0;
1104 packet.ack_only = 0;
1105 adb_polling = 1;
1106 adb_pass_up(&packet);
1107 adb_polling = 0;
1108
1109 adbWaiting = 0;
1110 adbBuffer = (long)0;
1111 adbCompRout = (long)0;
1112 adbCompData = (long)0;
1113 }
1114
1115
1116 void
1117 pm_adb_get_ADB_data(pmdata)
1118 PMData *pmdata;
1119 {
1120 int i;
1121 struct adbCommand packet;
1122
1123 /* set up data for adb_pass_up */
1124 packet.data[0] = pmdata->num_data-1; /* number of raw data */
1125 packet.data[1] = pmdata->data[3]; /* ADB command */
1126 for (i = 0; i <packet.data[0]-1; i++)
1127 packet.data[i+2] = pmdata->data[i+4];
1128 packet.unsol = 1;
1129 packet.ack_only = 0;
1130 adb_pass_up(&packet);
1131 }
1132
1133
1134 void
1135 pm_adb_poll_next_device_pm1(pmdata)
1136 PMData *pmdata;
1137 {
1138 int i;
1139 int ndid;
1140 u_short bendid = 0x1;
1141 int rval;
1142 PMData tmp_pmdata;
1143
1144 /* find another existent ADB device to poll */
1145 for (i = 1; i < 16; i++) {
1146 ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf;
1147 bendid <<= ndid;
1148 if ((pm_existent_ADB_devices & bendid) != 0)
1149 break;
1150 }
1151
1152 /* poll the other device */
1153 tmp_pmdata.command = 0x20;
1154 tmp_pmdata.num_data = 3;
1155 tmp_pmdata.s_buf = tmp_pmdata.data;
1156 tmp_pmdata.r_buf = tmp_pmdata.data;
1157 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1158 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */
1159 tmp_pmdata.data[2] = 0x00;
1160 rval = pmgrop(&tmp_pmdata);
1161 }
1162
1163
1164
1165