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