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