pm_direct.c revision 1.14 1 /* $NetBSD: pm_direct.c,v 1.14 2000/07/03 08:59:27 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, timo)
389 u_char data;
390 int timo;
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 0
399 if (pm_wait_busy(0x400) == 0) {
400 #else
401 if (pm_wait_busy(timo) == 0) {
402 #endif
403 PM_SET_STATE_ACKON();
404 if (pm_wait_free(0x40) != 0)
405 rval = 0x0;
406 else
407 rval = 0xffffcd35;
408 } else {
409 rval = 0xffffcd36;
410 }
411
412 PM_SET_STATE_ACKON();
413 via_reg(VIA2, vDirA) = 0x00;
414
415 return rval;
416 }
417
418
419 /*
420 * My PMgrOp routine for the PB1XX series
421 */
422 int
423 pm_pmgrop_pm1(pmdata)
424 PMData *pmdata;
425 {
426 int i;
427 int s = 0x81815963;
428 u_char via1_vIER, via1_vDirA;
429 int rval = 0;
430 int num_pm_data = 0;
431 u_char pm_cmd;
432 u_char pm_data;
433 u_char *pm_buf;
434
435 /* disable all inetrrupts but PM */
436 via1_vIER = via_reg(VIA1, vIER);
437 PM_VIA_INTR_DISABLE();
438
439 via1_vDirA = via_reg(VIA1, vDirA);
440
441 switch (pmdata->command) {
442 default:
443 for (i = 0; i < 7; i++) {
444 via_reg(VIA2, vDirA) = 0x00;
445
446 /* wait until PM is free */
447 if (pm_wait_free(ADBDelay) == 0) { /* timeout */
448 via_reg(VIA2, vDirA) = 0x00;
449 /* restore formar value */
450 via_reg(VIA1, vDirA) = via1_vDirA;
451 via_reg(VIA1, vIER) = via1_vIER;
452 return 0xffffcd38;
453 }
454
455 switch (mac68k_machine.machineid) {
456 case MACH_MACPB160:
457 case MACH_MACPB165:
458 case MACH_MACPB165C:
459 case MACH_MACPB170:
460 case MACH_MACPB180:
461 case MACH_MACPB180C:
462 {
463 int delay = ADBDelay * 16;
464
465 via_reg(VIA2, vDirA) = 0x00;
466 while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
467 delay--;
468
469 if (delay < 0) { /* timeout */
470 via_reg(VIA2, vDirA) = 0x00;
471 /* restore formar value */
472 via_reg(VIA1, vIER) = via1_vIER;
473 return 0xffffcd38;
474 }
475 }
476 } /* end switch */
477
478 s = splhigh();
479
480 via1_vDirA = via_reg(VIA1, vDirA);
481 via_reg(VIA1, vDirA) &= 0x7f;
482
483 pm_cmd = (u_char)(pmdata->command & 0xff);
484 if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
485 break; /* send command succeeded */
486
487 via_reg(VIA1, vDirA) = via1_vDirA;
488 splx(s);
489 } /* end for */
490
491 /* failed to send a command */
492 if (i == 7) {
493 via_reg(VIA2, vDirA) = 0x00;
494 /* restore formar value */
495 via_reg(VIA1, vDirA) = via1_vDirA;
496 via_reg(VIA1, vIER) = via1_vIER;
497 if (s != 0x81815963)
498 splx(s);
499 return 0xffffcd38;
500 }
501
502 /* send # of PM data */
503 num_pm_data = pmdata->num_data;
504 if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
505 break; /* timeout */
506
507 /* send PM data */
508 pm_buf = (u_char *)pmdata->s_buf;
509 for (i = 0; i < num_pm_data; i++)
510 if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
511 break; /* timeout */
512 if ((i != num_pm_data) && (num_pm_data != 0))
513 break; /* timeout */
514
515 /* Will PM IC return data? */
516 if ((pm_cmd & 0x08) == 0) {
517 rval = 0;
518 break; /* no returned data */
519 }
520
521 rval = 0xffffcd37;
522 if (pm_wait_busy(ADBDelay) != 0)
523 break; /* timeout */
524
525 /* receive PM command */
526 if ((rval = pm_receive_pm1(&pm_data)) != 0)
527 break;
528
529 pmdata->command = pm_data;
530
531 /* receive number of PM data */
532 if ((rval = pm_receive_pm1(&pm_data)) != 0)
533 break; /* timeout */
534 num_pm_data = pm_data;
535 pmdata->num_data = num_pm_data;
536
537 /* receive PM data */
538 pm_buf = (u_char *)pmdata->r_buf;
539 for (i = 0; i < num_pm_data; i++) {
540 if ((rval = pm_receive_pm1(&pm_data)) != 0)
541 break; /* timeout */
542 pm_buf[i] = pm_data;
543 }
544
545 rval = 0;
546 }
547
548 via_reg(VIA2, vDirA) = 0x00;
549
550 /* restore formar value */
551 via_reg(VIA1, vDirA) = via1_vDirA;
552 via_reg(VIA1, vIER) = via1_vIER;
553 if (s != 0x81815963)
554 splx(s);
555
556 return rval;
557 }
558
559
560 /*
561 * My PM interrupt routine for PB1XX series
562 */
563 void
564 pm_intr_pm1(arg)
565 void *arg;
566 {
567 int s;
568 int rval;
569 PMData pmdata;
570
571 s = splhigh();
572
573 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
574
575 /* ask PM what happend */
576 pmdata.command = 0x78;
577 pmdata.num_data = 0;
578 pmdata.data[0] = pmdata.data[1] = 0;
579 pmdata.s_buf = &pmdata.data[2];
580 pmdata.r_buf = &pmdata.data[2];
581 rval = pm_pmgrop_pm1(&pmdata);
582 if (rval != 0) {
583 #ifdef ADB_DEBUG
584 if (adb_debug)
585 printf("pm: PM is not ready. error code=%08x\n", rval);
586 #endif
587 splx(s);
588 }
589
590 if ((pmdata.data[2] & 0x10) == 0x10) {
591 if ((pmdata.data[2] & 0x0f) == 0) {
592 /* ADB data that were requested by TALK command */
593 pm_adb_get_TALK_result(&pmdata);
594 } else if ((pmdata.data[2] & 0x08) == 0x8) {
595 /* PM is requesting to poll */
596 pm_adb_poll_next_device_pm1(&pmdata);
597 } else if ((pmdata.data[2] & 0x04) == 0x4) {
598 /* ADB device event */
599 pm_adb_get_ADB_data(&pmdata);
600 }
601 } else {
602 #ifdef ADB_DEBUG
603 if (adb_debug)
604 pm_printerr("driver does not supported this event.",
605 rval, pmdata.num_data, pmdata.data);
606 #endif
607 }
608
609 splx(s);
610 }
611
612
613
614 /*
615 * Functions for the PB Duo series and the PB 5XX series
616 */
617
618 /*
619 * Receive data from PM for the PB Duo series and the PB 5XX series
620 */
621 int
622 pm_receive_pm2(data)
623 u_char *data;
624 {
625 int i;
626 int rval;
627
628 rval = 0xffffcd34;
629
630 switch (1) {
631 default:
632 /* set VIA SR to input mode */
633 via_reg(VIA1, vACR) |= 0x0c;
634 via_reg(VIA1, vACR) &= ~0x10;
635 i = PM_SR();
636
637 PM_SET_STATE_ACKOFF();
638 if (pm_wait_busy((int)ADBDelay*32) != 0)
639 break; /* timeout */
640
641 PM_SET_STATE_ACKON();
642 rval = 0xffffcd33;
643 if (pm_wait_free((int)ADBDelay*32) == 0)
644 break; /* timeout */
645
646 *data = PM_SR();
647 rval = 0;
648
649 break;
650 }
651
652 PM_SET_STATE_ACKON();
653 via_reg(VIA1, vACR) |= 0x1c;
654
655 return rval;
656 }
657
658
659
660 /*
661 * Send data to PM for the PB Duo series and the PB 5XX series
662 */
663 int
664 pm_send_pm2(data)
665 u_char data;
666 {
667 int rval;
668
669 via_reg(VIA1, vACR) |= 0x1c;
670 PM_SR() = data;
671
672 PM_SET_STATE_ACKOFF();
673 if (pm_wait_busy((int)ADBDelay*32) == 0) {
674 PM_SET_STATE_ACKON();
675 if (pm_wait_free((int)ADBDelay*32) != 0)
676 rval = 0;
677 else
678 rval = 0xffffcd35;
679 } else {
680 rval = 0xffffcd36;
681 }
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(arg)
831 void *arg;
832 {
833 int s;
834 int rval;
835 PMData pmdata;
836
837 s = splhigh();
838
839 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
840 /* ask PM what happend */
841 pmdata.command = 0x78;
842 pmdata.num_data = 0;
843 pmdata.s_buf = &pmdata.data[2];
844 pmdata.r_buf = &pmdata.data[2];
845 rval = pm_pmgrop_pm2(&pmdata);
846 if (rval != 0) {
847 #ifdef ADB_DEBUG
848 if (adb_debug)
849 printf("pm: PM is not ready. error code: %08x\n", rval);
850 #endif
851 splx(s);
852 }
853
854 switch ((u_int)(pmdata.data[2] & 0xff)) {
855 case 0x00: /* 1 sec interrupt? */
856 break;
857 case 0x80: /* 1 sec interrupt? */
858 pm_counter++;
859 break;
860 case 0x08: /* Brightness/Contrast button on LCD panel */
861 /* get brightness and contrast of the LCD */
862 pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
863 pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
864 /*
865 pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
866 pmdata.command = 0x33;
867 pmdata.num_data = 1;
868 pmdata.s_buf = pmdata.data;
869 pmdata.r_buf = pmdata.data;
870 pmdata.data[0] = pm_LCD_contrast;
871 rval = pm_pmgrop_pm2(&pmdata);
872 pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
873 */
874 /* this is an experimental code */
875 pmdata.command = 0x41;
876 pmdata.num_data = 1;
877 pmdata.s_buf = pmdata.data;
878 pmdata.r_buf = pmdata.data;
879 pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
880 if (pm_LCD_brightness < 0x25)
881 pm_LCD_brightness = 0x25;
882 if (pm_LCD_brightness > 0x5a)
883 pm_LCD_brightness = 0x7f;
884 pmdata.data[0] = pm_LCD_brightness;
885 rval = pm_pmgrop_pm2(&pmdata);
886 break;
887 case 0x10: /* ADB data that were requested by TALK command */
888 case 0x14:
889 pm_adb_get_TALK_result(&pmdata);
890 break;
891 case 0x16: /* ADB device event */
892 case 0x18:
893 case 0x1e:
894 pm_adb_get_ADB_data(&pmdata);
895 break;
896 default:
897 #ifdef ADB_DEBUG
898 if (adb_debug)
899 pm_printerr("driver does not supported this event.",
900 pmdata.data[2], pmdata.num_data,
901 pmdata.data);
902 #endif
903 break;
904 }
905
906 splx(s);
907 }
908
909
910 /*
911 * MRG-based PMgrOp routine
912 */
913 int
914 pm_pmgrop_mrg(pmdata)
915 PMData *pmdata;
916 {
917 u_int32_t rval=0;
918
919 asm("
920 movl %1, a0
921 .word 0xa085
922 movl d0, %0"
923 : "=g" (rval)
924 : "g" (pmdata)
925 : "a0", "d0" );
926
927 return rval;
928 }
929
930
931 /*
932 * My PMgrOp routine
933 */
934 int
935 pmgrop(pmdata)
936 PMData *pmdata;
937 {
938 switch (pmHardware) {
939 case PM_HW_PB1XX:
940 return (pm_pmgrop_pm1(pmdata));
941 break;
942 case PM_HW_PB5XX:
943 return (pm_pmgrop_pm2(pmdata));
944 break;
945 default:
946 /* return (pmgrop_mrg(pmdata)); */
947 return 1;
948 }
949 }
950
951
952 /*
953 * My PM interrupt routine
954 */
955 void
956 pm_intr(arg)
957 void *arg;
958 {
959 switch (pmHardware) {
960 case PM_HW_PB1XX:
961 pm_intr_pm1(arg);
962 break;
963 case PM_HW_PB5XX:
964 pm_intr_pm2(arg);
965 break;
966 default:
967 break;
968 }
969 }
970
971
972 void
973 pm_hw_setup()
974 {
975 switch (pmHardware) {
976 case PM_HW_PB1XX:
977 via1_register_irq(4, pm_intr_pm1, (void *)0);
978 PM_VIA_CLR_INTR();
979 break;
980 case PM_HW_PB5XX:
981 via1_register_irq(4, pm_intr_pm2, (void *)0);
982 PM_VIA_CLR_INTR();
983 break;
984 default:
985 break;
986 }
987 }
988
989
990 /*
991 * Synchronous ADBOp routine for the Power Manager
992 */
993 int
994 pm_adb_op(buffer, compRout, data, command)
995 u_char *buffer;
996 void *compRout;
997 void *data;
998 int command;
999 {
1000 int i;
1001 int s;
1002 int rval;
1003 int delay;
1004 PMData pmdata;
1005 struct adbCommand packet;
1006
1007 if (adbWaiting == 1)
1008 return 1;
1009
1010 s = splhigh();
1011 via_reg(VIA1, vIER) = 0x10;
1012
1013 adbBuffer = buffer;
1014 adbCompRout = compRout;
1015 adbCompData = data;
1016
1017 pmdata.command = 0x20;
1018 pmdata.s_buf = pmdata.data;
1019 pmdata.r_buf = pmdata.data;
1020
1021 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, add number of ADB data to number of PM data */
1022 if (buffer != (u_char *)0)
1023 pmdata.num_data = buffer[0] + 3;
1024 } else {
1025 pmdata.num_data = 3;
1026 }
1027
1028 pmdata.data[0] = (u_char)(command & 0xff);
1029 pmdata.data[1] = 0;
1030 if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */
1031 if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1032 pmdata.data[2] = buffer[0]; /* number of data */
1033 for (i = 0; i < buffer[0]; i++)
1034 pmdata.data[3 + i] = buffer[1 + i];
1035 } else
1036 pmdata.data[2] = 0;
1037 } else
1038 pmdata.data[2] = 0;
1039
1040 if ((command & 0xc) != 0xc) { /* if the command is not TALK */
1041 /* set up stuff fNULLor adb_pass_up */
1042 packet.data[0] = 1 + pmdata.data[2];
1043 packet.data[1] = command;
1044 for (i = 0; i < pmdata.data[2]; i++)
1045 packet.data[i+2] = pmdata.data[i+3];
1046 packet.saveBuf = adbBuffer;
1047 packet.compRout = adbCompRout;
1048 packet.compData = adbCompData;
1049 packet.cmd = command;
1050 packet.unsol = 0;
1051 packet.ack_only = 1;
1052 adb_polling = 1;
1053 adb_pass_up(&packet);
1054 adb_polling = 0;
1055 }
1056
1057 rval = pmgrop(&pmdata);
1058 if (rval != 0) {
1059 splx(s);
1060 return 1;
1061 }
1062
1063 adbWaiting = 1;
1064 adbWaitingCmd = command;
1065
1066 PM_VIA_INTR_ENABLE();
1067
1068 /* wait until the PM interrupt is occured */
1069 delay = 0x80000;
1070 while (adbWaiting == 1) {
1071 if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
1072 pm_intr((void *)0);
1073 #ifdef PM_GRAB_SI
1074 #if 0
1075 zshard(0); /* grab any serial interrupts */
1076 #else
1077 (void)intr_dispatch(0x70);
1078 #endif
1079 #endif
1080 if ((--delay) < 0) {
1081 splx(s);
1082 return 1;
1083 }
1084 }
1085
1086 /* this command enables the interrupt by operating ADB devices */
1087 if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */
1088 pmdata.command = 0x20;
1089 pmdata.num_data = 4;
1090 pmdata.s_buf = pmdata.data;
1091 pmdata.r_buf = pmdata.data;
1092 pmdata.data[0] = 0x00;
1093 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
1094 pmdata.data[2] = 0x00;
1095 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
1096 } else { /* PB 1XX series */
1097 pmdata.command = 0x20;
1098 pmdata.num_data = 3;
1099 pmdata.s_buf = pmdata.data;
1100 pmdata.r_buf = pmdata.data;
1101 pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1102 pmdata.data[1] = 0x04;
1103 pmdata.data[2] = 0x00;
1104 }
1105 rval = pmgrop(&pmdata);
1106
1107 splx(s);
1108 return rval;
1109 }
1110
1111
1112 void
1113 pm_adb_get_TALK_result(pmdata)
1114 PMData *pmdata;
1115 {
1116 int i;
1117 struct adbCommand packet;
1118
1119 /* set up data for adb_pass_up */
1120 packet.data[0] = pmdata->num_data-1;
1121 packet.data[1] = pmdata->data[3];
1122 for (i = 0; i <packet.data[0]-1; i++)
1123 packet.data[i+2] = pmdata->data[i+4];
1124
1125 packet.saveBuf = adbBuffer;
1126 packet.compRout = adbCompRout;
1127 packet.compData = adbCompData;
1128 packet.unsol = 0;
1129 packet.ack_only = 0;
1130 adb_polling = 1;
1131 adb_pass_up(&packet);
1132 adb_polling = 0;
1133
1134 adbWaiting = 0;
1135 adbBuffer = (long)0;
1136 adbCompRout = (long)0;
1137 adbCompData = (long)0;
1138 }
1139
1140
1141 void
1142 pm_adb_get_ADB_data(pmdata)
1143 PMData *pmdata;
1144 {
1145 int i;
1146 struct adbCommand packet;
1147
1148 /* set up data for adb_pass_up */
1149 packet.data[0] = pmdata->num_data-1; /* number of raw data */
1150 packet.data[1] = pmdata->data[3]; /* ADB command */
1151 for (i = 0; i <packet.data[0]-1; i++)
1152 packet.data[i+2] = pmdata->data[i+4];
1153 packet.unsol = 1;
1154 packet.ack_only = 0;
1155 adb_pass_up(&packet);
1156 }
1157
1158
1159 void
1160 pm_adb_poll_next_device_pm1(pmdata)
1161 PMData *pmdata;
1162 {
1163 int i;
1164 int ndid;
1165 u_short bendid = 0x1;
1166 int rval;
1167 PMData tmp_pmdata;
1168
1169 /* find another existent ADB device to poll */
1170 for (i = 1; i < 16; i++) {
1171 ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1172 bendid <<= ndid;
1173 if ((pm_existent_ADB_devices & bendid) != 0)
1174 break;
1175 }
1176
1177 /* poll the other device */
1178 tmp_pmdata.command = 0x20;
1179 tmp_pmdata.num_data = 3;
1180 tmp_pmdata.s_buf = tmp_pmdata.data;
1181 tmp_pmdata.r_buf = tmp_pmdata.data;
1182 tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1183 tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */
1184 tmp_pmdata.data[2] = 0x00;
1185 rval = pmgrop(&tmp_pmdata);
1186 }
1187
1188
1189
1190