Annotation of src/sys/arch/macppc/dev/pm_direct.c, Revision 1.9.2.1
1.9.2.1 ! he 1: /* $NetBSD: pm_direct.c,v 1.9 2000/06/08 22:10:46 tsubai Exp $ */
1.1 tsubai 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: #ifdef DEBUG
35: #ifndef ADB_DEBUG
36: #define ADB_DEBUG
37: #endif
38: #endif
39:
40: /* #define PM_GRAB_SI 1 */
41:
42: #include <sys/param.h>
43: #include <sys/cdefs.h>
44: #include <sys/device.h>
45: #include <sys/systm.h>
46:
47: #include <machine/adbsys.h>
48: #include <machine/cpu.h>
49:
50: #include <macppc/dev/adbvar.h>
51: #include <macppc/dev/pm_direct.h>
52: #include <macppc/dev/viareg.h>
53:
54: extern int adb_polling; /* Are we polling? (Debugger mode) */
55:
56: /* hardware dependent values */
57: #define ADBDelay 100 /* XXX */
58: #define HwCfgFlags3 0x20000 /* XXX */
59:
60: /* define the types of the Power Manager */
61: #define PM_HW_UNKNOWN 0x00 /* don't know */
62: #define PM_HW_PB1XX 0x01 /* PowerBook 1XX series */
63: #define PM_HW_PB5XX 0x02 /* PowerBook Duo and 5XX series */
64:
65: /* useful macros */
66: #define PM_SR() read_via_reg(VIA1, vSR)
67: #define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90)
68: #define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10)
69: #define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90)
70: #if 0
71: #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x04)
72: #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x04)
73: #define PM_IS_ON (0x02 == (read_via_reg(VIA2, vBufB) & 0x02))
74: #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x02))
75: #else
76: #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10)
77: #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10)
78: #define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08))
79: #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08))
80: #endif
81:
82: /*
83: * Variables for internal use
84: */
85: int pmHardware = PM_HW_UNKNOWN;
86: u_short pm_existent_ADB_devices = 0x0; /* each bit expresses the existent ADB device */
87: u_int pm_LCD_brightness = 0x0;
88: u_int pm_LCD_contrast = 0x0;
89: u_int pm_counter = 0; /* clock count */
90:
91: /* these values shows that number of data returned after 'send' cmd is sent */
92: signed char pm_send_cmd_type[] = {
93: -1, -1, -1, -1, -1, -1, -1, -1,
94: -1, -1, -1, -1, -1, -1, -1, -1,
95: 0x01, 0x01, -1, -1, -1, -1, -1, -1,
96: 0x00, 0x00, -1, -1, -1, -1, -1, 0x00,
97: -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1,
98: 0x00, -1, -1, -1, -1, -1, -1, -1,
1.5 tsubai 99: 0x04, 0x14, -1, 0x03, -1, -1, -1, -1,
100: 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1,
1.1 tsubai 101: 0x01, 0x01, -1, -1, -1, -1, -1, -1,
1.7 tsubai 102: 0x00, 0x00, -1, -1, 0x01, -1, -1, -1,
1.1 tsubai 103: 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01,
104: 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1,
105: 0x02, -1, -1, -1, -1, -1, -1, -1,
106: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1,
107: 0x01, 0x01, 0x01, -1, -1, -1, -1, -1,
108: 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04,
109: 0x04, -1, 0x00, -1, -1, -1, -1, -1,
110: 0x00, -1, -1, -1, -1, -1, -1, -1,
111: 0x01, 0x02, -1, -1, -1, -1, -1, -1,
112: 0x00, 0x00, -1, -1, -1, -1, -1, -1,
113: 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1,
114: 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1,
115: -1, -1, -1, -1, -1, -1, -1, -1,
116: -1, -1, -1, -1, -1, -1, -1, -1,
117: -1, -1, -1, -1, -1, -1, -1, -1,
118: -1, -1, -1, -1, -1, -1, -1, -1,
119: 0x00, -1, -1, -1, -1, -1, -1, -1,
120: 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1,
121: -1, 0x04, 0x00, -1, -1, -1, -1, -1,
122: 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00,
123: -1, -1, -1, -1, -1, -1, -1, -1,
124: -1, -1, -1, -1, -1, -1, -1, -1
125: };
126:
127: /* these values shows that number of data returned after 'receive' cmd is sent */
128: signed char pm_receive_cmd_type[] = {
129: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130: -1, -1, -1, -1, -1, -1, -1, -1,
131: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132: 0x02, 0x02, -1, -1, -1, -1, -1, 0x00,
133: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134: -1, -1, -1, -1, -1, -1, -1, -1,
135: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1.5 tsubai 136: 0x05, 0x15, -1, 0x02, -1, -1, -1, -1,
1.1 tsubai 137: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138: 0x02, 0x02, -1, -1, -1, -1, -1, -1,
139: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140: 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1,
141: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142: 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1,
143: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144: -1, -1, -1, -1, -1, -1, 0x01, 0x01,
145: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146: 0x06, -1, -1, -1, -1, -1, -1, -1,
147: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
148: 0x02, 0x02, -1, -1, -1, -1, -1, -1,
149: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150: 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1,
151: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152: -1, -1, -1, -1, -1, -1, -1, -1,
153: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154: -1, -1, -1, -1, -1, -1, -1, -1,
155: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156: 0x02, 0x02, -1, -1, 0x02, -1, -1, -1,
157: 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
158: -1, -1, 0x02, -1, -1, -1, -1, 0x00,
159: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160: -1, -1, -1, -1, -1, -1, -1, -1,
161: };
162:
163:
164: /*
165: * Define the private functions
166: */
167:
168: /* for debugging */
169: #ifdef ADB_DEBUG
170: void pm_printerr __P((char *, int, int, char *));
171: #endif
172:
173: int pm_wait_busy __P((int));
174: int pm_wait_free __P((int));
175:
176: /* these functions are for the PB1XX series */
177: int pm_receive_pm1 __P((u_char *));
178: int pm_send_pm1 __P((u_char,int));
179: int pm_pmgrop_pm1 __P((PMData *));
180: void pm_intr_pm1 __P((void));
181:
182: /* these functions are for the PB Duo series and the PB 5XX series */
183: int pm_receive_pm2 __P((u_char *));
184: int pm_send_pm2 __P((u_char));
185: int pm_pmgrop_pm2 __P((PMData *));
186: void pm_intr_pm2 __P((void));
187:
188: /* this function is MRG-Based (for testing) */
189: int pm_pmgrop_mrg __P((PMData *));
190:
191: /* these functions are called from adb_direct.c */
192: void pm_setup_adb __P((void));
193: void pm_check_adb_devices __P((int));
194: void pm_intr __P((void));
195: int pm_adb_op __P((u_char *, void *, void *, int));
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: #if 0
228: /*
229: * Define the external functions
230: */
231: extern int zshard __P((int)); /* from zs.c */
232: #endif
233:
234: #ifdef ADB_DEBUG
235: /*
236: * This function dumps contents of the PMData
237: */
238: void
239: pm_printerr(ttl, rval, num, data)
240: char *ttl;
241: int rval;
242: int num;
243: char *data;
244: {
245: int i;
246:
247: printf("pm: %s:%04x %02x ", ttl, rval, num);
248: for (i = 0; i < num; i++)
249: printf("%02x ", data[i]);
250: printf("\n");
251: }
252: #endif
253:
254:
255:
256: /*
257: * Check the hardware type of the Power Manager
258: */
259: void
260: pm_setup_adb()
261: {
262: pmHardware = PM_HW_PB5XX; /* XXX */
263: }
264:
265:
266: /*
267: * Check the existent ADB devices
268: */
269: void
270: pm_check_adb_devices(id)
271: int id;
272: {
273: u_short ed = 0x1;
274:
275: ed <<= id;
276: pm_existent_ADB_devices |= ed;
277: }
278:
279:
280: /*
281: * Wait until PM IC is busy
282: */
283: int
284: pm_wait_busy(delay)
285: int delay;
286: {
287: while (PM_IS_ON) {
288: #ifdef PM_GRAB_SI
289: #if 0
290: zshard(0); /* grab any serial interrupts */
291: #else
292: (void)intr_dispatch(0x70);
293: #endif
294: #endif
295: if ((--delay) < 0)
296: return 1; /* timeout */
297: }
298: return 0;
299: }
300:
301:
302: /*
303: * Wait until PM IC is free
304: */
305: int
306: pm_wait_free(delay)
307: int delay;
308: {
309: while (PM_IS_OFF) {
310: #ifdef PM_GRAB_SI
311: #if 0
312: zshard(0); /* grab any serial interrupts */
313: #else
314: (void)intr_dispatch(0x70);
315: #endif
316: #endif
317: if ((--delay) < 0)
318: return 0; /* timeout */
319: }
320: return 1;
321: }
322:
323:
324:
325: /*
326: * Functions for the PB1XX series
327: */
328:
329: /*
330: * Receive data from PM for the PB1XX series
331: */
332: int
333: pm_receive_pm1(data)
334: u_char *data;
335: {
336: #if 0
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: #else
362: panic("pm_receive_pm1");
363: #endif
364: }
365:
366:
367:
368: /*
369: * Send data to PM for the PB1XX series
370: */
371: int
372: pm_send_pm1(data, delay)
373: u_char data;
374: int delay;
375: {
376: #if 0
377: int rval;
378:
379: via_reg(VIA2, vDirA) = 0xff;
380: via_reg(VIA2, 0x200) = data;
381:
382: PM_SET_STATE_ACKOFF();
383: if (pm_wait_busy(0x400) != 0) {
384: PM_SET_STATE_ACKON();
385: via_reg(VIA2, vDirA) = 0x00;
386:
387: return 0xffffcd36;
388: }
389:
390: rval = 0x0;
391: PM_SET_STATE_ACKON();
392: if (pm_wait_free(0x40) == 0)
393: rval = 0xffffcd35;
394:
395: PM_SET_STATE_ACKON();
396: via_reg(VIA2, vDirA) = 0x00;
397:
398: return rval;
399: #else
400: panic("pm_send_pm1");
401: #endif
402: }
403:
404:
405: /*
406: * My PMgrOp routine for the PB1XX series
407: */
408: int
409: pm_pmgrop_pm1(pmdata)
410: PMData *pmdata;
411: {
412: #if 0
413: int i;
414: int s = 0x81815963;
415: u_char via1_vIER, via1_vDirA;
416: int rval = 0;
417: int num_pm_data = 0;
418: u_char pm_cmd;
419: u_char pm_data;
420: u_char *pm_buf;
421:
422: /* disable all inetrrupts but PM */
423: via1_vIER = via_reg(VIA1, vIER);
424: PM_VIA_INTR_DISABLE();
425:
426: via1_vDirA = via_reg(VIA1, vDirA);
427:
428: switch (pmdata->command) {
429: default:
430: for (i = 0; i < 7; i++) {
431: via_reg(VIA2, vDirA) = 0x00;
432:
433: /* wait until PM is free */
434: if (pm_wait_free(ADBDelay) == 0) { /* timeout */
435: via_reg(VIA2, vDirA) = 0x00;
436: /* restore formar value */
437: via_reg(VIA1, vDirA) = via1_vDirA;
438: via_reg(VIA1, vIER) = via1_vIER;
439: return 0xffffcd38;
440: }
441:
442: switch (mac68k_machine.machineid) {
443: case MACH_MACPB160:
444: case MACH_MACPB165:
445: case MACH_MACPB165C:
446: case MACH_MACPB180:
447: case MACH_MACPB180C:
448: {
449: int delay = ADBDelay * 16;
450:
451: via_reg(VIA2, vDirA) = 0x00;
452: while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
453: delay--;
454:
455: if (delay < 0) { /* timeout */
456: via_reg(VIA2, vDirA) = 0x00;
457: /* restore formar value */
458: via_reg(VIA1, vIER) = via1_vIER;
459: return 0xffffcd38;
460: }
461: }
462: } /* end switch */
463:
464: s = splhigh();
465:
466: via1_vDirA = via_reg(VIA1, vDirA);
467: via_reg(VIA1, vDirA) &= 0x7f;
468:
469: pm_cmd = (u_char)(pmdata->command & 0xff);
470: if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
471: break; /* send command succeeded */
472:
473: via_reg(VIA1, vDirA) = via1_vDirA;
474: splx(s);
475: } /* end for */
476:
477: /* failed to send a command */
478: if (i == 7) {
479: via_reg(VIA2, vDirA) = 0x00;
480: /* restore formar value */
481: via_reg(VIA1, vDirA) = via1_vDirA;
482: via_reg(VIA1, vIER) = via1_vIER;
1.9 tsubai 483: if (s != 0x81815963)
484: splx(s);
485: return 0xffffcd38;
1.1 tsubai 486: }
487:
488: /* send # of PM data */
489: num_pm_data = pmdata->num_data;
490: if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
491: break; /* timeout */
492:
493: /* send PM data */
494: pm_buf = (u_char *)pmdata->s_buf;
495: for (i = 0; i < num_pm_data; i++)
496: if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
497: break; /* timeout */
498: if ((i != num_pm_data) && (num_pm_data != 0))
499: break; /* timeout */
500:
501: /* Will PM IC return data? */
502: if ((pm_cmd & 0x08) == 0) {
503: rval = 0;
504: break; /* no returned data */
505: }
506:
507: rval = 0xffffcd37;
508: if (pm_wait_busy(ADBDelay) != 0)
509: break; /* timeout */
510:
511: /* receive PM command */
512: if ((rval = pm_receive_pm1(&pm_data)) != 0)
513: break;
514:
515: pmdata->command = pm_data;
516:
517: /* receive number of PM data */
518: if ((rval = pm_receive_pm1(&pm_data)) != 0)
519: break; /* timeout */
520: num_pm_data = pm_data;
521: pmdata->num_data = num_pm_data;
522:
523: /* receive PM data */
524: pm_buf = (u_char *)pmdata->r_buf;
525: for (i = 0; i < num_pm_data; i++) {
526: if ((rval = pm_receive_pm1(&pm_data)) != 0)
1.9 tsubai 527: break; /* timeout */
1.1 tsubai 528: pm_buf[i] = pm_data;
529: }
530:
531: rval = 0;
532: }
533:
534: via_reg(VIA2, vDirA) = 0x00;
535:
536: /* restore formar value */
537: via_reg(VIA1, vDirA) = via1_vDirA;
538: via_reg(VIA1, vIER) = via1_vIER;
539: if (s != 0x81815963)
540: splx(s);
541:
542: return rval;
543: #else
544: panic("pm_pmgrop_pm1");
545: #endif
546: }
547:
548:
549: /*
550: * My PM interrupt routine for PB1XX series
551: */
552: void
553: pm_intr_pm1()
554: {
555: #if 0
556: int s;
557: int rval;
558: PMData pmdata;
559:
560: s = splhigh();
561:
562: PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
563:
564: /* ask PM what happend */
565: pmdata.command = 0x78;
566: pmdata.num_data = 0;
567: pmdata.data[0] = pmdata.data[1] = 0;
568: pmdata.s_buf = &pmdata.data[2];
569: pmdata.r_buf = &pmdata.data[2];
570: rval = pm_pmgrop_pm1(&pmdata);
571: if (rval != 0) {
572: #ifdef ADB_DEBUG
573: if (adb_debug)
574: printf("pm: PM is not ready. error code=%08x\n", rval);
575: #endif
576: splx(s);
577: }
578:
579: if ((pmdata.data[2] & 0x10) == 0x10) {
580: if ((pmdata.data[2] & 0x0f) == 0) {
581: /* ADB data that were requested by TALK command */
582: pm_adb_get_TALK_result(&pmdata);
583: } else if ((pmdata.data[2] & 0x08) == 0x8) {
584: /* PM is requesting to poll */
585: pm_adb_poll_next_device_pm1(&pmdata);
586: } else if ((pmdata.data[2] & 0x04) == 0x4) {
587: /* ADB device event */
588: pm_adb_get_ADB_data(&pmdata);
589: }
590: } else {
591: #ifdef ADB_DEBUG
592: if (adb_debug)
593: pm_printerr("driver does not supported this event.",
594: rval, pmdata.num_data, pmdata.data);
595: #endif
596: }
597:
598: splx(s);
599: #else
600: panic("pm_intr_pm1");
601: #endif
602: }
603:
604:
605:
606: /*
607: * Functions for the PB Duo series and the PB 5XX series
608: */
609:
610: /*
611: * Receive data from PM for the PB Duo series and the PB 5XX series
612: */
613: int
614: pm_receive_pm2(data)
615: u_char *data;
616: {
617: int i;
618: int rval;
619:
620: rval = 0xffffcd34;
621:
622: switch (1) {
623: default:
624: /* set VIA SR to input mode */
625: via_reg_or(VIA1, vACR, 0x0c);
626: via_reg_and(VIA1, vACR, ~0x10);
627: i = PM_SR();
628:
629: PM_SET_STATE_ACKOFF();
630: if (pm_wait_busy((int)ADBDelay*32) != 0)
631: break; /* timeout */
632:
633: PM_SET_STATE_ACKON();
634: rval = 0xffffcd33;
635: if (pm_wait_free((int)ADBDelay*32) == 0)
636: break; /* timeout */
637:
638: *data = PM_SR();
639: rval = 0;
640:
641: break;
642: }
643:
644: PM_SET_STATE_ACKON();
645: via_reg_or(VIA1, vACR, 0x1c);
646:
647: return rval;
648: }
649:
650:
651:
652: /*
653: * Send data to PM for the PB Duo series and the PB 5XX series
654: */
655: int
656: pm_send_pm2(data)
657: u_char data;
658: {
659: int rval;
660:
661: via_reg_or(VIA1, vACR, 0x1c);
662: write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */
663:
664: PM_SET_STATE_ACKOFF();
665: rval = 0xffffcd36;
666: if (pm_wait_busy((int)ADBDelay*32) != 0) {
667: PM_SET_STATE_ACKON();
668:
669: via_reg_or(VIA1, vACR, 0x1c);
670:
671: return rval;
672: }
673:
674: PM_SET_STATE_ACKON();
675: rval = 0xffffcd35;
676: if (pm_wait_free((int)ADBDelay*32) != 0)
677: rval = 0;
678:
679: PM_SET_STATE_ACKON();
680: via_reg_or(VIA1, vACR, 0x1c);
681:
682: return rval;
683: }
684:
685:
686:
687: /*
688: * My PMgrOp routine for the PB Duo series and the PB 5XX series
689: */
690: int
691: pm_pmgrop_pm2(pmdata)
692: PMData *pmdata;
693: {
694: int i;
695: int s;
696: u_char via1_vIER;
697: int rval = 0;
698: int num_pm_data = 0;
699: u_char pm_cmd;
700: short pm_num_rx_data;
701: u_char pm_data;
702: u_char *pm_buf;
703:
704: s = splhigh();
705:
706: /* disable all inetrrupts but PM */
707: via1_vIER = 0x10;
708: via1_vIER &= read_via_reg(VIA1, vIER);
709: write_via_reg(VIA1, vIER, via1_vIER);
710: if (via1_vIER != 0x0)
711: via1_vIER |= 0x80;
712:
713: switch (pmdata->command) {
714: default:
715: /* wait until PM is free */
716: pm_cmd = (u_char)(pmdata->command & 0xff);
717: rval = 0xcd38;
718: if (pm_wait_free(ADBDelay * 4) == 0)
719: break; /* timeout */
720:
721: if (HwCfgFlags3 & 0x00200000) {
722: /* PB 160, PB 165(c), PB 180(c)? */
723: int delay = ADBDelay * 16;
724:
725: write_via_reg(VIA2, vDirA, 0x00);
726: while ((read_via_reg(VIA2, 0x200) == 0x07) &&
727: (delay >= 0))
728: delay--;
729:
730: if (delay < 0) {
731: rval = 0xffffcd38;
732: break; /* timeout */
733: }
734: }
735:
736: /* send PM command */
737: if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
738: break; /* timeout */
739:
740: /* send number of PM data */
741: num_pm_data = pmdata->num_data;
742: if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
743: if (pm_send_cmd_type[pm_cmd] < 0) {
744: if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
745: break; /* timeout */
746: pmdata->command = 0;
747: }
748: } else { /* PB 1XX series ? */
749: if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
750: break; /* timeout */
751: }
752: /* send PM data */
753: pm_buf = (u_char *)pmdata->s_buf;
754: for (i = 0 ; i < num_pm_data; i++)
755: if ((rval = pm_send_pm2(pm_buf[i])) != 0)
756: break; /* timeout */
757: if (i != num_pm_data)
758: break; /* timeout */
759:
760:
761: /* check if PM will send me data */
762: pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
763: pmdata->num_data = pm_num_rx_data;
764: if (pm_num_rx_data == 0) {
765: rval = 0;
766: break; /* no return data */
767: }
768:
769: /* receive PM command */
770: pm_data = pmdata->command;
771: if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
772: pm_num_rx_data--;
773: if (pm_num_rx_data == 0)
774: if ((rval = pm_receive_pm2(&pm_data)) != 0) {
775: rval = 0xffffcd37;
776: break;
777: }
778: pmdata->command = pm_data;
779: } else { /* PB 1XX series ? */
780: if ((rval = pm_receive_pm2(&pm_data)) != 0) {
781: rval = 0xffffcd37;
782: break;
783: }
784: pmdata->command = pm_data;
785: }
786:
787: /* receive number of PM data */
788: if (HwCfgFlags3 & 0x00020000) { /* PB Duo, PB 5XX */
789: if (pm_num_rx_data < 0) {
790: if ((rval = pm_receive_pm2(&pm_data)) != 0)
791: break; /* timeout */
792: num_pm_data = pm_data;
793: } else
794: num_pm_data = pm_num_rx_data;
795: pmdata->num_data = num_pm_data;
796: } else { /* PB 1XX serias ? */
797: if ((rval = pm_receive_pm2(&pm_data)) != 0)
798: break; /* timeout */
799: num_pm_data = pm_data;
800: pmdata->num_data = num_pm_data;
801: }
802:
803: /* receive PM data */
804: pm_buf = (u_char *)pmdata->r_buf;
805: for (i = 0; i < num_pm_data; i++) {
806: if ((rval = pm_receive_pm2(&pm_data)) != 0)
807: break; /* timeout */
808: pm_buf[i] = pm_data;
809: }
810:
811: rval = 0;
812: }
813:
814: /* restore former value */
815: write_via_reg(VIA1, vIER, via1_vIER);
816: splx(s);
817:
818: return rval;
819: }
820:
821:
822: /*
823: * My PM interrupt routine for the PB Duo series and the PB 5XX series
824: */
825: void
826: pm_intr_pm2()
827: {
828: int s;
829: int rval;
830: PMData pmdata;
831:
832: s = splhigh();
833:
834: PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
835: /* ask PM what happend */
836: pmdata.command = 0x78;
837: pmdata.num_data = 0;
838: pmdata.s_buf = &pmdata.data[2];
839: pmdata.r_buf = &pmdata.data[2];
840: rval = pm_pmgrop_pm2(&pmdata);
841: if (rval != 0) {
842: #ifdef ADB_DEBUG
843: if (adb_debug)
844: printf("pm: PM is not ready. error code: %08x\n", rval);
845: #endif
846: splx(s);
847: }
848:
849: switch ((u_int)(pmdata.data[2] & 0xff)) {
850: case 0x00: /* 1 sec interrupt? */
851: break;
852: case 0x80: /* 1 sec interrupt? */
853: pm_counter++;
854: break;
855: case 0x08: /* Brightness/Contrast button on LCD panel */
856: /* get brightness and contrast of the LCD */
857: pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
858: pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
859: /*
860: pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
861: pmdata.command = 0x33;
862: pmdata.num_data = 1;
863: pmdata.s_buf = pmdata.data;
864: pmdata.r_buf = pmdata.data;
865: pmdata.data[0] = pm_LCD_contrast;
866: rval = pm_pmgrop_pm2(&pmdata);
867: pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
868: */
869: /* this is an experimental code */
870: pmdata.command = 0x41;
871: pmdata.num_data = 1;
872: pmdata.s_buf = pmdata.data;
873: pmdata.r_buf = pmdata.data;
874: pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
1.2 tsubai 875: if (pm_LCD_brightness < 0x08)
876: pm_LCD_brightness = 0x08;
877: if (pm_LCD_brightness > 0x78)
878: pm_LCD_brightness = 0x78;
1.1 tsubai 879: pmdata.data[0] = pm_LCD_brightness;
880: rval = pm_pmgrop_pm2(&pmdata);
881: break;
882: case 0x10: /* ADB data that were requested by TALK command */
883: case 0x14:
884: pm_adb_get_TALK_result(&pmdata);
885: break;
886: case 0x16: /* ADB device event */
887: case 0x18:
888: case 0x1e:
889: pm_adb_get_ADB_data(&pmdata);
890: break;
891: default:
892: #ifdef ADB_DEBUG
893: if (adb_debug)
894: pm_printerr("driver does not supported this event.",
895: pmdata.data[2], pmdata.num_data,
896: pmdata.data);
897: #endif
898: break;
899: }
900:
901: splx(s);
902: }
903:
904:
905: #if 0
906: /*
907: * MRG-based PMgrOp routine
908: */
909: int
910: pm_pmgrop_mrg(pmdata)
911: PMData *pmdata;
912: {
913: u_int32_t rval=0;
914:
915: asm("
916: movl %1, a0
917: .word 0xa085
918: movl d0, %0"
919: : "=g" (rval)
920: : "g" (pmdata)
921: : "a0", "d0" );
922:
923: return rval;
924: }
925: #endif
926:
927:
928: /*
929: * My PMgrOp routine
930: */
931: int
932: pmgrop(pmdata)
933: PMData *pmdata;
934: {
935: switch (pmHardware) {
936: case PM_HW_PB1XX:
937: return (pm_pmgrop_pm1(pmdata));
938: break;
939: case PM_HW_PB5XX:
940: return (pm_pmgrop_pm2(pmdata));
941: break;
942: default:
943: /* return (pmgrop_mrg(pmdata)); */
944: return 1;
945: }
946: }
947:
948:
949: /*
950: * My PM interrupt routine
951: */
952: void
953: pm_intr()
954: {
955: switch (pmHardware) {
956: case PM_HW_PB1XX:
957: pm_intr_pm1();
958: break;
959: case PM_HW_PB5XX:
960: pm_intr_pm2();
961: break;
962: default:
963: break;
964: }
965: }
966:
967:
968:
969: /*
970: * Synchronous ADBOp routine for the Power Manager
971: */
972: int
973: pm_adb_op(buffer, compRout, data, command)
974: u_char *buffer;
975: void *compRout;
976: void *data;
977: int command;
978: {
979: int i;
980: int s;
981: int rval;
1.9.2.1 ! he 982: int timo;
1.1 tsubai 983: PMData pmdata;
984: struct adbCommand packet;
985:
986: if (adbWaiting == 1)
987: return 1;
988:
989: s = splhigh();
990: write_via_reg(VIA1, vIER, 0x10);
991:
992: adbBuffer = buffer;
993: adbCompRout = compRout;
994: adbCompData = data;
995:
996: pmdata.command = 0x20;
997: pmdata.s_buf = pmdata.data;
998: pmdata.r_buf = pmdata.data;
999:
1000: /* if the command is LISTEN, add number of ADB data to number of PM data */
1001: if ((command & 0xc) == 0x8) {
1002: if (buffer != (u_char *)0)
1003: pmdata.num_data = buffer[0] + 3;
1004: } else {
1005: pmdata.num_data = 3;
1006: }
1007:
1008: pmdata.data[0] = (u_char)(command & 0xff);
1009: pmdata.data[1] = 0;
1010: if ((command & 0xc) == 0x8) { /* if the command is LISTEN, copy ADB data to PM buffer */
1011: if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1012: pmdata.data[2] = buffer[0]; /* number of data */
1013: for (i = 0; i < buffer[0]; i++)
1014: pmdata.data[3 + i] = buffer[1 + i];
1015: } else
1016: pmdata.data[2] = 0;
1017: } else
1018: pmdata.data[2] = 0;
1019:
1020: if ((command & 0xc) != 0xc) { /* if the command is not TALK */
1021: /* set up stuff for adb_pass_up */
1022: packet.data[0] = 1 + pmdata.data[2];
1023: packet.data[1] = command;
1024: for (i = 0; i < pmdata.data[2]; i++)
1025: packet.data[i+2] = pmdata.data[i+3];
1026: packet.saveBuf = adbBuffer;
1027: packet.compRout = adbCompRout;
1028: packet.compData = adbCompData;
1029: packet.cmd = command;
1030: packet.unsol = 0;
1031: packet.ack_only = 1;
1032: adb_polling = 1;
1033: adb_pass_up(&packet);
1034: adb_polling = 0;
1035: }
1036:
1037: rval = pmgrop(&pmdata);
1.9 tsubai 1038: if (rval != 0) {
1039: splx(s);
1.1 tsubai 1040: return 1;
1.9 tsubai 1041: }
1.1 tsubai 1042:
1.9.2.1 ! he 1043: delay(10000);
! 1044:
1.1 tsubai 1045: adbWaiting = 1;
1046: adbWaitingCmd = command;
1047:
1048: PM_VIA_INTR_ENABLE();
1049:
1050: /* wait until the PM interrupt is occured */
1.9.2.1 ! he 1051: timo = 0x80000;
1.1 tsubai 1052: while (adbWaiting == 1) {
1053: if (read_via_reg(VIA1, vIFR) & 0x14)
1054: pm_intr();
1055: #ifdef PM_GRAB_SI
1056: #if 0
1057: zshard(0); /* grab any serial interrupts */
1058: #else
1059: (void)intr_dispatch(0x70);
1060: #endif
1061: #endif
1.9.2.1 ! he 1062: if ((--timo) < 0) {
1.9 tsubai 1063: splx(s);
1.1 tsubai 1064: return 1;
1.9 tsubai 1065: }
1.1 tsubai 1066: }
1067:
1068: /* this command enables the interrupt by operating ADB devices */
1069: if (HwCfgFlags3 & 0x00020000) { /* PB Duo series, PB 5XX series */
1070: pmdata.command = 0x20;
1071: pmdata.num_data = 4;
1072: pmdata.s_buf = pmdata.data;
1073: pmdata.r_buf = pmdata.data;
1074: pmdata.data[0] = 0x00;
1075: pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
1076: pmdata.data[2] = 0x00;
1077: pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
1078: } else { /* PB 1XX series */
1079: pmdata.command = 0x20;
1080: pmdata.num_data = 3;
1081: pmdata.s_buf = pmdata.data;
1082: pmdata.r_buf = pmdata.data;
1083: pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1084: pmdata.data[1] = 0x04;
1085: pmdata.data[2] = 0x00;
1086: }
1087: rval = pmgrop(&pmdata);
1088:
1089: splx(s);
1090: return rval;
1091: }
1092:
1093:
1094: void
1095: pm_adb_get_TALK_result(pmdata)
1096: PMData *pmdata;
1097: {
1098: int i;
1099: struct adbCommand packet;
1100:
1101: /* set up data for adb_pass_up */
1102: packet.data[0] = pmdata->num_data-1;
1103: packet.data[1] = pmdata->data[3];
1104: for (i = 0; i <packet.data[0]-1; i++)
1105: packet.data[i+2] = pmdata->data[i+4];
1106:
1107: packet.saveBuf = adbBuffer;
1108: packet.compRout = adbCompRout;
1109: packet.compData = adbCompData;
1110: packet.unsol = 0;
1111: packet.ack_only = 0;
1112: adb_polling = 1;
1113: adb_pass_up(&packet);
1114: adb_polling = 0;
1115:
1116: adbWaiting = 0;
1117: adbBuffer = (long)0;
1118: adbCompRout = (long)0;
1119: adbCompData = (long)0;
1120: }
1121:
1122:
1123: void
1124: pm_adb_get_ADB_data(pmdata)
1125: PMData *pmdata;
1126: {
1127: int i;
1128: struct adbCommand packet;
1129:
1130: /* set up data for adb_pass_up */
1131: packet.data[0] = pmdata->num_data-1; /* number of raw data */
1132: packet.data[1] = pmdata->data[3]; /* ADB command */
1133: for (i = 0; i <packet.data[0]-1; i++)
1134: packet.data[i+2] = pmdata->data[i+4];
1135: packet.unsol = 1;
1136: packet.ack_only = 0;
1137: adb_pass_up(&packet);
1138: }
1139:
1140:
1141: void
1142: pm_adb_poll_next_device_pm1(pmdata)
1143: PMData *pmdata;
1144: {
1145: int i;
1146: int ndid;
1147: u_short bendid = 0x1;
1148: int rval;
1149: PMData tmp_pmdata;
1150:
1151: /* find another existent ADB device to poll */
1152: for (i = 1; i < 16; i++) {
1.9 tsubai 1153: ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1.1 tsubai 1154: bendid <<= ndid;
1155: if ((pm_existent_ADB_devices & bendid) != 0)
1156: break;
1157: }
1158:
1159: /* poll the other device */
1160: tmp_pmdata.command = 0x20;
1161: tmp_pmdata.num_data = 3;
1162: tmp_pmdata.s_buf = tmp_pmdata.data;
1163: tmp_pmdata.r_buf = tmp_pmdata.data;
1164: tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1165: tmp_pmdata.data[1] = 0x04; /* magic spell for awaking the PM */
1166: tmp_pmdata.data[2] = 0x00;
1167: rval = pmgrop(&tmp_pmdata);
1168: }
1169:
1170: void
1171: pm_adb_restart()
1172: {
1173: PMData p;
1174:
1.4 tsubai 1175: p.command = PMU_RESET_CPU;
1.1 tsubai 1176: p.num_data = 0;
1177: p.s_buf = p.data;
1178: p.r_buf = p.data;
1.6 tsubai 1179: pmgrop(&p);
1180: }
1181:
1182: void
1183: pm_adb_poweroff()
1184: {
1185: PMData p;
1186:
1187: p.command = PMU_POWER_OFF;
1188: p.num_data = 4;
1189: p.s_buf = p.data;
1190: p.r_buf = p.data;
1191: strcpy(p.data, "MATT");
1.1 tsubai 1192: pmgrop(&p);
1.2 tsubai 1193: }
1194:
1195: void
1196: pm_read_date_time(time)
1197: u_long *time;
1198: {
1199: PMData p;
1200:
1.4 tsubai 1201: p.command = PMU_READ_RTC;
1.2 tsubai 1202: p.num_data = 0;
1203: p.s_buf = p.data;
1204: p.r_buf = p.data;
1205: pmgrop(&p);
1206:
1.3 tsubai 1207: bcopy(p.data, time, 4);
1.4 tsubai 1208: }
1209:
1210: void
1211: pm_set_date_time(time)
1212: u_long time;
1213: {
1214: PMData p;
1215:
1216: p.command = PMU_SET_RTC;
1217: p.num_data = 4;
1218: p.s_buf = p.r_buf = p.data;
1219: bcopy(&time, p.data, 4);
1.7 tsubai 1220: pmgrop(&p);
1221: }
1222:
1223: int
1224: pm_read_brightness()
1225: {
1226: PMData p;
1227:
1228: p.command = PMU_READ_BRIGHTNESS;
1229: p.num_data = 1; /* XXX why 1? */
1230: p.s_buf = p.r_buf = p.data;
1231: p.data[0] = 0;
1232: pmgrop(&p);
1233:
1234: return p.data[0];
1235: }
1236:
1237: void
1238: pm_set_brightness(val)
1239: int val;
1240: {
1241: PMData p;
1242:
1243: val = 0x7f - val / 2;
1244: if (val < 0x08)
1245: val = 0x08;
1246: if (val > 0x78)
1247: val = 0x78;
1248:
1249: p.command = PMU_SET_BRIGHTNESS;
1250: p.num_data = 1;
1251: p.s_buf = p.r_buf = p.data;
1252: p.data[0] = val;
1253: pmgrop(&p);
1254: }
1255:
1256: void
1257: pm_init_brightness()
1258: {
1259: int val;
1260:
1261: val = pm_read_brightness();
1262: pm_set_brightness(val);
1263: }
1264:
1265: void
1266: pm_eject_pcmcia(slot)
1267: int slot;
1268: {
1269: PMData p;
1270:
1271: if (slot != 0 && slot != 1)
1272: return;
1273:
1274: p.command = PMU_EJECT_PCMCIA;
1275: p.num_data = 1;
1276: p.s_buf = p.r_buf = p.data;
1.8 tsubai 1277: p.data[0] = 5 + slot; /* XXX */
1.5 tsubai 1278: pmgrop(&p);
1279: }
1280:
1281: int
1282: pm_read_nvram(addr)
1283: int addr;
1284: {
1285: PMData p;
1286:
1287: p.command = PMU_READ_NVRAM;
1288: p.num_data = 2;
1289: p.s_buf = p.r_buf = p.data;
1290: p.data[0] = addr >> 8;
1291: p.data[1] = addr;
1292: pmgrop(&p);
1293:
1294: return p.data[0];
1295: }
1296:
1297: void
1298: pm_write_nvram(addr, val)
1299: int addr, val;
1300: {
1301: PMData p;
1302:
1303: p.command = PMU_WRITE_NVRAM;
1304: p.num_data = 3;
1305: p.s_buf = p.r_buf = p.data;
1306: p.data[0] = addr >> 8;
1307: p.data[1] = addr;
1308: p.data[2] = val;
1.4 tsubai 1309: pmgrop(&p);
1.1 tsubai 1310: }
CVSweb <webmaster@jp.NetBSD.org>