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