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