pm_direct.c revision 1.7
1/*	$NetBSD: pm_direct.c,v 1.7 1998/10/23 01:16:24 ender 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
223extern int ite_polling;		/* Are we polling?  (Debugger mode) */
224
225#if 0
226/*
227 * Define the external functions
228 */
229extern int	zshard __P((int));		/* from zs.c */
230#endif
231
232#ifdef ADB_DEBUG
233/*
234 * This function dumps contents of the PMData
235 */
236void
237pm_printerr(ttl, rval, num, data)
238	char *ttl;
239	int rval;
240	int num;
241	char *data;
242{
243	int i;
244
245	printf("pm: %s:%04x %02x ", ttl, rval, num);
246	for (i = 0; i < num; i++)
247		printf("%02x ", data[i]);
248	printf("\n");
249}
250#endif
251
252
253
254/*
255 * Check the hardware type of the Power Manager
256 */
257void
258pm_setup_adb()
259{
260	switch (mac68k_machine.machineid) {
261		case MACH_MACPB140:
262		case MACH_MACPB145:
263		case MACH_MACPB150:
264		case MACH_MACPB160:
265		case MACH_MACPB165:
266		case MACH_MACPB165C:
267		case MACH_MACPB170:
268		case MACH_MACPB180:
269		case MACH_MACPB180C:
270			pmHardware = PM_HW_PB1XX;
271			break;
272		case MACH_MACPB210:
273		case MACH_MACPB230:
274		case MACH_MACPB250:
275		case MACH_MACPB270:
276		case MACH_MACPB280:
277		case MACH_MACPB280C:
278		case MACH_MACPB500:
279			pmHardware = PM_HW_PB5XX;
280			break;
281		default:
282			break;
283	}
284}
285
286
287/*
288 * Check the existent ADB devices
289 */
290void
291pm_check_adb_devices(id)
292	int id;
293{
294	u_short ed = 0x1;
295
296	ed <<= id;
297	pm_existent_ADB_devices |= ed;
298}
299
300
301/*
302 * Wait until PM IC is busy
303 */
304int
305pm_wait_busy(delay)
306	int delay;
307{
308	while (PM_IS_ON) {
309#ifdef PM_GRAB_SI
310#if 0
311		zshard(0);		/* grab any serial interrupts */
312#else
313		(void)intr_dispatch(0x70);
314#endif
315#endif
316		if ((--delay) < 0)
317			return 1;	/* timeout */
318	}
319	return 0;
320}
321
322
323/*
324 * Wait until PM IC is free
325 */
326int
327pm_wait_free(delay)
328	int delay;
329{
330	while (PM_IS_OFF) {
331#ifdef PM_GRAB_SI
332#if 0
333		zshard(0);		/* grab any serial interrupts */
334#else
335		(void)intr_dispatch(0x70);
336#endif
337#endif
338		if ((--delay) < 0)
339			return 0;	/* timeout */
340	}
341	return 1;
342}
343
344
345
346/*
347 * Functions for the PB1XX series
348 */
349
350/*
351 * Receive data from PM for the PB1XX series
352 */
353int
354pm_receive_pm1(data)
355	u_char *data;
356{
357	int rval = 0xffffcd34;
358
359	via_reg(VIA2, vDirA) = 0x00;
360
361	switch (1) {
362		default:
363			if (pm_wait_busy(0x40) != 0)
364				break;			/* timeout */
365
366			PM_SET_STATE_ACKOFF();
367			*data = via_reg(VIA2, 0x200);
368
369			rval = 0xffffcd33;
370			if (pm_wait_free(0x40) == 0)
371				break;			/* timeout */
372
373			rval = 0x00;
374			break;
375	}
376
377	PM_SET_STATE_ACKON();
378	via_reg(VIA2, vDirA) = 0x00;
379
380	return rval;
381}
382
383
384
385/*
386 * Send data to PM for the PB1XX series
387 */
388int
389pm_send_pm1(data, delay)
390	u_char data;
391	int delay;
392{
393	int rval;
394
395	via_reg(VIA2, vDirA) = 0xff;
396	via_reg(VIA2, 0x200) = data;
397
398	PM_SET_STATE_ACKOFF();
399	if (pm_wait_busy(0x400) != 0) {
400		PM_SET_STATE_ACKON();
401		via_reg(VIA2, vDirA) = 0x00;
402
403		return 0xffffcd36;
404	}
405
406	rval = 0x0;
407	PM_SET_STATE_ACKON();
408	if (pm_wait_free(0x40) == 0)
409		rval = 0xffffcd35;
410
411	PM_SET_STATE_ACKON();
412	via_reg(VIA2, vDirA) = 0x00;
413
414	return rval;
415}
416
417
418/*
419 * My PMgrOp routine for the PB1XX series
420 */
421int
422pm_pmgrop_pm1(pmdata)
423	PMData *pmdata;
424{
425	int i;
426	int s = 0x81815963;
427	u_char via1_vIER, via1_vDirA;
428	int rval = 0;
429	int num_pm_data = 0;
430	u_char pm_cmd;
431	u_char pm_data;
432	u_char *pm_buf;
433
434	/* disable all inetrrupts but PM */
435	via1_vIER = via_reg(VIA1, vIER);
436	PM_VIA_INTR_DISABLE();
437
438	via1_vDirA = via_reg(VIA1, vDirA);
439
440	switch (pmdata->command) {
441		default:
442			for (i = 0; i < 7; i++) {
443				via_reg(VIA2, vDirA) = 0x00;
444
445				/* wait until PM is free */
446				if (pm_wait_free(ADBDelay) == 0) {	/* timeout */
447					via_reg(VIA2, vDirA) = 0x00;
448					/* restore formar value */
449					via_reg(VIA1, vDirA) = via1_vDirA;
450					via_reg(VIA1, vIER) = via1_vIER;
451					return 0xffffcd38;
452				}
453
454				switch (mac68k_machine.machineid) {
455					case MACH_MACPB160:
456					case MACH_MACPB165:
457					case MACH_MACPB165C:
458					case MACH_MACPB180:
459					case MACH_MACPB180C:
460						{
461							int delay = ADBDelay * 16;
462
463							via_reg(VIA2, vDirA) = 0x00;
464							while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
465								delay--;
466
467							if (delay < 0) {	/* timeout */
468								via_reg(VIA2, vDirA) = 0x00;
469								/* restore formar value */
470								via_reg(VIA1, vIER) = via1_vIER;
471								return 0xffffcd38;
472							}
473						}
474				} /* end switch */
475
476				s = splhigh();
477
478				via1_vDirA = via_reg(VIA1, vDirA);
479				via_reg(VIA1, vDirA) &= 0x7f;
480
481				pm_cmd = (u_char)(pmdata->command & 0xff);
482				if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
483					break;	/* send command succeeded */
484
485				via_reg(VIA1, vDirA) = via1_vDirA;
486				splx(s);
487			} /* end for */
488
489			/* failed to send a command */
490			if (i == 7) {
491				via_reg(VIA2, vDirA) = 0x00;
492				/* restore formar value */
493				via_reg(VIA1, vDirA) = via1_vDirA;
494				via_reg(VIA1, vIER) = via1_vIER;
495					return 0xffffcd38;
496			}
497
498			/* send # of PM data */
499			num_pm_data = pmdata->num_data;
500			if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
501				break;			/* timeout */
502
503			/* send PM data */
504			pm_buf = (u_char *)pmdata->s_buf;
505			for (i = 0; i < num_pm_data; i++)
506				if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
507					break;		/* timeout */
508			if ((i != num_pm_data) && (num_pm_data != 0))
509				break;			/* timeout */
510
511			/* Will PM IC return data? */
512			if ((pm_cmd & 0x08) == 0) {
513				rval = 0;
514				break;			/* no returned data */
515			}
516
517			rval = 0xffffcd37;
518			if (pm_wait_busy(ADBDelay) != 0)
519				break;			/* timeout */
520
521			/* receive PM command */
522			if ((rval = pm_receive_pm1(&pm_data)) != 0)
523				break;
524
525			pmdata->command = pm_data;
526
527			/* receive number of PM data */
528			if ((rval = pm_receive_pm1(&pm_data)) != 0)
529				break;			/* timeout */
530			num_pm_data = pm_data;
531			pmdata->num_data = num_pm_data;
532
533			/* receive PM data */
534			pm_buf = (u_char *)pmdata->r_buf;
535			for (i = 0; i < num_pm_data; i++) {
536				if ((rval = pm_receive_pm1(&pm_data)) != 0)
537					break;				/* timeout */
538				pm_buf[i] = pm_data;
539			}
540
541			rval = 0;
542	}
543
544	via_reg(VIA2, vDirA) = 0x00;
545
546	/* restore formar value */
547	via_reg(VIA1, vDirA) = via1_vDirA;
548	via_reg(VIA1, vIER) = via1_vIER;
549	if (s != 0x81815963)
550		splx(s);
551
552	return rval;
553}
554
555
556/*
557 * My PM interrupt routine for PB1XX series
558 */
559void
560pm_intr_pm1()
561{
562	int s;
563	int rval;
564	PMData pmdata;
565
566	s = splhigh();
567
568	PM_VIA_CLR_INTR();				/* clear VIA1 interrupt */
569
570	/* ask PM what happend */
571	pmdata.command = 0x78;
572	pmdata.num_data = 0;
573	pmdata.data[0] = pmdata.data[1] = 0;
574	pmdata.s_buf = &pmdata.data[2];
575	pmdata.r_buf = &pmdata.data[2];
576	rval = pm_pmgrop_pm1(&pmdata);
577	if (rval != 0) {
578#ifdef ADB_DEBUG
579		if (adb_debug)
580			printf("pm: PM is not ready. error code=%08x\n", rval);
581#endif
582		splx(s);
583	}
584
585	if ((pmdata.data[2] & 0x10) == 0x10) {
586		if ((pmdata.data[2] & 0x0f) == 0) {
587			/* ADB data that were requested by TALK command */
588			pm_adb_get_TALK_result(&pmdata);
589		} else if ((pmdata.data[2] & 0x08) == 0x8) {
590			/* PM is requesting to poll  */
591			pm_adb_poll_next_device_pm1(&pmdata);
592		} else if ((pmdata.data[2] & 0x04) == 0x4) {
593			/* ADB device event */
594			pm_adb_get_ADB_data(&pmdata);
595		}
596	} else {
597#ifdef ADB_DEBUG
598		if (adb_debug)
599			pm_printerr("driver does not supported this event.",
600			    rval, pmdata.num_data, pmdata.data);
601#endif
602	}
603
604	splx(s);
605}
606
607
608
609/*
610 * Functions for the PB Duo series and the PB 5XX series
611 */
612
613/*
614 * Receive data from PM for the PB Duo series and the PB 5XX series
615 */
616int
617pm_receive_pm2(data)
618	u_char *data;
619{
620	int i;
621	int rval;
622
623	rval = 0xffffcd34;
624
625	switch (1) {
626		default:
627			/* set VIA SR to input mode */
628			via_reg(VIA1, vACR) |= 0x0c;
629			via_reg(VIA1, vACR) &= ~0x10;
630			i = PM_SR();
631
632			PM_SET_STATE_ACKOFF();
633			if (pm_wait_busy((int)ADBDelay*32) != 0)
634				break;		/* timeout */
635
636			PM_SET_STATE_ACKON();
637			rval = 0xffffcd33;
638			if (pm_wait_free((int)ADBDelay*32) == 0)
639				break;		/* timeout */
640
641			*data = PM_SR();
642			rval = 0;
643
644			break;
645	}
646
647	PM_SET_STATE_ACKON();
648	via_reg(VIA1, vACR) |= 0x1c;
649
650	return rval;
651}
652
653
654
655/*
656 * Send data to PM for the PB Duo series and the PB 5XX series
657 */
658int
659pm_send_pm2(data)
660	u_char data;
661{
662	int rval;
663
664	via_reg(VIA1, vACR) |= 0x1c;
665	PM_SR() = data;
666
667	PM_SET_STATE_ACKOFF();
668	rval = 0xffffcd36;
669	if (pm_wait_busy((int)ADBDelay*32) != 0) {
670		PM_SET_STATE_ACKON();
671
672		via_reg(VIA1, vACR) |= 0x1c;
673
674		return rval;
675	}
676
677	PM_SET_STATE_ACKON();
678	rval = 0xffffcd35;
679	if (pm_wait_free((int)ADBDelay*32) != 0)
680		rval = 0;
681
682	PM_SET_STATE_ACKON();
683	via_reg(VIA1, vACR) |= 0x1c;
684
685	return rval;
686}
687
688
689
690/*
691 * My PMgrOp routine for the PB Duo series and the PB 5XX series
692 */
693int
694pm_pmgrop_pm2(pmdata)
695	PMData *pmdata;
696{
697	int i;
698	int s;
699	u_char via1_vIER;
700	int rval = 0;
701	int num_pm_data = 0;
702	u_char pm_cmd;
703	short pm_num_rx_data;
704	u_char pm_data;
705	u_char *pm_buf;
706
707	s = splhigh();
708
709	/* disable all inetrrupts but PM */
710	via1_vIER = 0x10;
711	via1_vIER &= via_reg(VIA1, vIER);
712	via_reg(VIA1, vIER) = via1_vIER;
713	if (via1_vIER != 0x0)
714		via1_vIER |= 0x80;
715
716	switch (pmdata->command) {
717		default:
718			/* wait until PM is free */
719			pm_cmd = (u_char)(pmdata->command & 0xff);
720			rval = 0xcd38;
721			if (pm_wait_free(ADBDelay * 4) == 0)
722				break;			/* timeout */
723
724			if (HwCfgFlags3 & 0x00200000) {
725				/* PB 160, PB 165(c), PB 180(c)? */
726				int delay = ADBDelay * 16;
727
728				via_reg(VIA2, vDirA) = 0x00;
729				while ((via_reg(VIA2, 0x200) == 0x07) &&
730				    (delay >= 0))
731					delay--;
732
733				if (delay < 0) {
734					rval = 0xffffcd38;
735					break;		/* timeout */
736				}
737			}
738
739			/* send PM command */
740			if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
741				break;				/* timeout */
742
743			/* send number of PM data */
744			num_pm_data = pmdata->num_data;
745			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
746				if (pm_send_cmd_type[pm_cmd] < 0) {
747					if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
748						break;		/* timeout */
749					pmdata->command = 0;
750				}
751			} else {				/* PB 1XX series ? */
752				if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
753					break;			/* timeout */
754			}
755			/* send PM data */
756			pm_buf = (u_char *)pmdata->s_buf;
757			for (i = 0 ; i < num_pm_data; i++)
758				if ((rval = pm_send_pm2(pm_buf[i])) != 0)
759					break;			/* timeout */
760			if (i != num_pm_data)
761				break;				/* timeout */
762
763
764			/* check if PM will send me data  */
765			pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
766			pmdata->num_data = pm_num_rx_data;
767			if (pm_num_rx_data == 0) {
768				rval = 0;
769				break;				/* no return data */
770			}
771
772			/* receive PM command */
773			pm_data = pmdata->command;
774			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
775				pm_num_rx_data--;
776				if (pm_num_rx_data == 0)
777					if ((rval = pm_receive_pm2(&pm_data)) != 0) {
778						rval = 0xffffcd37;
779						break;
780					}
781				pmdata->command = pm_data;
782			} else {				/* PB 1XX series ? */
783				if ((rval = pm_receive_pm2(&pm_data)) != 0) {
784					rval = 0xffffcd37;
785					break;
786				}
787				pmdata->command = pm_data;
788			}
789
790			/* receive number of PM data */
791			if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
792				if (pm_num_rx_data < 0) {
793					if ((rval = pm_receive_pm2(&pm_data)) != 0)
794						break;		/* timeout */
795					num_pm_data = pm_data;
796				} else
797					num_pm_data = pm_num_rx_data;
798				pmdata->num_data = num_pm_data;
799			} else {				/* PB 1XX serias ? */
800				if ((rval = pm_receive_pm2(&pm_data)) != 0)
801					break;			/* timeout */
802				num_pm_data = pm_data;
803				pmdata->num_data = num_pm_data;
804			}
805
806			/* receive PM data */
807			pm_buf = (u_char *)pmdata->r_buf;
808			for (i = 0; i < num_pm_data; i++) {
809				if ((rval = pm_receive_pm2(&pm_data)) != 0)
810					break;			/* timeout */
811				pm_buf[i] = pm_data;
812			}
813
814			rval = 0;
815	}
816
817	/* restore former value */
818	via_reg(VIA1, vIER) = via1_vIER;
819	splx(s);
820
821	return rval;
822}
823
824
825/*
826 * My PM interrupt routine for the PB Duo series and the PB 5XX series
827 */
828void
829pm_intr_pm2()
830{
831	int s;
832	int rval;
833	PMData pmdata;
834
835	s = splhigh();
836
837	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
838						/* ask PM what happend */
839	pmdata.command = 0x78;
840	pmdata.num_data = 0;
841	pmdata.s_buf = &pmdata.data[2];
842	pmdata.r_buf = &pmdata.data[2];
843	rval = pm_pmgrop_pm2(&pmdata);
844	if (rval != 0) {
845#ifdef ADB_DEBUG
846		if (adb_debug)
847			printf("pm: PM is not ready. error code: %08x\n", rval);
848#endif
849		splx(s);
850	}
851
852	switch ((u_int)(pmdata.data[2] & 0xff)) {
853		case 0x00:			/* 1 sec interrupt? */
854			break;
855		case 0x80:			/* 1 sec interrupt? */
856			pm_counter++;
857			break;
858		case 0x08:			/* Brightness/Contrast button on LCD panel */
859			/* get brightness and contrast of the LCD */
860			pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
861			pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
862/*
863			pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
864			pmdata.command = 0x33;
865			pmdata.num_data = 1;
866			pmdata.s_buf = pmdata.data;
867			pmdata.r_buf = pmdata.data;
868			pmdata.data[0] = pm_LCD_contrast;
869			rval = pm_pmgrop_pm2(&pmdata);
870			pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
871*/
872			/* this is an experimental code */
873			pmdata.command = 0x41;
874			pmdata.num_data = 1;
875			pmdata.s_buf = pmdata.data;
876			pmdata.r_buf = pmdata.data;
877			pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
878			if (pm_LCD_brightness < 0x25)
879				pm_LCD_brightness = 0x25;
880			if (pm_LCD_brightness > 0x5a)
881				pm_LCD_brightness = 0x7f;
882			pmdata.data[0] = pm_LCD_brightness;
883			rval = pm_pmgrop_pm2(&pmdata);
884			break;
885		case 0x10:			/* ADB data that were requested by TALK command */
886		case 0x14:
887			pm_adb_get_TALK_result(&pmdata);
888			break;
889		case 0x16:			/* ADB device event */
890		case 0x18:
891		case 0x1e:
892			pm_adb_get_ADB_data(&pmdata);
893			break;
894		default:
895#ifdef ADB_DEBUG
896			if (adb_debug)
897				pm_printerr("driver does not supported this event.",
898				    pmdata.data[2], pmdata.num_data,
899				    pmdata.data);
900#endif
901			break;
902	}
903
904	splx(s);
905}
906
907
908/*
909 * MRG-based PMgrOp routine
910 */
911int
912pm_pmgrop_mrg(pmdata)
913	PMData *pmdata;
914{
915	u_int32_t rval=0;
916
917	asm("
918		movl	%1, a0
919		.word	0xa085
920		movl	d0, %0"
921		: "=g" (rval)
922		: "g" (pmdata)
923		: "a0", "d0" );
924
925	return rval;
926}
927
928
929/*
930 * My PMgrOp routine
931 */
932int
933pmgrop(pmdata)
934	PMData *pmdata;
935{
936	switch (pmHardware) {
937		case PM_HW_PB1XX:
938			return (pm_pmgrop_pm1(pmdata));
939			break;
940		case PM_HW_PB5XX:
941			return (pm_pmgrop_pm2(pmdata));
942			break;
943		default:
944			/* return (pmgrop_mrg(pmdata)); */
945			return 1;
946	}
947}
948
949
950/*
951 * My PM interrupt routine
952 */
953void
954pm_intr()
955{
956	switch (pmHardware) {
957		case PM_HW_PB1XX:
958			pm_intr_pm1();
959			break;
960		case PM_HW_PB5XX:
961			pm_intr_pm2();
962			break;
963		default:
964			break;
965	}
966}
967
968
969
970/*
971 * Synchronous ADBOp routine for the Power Manager
972 */
973int
974pm_adb_op(buffer, compRout, data, command)
975	u_char *buffer;
976	void *compRout;
977	void *data;
978	int command;
979{
980	int i;
981	int s;
982	int rval;
983	int delay;
984	PMData pmdata;
985	struct adbCommand packet;
986
987	if (adbWaiting == 1)
988		return 1;
989
990	s = splhigh();
991	via_reg(VIA1, vIER) = 0x10;
992
993 	adbBuffer = buffer;
994	adbCompRout = compRout;
995	adbCompData = data;
996
997	pmdata.command = 0x20;
998	pmdata.s_buf = pmdata.data;
999	pmdata.r_buf = pmdata.data;
1000
1001	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, add number of ADB data to number of PM data */
1002		if (buffer != (u_char *)0)
1003			pmdata.num_data = buffer[0] + 3;
1004	} else {
1005		pmdata.num_data = 3;
1006	}
1007
1008	pmdata.data[0] = (u_char)(command & 0xff);
1009	pmdata.data[1] = 0;
1010	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
1011		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
1012			pmdata.data[2] = buffer[0];		/* number of data */
1013			for (i = 0; i < buffer[0]; i++)
1014				pmdata.data[3 + i] = buffer[1 + i];
1015		} else
1016			pmdata.data[2] = 0;
1017	} else
1018		pmdata.data[2] = 0;
1019
1020	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
1021		/* set up stuff for adb_pass_up */
1022		packet.data[0] = 1 + pmdata.data[2];
1023		packet.data[1] = command;
1024		for (i = 0; i < pmdata.data[2]; i++)
1025			packet.data[i+2] = pmdata.data[i+3];
1026		packet.saveBuf = adbBuffer;
1027		packet.compRout = adbCompRout;
1028		packet.compData = adbCompData;
1029		packet.cmd = command;
1030		packet.unsol = 0;
1031		packet.ack_only = 1;
1032		ite_polling = 1;
1033		adb_pass_up(&packet);
1034		ite_polling = 0;
1035	}
1036
1037	rval = pmgrop(&pmdata);
1038	if (rval != 0)
1039		return 1;
1040
1041	adbWaiting = 1;
1042	adbWaitingCmd = command;
1043
1044	PM_VIA_INTR_ENABLE();
1045
1046	/* wait until the PM interrupt is occured */
1047	delay = 0x80000;
1048	while (adbWaiting == 1) {
1049		if ((via_reg(VIA1, vIFR) & 0x10) == 0x10)
1050			pm_intr();
1051#ifdef PM_GRAB_SI
1052#if 0
1053			zshard(0);		/* grab any serial interrupts */
1054#else
1055			(void)intr_dispatch(0x70);
1056#endif
1057#endif
1058		if ((--delay) < 0)
1059			return 1;
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)
1090	PMData *pmdata;
1091{
1092	int i;
1093	struct adbCommand packet;
1094
1095	/* set up data for adb_pass_up */
1096	packet.data[0] = pmdata->num_data-1;
1097	packet.data[1] = pmdata->data[3];
1098	for (i = 0; i <packet.data[0]-1; i++)
1099		packet.data[i+2] = pmdata->data[i+4];
1100
1101	packet.saveBuf = adbBuffer;
1102	packet.compRout = adbCompRout;
1103	packet.compData = adbCompData;
1104	packet.unsol = 0;
1105	packet.ack_only = 0;
1106	ite_polling = 1;
1107	adb_pass_up(&packet);
1108	ite_polling = 0;
1109
1110	adbWaiting = 0;
1111	adbBuffer = (long)0;
1112	adbCompRout = (long)0;
1113	adbCompData = (long)0;
1114}
1115
1116
1117void
1118pm_adb_get_ADB_data(pmdata)
1119	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)
1137	PMData *pmdata;
1138{
1139	int i;
1140	int ndid;
1141	u_short bendid = 0x1;
1142	int rval;
1143	PMData tmp_pmdata;
1144
1145	/* find another existent ADB device to poll */
1146	for (i = 1; i < 16; i++) {
1147		ndid = (((pmdata->data[3] & 0xf0) >> 4) + i) & 0xf;
1148		bendid <<= ndid;
1149		if ((pm_existent_ADB_devices & bendid) != 0)
1150			break;
1151	}
1152
1153	/* poll the other device */
1154	tmp_pmdata.command = 0x20;
1155	tmp_pmdata.num_data = 3;
1156	tmp_pmdata.s_buf = tmp_pmdata.data;
1157	tmp_pmdata.r_buf = tmp_pmdata.data;
1158	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
1159	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
1160	tmp_pmdata.data[2] = 0x00;
1161	rval = pmgrop(&tmp_pmdata);
1162}
1163
1164
1165
1166