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