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