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