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