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