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