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