pm_direct.c revision 1.5 1 /* $NetBSD: pm_direct.c,v 1.5 1998/03/29 03:50:30 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 /*
225 * Define the external functions
226 */
227 extern int zshard __P((int)); /* from zs.c */
228
229 #ifdef ADB_DEBUG
230 /*
231 * This function dumps contents of the PMData
232 */
233 void
234 pm_printerr(ttl, rval, num, data)
235 char *ttl;
236 int rval;
237 int num;
238 char *data;
239 {
240 int i;
241
242 printf("pm: %s:%04x %02x ", ttl, rval, num);
243 for (i = 0; i < num; i++)
244 printf("%02x ", data[i]);
245 printf("\n");
246 }
247 #endif
248
249
250
251 /*
252 * Check the hardware type of the Power Manager
253 */
254 void
255 pm_setup_adb()
256 {
257 switch (mac68k_machine.machineid) {
258 case MACH_MACPB140:
259 case MACH_MACPB145:
260 case MACH_MACPB150:
261 case MACH_MACPB160:
262 case MACH_MACPB165:
263 case MACH_MACPB165C:
264 case MACH_MACPB170:
265 case MACH_MACPB180:
266 case MACH_MACPB180C:
267 pmHardware = PM_HW_PB1XX;
268 break;
269 case MACH_MACPB210:
270 case MACH_MACPB230:
271 case MACH_MACPB250:
272 case MACH_MACPB270:
273 case MACH_MACPB280:
274 case MACH_MACPB280C:
275 case MACH_MACPB500:
276 pmHardware = PM_HW_PB5XX;
277 break;
278 default:
279 break;
280 }
281 }
282
283
284 /*
285 * Check the existent ADB devices
286 */
287 void
288 pm_check_adb_devices(id)
289 int id;
290 {
291 u_short ed = 0x1;
292
293 ed <<= id;
294 pm_existent_ADB_devices |= ed;
295 }
296
297
298 /*
299 * Wait until PM IC is busy
300 */
301 int
302 pm_wait_busy(delay)
303 int delay;
304 {
305 while (PM_IS_ON) {
306 #ifdef PM_GRAB_SI
307 zshard(0); /* grab any serial interrupts */
308 #endif
309 if ((--delay) < 0)
310 return 1; /* timeout */
311 }
312 return 0;
313 }
314
315
316 /*
317 * Wait until PM IC is free
318 */
319 int
320 pm_wait_free(delay)
321 int delay;
322 {
323 while (PM_IS_OFF) {
324 #ifdef PM_GRAB_SI
325 zshard(0); /* grab any serial interrupts */
326 #endif
327 if ((--delay) < 0)
328 return 0; /* timeout */
329 }
330 return 1;
331 }
332
333
334
335 /*
336 * Functions for the PB1XX series
337 */
338
339 /*
340 * Receive data from PM for the PB1XX series
341 */
342 int
343 pm_receive_pm1(data)
344 u_char *data;
345 {
346 int rval = 0xffffcd34;
347
348 via_reg(VIA2, vDirA) = 0x00;
349
350 switch (1) {
351 default:
352 if (pm_wait_busy(0x40) != 0)
353 break; /* timeout */
354
355 PM_SET_STATE_ACKOFF();
356 *data = via_reg(VIA2, 0x200);
357
358 rval = 0xffffcd33;
359 if (pm_wait_free(0x40) == 0)
360 break; /* timeout */
361
362 rval = 0x00;
363 break;
364 }
365
366 PM_SET_STATE_ACKON();
367 via_reg(VIA2, vDirA) = 0x00;
368
369 return rval;
370 }
371
372
373
374 /*
375 * Send data to PM for the PB1XX series
376 */
377 int
378 pm_send_pm1(data, delay)
379 u_char data;
380 int delay;
381 {
382 int rval;
383
384 via_reg(VIA2, vDirA) = 0xff;
385 via_reg(VIA2, 0x200) = data;
386
387 PM_SET_STATE_ACKOFF();
388 if (pm_wait_busy(0x400) != 0) {
389 PM_SET_STATE_ACKON();
390 via_reg(VIA2, vDirA) = 0x00;
391
392 return 0xffffcd36;
393 }
394
395 rval = 0x0;
396 PM_SET_STATE_ACKON();
397 if (pm_wait_free(0x40) == 0)
398 rval = 0xffffcd35;
399
400 PM_SET_STATE_ACKON();
401 via_reg(VIA2, vDirA) = 0x00;
402
403 return rval;
404 }
405
406
407 /*
408 * My PMgrOp routine for the PB1XX series
409 */
410 int
411 pm_pmgrop_pm1(pmdata)
412 PMData *pmdata;
413 {
414 int i;
415 int s = 0x81815963;
416 u_char via1_vIER, via1_vDirA;
417 int rval = 0;
418 int num_pm_data = 0;
419 u_char pm_cmd;
420 u_char pm_data;
421 u_char *pm_buf;
422
423 /* disable all inetrrupts but PM */
424 via1_vIER = via_reg(VIA1, vIER);
425 PM_VIA_INTR_DISABLE();
426
427 via1_vDirA = via_reg(VIA1, vDirA);
428
429 switch (pmdata->command) {
430 default:
431 for (i = 0; i < 7; i++) {
432 via_reg(VIA2, vDirA) = 0x00;
433
434 /* wait until PM is free */
435 if (pm_wait_free(ADBDelay) == 0) { /* timeout */
436 via_reg(VIA2, vDirA) = 0x00;
437 /* restore formar value */
438 via_reg(VIA1, vDirA) = via1_vDirA;
439 via_reg(VIA1, vIER) = via1_vIER;
440 return 0xffffcd38;
441 }
442
443 switch (mac68k_machine.machineid) {
444 case MACH_MACPB160:
445 case MACH_MACPB165:
446 case MACH_MACPB165C:
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 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()
550 {
551 int s;
552 int rval;
553 PMData pmdata;
554
555 s = splhigh();
556
557 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
558
559 /* ask PM what happend */
560 pmdata.command = 0x78;
561 pmdata.num_data = 0;
562 pmdata.data[0] = pmdata.data[1] = 0;
563 pmdata.s_buf = &pmdata.data[2];
564 pmdata.r_buf = &pmdata.data[2];
565 rval = pm_pmgrop_pm1(&pmdata);
566 if (rval != 0) {
567 #ifdef ADB_DEBUG
568 if (adb_debug)
569 printf("pm: PM is not ready. error code=%08x\n", rval);
570 #endif
571 splx(s);
572 }
573
574 if ((pmdata.data[2] & 0x10) == 0x10) {
575 if ((pmdata.data[2] & 0x0f) == 0) {
576 /* ADB data that were requested by TALK command */
577 pm_adb_get_TALK_result(&pmdata);
578 } else if ((pmdata.data[2] & 0x08) == 0x8) {
579 /* PM is requesting to poll */
580 pm_adb_poll_next_device_pm1(&pmdata);
581 } else if ((pmdata.data[2] & 0x04) == 0x4) {
582 /* ADB device event */
583 pm_adb_get_ADB_data(&pmdata);
584 }
585 } else {
586 #ifdef ADB_DEBUG
587 if (adb_debug)
588 pm_printerr("driver does not supported this event.",
589 rval, pmdata.num_data, pmdata.data);
590 #endif
591 }
592
593 splx(s);
594 }
595
596
597
598 /*
599 * Functions for the PB Duo series and the PB 5XX series
600 */
601
602 /*
603 * Receive data from PM for the PB Duo series and the PB 5XX series
604 */
605 int
606 pm_receive_pm2(data)
607 u_char *data;
608 {
609 int i;
610 int rval;
611
612 rval = 0xffffcd34;
613
614 switch (1) {
615 default:
616 /* set VIA SR to input mode */
617 via_reg(VIA1, vACR) |= 0x0c;
618 via_reg(VIA1, vACR) &= ~0x10;
619 i = PM_SR();
620
621 PM_SET_STATE_ACKOFF();
622 if (pm_wait_busy((int)ADBDelay*32) != 0)
623 break; /* timeout */
624
625 PM_SET_STATE_ACKON();
626 rval = 0xffffcd33;
627 if (pm_wait_free((int)ADBDelay*32) == 0)
628 break; /* timeout */
629
630 *data = PM_SR();
631 rval = 0;
632
633 break;
634 }
635
636 PM_SET_STATE_ACKON();
637 via_reg(VIA1, vACR) |= 0x1c;
638
639 return rval;
640 }
641
642
643
644 /*
645 * Send data to PM for the PB Duo series and the PB 5XX series
646 */
647 int
648 pm_send_pm2(data)
649 u_char data;
650 {
651 int rval;
652
653 via_reg(VIA1, vACR) |= 0x1c;
654 PM_SR() = data;
655
656 PM_SET_STATE_ACKOFF();
657 rval = 0xffffcd36;
658 if (pm_wait_busy((int)ADBDelay*32) != 0) {
659 PM_SET_STATE_ACKON();
660
661 via_reg(VIA1, vACR) |= 0x1c;
662
663 return rval;
664 }
665
666 PM_SET_STATE_ACKON();
667 rval = 0xffffcd35;
668 if (pm_wait_free((int)ADBDelay*32) != 0)
669 rval = 0;
670
671 PM_SET_STATE_ACKON();
672 via_reg(VIA1, vACR) |= 0x1c;
673
674 return rval;
675 }
676
677
678
679 /*
680 * My PMgrOp routine for the PB Duo series and the PB 5XX series
681 */
682 int
683 pm_pmgrop_pm2(pmdata)
684 PMData *pmdata;
685 {
686 int i;
687 int s;
688 u_char via1_vIER;
689 int rval = 0;
690 int num_pm_data = 0;
691 u_char pm_cmd;
692 short pm_num_rx_data;
693 u_char pm_data;
694 u_char *pm_buf;
695
696 s = splhigh();
697
698 /* disable all inetrrupts but PM */
699 via1_vIER = 0x10;
700 via1_vIER &= via_reg(VIA1, vIER);
701 via_reg(VIA1, vIER) = via1_vIER;
702 if (via1_vIER != 0x0)
703 via1_vIER |= 0x80;
704
705 switch (pmdata->command) {
706 default:
707 /* wait until PM is free */
708 pm_cmd = (u_char)(pmdata->command & 0xff);
709 rval = 0xcd38;
710 if (pm_wait_free(ADBDelay * 4) == 0)
711 break; /* timeout */
712
713 if (HwCfgFlags3 & 0x00200000) {
714 /* PB 160, PB 165(c), PB 180(c)? */
715 int delay = ADBDelay * 16;
716
717 via_reg(VIA2, vDirA) = 0x00;
718 while ((via_reg(VIA2, 0x200) == 0x07) &&
719 (delay >= 0))
720 delay--;
721
722 if (delay < 0) {
723 rval = 0xffffcd38;
724 break; /* timeout */
725 }
726 }
727
728 /* send PM command */
729 if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
730 break; /* timeout */
731
732 /* send number of PM data */
733 num_pm_data = pmdata->num_data;
734 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
735 if (pm_send_cmd_type[pm_cmd] < 0) {
736 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
737 break; /* timeout */
738 pmdata->command = 0;
739 }
740 } else { /* PB 1XX series ? */
741 if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
742 break; /* timeout */
743 }
744 /* send PM data */
745 pm_buf = (u_char *)pmdata->s_buf;
746 for (i = 0 ; i < num_pm_data; i++)
747 if ((rval = pm_send_pm2(pm_buf[i])) != 0)
748 break; /* timeout */
749 if (i != num_pm_data)
750 break; /* timeout */
751
752
753 /* check if PM will send me data */
754 pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
755 pmdata->num_data = pm_num_rx_data;
756 if (pm_num_rx_data == 0) {
757 rval = 0;
758 break; /* no return data */
759 }
760
761 /* receive PM command */
762 pm_data = pmdata->command;
763 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
764 pm_num_rx_data--;
765 if (pm_num_rx_data == 0)
766 if ((rval = pm_receive_pm2(&pm_data)) != 0) {
767 rval = 0xffffcd37;
768 break;
769 }
770 pmdata->command = pm_data;
771 } else { /* PB 1XX series ? */
772 if ((rval = pm_receive_pm2(&pm_data)) != 0) {
773 rval = 0xffffcd37;
774 break;
775 }
776 pmdata->command = pm_data;
777 }
778
779 /* receive number of PM data */
780 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
781 if (pm_num_rx_data < 0) {
782 if ((rval = pm_receive_pm2(&pm_data)) != 0)
783 break; /* timeout */
784 num_pm_data = pm_data;
785 } else
786 num_pm_data = pm_num_rx_data;
787 pmdata->num_data = num_pm_data;
788 } else { /* PB 1XX serias ? */
789 if ((rval = pm_receive_pm2(&pm_data)) != 0)
790 break; /* timeout */
791 num_pm_data = pm_data;
792 pmdata->num_data = num_pm_data;
793 }
794
795 /* receive PM data */
796 pm_buf = (u_char *)pmdata->r_buf;
797 for (i = 0; i < num_pm_data; i++) {
798 if ((rval = pm_receive_pm2(&pm_data)) != 0)
799 break; /* timeout */
800 pm_buf[i] = pm_data;
801 }
802
803 rval = 0;
804 }
805
806 /* restore former value */
807 via_reg(VIA1, vIER) = via1_vIER;
808 splx(s);
809
810 return rval;
811 }
812
813
814 /*
815 * My PM interrupt routine for the PB Duo series and the PB 5XX series
816 */
817 void
818 pm_intr_pm2()
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("
907 movl %1, a0
908 .word 0xa085
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()
944 {
945 switch (pmHardware) {
946 case PM_HW_PB1XX:
947 pm_intr_pm1();
948 break;
949 case PM_HW_PB5XX:
950 pm_intr_pm2();
951 break;
952 default:
953 break;
954 }
955 }
956
957
958
959 /*
960 * Synchronous ADBOp routine for the Power Manager
961 */
962 int
963 pm_adb_op(buffer, compRout, data, command)
964 u_char *buffer;
965 void *compRout;
966 void *data;
967 int command;
968 {
969 int i;
970 int s;
971 int rval;
972 int delay;
973 PMData pmdata;
974 struct adbCommand packet;
975
976 if (adbWaiting == 1)
977 return 1;
978
979 s = splhigh();
980 via_reg(VIA1, vIER) = 0x10;
981
982 adbBuffer = buffer;
983 adbCompRout = compRout;
984 adbCompData = data;
985
986 pmdata.command = 0x20;
987 pmdata.s_buf = pmdata.data;
988 pmdata.r_buf = pmdata.data;
989
990 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, add number of ADB data to number of PM data */
991 if (buffer != (u_char *)0)
992 pmdata.num_data = buffer[0] + 3;
993 } else {
994 pmdata.num_data = 3;
995 }
996
997 pmdata.data[0] = (u_char)(command & 0xff);
998 pmdata.data[1] = 0;
999 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */
1000 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1001 pmdata.data[2] = buffer[0]; /* number of data */
1002 for (i = 0; i < buffer[0]; i++)
1003 pmdata.data[3 + i] = buffer[1 + i];
1004 } else
1005 pmdata.data[2] = 0;
1006 } else
1007 pmdata.data[2] = 0;
1008
1009 if ((command & 0xc) != 0xc) { /* if the command is not TALK */
1010 /* set up stuff for adb_pass_up */
1011 packet.data[0] = 1 + pmdata.data[2];
1012 packet.data[1] = command;
1013 for (i = 0; i < pmdata.data[2]; i++)
1014 packet.data[i+2] = pmdata.data[i+3];
1015 packet.saveBuf = adbBuffer;
1016 packet.compRout = adbCompRout;
1017 packet.compData = adbCompData;
1018 packet.cmd = command;
1019 packet.unsol = 0;
1020 packet.ack_only = 1;
1021 adb_polling = 1;
1022 adb_pass_up(&packet);
1023 adb_polling = 0;
1024 }
1025
1026 rval = pmgrop(&pmdata);
1027 if (rval != 0)
1028 return 1;
1029
1030 adbWaiting = 1;
1031 adbWaitingCmd = command;
1032
1033 PM_VIA_INTR_ENABLE();
1034
1035 /* wait until the PM interrupt is occured */
1036 delay = 0x80000;
1037 while (adbWaiting == 1) {
1038 if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
1039 pm_intr();
1040 #ifdef PM_GRAB_SI
1041 zshard(0); /* grab any serial interrupts */
1042 #endif
1043 if ((--delay) < 0)
1044 return 1;
1045 }
1046
1047 /* this command enables the interrupt by operating ADB devices */
1048 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */
1049 pmdata.command = 0x20;
1050 pmdata.num_data = 4;
1051 pmdata.s_buf = pmdata.data;
1052 pmdata.r_buf = pmdata.data;
1053 pmdata.data[0] = 0x00;
1054 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
1055 pmdata.data[2] = 0x00;
1056 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
1057 } else { /* PB 1XX series */
1058 pmdata.command = 0x20;
1059 pmdata.num_data = 3;
1060 pmdata.s_buf = pmdata.data;
1061 pmdata.r_buf = pmdata.data;
1062 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1063 pmdata.data[1] = 0x04;
1064 pmdata.data[2] = 0x00;
1065 }
1066 rval = pmgrop(&pmdata);
1067
1068 splx(s);
1069 return rval;
1070 }
1071
1072
1073 void
1074 pm_adb_get_TALK_result(pmdata)
1075 PMData *pmdata;
1076 {
1077 int i;
1078 struct adbCommand packet;
1079
1080 /* set up data for adb_pass_up */
1081 packet.data[0] = pmdata->num_data-1;
1082 packet.data[1] = pmdata->data[3];
1083 for (i = 0; i <packet.data[0]-1; i++)
1084 packet.data[i+2] = pmdata->data[i+4];
1085
1086 packet.saveBuf = adbBuffer;
1087 packet.compRout = adbCompRout;
1088 packet.compData = adbCompData;
1089 packet.unsol = 0;
1090 packet.ack_only = 0;
1091 adb_polling = 1;
1092 adb_pass_up(&packet);
1093 adb_polling = 0;
1094
1095 adbWaiting = 0;
1096 adbBuffer = (long)0;
1097 adbCompRout = (long)0;
1098 adbCompData = (long)0;
1099 }
1100
1101
1102 void
1103 pm_adb_get_ADB_data(pmdata)
1104 PMData *pmdata;
1105 {
1106 int i;
1107 struct adbCommand packet;
1108
1109 /* set up data for adb_pass_up */
1110 packet.data[0] = pmdata->num_data-1; /* number of raw data */
1111 packet.data[1] = pmdata->data[3]; /* ADB command */
1112 for (i = 0; i <packet.data[0]-1; i++)
1113 packet.data[i+2] = pmdata->data[i+4];
1114 packet.unsol = 1;
1115 packet.ack_only = 0;
1116 adb_pass_up(&packet);
1117 }
1118
1119
1120 void
1121 pm_adb_poll_next_device_pm1(pmdata)
1122 PMData *pmdata;
1123 {
1124 int i;
1125 int ndid;
1126 u_short bendid = 0x1;
1127 int rval;
1128 PMData tmp_pmdata;
1129
1130 /* find another existent ADB device to poll */
1131 for (i = 1; i < 16; i++) {
1132 ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf;
1133 bendid <<= ndid;
1134 if ((pm_existent_ADB_devices & bendid) != 0)
1135 break;
1136 }
1137
1138 /* poll the other device */
1139 tmp_pmdata.command = 0x20;
1140 tmp_pmdata.num_data = 3;
1141 tmp_pmdata.s_buf = tmp_pmdata.data;
1142 tmp_pmdata.r_buf = tmp_pmdata.data;
1143 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1144 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */
1145 tmp_pmdata.data[2] = 0x00;
1146 rval = pmgrop(&tmp_pmdata);
1147 }
1148
1149
1150
1151