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