xref: /openbsd/sys/arch/macppc/dev/pm_direct.c (revision 6784ab1f)
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