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