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