1 /* $OpenBSD: pm_direct.c,v 1.35 2023/11/22 18:14:35 tobhe Exp $ */
2 /* $NetBSD: pm_direct.c,v 1.9 2000/06/08 22:10:46 tsubai 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
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/device.h>
44 #include <sys/systm.h>
45 #include <sys/sensors.h>
46
47 #include <machine/cpu.h>
48
49 #include <dev/adb/adb.h>
50 #include <macppc/dev/adbvar.h>
51 #include <macppc/dev/pm_direct.h>
52 #include <macppc/dev/viareg.h>
53
54 /* hardware dependent values */
55 #define ADBDelay 100 /* XXX */
56
57 /* useful macros */
58 #define PM_SR() read_via_reg(VIA1, vSR)
59 #define PM_VIA_INTR_ENABLE() write_via_reg(VIA1, vIER, 0x90)
60 #define PM_VIA_INTR_DISABLE() write_via_reg(VIA1, vIER, 0x10)
61 #define PM_VIA_CLR_INTR() write_via_reg(VIA1, vIFR, 0x90)
62 #if 0
63 #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x04)
64 #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x04)
65 #define PM_IS_ON (0x02 == (read_via_reg(VIA2, vBufB) & 0x02))
66 #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x02))
67 #else
68 #define PM_SET_STATE_ACKON() via_reg_or(VIA2, vBufB, 0x10)
69 #define PM_SET_STATE_ACKOFF() via_reg_and(VIA2, vBufB, ~0x10)
70 #define PM_IS_ON (0x08 == (read_via_reg(VIA2, vBufB) & 0x08))
71 #define PM_IS_OFF (0x00 == (read_via_reg(VIA2, vBufB) & 0x08))
72 #endif
73
74 /* these values shows that number of data returned after 'send' cmd is sent */
75 const signed char pm_send_cmd_type[] = {
76 -1, -1, -1, -1, -1, -1, -1, -1,
77 -1, -1, -1, -1, -1, -1, -1, -1,
78 0x01, 0x01, -1, -1, -1, -1, -1, -1,
79 0x00, 0x00, -1, -1, -1, -1, -1, 0x00,
80 -1, 0x00, 0x02, 0x01, 0x01, -1, -1, -1,
81 0x00, -1, -1, -1, -1, -1, -1, -1,
82 0x04, 0x14, -1, 0x03, -1, -1, -1, -1,
83 0x00, 0x00, 0x02, 0x02, -1, -1, -1, -1,
84 0x01, 0x01, -1, -1, -1, -1, -1, -1,
85 0x00, 0x00, -1, -1, 0x01, -1, -1, -1,
86 0x01, 0x00, 0x02, 0x02, -1, 0x01, 0x03, 0x01,
87 0x00, 0x01, 0x00, 0x00, 0x00, -1, -1, -1,
88 0x02, -1, -1, -1, -1, -1, -1, -1,
89 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -1, -1,
90 0x01, 0x01, 0x01, -1, -1, -1, -1, -1,
91 0x00, 0x00, -1, -1, -1, -1, 0x04, 0x04,
92 0x04, -1, 0x00, -1, -1, -1, -1, -1,
93 0x00, -1, -1, -1, -1, -1, -1, -1,
94 0x01, 0x02, -1, -1, -1, -1, -1, -1,
95 0x00, 0x00, -1, -1, -1, -1, -1, -1,
96 0x02, 0x02, 0x02, 0x04, -1, 0x00, -1, -1,
97 0x01, 0x01, 0x03, 0x02, -1, -1, -1, -1,
98 -1, -1, -1, -1, -1, -1, -1, -1,
99 -1, -1, -1, -1, -1, -1, -1, -1,
100 -1, -1, -1, -1, -1, -1, -1, -1,
101 -1, -1, -1, -1, -1, -1, -1, -1,
102 0x00, -1, -1, -1, -1, -1, -1, -1,
103 0x01, 0x01, -1, -1, 0x00, 0x00, -1, -1,
104 -1, 0x04, 0x00, -1, -1, -1, -1, -1,
105 0x03, -1, 0x00, -1, 0x00, -1, -1, 0x00,
106 -1, -1, -1, -1, -1, -1, -1, -1,
107 -1, -1, -1, -1, -1, -1, -1, -1
108 };
109
110 /* these values shows that number of data returned after 'receive' cmd is sent */
111 const signed char pm_receive_cmd_type[] = {
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113 -1, -1, -1, -1, -1, -1, -1, -1,
114 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 0x02, 0x02, -1, -1, -1, -1, -1, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 -1, -1, -1, -1, -1, -1, -1, -1,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x05, 0x15, -1, 0x02, -1, -1, -1, -1,
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x02, 0x02, -1, -1, -1, -1, -1, -1,
122 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123 0x02, 0x00, 0x03, 0x03, -1, -1, -1, -1,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x04, 0x04, 0x03, 0x09, -1, -1, -1, -1,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 -1, -1, -1, -1, -1, -1, 0x01, 0x01,
128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 0x06, -1, -1, -1, -1, -1, -1, -1,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 0x02, 0x02, -1, -1, -1, -1, -1, -1,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x02, 0x00, 0x00, 0x00, -1, -1, -1, -1,
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135 -1, -1, -1, -1, -1, -1, -1, -1,
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137 -1, -1, -1, -1, -1, -1, -1, -1,
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 0x02, 0x02, -1, -1, 0x02, -1, -1, -1,
140 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
141 -1, -1, 0x02, -1, -1, -1, -1, 0x00,
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 -1, -1, -1, -1, -1, -1, -1, -1,
144 };
145
146 int pm_old_env;
147 struct ksensor pm_lid_sens;
148 struct ksensordev pm_sensdev;
149
150 /*
151 * Define the private functions
152 */
153
154 /* for debugging */
155 #ifdef ADB_DEBUG
156 void pm_printerr(char *, int, int, char *);
157 #endif
158
159 int pm_wait_busy(int);
160 int pm_wait_free(int);
161 int pm_receive(u_char *);
162 int pm_send(u_char);
163
164 /* these functions also use the variables of adb_direct.c */
165 void pm_adb_get_TALK_result(PMData *);
166 void pm_adb_get_ADB_data(PMData *);
167
168 void pm_env_intr(PMData *);
169
170
171 extern int hw_power;
172
173 /*
174 * These variables are in adb_direct.c.
175 */
176 extern u_char *adbBuffer; /* pointer to user data area */
177 extern void *adbCompRout; /* pointer to the completion routine */
178 extern void *adbCompData; /* pointer to the completion routine data */
179 extern int adbWaiting; /* waiting for return data from the device */
180 extern int adbWaitingCmd; /* ADB command we are waiting for */
181 extern int adbStarting; /* doing ADB reinit, so do "polling" differently */
182
183 #define ADB_MAX_MSG_LENGTH 16
184 #define ADB_MAX_HDR_LENGTH 8
185 struct adbCommand {
186 u_char header[ADB_MAX_HDR_LENGTH]; /* not used yet */
187 u_char data[ADB_MAX_MSG_LENGTH]; /* packet data only */
188 u_char *saveBuf; /* where to save result */
189 u_char *compRout; /* completion routine pointer */
190 u_char *compData; /* completion routine data pointer */
191 u_int cmd; /* the original command for this data */
192 u_int unsol; /* 1 if packet was unsolicited */
193 u_int ack_only; /* 1 for no special processing */
194 };
195 extern void adb_pass_up(struct adbCommand *);
196
197
198 #ifdef ADB_DEBUG
199 /*
200 * This function dumps contents of the PMData
201 */
202 void
pm_printerr(char * ttl,int rval,int num,char * data)203 pm_printerr(char *ttl, int rval, int num, char *data)
204 {
205 int i;
206
207 printf("pm: %s:%04x %02x ", ttl, rval, num);
208 for (i = 0; i < num; i++)
209 printf("%02x ", data[i]);
210 printf("\n");
211 }
212 #endif
213
214 /*
215 * Wait until PM IC is busy
216 */
217 int
pm_wait_busy(int delay)218 pm_wait_busy(int delay)
219 {
220 while (PM_IS_ON) {
221 #ifdef PM_GRAB_SI
222 (void)intr_dispatch(0x70);
223 #endif
224 if ((--delay) < 0)
225 return 1; /* timeout */
226 }
227 return 0;
228 }
229
230
231 /*
232 * Wait until PM IC is free
233 */
234 int
pm_wait_free(int delay)235 pm_wait_free(int delay)
236 {
237 while (PM_IS_OFF) {
238 #ifdef PM_GRAB_SI
239 (void)intr_dispatch(0x70);
240 #endif
241 if ((--delay) < 0)
242 return 0; /* timeout */
243 }
244 return 1;
245 }
246
247 /*
248 * Functions for the PB Duo series and the PB 5XX series
249 */
250
251 /*
252 * Receive data from PM for the PB Duo series and the PB 5XX series
253 */
254 int
pm_receive(u_char * data)255 pm_receive(u_char *data)
256 {
257 int i;
258 int rval;
259
260 rval = 0xffffcd34;
261
262 switch (1) {
263 default:
264 /* set VIA SR to input mode */
265 via_reg_or(VIA1, vACR, 0x0c);
266 via_reg_and(VIA1, vACR, ~0x10);
267 i = PM_SR();
268
269 PM_SET_STATE_ACKOFF();
270 if (pm_wait_busy((int)ADBDelay*32) != 0)
271 break; /* timeout */
272
273 PM_SET_STATE_ACKON();
274 rval = 0xffffcd33;
275 if (pm_wait_free((int)ADBDelay*32) == 0)
276 break; /* timeout */
277
278 *data = PM_SR();
279 rval = 0;
280
281 break;
282 }
283
284 PM_SET_STATE_ACKON();
285 via_reg_or(VIA1, vACR, 0x1c);
286
287 return rval;
288 }
289
290 /*
291 * Send data to PM for the PB Duo series and the PB 5XX series
292 */
293 int
pm_send(u_char data)294 pm_send(u_char data)
295 {
296 int rval;
297
298 via_reg_or(VIA1, vACR, 0x1c);
299 write_via_reg(VIA1, vSR, data); /* PM_SR() = data; */
300
301 PM_SET_STATE_ACKOFF();
302 rval = 0xffffcd36;
303 if (pm_wait_busy((int)ADBDelay*32) != 0) {
304 PM_SET_STATE_ACKON();
305 via_reg_or(VIA1, vACR, 0x1c);
306 return rval;
307 }
308
309 PM_SET_STATE_ACKON();
310 rval = 0xffffcd35;
311 if (pm_wait_free((int)ADBDelay*32) != 0)
312 rval = 0;
313
314 PM_SET_STATE_ACKON();
315 via_reg_or(VIA1, vACR, 0x1c);
316
317 return rval;
318 }
319
320
321
322 /*
323 * My PMgrOp routine for the PB Duo series and the PB 5XX series
324 */
325 int
pmgrop(PMData * pmdata)326 pmgrop(PMData *pmdata)
327 {
328 int i;
329 int s;
330 u_char via1_vIER;
331 int rval = 0;
332 int num_pm_data = 0;
333 u_char pm_cmd;
334 short pm_num_rx_data;
335 u_char pm_data;
336 u_char *pm_buf;
337
338 s = splhigh();
339
340 /* disable all interrupts but PM */
341 via1_vIER = 0x10;
342 via1_vIER &= read_via_reg(VIA1, vIER);
343 write_via_reg(VIA1, vIER, via1_vIER);
344 if (via1_vIER != 0x0)
345 via1_vIER |= 0x80;
346
347 switch (pmdata->command) {
348 default:
349 /* wait until PM is free */
350 pm_cmd = (u_char)(pmdata->command & 0xff);
351 rval = 0xcd38;
352 if (pm_wait_free(ADBDelay * 4) == 0)
353 break; /* timeout */
354
355 /* send PM command */
356 if ((rval = pm_send((u_char)(pm_cmd & 0xff))))
357 break; /* timeout */
358
359 /* send number of PM data */
360 num_pm_data = pmdata->num_data;
361 if (pm_send_cmd_type[pm_cmd] < 0) {
362 if ((rval = pm_send((u_char)(num_pm_data & 0xff))) != 0)
363 break; /* timeout */
364 pmdata->command = 0;
365 }
366 /* send PM data */
367 pm_buf = (u_char *)pmdata->s_buf;
368 for (i = 0 ; i < num_pm_data; i++)
369 if ((rval = pm_send(pm_buf[i])) != 0)
370 break; /* timeout */
371 if (i != num_pm_data)
372 break; /* timeout */
373
374
375 /* check if PM will send me data */
376 pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
377 pmdata->num_data = pm_num_rx_data;
378 if (pm_num_rx_data == 0) {
379 rval = 0;
380 break; /* no return data */
381 }
382
383 /* receive PM command */
384 pm_data = pmdata->command;
385 pm_num_rx_data--;
386 if (pm_num_rx_data == 0)
387 if ((rval = pm_receive(&pm_data)) != 0) {
388 rval = 0xffffcd37;
389 break;
390 }
391 pmdata->command = pm_data;
392
393 /* receive number of PM data */
394 if (pm_num_rx_data < 0) {
395 if ((rval = pm_receive(&pm_data)) != 0)
396 break; /* timeout */
397 num_pm_data = pm_data;
398 } else
399 num_pm_data = pm_num_rx_data;
400 pmdata->num_data = num_pm_data;
401
402 /* receive PM data */
403 pm_buf = (u_char *)pmdata->r_buf;
404 for (i = 0; i < num_pm_data; i++) {
405 if ((rval = pm_receive(&pm_data)) != 0)
406 break; /* timeout */
407 pm_buf[i] = pm_data;
408 }
409
410 rval = 0;
411 }
412
413 /* restore former value */
414 write_via_reg(VIA1, vIER, via1_vIER);
415 splx(s);
416
417 return rval;
418 }
419
420 void
pm_in_adbattach(const char * devname)421 pm_in_adbattach(const char *devname)
422 {
423 /* A PowerBook (including iBook) has a lid. */
424 if (strncmp(hw_prod, "PowerBook", 9) == 0) {
425 strlcpy(pm_sensdev.xname, devname,
426 sizeof(pm_sensdev.xname));
427 strlcpy(pm_lid_sens.desc, "lid open",
428 sizeof(pm_lid_sens.desc));
429 pm_lid_sens.type = SENSOR_INDICATOR;
430 sensor_attach(&pm_sensdev, &pm_lid_sens);
431 sensordev_install(&pm_sensdev);
432 pm_lid_sens.value = 1; /* This is a guess. */
433 }
434 }
435
436 /*
437 * My PM interrupt routine for the PB Duo series and the PB 5XX series
438 */
439 void
pm_intr(void)440 pm_intr(void)
441 {
442 int s;
443 int rval;
444 PMData pmdata;
445
446 s = splhigh();
447
448 PM_VIA_CLR_INTR(); /* clear VIA1 interrupt */
449 /* ask PM what happened */
450 pmdata.command = PMU_INT_ACK;
451 pmdata.num_data = 0;
452 pmdata.s_buf = &pmdata.data[2];
453 pmdata.r_buf = &pmdata.data[2];
454 rval = pmgrop(&pmdata);
455 if (rval != 0) {
456 #ifdef ADB_DEBUG
457 if (adb_debug)
458 printf("pm: PM is not ready. error code: %08x\n", rval);
459 #endif
460 splx(s);
461 return;
462 }
463
464 switch ((u_int)(pmdata.data[2] & 0xff)) {
465 case 0x00: /* 1 sec interrupt? */
466 break;
467 case PMU_INT_TICK: /* 1 sec interrupt? */
468 break;
469 case PMU_INT_SNDBRT: /* Brightness/Contrast button on LCD panel */
470 break;
471 case PMU_INT_ADB: /* ADB data requested by TALK command */
472 case PMU_INT_ADB|PMU_INT_ADB_AUTO:
473 pm_adb_get_TALK_result(&pmdata);
474 break;
475 case 0x16: /* ADB device event */
476 case 0x18:
477 case 0x1e:
478 pm_adb_get_ADB_data(&pmdata);
479 break;
480 case PMU_INT_ENVIRONMENT:
481 pm_env_intr(&pmdata);
482 break;
483 default:
484 #ifdef ADB_DEBUG
485 if (adb_debug)
486 pm_printerr("driver does not support this event.",
487 pmdata.data[2], pmdata.num_data,
488 pmdata.data);
489 #endif
490 break;
491 }
492
493 splx(s);
494 }
495
496 /*
497 * Synchronous ADBOp routine for the Power Manager
498 */
499 int
pm_adb_op(u_char * buffer,void * compRout,void * data,int command)500 pm_adb_op(u_char *buffer, void *compRout, void *data, int command)
501 {
502 int i;
503 int s;
504 int rval;
505 int ndelay;
506 int waitfor; /* interrupts to poll for */
507 int ifr;
508 #ifdef ADB_DEBUG
509 int oldifr;
510 #endif
511 PMData pmdata;
512 struct adbCommand packet;
513 extern int adbempty;
514
515 if (adbWaiting == 1)
516 return 1;
517
518 s = splhigh();
519 write_via_reg(VIA1, vIER, 0x10);
520
521 adbBuffer = buffer;
522 adbCompRout = compRout;
523 adbCompData = data;
524
525 pmdata.command = 0x20;
526 pmdata.s_buf = pmdata.data;
527 pmdata.r_buf = pmdata.data;
528
529 /*
530 * if the command is LISTEN,
531 * add number of ADB data to number of PM data
532 */
533 if ((command & 0xc) == 0x8) {
534 if (buffer != NULL)
535 pmdata.num_data = buffer[0] + 3;
536 } else
537 pmdata.num_data = 3;
538
539 /*
540 * Resetting adb on several models, such as
541 * - PowerBook3,*
542 * - PowerBook5,*
543 * - PowerMac10,1
544 * causes several pmu interrupts with ifr set to PMU_INT_SNDBRT.
545 * Not processing them prevents us from seeing the adb devices
546 * afterwards, so we have to expect it unless we know the adb
547 * bus is empty.
548 */
549 if (command == PMU_RESET_ADB) {
550 waitfor = PMU_INT_ADB_AUTO | PMU_INT_ADB;
551 if (adbempty == 0)
552 waitfor |= PMU_INT_SNDBRT;
553 } else
554 waitfor = PMU_INT_ALL;
555
556 pmdata.data[0] = (u_char)(command & 0xff);
557 pmdata.data[1] = 0;
558 /* if the command is LISTEN, copy ADB data to PM buffer */
559 if ((command & 0xc) == 0x8) {
560 if (buffer != NULL && buffer[0] <= 24) {
561 pmdata.data[2] = buffer[0]; /* number of data */
562 for (i = 0; i < buffer[0]; i++)
563 pmdata.data[3 + i] = buffer[1 + i];
564 } else
565 pmdata.data[2] = 0;
566 } else
567 pmdata.data[2] = 0;
568
569 if ((command & 0xc) != 0xc) { /* if the command is not TALK */
570 /* set up stuff for adb_pass_up */
571 packet.data[0] = 1 + pmdata.data[2];
572 packet.data[1] = command;
573 for (i = 0; i < pmdata.data[2]; i++)
574 packet.data[i+2] = pmdata.data[i+3];
575 packet.saveBuf = adbBuffer;
576 packet.compRout = adbCompRout;
577 packet.compData = adbCompData;
578 packet.cmd = command;
579 packet.unsol = 0;
580 packet.ack_only = 1;
581 adb_polling = 1;
582 adb_pass_up(&packet);
583 adb_polling = 0;
584 }
585
586 rval = pmgrop(&pmdata);
587 if (rval != 0) {
588 splx(s);
589 return 1;
590 }
591
592 delay (1000);
593
594 adbWaiting = 1;
595 adbWaitingCmd = command;
596
597 PM_VIA_INTR_ENABLE();
598
599 /* wait until the PM interrupt is occurred */
600 ndelay = 0x8000;
601 #ifdef ADB_DEBUG
602 oldifr = 0;
603 #endif
604 while (adbWaiting == 1) {
605 ifr = read_via_reg(VIA1, vIFR);
606 if (ifr & waitfor) {
607 pm_intr();
608 #ifdef PM_GRAB_SI
609 (void)intr_dispatch(0x70);
610 #endif
611 #ifdef ADB_DEBUG
612 } else if (ifr != oldifr) {
613 if (adb_debug)
614 printf("pm_adb_op: ignoring ifr %02x"
615 ", expecting %02x\n",
616 (u_int)ifr, (u_int)waitfor);
617 oldifr = ifr;
618 #endif
619 }
620 if ((--ndelay) < 0) {
621 splx(s);
622 return 1;
623 }
624 delay(10);
625 }
626
627 /* this command enables the interrupt by operating ADB devices */
628 pmdata.command = PMU_ADB_CMD;
629 pmdata.num_data = 4;
630 pmdata.s_buf = pmdata.data;
631 pmdata.r_buf = pmdata.data;
632 pmdata.data[0] = 0x00;
633 pmdata.data[1] = 0x86; /* magic spell for awaking the PM */
634 pmdata.data[2] = 0x00;
635 pmdata.data[3] = 0x0c; /* each bit may express the existent ADB device */
636 rval = pmgrop(&pmdata);
637
638 splx(s);
639 return rval;
640 }
641
642
643 void
pm_adb_get_TALK_result(PMData * pmdata)644 pm_adb_get_TALK_result(PMData *pmdata)
645 {
646 int i;
647 struct adbCommand packet;
648
649 /* set up data for adb_pass_up */
650 packet.data[0] = pmdata->num_data-1;
651 packet.data[1] = pmdata->data[3];
652 for (i = 0; i <packet.data[0]-1; i++)
653 packet.data[i+2] = pmdata->data[i+4];
654
655 packet.saveBuf = adbBuffer;
656 packet.compRout = adbCompRout;
657 packet.compData = adbCompData;
658 packet.unsol = 0;
659 packet.ack_only = 0;
660 adb_polling = 1;
661 adb_pass_up(&packet);
662 adb_polling = 0;
663
664 adbWaiting = 0;
665 adbBuffer = NULL;
666 adbCompRout = NULL;
667 adbCompData = NULL;
668 }
669
670
671 void
pm_adb_get_ADB_data(PMData * pmdata)672 pm_adb_get_ADB_data(PMData *pmdata)
673 {
674 int i;
675 struct adbCommand packet;
676
677 /* set up data for adb_pass_up */
678 packet.data[0] = pmdata->num_data-1; /* number of raw data */
679 packet.data[1] = pmdata->data[3]; /* ADB command */
680 for (i = 0; i <packet.data[0]-1; i++)
681 packet.data[i+2] = pmdata->data[i+4];
682 packet.unsol = 1;
683 packet.ack_only = 0;
684 adb_pass_up(&packet);
685 }
686
687 void
pm_env_intr(PMData * pmdata)688 pm_env_intr(PMData *pmdata)
689 {
690 int env, old;
691
692 /* We might have 3 bytes data[3..5], but use only data[3]. */
693 if (pmdata->num_data < 3)
694 return;
695 env = pmdata->data[3];
696 old = pm_old_env;
697
698 pm_lid_sens.value = !(env & PMU_ENV_LID_CLOSED);
699 if (!(old & PMU_ENV_LID_CLOSED) && (env & PMU_ENV_LID_CLOSED))
700 adb_lid_closed_intr();
701
702 hw_power = !!(env & PMU_ENV_AC_POWER);
703
704 /*
705 * Act if one presses and releases the power button on a Mac
706 * with no ADB keyboard.
707 */
708 if ((old & PMU_ENV_POWER_BUTTON) && !(env & PMU_ENV_POWER_BUTTON))
709 adb_power_button_intr();
710
711 pm_old_env = env;
712 }
713
714 void
pm_adb_restart(void)715 pm_adb_restart(void)
716 {
717 PMData p;
718
719 p.command = PMU_RESET_CPU;
720 p.num_data = 0;
721 p.s_buf = p.data;
722 p.r_buf = p.data;
723 pmgrop(&p);
724 }
725
726 void
pm_adb_poweroff(void)727 pm_adb_poweroff(void)
728 {
729 PMData p;
730
731 bzero(&p, sizeof p);
732 p.command = PMU_POWER_OFF;
733 p.num_data = 4;
734 p.s_buf = p.data;
735 p.r_buf = p.data;
736 strlcpy(p.data, "MATT", sizeof p.data);
737 pmgrop(&p);
738 }
739
740 void
pm_read_date_time(time_t * time)741 pm_read_date_time(time_t *time)
742 {
743 PMData p;
744 u_int32_t t;
745
746 p.command = PMU_READ_RTC;
747 p.num_data = 0;
748 p.s_buf = p.data;
749 p.r_buf = p.data;
750 pmgrop(&p);
751
752 bcopy(p.data, &t, sizeof(t));
753 *time = (time_t)t;
754 }
755
756 void
pm_set_date_time(time_t time)757 pm_set_date_time(time_t time)
758 {
759 PMData p;
760 u_int32_t t = time; /* XXX eventually truncates */
761
762 p.command = PMU_SET_RTC;
763 p.num_data = sizeof(t);
764 p.s_buf = p.r_buf = p.data;
765 bcopy(&t, p.data, sizeof(t));
766 pmgrop(&p);
767 }
768
769 #if 0
770 void
771 pm_eject_pcmcia(int slot)
772 {
773 PMData p;
774
775 if (slot != 0 && slot != 1)
776 return;
777
778 p.command = PMU_EJECT_PCMCIA;
779 p.num_data = 1;
780 p.s_buf = p.r_buf = p.data;
781 p.data[0] = 5 + slot; /* XXX */
782 pmgrop(&p);
783 }
784 #endif
785
786
787 /*
788 * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation
789 * for a clear description of the PMU results.
790 */
791
792 int
pm_battery_info(int battery,struct pmu_battery_info * info)793 pm_battery_info(int battery, struct pmu_battery_info *info)
794 {
795 PMData p;
796
797 p.command = PMU_SMART_BATTERY_STATE;
798 p.num_data = 1;
799 p.s_buf = p.r_buf = p.data;
800 p.data[0] = battery + 1;
801 pmgrop(&p);
802
803 info->flags = p.data[1];
804 hw_power = !!(info->flags & PMU_PWR_AC_PRESENT);
805
806 switch (p.data[0]) {
807 case 3:
808 case 4:
809 info->cur_charge = p.data[2];
810 info->max_charge = p.data[3];
811 info->draw = *((signed char *)&p.data[4]);
812 info->voltage = p.data[5];
813 break;
814 case 5:
815 info->cur_charge = ((p.data[2] << 8) | (p.data[3]));
816 info->max_charge = ((p.data[4] << 8) | (p.data[5]));
817 info->draw = *((signed short *)&p.data[6]);
818 info->voltage = ((p.data[8] << 8) | (p.data[7]));
819 break;
820 default:
821 /* XXX - Error condition */
822 info->cur_charge = 0;
823 info->max_charge = 0;
824 info->draw = 0;
825 info->voltage = 0;
826 break;
827 }
828
829 return 1;
830 }
831
832 void
pmu_fileserver_mode(int on)833 pmu_fileserver_mode(int on)
834 {
835 PMData p;
836
837 p.command = PMU_POWER_EVENTS;
838 p.num_data = 1;
839 p.s_buf = p.r_buf = p.data;
840 p.data[0] = PMU_PWR_GET_POWERUP_EVENTS;
841 pmgrop(&p);
842
843 p.command = PMU_POWER_EVENTS;
844 p.num_data = 3;
845 p.s_buf = p.r_buf = p.data;
846 p.data[1] = p.data[0]; /* result from the get */
847 if (on) {
848 p.data[0] = PMU_PWR_SET_POWERUP_EVENTS;
849 p.data[2] = PMU_WAKE_AC_LOSS;
850 } else {
851 p.data[0] = PMU_PWR_CLR_POWERUP_EVENTS;
852 p.data[2] = PMU_WAKE_AC_LOSS;
853 }
854 pmgrop(&p);
855 }
856
857 int
pmu_set_kbl(unsigned int level)858 pmu_set_kbl(unsigned int level)
859 {
860 if (level > 0xff)
861 return (EINVAL);
862
863 PMData p;
864
865 p.command = 0x4F;
866 p.num_data = 3;
867 p.s_buf = p.r_buf = p.data;
868 p.data[0] = 0;
869 p.data[1] = 0;
870 p.data[2] = level;
871 pmgrop(&p);
872 return (0);
873 }
874
875