pm_direct.c revision 1.1 1 /* $NetBSD: pm_direct.c,v 1.1 1997/04/08 03:11:37 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.22 01/09/97 Takashi Hamada */
33
34
35 /* #define PM_DEBUG 1 */
36 /* #define PM_GRAB_SI 1 */
37
38 #include <sys/types.h>
39 #include <sys/cdefs.h>
40
41 #include <machine/viareg.h>
42 #include <machine/param.h>
43 #include <machine/cpu.h>
44 #include <machine/adbsys.h>
45
46 #include <arch/mac68k/mac68k/macrom.h>
47 #include "adbvar.h"
48 #include "pm_direct.h"
49
50 /* hardware dependent values */
51 extern u_short ADBDelay;
52 extern u_int32_t HwCfgFlags3;
53 extern struct mac68k_machine_S mac68k_machine;
54
55
56 /* define the types of the Power Manager */
57 #define PM_HW_UNKNOWN 0x00 /* don't know */
58 #define PM_HW_PB1XX 0x01 /* PowerBook 1XX series */
59 #define PM_HW_PB5XX 0x02 /* PowerBook Duo and 5XX series */
60
61 /* useful macros */
62 #define PM_SR() via_reg(VIA1, vSR)
63 #define PM_VIA_INTR_ENABLE() via_reg(VIA1, vIER) = 0x90
64 #define PM_VIA_INTR_DISABLE() via_reg(VIA1, vIER) = 0x10
65 #define PM_VIA_CLR_INTR() via_reg(VIA1, vIFR) = 0x90
66 #define PM_SET_STATE_ACKON() via_reg(VIA2, vBufB) |= 0x04
67 #define PM_SET_STATE_ACKOFF() via_reg(VIA2, vBufB) &= ~0x04
68 #define PM_IS_ON ( 0x02 == (via_reg(VIA2, vBufB) & 0x02) )
69 #define PM_IS_OFF ( 0x00 == (via_reg(VIA2, vBufB) & 0x02) )
70
71 /*
72 * Valiables for internal use
73 */
74 int pmHardware = PM_HW_UNKNOWN;
75 u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */
76 u_int pm_LCD_brightness = 0x0;
77 u_int pm_LCD_contrast = 0x0;
78 u_int pm_counter = 0; /* clock count */
79
80 /* these values shows that number of data returned after 'send' cmd is sent */
81 char pm_send_cmd_type[] = {
82 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
83 0x01,0x01,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0x00,
84 0xff,0x00,0x02,0x01,0x01,0xff,0xff,0xff, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
85 0x04,0x14,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x02,0xff,0xff,0xff,0xff,0xff,
86 0x01,0x01,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
87 0x01,0x00,0x02,0x02,0xff,0x01,0x03,0x01, 0x00,0x01,0x00,0x00,0x00,0xff,0xff,0xff,
88 0x02,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
89 0x01,0x01,0x01,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0x04,0x04,
90 0x04,0xff,0x00,0xff,0xff,0xff,0xff,0xff, 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
91 0x01,0x02,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,
92 0x02,0x02,0x02,0x04,0xff,0x00,0xff,0xff, 0x01,0x01,0x03,0x02,0xff,0xff,0xff,0xff,
93 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
94 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
95 0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x01,0x01,0xff,0xff,0x00,0x00,0xff,0xff,
96 0xff,0x04,0x00,0xff,0xff,0xff,0xff,0xff, 0x03,0xff,0x00,0xff,0x00,0xff,0xff,0x00,
97 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
98 };
99
100 /* these values shows that number of data returned after 'receive' cmd is sent */
101 char pm_receive_cmd_type[] = {
102 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
103 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0xff,0xff,0xff,0x00,
104 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
105 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x05,0x15,0xff,0xff,0xff,0xff,0xff,0xff,
106 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0xff,0xff,0xff,0xff,
107 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x00,0x03,0x03,0xff,0xff,0xff,0xff,
108 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x04,0x04,0x03,0x09,0xff,0xff,0xff,0xff,
109 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0x01,0x01,
110 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x06,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
111 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0xff,0xff,0xff,0xff,
112 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
113 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
114 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
115 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x02,0xff,0xff,0x02,0xff,0xff,0xff,
116 0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0x02,0xff,0xff,0xff,0xff,0x00,
117 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
118 };
119
120
121 /*
122 * Define the private functions
123 */
124
125 /* for debugging */
126 #ifdef PM_DEBUG
127 void pm_printerr __P(( char *, int, int, char * ));
128 #endif
129
130 int pm_wait_busy __P((int));
131 int pm_wait_free __P((int));
132
133 /* these functions are for the PB1XX series */
134 int pm_receive_pm1 __P((u_char *));
135 int pm_send_pm1 __P((u_char,int));
136 int pm_pmgrop_pm1 __P((PMData *));
137 void pm_intr_pm1 __P((void));
138
139 /* these functions are for the PB Duo series and the PB 5XX series */
140 int pm_receive_pm2 __P((u_char *));
141 int pm_send_pm2 __P((u_char));
142 int pm_pmgrop_pm2 __P((PMData *));
143 void pm_intr_pm2 __P((void));
144
145 /* this function is MRG-Based (for testing) */
146 int pm_pmgrop_mrg __P((PMData *));
147
148 /* these functions are called from adb_direct.c */
149 void pm_setup_adb __P((void));
150 void pm_check_adb_devices __P((int));
151 void pm_intr __P((void));
152 int pm_adb_op __P((u_char *, void *, void *, int));
153
154 /* these functions also use the variables of adb_direct.c */
155 void pm_adb_get_TALK_result __P((PMData *));
156 void pm_adb_get_ADB_data __P((PMData *));
157 void pm_adb_poll_next_device_pm1 __P((PMData *));
158
159
160 /*
161 * These variables are in adb_direct.c.
162 */
163 extern u_char *adbBuffer; /* pointer to user data area */
164 #define MAX_ADB_MSG_LENGTH 20
165 extern u_char adbInputBuffer[MAX_ADB_MSG_LENGTH]; /* data input buffer */
166 extern void *adbCompRout; /* pointer to the completion routine */
167 extern void *adbCompData; /* pointer to the completion routine data */
168 extern int adbWaiting; /* waiting for return data from the device */
169 extern int adbWaitingCmd; /* ADB command we are waiting for */
170 extern int adbStarting; /* doing ADB reinit, so do "polling" differently */
171
172 /*
173 * Define the external functions
174 */
175 extern int zshard(int); /* from zs.c */
176 extern void adb_comp_exec(void); /* from adb_direct.c */
177
178
179 #ifdef PM_DEBUG
180 /*
181 * This function dumps contents of the PMData
182 */
183 void
184 pm_printerr(ttl, rval, num, data)
185 char *ttl;
186 int rval;
187 int num;
188 char *data;
189 {
190 int i;
191
192 printf( "pm: %s:%04x %02x ", ttl, rval, num );
193 for( i=0; i<num; i++ )
194 printf( "%02x ", data[i] );
195 printf( "\n" );
196 }
197 #endif
198
199
200
201 /*
202 * Check the hardware type of the Power Manager
203 */
204 void
205 pm_setup_adb(void)
206 {
207 switch (mac68k_machine.machineid) {
208 case MACH_MACPB140:
209 case MACH_MACPB145:
210 case MACH_MACPB150:
211 case MACH_MACPB160:
212 case MACH_MACPB165:
213 case MACH_MACPB165C:
214 case MACH_MACPB170:
215 case MACH_MACPB180:
216 case MACH_MACPB180C:
217 pmHardware = PM_HW_PB1XX;
218 break;
219 case MACH_MACPB210:
220 case MACH_MACPB230:
221 case MACH_MACPB250:
222 case MACH_MACPB270:
223 case MACH_MACPB280:
224 case MACH_MACPB280C:
225 case MACH_MACPB500:
226 pmHardware = PM_HW_PB5XX;
227 break;
228 default:
229 break;
230 }
231 }
232
233
234 /*
235 * Check the existent ADB devices
236 */
237 void
238 pm_check_adb_devices(id)
239 int id;
240 {
241 u_short ed = 0x1;
242
243 ed <<= id;
244 pm_existent_ADB_devices |= ed;
245 }
246
247
248 /*
249 * Wait until PM IC is busy
250 */
251 int
252 pm_wait_busy(delay)
253 int delay;
254 {
255 while(PM_IS_ON) {
256 #ifdef PM_GRAB_SI
257 zshard(0); /* grab any serial interrupts */
258 #endif
259 if ((--delay) < 0)
260 return( 1 ); /* timeout */
261 }
262 return( 0 );
263 }
264
265
266 /*
267 * Wait until PM IC is free
268 */
269 int
270 pm_wait_free(delay)
271 int delay;
272 {
273 while(PM_IS_OFF) {
274 #ifdef PM_GRAB_SI
275 zshard(0); /* grab any serial interrupts */
276 #endif
277 if ((--delay) < 0)
278 return( 0 ); /* timeout */
279 }
280 return( 1 );
281 }
282
283
284
285 /*
286 * Functions for the PB1XX series
287 */
288
289 /*
290 * Receive data from PM for the PB1XX series
291 */
292 int
293 pm_receive_pm1(data)
294 u_char *data;
295 {
296 int rval = 0xffffcd34;
297
298 via_reg(VIA2, vDirA) = 0x00;
299
300 switch( 1 ) {
301 default:
302 if (pm_wait_busy( 0x40 ) != 0)
303 break; /* timeout */
304
305 PM_SET_STATE_ACKOFF();
306 *data = via_reg(VIA2, 0x200);
307
308 rval = 0xffffcd33;
309 if (pm_wait_free( 0x40 ) == 0)
310 break; /* timeout */
311
312 rval = 0x00;
313 break;
314 }
315
316 PM_SET_STATE_ACKON();
317 via_reg(VIA2, vDirA) = 0x00;
318
319 return( rval );
320 }
321
322
323
324 /*
325 * Send data to PM for the PB1XX series
326 */
327 int
328 pm_send_pm1(data, delay)
329 u_char data;
330 int delay;
331 {
332 int rval;
333
334 via_reg(VIA2, vDirA) = 0xff;
335 via_reg(VIA2, 0x200) = data;
336
337 PM_SET_STATE_ACKOFF();
338 if (pm_wait_busy( 0x400 ) != 0) {
339 PM_SET_STATE_ACKON();
340 via_reg(VIA2, vDirA) = 0x00;
341
342 return( 0xffffcd36 );
343 }
344
345 rval = 0x0;
346 PM_SET_STATE_ACKON();
347 if (pm_wait_free( 0x40 ) == 0)
348 rval = 0xffffcd35;
349
350 PM_SET_STATE_ACKON();
351 via_reg(VIA2, vDirA) = 0x00;
352
353 return( rval );
354 }
355
356
357 /*
358 * My PMgrOp routine for the PB1XX series
359 */
360 int
361 pm_pmgrop_pm1(pmdata)
362 PMData *pmdata;
363 {
364 int i;
365 int s = 0x81815963;
366 u_char via1_vIER, via1_vDirA;
367 int rval = 0;
368 int num_pm_data = 0;
369 u_char pm_cmd;
370 u_char pm_data;
371 u_char *pm_buf;
372
373 /* disable all inetrrupts but PM */
374 via1_vIER = via_reg(VIA1, vIER);
375 PM_VIA_INTR_DISABLE();
376
377 via1_vDirA = via_reg(VIA1, vDirA);
378
379 switch( pmdata->command ) {
380 default:
381 for( i=0; i<7; i++ ) {
382 via_reg(VIA2, vDirA) = 0x00;
383
384 /* wait until PM is free */
385 if (pm_wait_free( ADBDelay ) == 0) { /* timeout */
386 via_reg(VIA2, vDirA) = 0x00;
387 /* restore formar value */
388 via_reg(VIA1, vDirA) = via1_vDirA;
389 via_reg(VIA1, vIER) = via1_vIER;
390 return( 0xffffcd38 );
391 }
392
393 switch( mac68k_machine.machineid ) {
394 case MACH_MACPB160:
395 case MACH_MACPB165:
396 case MACH_MACPB165C:
397 case MACH_MACPB180:
398 case MACH_MACPB180C:
399 {
400 int delay = ADBDelay * 16;
401
402 via_reg(VIA2, vDirA) = 0x00;
403 while((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
404 delay--;
405
406 if (delay < 0) { /* timeout */
407 via_reg(VIA2, vDirA) = 0x00;
408 /* restore formar value */
409 via_reg(VIA1, vIER) = via1_vIER;
410 return( 0xffffcd38 );
411 }
412 }
413 } /* end switch */
414
415 s=splhigh();
416
417 via1_vDirA = via_reg(VIA1, vDirA);
418 via_reg(VIA1, vDirA) &= 0x7f;
419
420 pm_cmd = (u_char)(pmdata->command & 0xff);
421 if ((rval = pm_send_pm1( pm_cmd, ADBDelay*8 )) == 0) /* succeeded to send PM command */
422 break;
423
424 via_reg(VIA1, vDirA) = via1_vDirA;
425 splx(s);
426 } /* end for */
427
428 /* failed to send a command */
429 if (i == 7) {
430 via_reg(VIA2, vDirA) = 0x00;
431 /* restore formar value */
432 via_reg(VIA1, vDirA) = via1_vDirA;
433 via_reg(VIA1, vIER) = via1_vIER;
434 return( 0xffffcd38 );
435 }
436
437 /* send # of PM data */
438 num_pm_data = pmdata->num_data;
439 if ((rval = pm_send_pm1( (u_char)(num_pm_data & 0xff), ADBDelay*8 )) != 0)
440 break; /* timeout */
441
442 /* send PM data */
443 pm_buf = (u_char *)pmdata->s_buf;
444 for( i=0; i<num_pm_data; i++ )
445 if((rval = pm_send_pm1( pm_buf[i], ADBDelay*8 )) != 0)
446 break; /* timeout */
447 if ((i != num_pm_data) && (num_pm_data != 0))
448 break; /* timeout */
449
450 /* Will PM IC return data? */
451 if ((pm_cmd & 0x08) == 0) {
452 rval = 0;
453 break; /* no returned data */
454 }
455
456 rval = 0xffffcd37;
457 if (pm_wait_busy( ADBDelay ) != 0)
458 break; /* timeout */
459
460 /* receive PM command */
461 if ((rval = pm_receive_pm1( &pm_data )) != 0)
462 break;
463
464 pmdata->command = pm_data;
465
466 /* receive number of PM data */
467 if ((rval = pm_receive_pm1( &pm_data )) != 0)
468 break; /* timeout */
469 num_pm_data = pm_data;
470 pmdata->num_data = num_pm_data;
471
472 /* receive PM data */
473 pm_buf = (u_char *)pmdata->r_buf;
474 for( i=0; i<num_pm_data; i++ ) {
475 if ((rval = pm_receive_pm1( &pm_data )) != 0)
476 break; /* timeout */
477 pm_buf[i] = pm_data;
478 }
479
480 rval = 0;
481 }
482
483 via_reg(VIA2, vDirA) = 0x00;
484
485 /* restore formar value */
486 via_reg(VIA1, vDirA) = via1_vDirA;
487 via_reg(VIA1, vIER) = via1_vIER;
488 if (s != 0x81815963)
489 splx(s);
490
491 return( rval );
492 }
493
494
495 /*
496 * My PM interrupt routine for PB100-series
497 */
498 void
499 pm_intr_pm1(void)
500 {
501 int s;
502 int rval;
503 PMData pmdata;
504
505 s = splhigh();
506
507 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
508
509 /* ask PM what happend */
510 pmdata.command = 0x78;
511 pmdata.num_data = 0;
512 pmdata.data[0] = pmdata.data[1] = 0;
513 pmdata.s_buf = &pmdata.data[2];
514 pmdata.r_buf = &pmdata.data[2];
515 rval = pm_pmgrop_pm1( &pmdata );
516 if (rval != 0) {
517 #ifdef PM_DEBUG
518 printf( "pm: PM is not ready. error code=%08x\n", rval );
519 #endif
520 splx(s);
521 }
522
523 if ((pmdata.data[2] & 0x10) == 0x10) {
524 if ((pmdata.data[2] & 0x0f) == 0) { /* ADB data that were requested by TALK command */
525 pm_adb_get_TALK_result(&pmdata);
526 } else if ((pmdata.data[2] & 0x08) == 0x8) { /* PM is requesting to poll */
527 pm_adb_poll_next_device_pm1(&pmdata);
528 } else if ((pmdata.data[2] & 0x04) == 0x4) { /* ADB device event */
529 pm_adb_get_ADB_data(&pmdata);
530 }
531 } else {
532 #ifdef PM_DEBUG
533 pm_printerr( "driver does not supported this event.", rval, pmdata.num_data, pmdata.data );
534 #endif
535 }
536
537 splx(s);
538 }
539
540
541
542 /*
543 * Functions for the PB Duo series and the PB 5XX series
544 */
545
546 /*
547 * Receive data from PM for the PB Duo series and the PB 5XX series
548 */
549 int
550 pm_receive_pm2(data)
551 u_char *data;
552 {
553 int i;
554 int rval;
555
556 rval = 0xffffcd34;
557
558 switch( 1 ) {
559 default:
560 /* set VIA SR to input mode */
561 via_reg(VIA1, vACR) |= 0x0c;
562 via_reg(VIA1, vACR) &= ~0x10;
563 i = PM_SR();
564
565 PM_SET_STATE_ACKOFF();
566 if (pm_wait_busy((int)ADBDelay*32) != 0)
567 break; /* timeout */
568
569 PM_SET_STATE_ACKON();
570 rval = 0xffffcd33;
571 if (pm_wait_free((int)ADBDelay*32) == 0)
572 break; /* timeout */
573
574 *data = PM_SR();
575 rval = 0;
576
577 break;
578 }
579
580 PM_SET_STATE_ACKON();
581 via_reg(VIA1, vACR) |= 0x1c;
582
583 return( rval );
584 }
585
586
587
588 /*
589 * Send data to PM for the PB Duo series and the PB 5XX series
590 */
591 int
592 pm_send_pm2(data)
593 u_char data;
594 {
595 int rval;
596
597 via_reg(VIA1, vACR) |= 0x1c;
598 PM_SR() = data;
599
600 PM_SET_STATE_ACKOFF();
601 rval = 0xffffcd36;
602 if (pm_wait_busy((int)ADBDelay*32) != 0) {
603 PM_SET_STATE_ACKON();
604
605 via_reg(VIA1, vACR) |= 0x1c;
606
607 return( rval );
608 }
609
610 PM_SET_STATE_ACKON();
611 rval = 0xffffcd35;
612 if (pm_wait_free((int)ADBDelay*32) != 0)
613 rval = 0;
614
615 PM_SET_STATE_ACKON();
616 via_reg(VIA1, vACR) |= 0x1c;
617
618 return( rval );
619 }
620
621
622
623 /*
624 * My PMgrOp routine for the PB Duo series and the PB 5XX series
625 */
626 int
627 pm_pmgrop_pm2(pmdata)
628 PMData *pmdata;
629 {
630 int i;
631 int s;
632 u_char via1_vIER;
633 int rval = 0;
634 int num_pm_data = 0;
635 u_char pm_cmd;
636 short pm_num_rx_data;
637 u_char pm_data;
638 u_char *pm_buf;
639
640 s=splhigh();
641
642 /* disable all inetrrupts but PM */
643 via1_vIER = 0x10;
644 via1_vIER &= via_reg(VIA1, vIER);
645 via_reg(VIA1, vIER) = via1_vIER;
646 if (via1_vIER != 0x0)
647 via1_vIER |= 0x80;
648
649 switch( pmdata->command ) {
650 default:
651 /* wait until PM is free */
652 pm_cmd = (u_char)(pmdata->command & 0xff);
653 rval = 0xcd38;
654 if (pm_wait_free( ADBDelay * 4 ) == 0)
655 break; /* timeout */
656
657 if (HwCfgFlags3 & 0x00200000) { /* PB 160, PB 165(c), PB 180(c) ? */
658 int delay = ADBDelay * 16;
659
660 via_reg(VIA2, vDirA) = 0x00;
661 while((via_reg(VIA2, 0x200) == 0x07) && (delay >= 0))
662 delay--;
663
664 if (delay < 0) {
665 rval = 0xffffcd38;
666 break; /* timeout */
667 }
668 }
669
670 /* send PM command */
671 if ((rval = pm_send_pm2( (u_char)(pm_cmd & 0xff) )))
672 break; /* timeout */
673
674 /* send number of PM data */
675 num_pm_data = pmdata->num_data;
676 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
677 if (pm_send_cmd_type[pm_cmd] < 0) {
678 if ((rval = pm_send_pm2( (u_char)(num_pm_data & 0xff) )) != 0)
679 break; /* timeout */
680 pmdata->command = 0;
681 }
682 } else { /* PB 1XX series ? */
683 if ((rval = pm_send_pm2( (u_char)(num_pm_data & 0xff) )) != 0)
684 break; /* timeout */
685 }
686 /* send PM data */
687 pm_buf = (u_char *)pmdata->s_buf;
688 for( i=0; i<num_pm_data; i++ )
689 if((rval = pm_send_pm2( pm_buf[i] )) != 0)
690 break; /* timeout */
691 if (i != num_pm_data)
692 break; /* timeout */
693
694
695 /* check if PM will send me data */
696 pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
697 pmdata->num_data = pm_num_rx_data;
698 if (pm_num_rx_data == 0) {
699 rval = 0;
700 break; /* no return data */
701 }
702
703 /* receive PM command */
704 pm_data = pmdata->command;
705 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
706 pm_num_rx_data--;
707 if (pm_num_rx_data == 0)
708 if ((rval = pm_receive_pm2( &pm_data )) != 0) {
709 rval = 0xffffcd37;
710 break;
711 }
712 pmdata->command = pm_data;
713 } else { /* PB 1XX series ? */
714 if ((rval = pm_receive_pm2( &pm_data )) != 0) {
715 rval = 0xffffcd37;
716 break;
717 }
718 pmdata->command = pm_data;
719 }
720
721 /* receive number of PM data */
722 if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
723 if (pm_num_rx_data < 0) {
724 if ((rval = pm_receive_pm2( &pm_data )) != 0)
725 break; /* timeout */
726 num_pm_data = pm_data;
727 } else
728 num_pm_data = pm_num_rx_data;
729 pmdata->num_data = num_pm_data;
730 } else { /* PB 1XX serias ? */
731 if ((rval = pm_receive_pm2( &pm_data )) != 0)
732 break; /* timeout */
733 num_pm_data = pm_data;
734 pmdata->num_data = num_pm_data;
735 }
736
737 /* receive PM data */
738 pm_buf = (u_char *)pmdata->r_buf;
739 for( i=0; i<num_pm_data; i++ ) {
740 if ((rval = pm_receive_pm2( &pm_data )) != 0)
741 break; /* timeout */
742 pm_buf[i] = pm_data;
743 }
744
745 rval = 0;
746 }
747
748 /* restore former value */
749 via_reg(VIA1, vIER) = via1_vIER;
750 splx(s);
751
752 return( rval );
753 }
754
755
756 /*
757 * My PM interrupt routine for the PB Duo series and the PB 5XX series
758 */
759 void
760 pm_intr_pm2(void)
761 {
762 int s;
763 int rval;
764 PMData pmdata;
765
766 s = splhigh();
767
768 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
769 /* ask PM what happend */
770 pmdata.command = 0x78;
771 pmdata.num_data = 0;
772 pmdata.s_buf = &pmdata.data[2];
773 pmdata.r_buf = &pmdata.data[2];
774 rval = pm_pmgrop_pm2( &pmdata );
775 if (rval != 0) {
776 #ifdef PM_DEBUG
777 printf( "pm: PM is not ready. error code: %08x\n", rval );
778 #endif
779 splx(s);
780 }
781
782 switch( (u_int)(pmdata.data[2] & 0xff) ) {
783 case 0x00: /* 1 sec interrupt? */
784 {
785 break;
786 }
787 case 0x80: /* 1 sec interrupt? */
788 {
789 pm_counter++;
790 break;
791 }
792 case 0x08: /* Brightness/Contrast button on LCD panel */
793 {
794 /* get brightness and contrast of the LCD */
795 pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
796 pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
797 /*
798 pm_printerr( "#08", rval, pmdata.num_data, pmdata.data );
799 pmdata.command = 0x33;
800 pmdata.num_data = 1;
801 pmdata.s_buf = pmdata.data;
802 pmdata.r_buf = pmdata.data;
803 pmdata.data[0] = pm_LCD_contrast;
804 rval = pm_pmgrop_pm2( &pmdata );
805 pm_printerr( "#33", rval, pmdata.num_data, pmdata.data );
806 */
807 /* this is an experimental code */
808 pmdata.command = 0x41;
809 pmdata.num_data = 1;
810 pmdata.s_buf = pmdata.data;
811 pmdata.r_buf = pmdata.data;
812 pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
813 if (pm_LCD_brightness < 0x25) pm_LCD_brightness = 0x25;
814 if (pm_LCD_brightness > 0x5a) pm_LCD_brightness = 0x7f;
815 pmdata.data[0] = pm_LCD_brightness;
816 rval = pm_pmgrop_pm2( &pmdata );
817 break;
818 }
819 /* ADB data that were requested by TALK command */
820 case 0x10:
821 case 0x14:
822 pm_adb_get_TALK_result(&pmdata);
823 break;
824 /* ADB device event */
825 case 0x16:
826 case 0x18:
827 case 0x1e:
828 pm_adb_get_ADB_data(&pmdata);
829 break;
830 default:
831 {
832 #ifdef PM_DEBUG
833 pm_printerr( "driver does not supported this event.", pmdata.data[2], pmdata.num_data, pmdata.data );
834 #endif
835 }
836 break;
837 }
838
839 splx(s);
840 }
841
842
843 /*
844 * MRG-based PMgrOp routine
845 */
846 int
847 pm_pmgrop_mrg(pmdata)
848 PMData *pmdata;
849 {
850 u_int32_t rval=0;
851
852 asm("
853 movl %1, a0
854 .word 0xa085
855 movl d0, %0"
856 : "=g" (rval)
857 : "g" (pmdata)
858 : "a0", "d0" );
859
860 return rval;
861 }
862
863
864 /*
865 * My PMgrOp routine
866 */
867 int
868 pmgrop(pmdata)
869 PMData *pmdata;
870 {
871 switch( pmHardware ) {
872 case PM_HW_PB1XX:
873 {
874 return( pm_pmgrop_pm1(pmdata) );
875 break;
876 }
877 case PM_HW_PB5XX:
878 {
879 return( pm_pmgrop_pm2(pmdata) );
880 break;
881 }
882 default:
883 /* return( pmgrop_mrg(pmdata) ); */
884 return( -1 );
885 }
886 }
887
888
889 /*
890 * My PM interrupt routine
891 */
892 void
893 pm_intr(void)
894 {
895 switch( pmHardware ) {
896 case PM_HW_PB1XX:
897 {
898 pm_intr_pm1();
899 break;
900 }
901 case PM_HW_PB5XX:
902 {
903 pm_intr_pm2();
904 break;
905 }
906 default:
907 break;
908 }
909 }
910
911
912
913 /*
914 * Synchronous ADBOp routine for the Power Manager
915 */
916 int
917 pm_adb_op(buffer, compRout, data, command)
918 u_char *buffer;
919 void *compRout;
920 void *data;
921 int command;
922 {
923 int i,len;
924 int s;
925 int rval;
926 int delay;
927 PMData pmdata;
928
929 if (adbWaiting == 1)
930 return( -1 );
931
932 s = splhigh();
933 via_reg(VIA1, vIER) = 0x10;
934
935 adbBuffer = buffer;
936 adbCompRout = compRout;
937 adbCompData = data;
938
939 pmdata.command = 0x20;
940 pmdata.s_buf = pmdata.data;
941 pmdata.r_buf = pmdata.data;
942
943 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, add number of ADB data to number of PM data */
944 if (buffer != (u_char *)0)
945 pmdata.num_data = buffer[0] + 3;
946 } else {
947 pmdata.num_data = 3;
948 }
949
950 pmdata.data[0] = (u_char)(command & 0xff);
951 pmdata.data[1] = 0;
952 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */
953 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
954 pmdata.data[2] = buffer[0]; /* number of data */
955 for( i=0; i<buffer[0]; i++ )
956 pmdata.data[3 + i] = buffer[1 + i];
957 } else
958 pmdata.data[2] = 0;
959 } else
960 pmdata.data[2] = 0;
961
962 rval = pmgrop( &pmdata );
963 if (rval != 0)
964 return( -1 );
965
966 if (adbWaiting == 0) {
967 adbWaiting = 1;
968 adbWaitingCmd = command;
969 }
970
971 PM_VIA_INTR_ENABLE();
972
973 /* wait until the PM interrupt is occured */
974 delay = 0x80000;
975 while(adbWaiting == 1) {
976 if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
977 pm_intr();
978 #ifdef PM_GRAB_SI
979 zshard(0); /* grab any serial interrupts */
980 #endif
981 if ((--delay) < 0)
982 return( -1 );
983 }
984
985 if (buffer != (u_char *)0) {
986 len = adbInputBuffer[3];
987 for (i=0; i<=len; i++)
988 buffer[i] = adbInputBuffer[3 + i];
989 if (len < 0)
990 buffer[0] = 0;
991 }
992
993 /* this command enables the interrupt by operating ADB devices */
994 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 500 series */
995 pmdata.command = 0x20;
996 pmdata.num_data = 4;
997 pmdata.s_buf = pmdata.data;
998 pmdata.r_buf = pmdata.data;
999 pmdata.data[0] = 0x00;
1000 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
1001 pmdata.data[2] = 0x00;
1002 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
1003 } else { /* PB 100-series */
1004 pmdata.command = 0x20;
1005 pmdata.num_data = 3;
1006 pmdata.s_buf = pmdata.data;
1007 pmdata.r_buf = pmdata.data;
1008 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1009 pmdata.data[1] = 0x04;
1010 pmdata.data[2] = 0x00;
1011 }
1012 rval = pmgrop( &pmdata );
1013
1014 splx(s);
1015 return( rval );
1016 }
1017
1018
1019 void
1020 pm_adb_get_TALK_result(pmdata)
1021 PMData *pmdata;
1022 {
1023 int i;
1024 int rx_pm_adb_cmd;
1025
1026 rx_pm_adb_cmd = (u_int)pmdata->data[3] & 0xff;
1027
1028 pmdata->data[2] &= 0xf;
1029 pmdata->data[1] = pmdata->data[3];
1030 pmdata->data[3] = pmdata->num_data - 2;
1031
1032 adbInputBuffer[0] = pmdata->num_data + 1;
1033 for( i=1; i<pmdata->num_data+2; i++ )
1034 adbInputBuffer[i] = pmdata->data[i];
1035
1036 if ((adbWaiting == 1) && (rx_pm_adb_cmd == adbWaitingCmd)) {
1037 if (adbStarting == 0)
1038 adb_complete( &pmdata->data[3] , (long)0, adbWaitingCmd );
1039 adbWaitingCmd = 0x0;
1040
1041 adbWaiting = 0;
1042 adb_comp_exec();
1043 adbBuffer = (long)0;
1044 adbCompRout = (long)0;
1045 adbCompData = (long)0;
1046 }
1047 }
1048
1049
1050 void
1051 pm_adb_get_ADB_data(pmdata)
1052 PMData *pmdata;
1053 {
1054 int i;
1055
1056 i = (u_int)pmdata->data[3] & 0xff;
1057 pmdata->data[2] &= 0xf;
1058 pmdata->data[1] = pmdata->data[3];
1059 pmdata->data[3] = pmdata->num_data - 2;
1060
1061 adbInputBuffer[0] = pmdata->num_data + 1;
1062 if (adbStarting == 0)
1063 adb_complete( &pmdata->data[3] , (long)0, i );
1064 }
1065
1066
1067 void
1068 pm_adb_poll_next_device_pm1(pmdata)
1069 PMData *pmdata;
1070 {
1071 int i;
1072 int ndid;
1073 u_short bendid = 0x1;
1074 int rval;
1075 PMData tmp_pmdata;
1076
1077 /* find another existent ADB device to poll */
1078 for( i=1; i<16; i++ ) {
1079 ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf;
1080 bendid <<= ndid;
1081 if ((pm_existent_ADB_devices & bendid) != 0)
1082 break;
1083 }
1084
1085 /* poll the other device */
1086 tmp_pmdata.command = 0x20;
1087 tmp_pmdata.num_data = 3;
1088 tmp_pmdata.s_buf = tmp_pmdata.data;
1089 tmp_pmdata.r_buf = tmp_pmdata.data;
1090 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1091 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */
1092 tmp_pmdata.data[2] = 0x00;
1093 rval = pmgrop( &tmp_pmdata );
1094 }
1095
1096
1097