pm_direct.c revision 1.23
1/*	$NetBSD: pm_direct.c,v 1.23 2005/01/15 16:00:59 chs 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.23 2005/01/15 16:00:59 chs 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/cdefs.h>
49#include <sys/systm.h>
50
51#include <machine/viareg.h>
52#include <machine/param.h>
53#include <machine/cpu.h>
54#include <machine/adbsys.h>
55
56#include <mac68k/mac68k/macrom.h>
57#include <mac68k/dev/adbvar.h>
58#include <mac68k/dev/pm_direct.h>
59
60/* hardware dependent values */
61extern u_short ADBDelay;
62extern u_int32_t HwCfgFlags3;
63extern struct mac68k_machine_S mac68k_machine;
64
65
66/* define the types of the Power Manager */
67#define PM_HW_UNKNOWN		0x00	/* don't know */
68#define PM_HW_PB1XX		0x01	/* PowerBook 1XX series */
69#define	PM_HW_PB5XX		0x02	/* PowerBook Duo and 5XX series */
70
71/* useful macros */
72#define PM_SR()			via_reg(VIA1, vSR)
73#define PM_VIA_INTR_ENABLE()	via_reg(VIA1, vIER) = 0x90
74#define PM_VIA_INTR_DISABLE()	via_reg(VIA1, vIER) = 0x10
75#define PM_VIA_CLR_INTR()	via_reg(VIA1, vIFR) = 0x90
76#define PM_SET_STATE_ACKON()	via_reg(VIA2, vBufB) |= 0x04
77#define PM_SET_STATE_ACKOFF()	via_reg(VIA2, vBufB) &= ~0x04
78#define PM_IS_ON		(0x02 == (via_reg(VIA2, vBufB) & 0x02))
79#define PM_IS_OFF		(0x00 == (via_reg(VIA2, vBufB) & 0x02))
80
81/*
82 * Variables for internal use
83 */
84int	pmHardware = PM_HW_UNKNOWN;
85u_short	pm_existent_ADB_devices = 0x0;	/* each bit expresses the existent ADB device */
86u_int	pm_LCD_brightness = 0x0;
87u_int	pm_LCD_contrast = 0x0;
88u_int	pm_counter = 0;			/* clock count */
89
90/* these values shows that number of data returned after 'send' cmd is sent */
91char pm_send_cmd_type[] = {
92	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
93	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
94	0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
95	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
96	0xff, 0x00, 0x02, 0x01, 0x01, 0xff, 0xff, 0xff,
97	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
98	0x04, 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
99	0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff,
100	0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
101	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
102	0x01, 0x00, 0x02, 0x02, 0xff, 0x01, 0x03, 0x01,
103	0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
104	0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
105	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
106	0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
107	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x04, 0x04,
108	0x04, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
109	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
110	0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
111	0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
112	0x02, 0x02, 0x02, 0x04, 0xff, 0x00, 0xff, 0xff,
113	0x01, 0x01, 0x03, 0x02, 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	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
118	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
119	0x01, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff,
120	0xff, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
121	0x03, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00,
122	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
123	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
124};
125
126/* these values shows that number of data returned after 'receive' cmd is sent */
127char pm_receive_cmd_type[] = {
128	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
130	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131	0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
132	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
134	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135	0x05, 0x15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
136	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
137	0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
138	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139	0x02, 0x00, 0x03, 0x03, 0xff, 0xff, 0xff, 0xff,
140	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141	0x04, 0x04, 0x03, 0x09, 0xff, 0xff, 0xff, 0xff,
142	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01,
144	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145	0x06, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
146	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147	0x02, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
148	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149	0x02, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
150	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
151	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
152	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
154	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
155	0x02, 0x02, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff,
156	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
157	0xff, 0xff, 0x02, 0xff, 0xff, 0xff, 0xff, 0x00,
158	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
159	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
160};
161
162
163/*
164 * Define the private functions
165 */
166
167/* for debugging */
168#ifdef ADB_DEBUG
169void	pm_printerr(char *, int, int, char *);
170#endif
171
172int	pm_wait_busy(int);
173int	pm_wait_free(int);
174
175/* these functions are for the PB1XX series */
176int	pm_receive_pm1(u_char *);
177int	pm_send_pm1(u_char, int);
178int	pm_pmgrop_pm1(PMData *);
179void	pm_intr_pm1(void *);
180
181/* these functions are for the PB Duo series and the PB 5XX series */
182int	pm_receive_pm2(u_char *);
183int	pm_send_pm2(u_char);
184int	pm_pmgrop_pm2(PMData *);
185void	pm_intr_pm2(void *);
186
187/* this function is MRG-Based (for testing) */
188int	pm_pmgrop_mrg(PMData *);
189
190/* these functions are called from adb_direct.c */
191void	pm_setup_adb(void);
192void	pm_check_adb_devices(int);
193void	pm_intr(void *);
194int	pm_adb_op(u_char *, void *, void *, int);
195void	pm_hw_setup(void);
196
197/* these functions also use the variables of adb_direct.c */
198void	pm_adb_get_TALK_result(PMData *);
199void	pm_adb_get_ADB_data(PMData *);
200void	pm_adb_poll_next_device_pm1(PMData *);
201
202
203/*
204 * These variables are in adb_direct.c.
205 */
206extern u_char	*adbBuffer;	/* pointer to user data area */
207extern void	*adbCompRout;	/* pointer to the completion routine */
208extern void	*adbCompData;	/* pointer to the completion routine data */
209extern int	adbWaiting;	/* waiting for return data from the device */
210extern int	adbWaitingCmd;	/* ADB command we are waiting for */
211extern int	adbStarting;	/* doing ADB reinit, so do "polling" differently */
212
213#define	ADB_MAX_MSG_LENGTH	16
214#define	ADB_MAX_HDR_LENGTH	8
215struct adbCommand {
216	u_char	header[ADB_MAX_HDR_LENGTH];	/* not used yet */
217	u_char	data[ADB_MAX_MSG_LENGTH];	/* packet data only */
218	u_char	*saveBuf;	/* where to save result */
219	u_char	*compRout;	/* completion routine pointer */
220	u_char	*compData;	/* completion routine data pointer */
221	u_int	cmd;		/* the original command for this data */
222	u_int	unsol;		/* 1 if packet was unsolicited */
223	u_int	ack_only;	/* 1 for no special processing */
224};
225extern	void	adb_pass_up(struct adbCommand *);
226
227#ifdef ADB_DEBUG
228/*
229 * This function dumps contents of the PMData
230 */
231void
232pm_printerr(char *ttl, int rval, int num, char *data)
233{
234	int i;
235
236	printf("pm: %s:%04x %02x ", ttl, rval, num);
237	for (i = 0; i < num; i++)
238		printf("%02x ", data[i]);
239	printf("\n");
240}
241#endif
242
243
244
245/*
246 * Check the hardware type of the Power Manager
247 */
248void
249pm_setup_adb(void)
250{
251	switch (mac68k_machine.machineid) {
252		case MACH_MACPB140:
253		case MACH_MACPB145:
254		case MACH_MACPB160:
255		case MACH_MACPB165:
256		case MACH_MACPB165C:
257		case MACH_MACPB170:
258		case MACH_MACPB180:
259		case MACH_MACPB180C:
260			pmHardware = PM_HW_PB1XX;
261			break;
262		case MACH_MACPB150:
263		case MACH_MACPB210:
264		case MACH_MACPB230:
265		case MACH_MACPB250:
266		case MACH_MACPB270:
267		case MACH_MACPB280:
268		case MACH_MACPB280C:
269		case MACH_MACPB500:
270		case MACH_MACPB190:
271		case MACH_MACPB190CS:
272			pmHardware = PM_HW_PB5XX;
273			break;
274		default:
275			break;
276	}
277}
278
279
280/*
281 * Check the existent ADB devices
282 */
283void
284pm_check_adb_devices(int id)
285{
286	u_short ed = 0x1;
287
288	ed <<= id;
289	pm_existent_ADB_devices |= ed;
290}
291
292
293/*
294 * Wait until PM IC is busy
295 */
296int
297pm_wait_busy(int delay)
298{
299	while (PM_IS_ON) {
300#ifdef PM_GRAB_SI
301		(void)intr_dispatch(0x70);	/* grab any serial interrupts */
302#endif
303		if ((--delay) < 0)
304			return 1;	/* timeout */
305	}
306	return 0;
307}
308
309
310/*
311 * Wait until PM IC is free
312 */
313int
314pm_wait_free(int delay)
315{
316	while (PM_IS_OFF) {
317#ifdef PM_GRAB_SI
318		(void)intr_dispatch(0x70);	/* grab any serial interrupts */
319#endif
320		if ((--delay) < 0)
321			return 0;	/* timeout */
322	}
323	return 1;
324}
325
326
327
328/*
329 * Functions for the PB1XX series
330 */
331
332/*
333 * Receive data from PM for the PB1XX series
334 */
335int
336pm_receive_pm1(u_char *data)
337{
338	int rval = 0xffffcd34;
339
340	via_reg(VIA2, vDirA) = 0x00;
341
342	switch (1) {
343		default:
344			if (pm_wait_busy(0x40) != 0)
345				break;			/* timeout */
346
347			PM_SET_STATE_ACKOFF();
348			*data = via_reg(VIA2, 0x200);
349
350			rval = 0xffffcd33;
351			if (pm_wait_free(0x40) == 0)
352				break;			/* timeout */
353
354			rval = 0x00;
355			break;
356	}
357
358	PM_SET_STATE_ACKON();
359	via_reg(VIA2, vDirA) = 0x00;
360
361	return rval;
362}
363
364
365
366/*
367 * Send data to PM for the PB1XX series
368 */
369int
370pm_send_pm1(u_char data, int timo)
371{
372	int rval;
373
374	via_reg(VIA2, vDirA) = 0xff;
375	via_reg(VIA2, 0x200) = data;
376
377	PM_SET_STATE_ACKOFF();
378#if 0
379	if (pm_wait_busy(0x400) == 0) {
380#else
381	if (pm_wait_busy(timo) == 0) {
382#endif
383		PM_SET_STATE_ACKON();
384		if (pm_wait_free(0x40) != 0)
385			rval = 0x0;
386		else
387			rval = 0xffffcd35;
388	} else {
389		rval = 0xffffcd36;
390	}
391
392	PM_SET_STATE_ACKON();
393	via_reg(VIA2, vDirA) = 0x00;
394
395	return rval;
396}
397
398
399/*
400 * My PMgrOp routine for the PB1XX series
401 */
402int
403pm_pmgrop_pm1(PMData *pmdata)
404{
405	int i;
406	int s = 0x81815963;
407	u_char via1_vIER, via1_vDirA;
408	int rval = 0;
409	int num_pm_data = 0;
410	u_char pm_cmd;
411	u_char pm_data;
412	u_char *pm_buf;
413
414	/* disable all inetrrupts but PM */
415	via1_vIER = via_reg(VIA1, vIER);
416	PM_VIA_INTR_DISABLE();
417
418	via1_vDirA = via_reg(VIA1, vDirA);
419
420	switch (pmdata->command) {
421		default:
422			for (i = 0; i < 7; i++) {
423				via_reg(VIA2, vDirA) = 0x00;
424
425				/* wait until PM is free */
426				if (pm_wait_free(ADBDelay) == 0) {	/* timeout */
427					via_reg(VIA2, vDirA) = 0x00;
428					/* restore formar value */
429					via_reg(VIA1, vDirA) = via1_vDirA;
430					via_reg(VIA1, vIER) = via1_vIER;
431					return 0xffffcd38;
432				}
433
434				switch (mac68k_machine.machineid) {
435					case MACH_MACPB160:
436					case MACH_MACPB165:
437					case MACH_MACPB165C:
438					case MACH_MACPB170:
439					case MACH_MACPB180:
440					case MACH_MACPB180C:
441						{
442							int delay = ADBDelay * 16;
443
444							via_reg(VIA2, vDirA) = 0x00;
445							while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
446								delay--;
447
448							if (delay < 0) {	/* timeout */
449								via_reg(VIA2, vDirA) = 0x00;
450								/* restore formar value */
451								via_reg(VIA1, vIER) = via1_vIER;
452								return 0xffffcd38;
453							}
454						}
455				} /* end switch */
456
457				s = splhigh();
458
459				via1_vDirA = via_reg(VIA1, vDirA);
460				via_reg(VIA1, vDirA) &= 0x7f;
461
462				pm_cmd = (u_char)(pmdata->command & 0xff);
463				if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
464					break;	/* send command succeeded */
465
466				via_reg(VIA1, vDirA) = via1_vDirA;
467				splx(s);
468			} /* end for */
469
470			/* failed to send a command */
471			if (i == 7) {
472				via_reg(VIA2, vDirA) = 0x00;
473				/* restore formar value */
474				via_reg(VIA1, vDirA) = via1_vDirA;
475				via_reg(VIA1, vIER) = via1_vIER;
476				if (s != 0x81815963)
477					splx(s);
478				return 0xffffcd38;
479			}
480
481			/* send # of PM data */
482			num_pm_data = pmdata->num_data;
483			if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
484				break;			/* timeout */
485
486			/* send PM data */
487			pm_buf = (u_char *)pmdata->s_buf;
488			for (i = 0; i < num_pm_data; i++)
489				if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
490					break;		/* timeout */
491			if ((i != num_pm_data) && (num_pm_data != 0))
492				break;			/* timeout */
493
494			/* Will PM IC return data? */
495			if ((pm_cmd & 0x08) == 0) {
496				rval = 0;
497				break;			/* no returned data */
498			}
499
500			rval = 0xffffcd37;
501			if (pm_wait_busy(ADBDelay) != 0)
502				break;			/* timeout */
503
504			/* receive PM command */
505			if ((rval = pm_receive_pm1(&pm_data)) != 0)
506				break;
507
508			pmdata->command = pm_data;
509
510			/* receive number of PM data */
511			if ((rval = pm_receive_pm1(&pm_data)) != 0)
512				break;			/* timeout */
513			num_pm_data = pm_data;
514			pmdata->num_data = num_pm_data;
515
516			/* receive PM data */
517			pm_buf = (u_char *)pmdata->r_buf;
518			for (i = 0; i < num_pm_data; i++) {
519				if ((rval = pm_receive_pm1(&pm_data)) != 0)
520					break;		/* timeout */
521				pm_buf[i] = pm_data;
522			}
523
524			rval = 0;
525	}
526
527	via_reg(VIA2, vDirA) = 0x00;
528
529	/* restore formar value */
530	via_reg(VIA1, vDirA) = via1_vDirA;
531	via_reg(VIA1, vIER) = via1_vIER;
532	if (s != 0x81815963)
533		splx(s);
534
535	return rval;
536}
537
538
539/*
540 * My PM interrupt routine for PB1XX series
541 */
542void
543pm_intr_pm1(void *arg)
544{
545	int s;
546	int rval;
547	PMData pmdata;
548
549	s = splhigh();
550
551	PM_VIA_CLR_INTR();				/* clear VIA1 interrupt */
552
553	/* ask PM what happend */
554	pmdata.command = 0x78;
555	pmdata.num_data = 0;
556	pmdata.data[0] = pmdata.data[1] = 0;
557	pmdata.s_buf = &pmdata.data[2];
558	pmdata.r_buf = &pmdata.data[2];
559	rval = pm_pmgrop_pm1(&pmdata);
560	if (rval != 0) {
561#ifdef ADB_DEBUG
562		if (adb_debug)
563			printf("pm: PM is not ready. error code=%08x\n", rval);
564#endif
565		splx(s);
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 i;
603	int rval;
604
605	rval = 0xffffcd34;
606
607	switch (1) {
608		default:
609			/* set VIA SR to input mode */
610			via_reg(VIA1, vACR) |= 0x0c;
611			via_reg(VIA1, vACR) &= ~0x10;
612			i = PM_SR();
613
614			PM_SET_STATE_ACKOFF();
615			if (pm_wait_busy((int)ADBDelay*32) != 0)
616				break;		/* timeout */
617
618			PM_SET_STATE_ACKON();
619			rval = 0xffffcd33;
620			if (pm_wait_free((int)ADBDelay*32) == 0)
621				break;		/* timeout */
622
623			*data = PM_SR();
624			rval = 0;
625
626			break;
627	}
628
629	PM_SET_STATE_ACKON();
630	via_reg(VIA1, vACR) |= 0x1c;
631
632	return rval;
633}
634
635
636
637/*
638 * Send data to PM for the PB Duo series and the PB 5XX series
639 */
640int
641pm_send_pm2(u_char data)
642{
643	int rval;
644
645	via_reg(VIA1, vACR) |= 0x1c;
646	PM_SR() = data;
647
648	PM_SET_STATE_ACKOFF();
649	if (pm_wait_busy((int)ADBDelay*32) == 0) {
650		PM_SET_STATE_ACKON();
651		if (pm_wait_free((int)ADBDelay*32) != 0)
652			rval = 0;
653		else
654			rval = 0xffffcd35;
655	} else {
656		rval = 0xffffcd36;
657	}
658
659	PM_SET_STATE_ACKON();
660	via_reg(VIA1, vACR) |= 0x1c;
661
662	return rval;
663}
664
665
666
667/*
668 * My PMgrOp routine for the PB Duo series and the PB 5XX series
669 */
670int
671pm_pmgrop_pm2(PMData *pmdata)
672{
673	int i;
674	int s;
675	u_char via1_vIER;
676	int rval = 0;
677	int num_pm_data = 0;
678	u_char pm_cmd;
679	short pm_num_rx_data;
680	u_char pm_data;
681	u_char *pm_buf;
682
683	s = splhigh();
684
685	/* disable all inetrrupts but PM */
686	via1_vIER = 0x10;
687	via1_vIER &= via_reg(VIA1, vIER);
688	via_reg(VIA1, vIER) = via1_vIER;
689	if (via1_vIER != 0x0)
690		via1_vIER |= 0x80;
691
692	switch (pmdata->command) {
693		default:
694			/* wait until PM is free */
695			pm_cmd = (u_char)(pmdata->command & 0xff);
696			rval = 0xcd38;
697			if (pm_wait_free(ADBDelay * 4) == 0)
698				break;			/* timeout */
699
700			if (HwCfgFlags3 & 0x00200000) {
701				/* PB 160, PB 165(c), PB 180(c)? */
702				int delay = ADBDelay * 16;
703
704				via_reg(VIA2, vDirA) = 0x00;
705				while ((via_reg(VIA2, 0x200) == 0x07) &&
706				    (delay >= 0))
707					delay--;
708
709				if (delay < 0) {
710					rval = 0xffffcd38;
711					break;		/* timeout */
712				}
713			}
714
715			/* send PM command */
716			if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
717				break;				/* timeout */
718
719			/* send number of PM data */
720			num_pm_data = pmdata->num_data;
721			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
722				if (pm_send_cmd_type[pm_cmd] < 0) {
723					if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
724						break;		/* timeout */
725					pmdata->command = 0;
726				}
727			} else {				/* PB 1XX series ? */
728				if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
729					break;			/* timeout */
730			}
731			/* send PM data */
732			pm_buf = (u_char *)pmdata->s_buf;
733			for (i = 0 ; i < num_pm_data; i++)
734				if ((rval = pm_send_pm2(pm_buf[i])) != 0)
735					break;			/* timeout */
736			if (i != num_pm_data)
737				break;				/* timeout */
738
739
740			/* check if PM will send me data  */
741			pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
742			pmdata->num_data = pm_num_rx_data;
743			if (pm_num_rx_data == 0) {
744				rval = 0;
745				break;				/* no return data */
746			}
747
748			/* receive PM command */
749			pm_data = pmdata->command;
750			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
751				pm_num_rx_data--;
752				if (pm_num_rx_data == 0)
753					if ((rval = pm_receive_pm2(&pm_data)) != 0) {
754						rval = 0xffffcd37;
755						break;
756					}
757				pmdata->command = pm_data;
758			} else {				/* PB 1XX series ? */
759				if ((rval = pm_receive_pm2(&pm_data)) != 0) {
760					rval = 0xffffcd37;
761					break;
762				}
763				pmdata->command = pm_data;
764			}
765
766			/* receive number of PM data */
767			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
768				if (pm_num_rx_data < 0) {
769					if ((rval = pm_receive_pm2(&pm_data)) != 0)
770						break;		/* timeout */
771					num_pm_data = pm_data;
772				} else
773					num_pm_data = pm_num_rx_data;
774				pmdata->num_data = num_pm_data;
775			} else {				/* PB 1XX serias ? */
776				if ((rval = pm_receive_pm2(&pm_data)) != 0)
777					break;			/* timeout */
778				num_pm_data = pm_data;
779				pmdata->num_data = num_pm_data;
780			}
781
782			/* receive PM data */
783			pm_buf = (u_char *)pmdata->r_buf;
784			for (i = 0; i < num_pm_data; i++) {
785				if ((rval = pm_receive_pm2(&pm_data)) != 0)
786					break;			/* timeout */
787				pm_buf[i] = pm_data;
788			}
789
790			rval = 0;
791	}
792
793	/* restore former value */
794	via_reg(VIA1, vIER) = via1_vIER;
795	splx(s);
796
797	return rval;
798}
799
800
801/*
802 * My PM interrupt routine for the PB Duo series and the PB 5XX series
803 */
804void
805pm_intr_pm2(void *arg)
806{
807	int s;
808	int rval;
809	PMData pmdata;
810
811	s = splhigh();
812
813	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
814						/* ask PM what happend */
815	pmdata.command = 0x78;
816	pmdata.num_data = 0;
817	pmdata.s_buf = &pmdata.data[2];
818	pmdata.r_buf = &pmdata.data[2];
819	rval = pm_pmgrop_pm2(&pmdata);
820	if (rval != 0) {
821#ifdef ADB_DEBUG
822		if (adb_debug)
823			printf("pm: PM is not ready. error code: %08x\n", rval);
824#endif
825		splx(s);
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 delay;
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	delay = 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 ((--delay) < 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	int rval;
1142	PMData tmp_pmdata;
1143
1144	/* find another existent ADB device to poll */
1145	for (i = 1; i < 16; i++) {
1146		ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
1147		bendid <<= ndid;
1148		if ((pm_existent_ADB_devices & bendid) != 0)
1149			break;
1150	}
1151
1152	/* poll the other device */
1153	tmp_pmdata.command = 0x20;
1154	tmp_pmdata.num_data = 3;
1155	tmp_pmdata.s_buf = tmp_pmdata.data;
1156	tmp_pmdata.r_buf = tmp_pmdata.data;
1157	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1158	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
1159	tmp_pmdata.data[2] = 0x00;
1160	rval = pmgrop(&tmp_pmdata);
1161}
1162
1163
1164
1165