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