pm_direct.c revision 1.30
1/*	$NetBSD: pm_direct.c,v 1.30 2021/08/21 11:55:24 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.30 2021/08/21 11:55:24 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 inetrrupts 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	}
566
567	if ((pmdata.data[2] & 0x10) == 0x10) {
568		if ((pmdata.data[2] & 0x0f) == 0) {
569			/* ADB data that were requested by TALK command */
570			pm_adb_get_TALK_result(&pmdata);
571		} else if ((pmdata.data[2] & 0x08) == 0x8) {
572			/* PM is requesting to poll  */
573			pm_adb_poll_next_device_pm1(&pmdata);
574		} else if ((pmdata.data[2] & 0x04) == 0x4) {
575			/* ADB device event */
576			pm_adb_get_ADB_data(&pmdata);
577		}
578	} else {
579#ifdef ADB_DEBUG
580		if (adb_debug)
581			pm_printerr("driver does not supported this event.",
582			    rval, pmdata.num_data, pmdata.data);
583#endif
584	}
585
586	splx(s);
587}
588
589
590
591/*
592 * Functions for the PB Duo series and the PB 5XX series
593 */
594
595/*
596 * Receive data from PM for the PB Duo series and the PB 5XX series
597 */
598int
599pm_receive_pm2(u_char *data)
600{
601	int rval;
602
603	rval = 0xffffcd34;
604
605	switch (1) {
606		default:
607			/* set VIA SR to input mode */
608			via_reg(VIA1, vACR) |= 0x0c;
609			via_reg(VIA1, vACR) &= ~0x10;
610			PM_SR();
611
612			PM_SET_STATE_ACKOFF();
613			if (pm_wait_busy((int)ADBDelay*32) != 0)
614				break;		/* timeout */
615
616			PM_SET_STATE_ACKON();
617			rval = 0xffffcd33;
618			if (pm_wait_free((int)ADBDelay*32) == 0)
619				break;		/* timeout */
620
621			*data = PM_SR();
622			rval = 0;
623
624			break;
625	}
626
627	PM_SET_STATE_ACKON();
628	via_reg(VIA1, vACR) |= 0x1c;
629
630	return rval;
631}
632
633
634
635/*
636 * Send data to PM for the PB Duo series and the PB 5XX series
637 */
638int
639pm_send_pm2(u_char data)
640{
641	int rval;
642
643	via_reg(VIA1, vACR) |= 0x1c;
644	PM_SR() = data;
645
646	PM_SET_STATE_ACKOFF();
647	if (pm_wait_busy((int)ADBDelay*32) == 0) {
648		PM_SET_STATE_ACKON();
649		if (pm_wait_free((int)ADBDelay*32) != 0)
650			rval = 0;
651		else
652			rval = 0xffffcd35;
653	} else {
654		rval = 0xffffcd36;
655	}
656
657	PM_SET_STATE_ACKON();
658	via_reg(VIA1, vACR) |= 0x1c;
659
660	return rval;
661}
662
663
664
665/*
666 * My PMgrOp routine for the PB Duo series and the PB 5XX series
667 */
668int
669pm_pmgrop_pm2(PMData *pmdata)
670{
671	int i;
672	int s;
673	u_char via1_vIER;
674	int rval = 0;
675	int num_pm_data = 0;
676	u_char pm_cmd;
677	short pm_num_rx_data;
678	u_char pm_data;
679	u_char *pm_buf;
680
681	s = splhigh();
682
683	/* disable all inetrrupts but PM */
684	via1_vIER = 0x10;
685	via1_vIER &= via_reg(VIA1, vIER);
686	via_reg(VIA1, vIER) = via1_vIER;
687	if (via1_vIER != 0x0)
688		via1_vIER |= 0x80;
689
690	switch (pmdata->command) {
691		default:
692			/* wait until PM is free */
693			pm_cmd = (u_char)(pmdata->command & 0xff);
694			rval = 0xcd38;
695			if (pm_wait_free(ADBDelay * 4) == 0)
696				break;			/* timeout */
697
698			if (HwCfgFlags3 & 0x00200000) {
699				/* PB 160, PB 165(c), PB 180(c)? */
700				int xdelay = ADBDelay * 16;
701
702				via_reg(VIA2, vDirA) = 0x00;
703				while ((via_reg(VIA2, 0x200) == 0x07) &&
704				    (xdelay >= 0))
705					xdelay--;
706
707				if (xdelay < 0) {
708					rval = 0xffffcd38;
709					break;		/* timeout */
710				}
711			}
712
713			/* send PM command */
714			if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
715				break;				/* timeout */
716
717			/* send number of PM data */
718			num_pm_data = pmdata->num_data;
719			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
720				if (pm_send_cmd_type[pm_cmd] < 0) {
721					if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
722						break;		/* timeout */
723					pmdata->command = 0;
724				}
725			} else {				/* PB 1XX series ? */
726				if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
727					break;			/* timeout */
728			}
729			/* send PM data */
730			pm_buf = (u_char *)pmdata->s_buf;
731			for (i = 0 ; i < num_pm_data; i++)
732				if ((rval = pm_send_pm2(pm_buf[i])) != 0)
733					break;			/* timeout */
734			if (i != num_pm_data)
735				break;				/* timeout */
736
737
738			/* check if PM will send me data  */
739			pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
740			pmdata->num_data = pm_num_rx_data;
741			if (pm_num_rx_data == 0) {
742				rval = 0;
743				break;				/* no return data */
744			}
745
746			/* receive PM command */
747			pm_data = pmdata->command;
748			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
749				pm_num_rx_data--;
750				if (pm_num_rx_data == 0)
751					if ((rval = pm_receive_pm2(&pm_data)) != 0) {
752						rval = 0xffffcd37;
753						break;
754					}
755				pmdata->command = pm_data;
756			} else {				/* PB 1XX series ? */
757				if ((rval = pm_receive_pm2(&pm_data)) != 0) {
758					rval = 0xffffcd37;
759					break;
760				}
761				pmdata->command = pm_data;
762			}
763
764			/* receive number of PM data */
765			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
766				if (pm_num_rx_data < 0) {
767					if ((rval = pm_receive_pm2(&pm_data)) != 0)
768						break;		/* timeout */
769					num_pm_data = pm_data;
770				} else
771					num_pm_data = pm_num_rx_data;
772				pmdata->num_data = num_pm_data;
773			} else {				/* PB 1XX serias ? */
774				if ((rval = pm_receive_pm2(&pm_data)) != 0)
775					break;			/* timeout */
776				num_pm_data = pm_data;
777				pmdata->num_data = num_pm_data;
778			}
779
780			/* receive PM data */
781			pm_buf = (u_char *)pmdata->r_buf;
782			for (i = 0; i < num_pm_data; i++) {
783				if ((rval = pm_receive_pm2(&pm_data)) != 0)
784					break;			/* timeout */
785				pm_buf[i] = pm_data;
786			}
787
788			rval = 0;
789	}
790
791	/* restore former value */
792	via_reg(VIA1, vIER) = via1_vIER;
793	splx(s);
794
795	return rval;
796}
797
798
799/*
800 * My PM interrupt routine for the PB Duo series and the PB 5XX series
801 */
802void
803pm_intr_pm2(void *arg)
804{
805	int s;
806	int rval;
807	PMData pmdata;
808
809	s = splhigh();
810
811	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
812						/* ask PM what happened */
813	pmdata.command = 0x78;
814	pmdata.num_data = 0;
815	pmdata.s_buf = &pmdata.data[2];
816	pmdata.r_buf = &pmdata.data[2];
817	rval = pm_pmgrop_pm2(&pmdata);
818	if (rval != 0) {
819#ifdef ADB_DEBUG
820		if (adb_debug)
821			printf("pm: PM is not ready. error code: %08x\n", rval);
822#endif
823		splx(s);
824	}
825
826	switch ((u_int)(pmdata.data[2] & 0xff)) {
827		case 0x00:			/* 1 sec interrupt? */
828			break;
829		case 0x80:			/* 1 sec interrupt? */
830			pm_counter++;
831			break;
832		case 0x08:			/* Brightness/Contrast button on LCD panel */
833			/* get brightness and contrast of the LCD */
834			pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
835			pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
836/*
837			pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
838			pmdata.command = 0x33;
839			pmdata.num_data = 1;
840			pmdata.s_buf = pmdata.data;
841			pmdata.r_buf = pmdata.data;
842			pmdata.data[0] = pm_LCD_contrast;
843			rval = pm_pmgrop_pm2(&pmdata);
844			pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
845*/
846			/* this is an experimental code */
847			pmdata.command = 0x41;
848			pmdata.num_data = 1;
849			pmdata.s_buf = pmdata.data;
850			pmdata.r_buf = pmdata.data;
851			pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
852			if (pm_LCD_brightness < 0x25)
853				pm_LCD_brightness = 0x25;
854			if (pm_LCD_brightness > 0x5a)
855				pm_LCD_brightness = 0x7f;
856			pmdata.data[0] = pm_LCD_brightness;
857			rval = pm_pmgrop_pm2(&pmdata);
858			break;
859		case 0x10:			/* ADB data that were requested by TALK command */
860		case 0x14:
861			pm_adb_get_TALK_result(&pmdata);
862			break;
863		case 0x16:			/* ADB device event */
864		case 0x18:
865		case 0x1e:
866			pm_adb_get_ADB_data(&pmdata);
867			break;
868		default:
869#ifdef ADB_DEBUG
870			if (adb_debug)
871				pm_printerr("driver does not supported this event.",
872				    pmdata.data[2], pmdata.num_data,
873				    pmdata.data);
874#endif
875			break;
876	}
877
878	splx(s);
879}
880
881
882/*
883 * MRG-based PMgrOp routine
884 */
885int
886pm_pmgrop_mrg(PMData *pmdata)
887{
888	u_int32_t rval=0;
889
890	__asm volatile(
891	"	movl	%1,%%a0	\n"
892	"	.word	0xa085	\n"
893	"	movl	%%d0,%0"
894		: "=g" (rval)
895		: "g" (pmdata)
896		: "a0","d0");
897
898	return rval;
899}
900
901
902/*
903 * My PMgrOp routine
904 */
905int
906pmgrop(PMData *pmdata)
907{
908	switch (pmHardware) {
909		case PM_HW_PB1XX:
910			return (pm_pmgrop_pm1(pmdata));
911			break;
912		case PM_HW_PB5XX:
913			return (pm_pmgrop_pm2(pmdata));
914			break;
915		default:
916			/* return (pmgrop_mrg(pmdata)); */
917			return 1;
918	}
919}
920
921
922/*
923 * My PM interrupt routine
924 */
925void
926pm_intr(void *arg)
927{
928	switch (pmHardware) {
929		case PM_HW_PB1XX:
930			pm_intr_pm1(arg);
931			break;
932		case PM_HW_PB5XX:
933			pm_intr_pm2(arg);
934			break;
935		default:
936			break;
937	}
938}
939
940
941void
942pm_hw_setup(void)
943{
944	switch (pmHardware) {
945		case PM_HW_PB1XX:
946			via1_register_irq(4, pm_intr_pm1, (void *)0);
947			PM_VIA_CLR_INTR();
948			break;
949		case PM_HW_PB5XX:
950			via1_register_irq(4, pm_intr_pm2, (void *)0);
951			PM_VIA_CLR_INTR();
952			break;
953		default:
954			break;
955	}
956}
957
958
959/*
960 * Synchronous ADBOp routine for the Power Manager
961 */
962int
963pm_adb_op(u_char *buffer, void *compRout, void *data, int command)
964{
965	int i;
966	int s;
967	int rval;
968	int xdelay;
969	PMData pmdata;
970	struct adbCommand packet;
971
972	if (adbWaiting == 1)
973		return 1;
974
975	s = splhigh();
976	via_reg(VIA1, vIER) = 0x10;
977
978 	adbBuffer = buffer;
979	adbCompRout = compRout;
980	adbCompData = data;
981
982	pmdata.command = 0x20;
983	pmdata.s_buf = pmdata.data;
984	pmdata.r_buf = pmdata.data;
985
986	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, add number of ADB data to number of PM data */
987		if (buffer != (u_char *)0)
988			pmdata.num_data = buffer[0] + 3;
989	} else {
990		pmdata.num_data = 3;
991	}
992
993	pmdata.data[0] = (u_char)(command & 0xff);
994	pmdata.data[1] = 0;
995	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
996		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
997			pmdata.data[2] = buffer[0];		/* number of data */
998			for (i = 0; i < buffer[0]; i++)
999				pmdata.data[3 + i] = buffer[1 + i];
1000		} else
1001			pmdata.data[2] = 0;
1002	} else
1003		pmdata.data[2] = 0;
1004
1005	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
1006		/* set up stuff fNULLor adb_pass_up */
1007		packet.data[0] = 1 + pmdata.data[2];
1008		packet.data[1] = command;
1009		for (i = 0; i < pmdata.data[2]; i++)
1010			packet.data[i+2] = pmdata.data[i+3];
1011		packet.saveBuf = adbBuffer;
1012		packet.compRout = adbCompRout;
1013		packet.compData = adbCompData;
1014		packet.cmd = command;
1015		packet.unsol = 0;
1016		packet.ack_only = 1;
1017		adb_polling = 1;
1018		adb_pass_up(&packet);
1019		adb_polling = 0;
1020	}
1021
1022	rval = pmgrop(&pmdata);
1023	if (rval != 0) {
1024		splx(s);
1025		return 1;
1026	}
1027
1028	adbWaiting = 1;
1029	adbWaitingCmd = command;
1030
1031	PM_VIA_INTR_ENABLE();
1032
1033	/* wait until the PM interrupt has occurred */
1034	xdelay = 0x80000;
1035	while (adbWaiting == 1) {
1036		switch (mac68k_machine.machineid) {
1037		case MACH_MACPB150:
1038		case MACH_MACPB210:
1039		case MACH_MACPB230:	/* daishi tested with Duo230 */
1040		case MACH_MACPB250:
1041		case MACH_MACPB270:
1042		case MACH_MACPB280:
1043		case MACH_MACPB280C:
1044		case MACH_MACPB190:
1045		case MACH_MACPB190CS:
1046			pm_intr((void *)0);
1047			break;
1048		default:
1049			if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
1050				pm_intr((void *)0);
1051			break;
1052		}
1053#ifdef PM_GRAB_SI
1054		(void)intr_dispatch(0x70);	/* grab any serial interrupts */
1055#endif
1056		if ((--xdelay) < 0) {
1057			splx(s);
1058			return 1;
1059		}
1060	}
1061
1062	/* this command enables the interrupt by operating ADB devices */
1063	if (HwCfgFlags3 & 0x00020000) {		/* PB Duo series, PB 5XX series */
1064		pmdata.command = 0x20;
1065		pmdata.num_data = 4;
1066		pmdata.s_buf = pmdata.data;
1067		pmdata.r_buf = pmdata.data;
1068		pmdata.data[0] = 0x00;
1069		pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
1070		pmdata.data[2] = 0x00;
1071		pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
1072	} else {				/* PB 1XX series */
1073		pmdata.command = 0x20;
1074		pmdata.num_data = 3;
1075		pmdata.s_buf = pmdata.data;
1076		pmdata.r_buf = pmdata.data;
1077		pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
1078		pmdata.data[1] = 0x04;
1079		pmdata.data[2] = 0x00;
1080	}
1081	rval = pmgrop(&pmdata);
1082
1083	splx(s);
1084	return rval;
1085}
1086
1087
1088void
1089pm_adb_get_TALK_result(PMData *pmdata)
1090{
1091	int i;
1092	struct adbCommand packet;
1093
1094	/* set up data for adb_pass_up */
1095	packet.data[0] = pmdata->num_data-1;
1096	packet.data[1] = pmdata->data[3];
1097	for (i = 0; i <packet.data[0]-1; i++)
1098		packet.data[i+2] = pmdata->data[i+4];
1099
1100	packet.saveBuf = adbBuffer;
1101	packet.compRout = adbCompRout;
1102	packet.compData = adbCompData;
1103	packet.unsol = 0;
1104	packet.ack_only = 0;
1105	adb_polling = 1;
1106	adb_pass_up(&packet);
1107	adb_polling = 0;
1108
1109	adbWaiting = 0;
1110	adbBuffer = (long)0;
1111	adbCompRout = (long)0;
1112	adbCompData = (long)0;
1113}
1114
1115
1116void
1117pm_adb_get_ADB_data(PMData *pmdata)
1118{
1119	int i;
1120	struct adbCommand packet;
1121
1122	/* set up data for adb_pass_up */
1123	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
1124	packet.data[1] = pmdata->data[3];	/* ADB command */
1125	for (i = 0; i <packet.data[0]-1; i++)
1126		packet.data[i+2] = pmdata->data[i+4];
1127	packet.unsol = 1;
1128	packet.ack_only = 0;
1129	adb_pass_up(&packet);
1130}
1131
1132
1133void
1134pm_adb_poll_next_device_pm1(PMData *pmdata)
1135{
1136	int i;
1137	int ndid;
1138	u_short bendid = 0x1;
1139	PMData tmp_pmdata;
1140
1141	/* find another existent ADB device to poll */
1142	for (i = 1; i < 16; i++) {
1143		ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1144		bendid <<= ndid;
1145		if ((pm_existent_ADB_devices & bendid) != 0)
1146			break;
1147	}
1148
1149	/* poll the other device */
1150	tmp_pmdata.command = 0x20;
1151	tmp_pmdata.num_data = 3;
1152	tmp_pmdata.s_buf = tmp_pmdata.data;
1153	tmp_pmdata.r_buf = tmp_pmdata.data;
1154	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1155	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
1156	tmp_pmdata.data[2] = 0x00;
1157	pmgrop(&tmp_pmdata);
1158}
1159