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