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