Home | History | Annotate | Line # | Download | only in dev
pm_direct.c revision 1.31.26.1
      1  1.31.26.1     yamt /*	$NetBSD: pm_direct.c,v 1.31.26.1 2007/10/18 08:32:09 yamt Exp $	*/
      2        1.1   tsubai 
      3        1.1   tsubai /*
      4        1.1   tsubai  * Copyright (C) 1997 Takashi Hamada
      5        1.1   tsubai  * All rights reserved.
      6        1.1   tsubai  *
      7        1.1   tsubai  * Redistribution and use in source and binary forms, with or without
      8        1.1   tsubai  * modification, are permitted provided that the following conditions
      9        1.1   tsubai  * are met:
     10        1.1   tsubai  * 1. Redistributions of source code must retain the above copyright
     11        1.1   tsubai  *    notice, this list of conditions and the following disclaimer.
     12        1.1   tsubai  * 2. Redistributions in binary form must reproduce the above copyright
     13        1.1   tsubai  *    notice, this list of conditions and the following disclaimer in the
     14        1.1   tsubai  *    documentation and/or other materials provided with the distribution.
     15        1.1   tsubai  * 3. All advertising materials mentioning features or use of this software
     16        1.1   tsubai  *    must display the following acknowledgement:
     17        1.1   tsubai  *  This product includes software developed by Takashi Hamada
     18        1.1   tsubai  * 4. The name of the author may not be used to endorse or promote products
     19        1.1   tsubai  *    derived from this software without specific prior written permission.
     20        1.1   tsubai  *
     21        1.1   tsubai  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22        1.1   tsubai  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23        1.1   tsubai  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24        1.1   tsubai  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25        1.1   tsubai  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26        1.1   tsubai  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27        1.1   tsubai  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28        1.1   tsubai  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29        1.1   tsubai  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30        1.1   tsubai  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31        1.1   tsubai  */
     32        1.1   tsubai /* From: pm_direct.c 1.3 03/18/98 Takashi Hamada */
     33       1.20    lukem 
     34       1.21   briggs /*
     35       1.21   briggs  * TODO : Check bounds on PMData in pmgrop
     36       1.21   briggs  *		callers should specify how much room for data is in the buffer
     37       1.21   briggs  *		and that should be respected by the pmgrop
     38       1.21   briggs  */
     39       1.21   briggs 
     40       1.20    lukem #include <sys/cdefs.h>
     41  1.31.26.1     yamt __KERNEL_RCSID(0, "$NetBSD: pm_direct.c,v 1.31.26.1 2007/10/18 08:32:09 yamt Exp $");
     42        1.1   tsubai 
     43        1.1   tsubai #ifdef DEBUG
     44        1.1   tsubai #ifndef ADB_DEBUG
     45        1.1   tsubai #define ADB_DEBUG
     46        1.1   tsubai #endif
     47        1.1   tsubai #endif
     48        1.1   tsubai 
     49        1.1   tsubai /* #define	PM_GRAB_SI	1 */
     50        1.1   tsubai 
     51        1.1   tsubai #include <sys/param.h>
     52        1.1   tsubai #include <sys/device.h>
     53        1.1   tsubai #include <sys/systm.h>
     54        1.1   tsubai 
     55        1.1   tsubai #include <machine/adbsys.h>
     56       1.23   briggs #include <machine/autoconf.h>
     57        1.1   tsubai #include <machine/cpu.h>
     58  1.31.26.1     yamt #include <machine/pio.h>
     59        1.1   tsubai 
     60       1.23   briggs #include <dev/ofw/openfirm.h>
     61       1.23   briggs 
     62        1.1   tsubai #include <macppc/dev/adbvar.h>
     63        1.1   tsubai #include <macppc/dev/pm_direct.h>
     64        1.1   tsubai #include <macppc/dev/viareg.h>
     65        1.1   tsubai 
     66        1.1   tsubai extern int adb_polling;		/* Are we polling?  (Debugger mode) */
     67        1.1   tsubai 
     68        1.1   tsubai /* hardware dependent values */
     69        1.1   tsubai #define ADBDelay 100		/* XXX */
     70        1.1   tsubai 
     71        1.1   tsubai /* useful macros */
     72        1.1   tsubai #define PM_SR()			read_via_reg(VIA1, vSR)
     73        1.1   tsubai #define PM_VIA_INTR_ENABLE()	write_via_reg(VIA1, vIER, 0x90)
     74        1.1   tsubai #define PM_VIA_INTR_DISABLE()	write_via_reg(VIA1, vIER, 0x10)
     75        1.1   tsubai #define PM_VIA_CLR_INTR()	write_via_reg(VIA1, vIFR, 0x90)
     76       1.25   briggs 
     77        1.1   tsubai #define PM_SET_STATE_ACKON()	via_reg_or(VIA2, vBufB, 0x10)
     78        1.1   tsubai #define PM_SET_STATE_ACKOFF()	via_reg_and(VIA2, vBufB, ~0x10)
     79        1.1   tsubai #define PM_IS_ON		(0x08 == (read_via_reg(VIA2, vBufB) & 0x08))
     80        1.1   tsubai #define PM_IS_OFF		(0x00 == (read_via_reg(VIA2, vBufB) & 0x08))
     81        1.1   tsubai 
     82        1.1   tsubai /*
     83        1.1   tsubai  * Variables for internal use
     84        1.1   tsubai  */
     85        1.1   tsubai u_short	pm_existent_ADB_devices = 0x0;	/* each bit expresses the existent ADB device */
     86        1.1   tsubai u_int	pm_LCD_brightness = 0x0;
     87        1.1   tsubai u_int	pm_LCD_contrast = 0x0;
     88        1.1   tsubai u_int	pm_counter = 0;			/* clock count */
     89        1.1   tsubai 
     90       1.23   briggs static enum batt_type { BATT_COMET, BATT_HOOPER, BATT_SMART } pmu_batt_type;
     91       1.23   briggs static int	pmu_nbatt;
     92       1.27  nathanw static int	strinlist(const char *, char *, int);
     93       1.23   briggs static enum pmu_type { PMU_UNKNOWN, PMU_OHARE, PMU_G3, PMU_KEYLARGO } pmu_type;
     94       1.23   briggs 
     95        1.1   tsubai /* these values shows that number of data returned after 'send' cmd is sent */
     96        1.1   tsubai signed char pm_send_cmd_type[] = {
     97        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
     98        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
     99        1.1   tsubai 	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
    100        1.1   tsubai 	0x00, 0x00,   -1,   -1,   -1,   -1,   -1, 0x00,
    101        1.1   tsubai 	  -1, 0x00, 0x02, 0x01, 0x01,   -1,   -1,   -1,
    102        1.1   tsubai 	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    103        1.5   tsubai 	0x04, 0x14,   -1, 0x03,   -1,   -1,   -1,   -1,
    104        1.5   tsubai 	0x00, 0x00, 0x02, 0x02,   -1,   -1,   -1,   -1,
    105        1.1   tsubai 	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
    106        1.7   tsubai 	0x00, 0x00,   -1,   -1, 0x01,   -1,   -1,   -1,
    107        1.1   tsubai 	0x01, 0x00, 0x02, 0x02,   -1, 0x01, 0x03, 0x01,
    108        1.1   tsubai 	0x00, 0x01, 0x00, 0x00, 0x00,   -1,   -1,   -1,
    109        1.1   tsubai 	0x02,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    110        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   -1,   -1,
    111        1.1   tsubai 	0x01, 0x01, 0x01,   -1,   -1,   -1,   -1,   -1,
    112        1.1   tsubai 	0x00, 0x00,   -1,   -1,   -1,   -1, 0x04, 0x04,
    113        1.1   tsubai 	0x04,   -1, 0x00,   -1,   -1,   -1,   -1,   -1,
    114        1.1   tsubai 	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    115        1.1   tsubai 	0x01, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
    116        1.1   tsubai 	0x00, 0x00,   -1,   -1,   -1,   -1,   -1,   -1,
    117        1.1   tsubai 	0x02, 0x02, 0x02, 0x04,   -1, 0x00,   -1,   -1,
    118        1.1   tsubai 	0x01, 0x01, 0x03, 0x02,   -1,   -1,   -1,   -1,
    119        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    120        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    121        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    122        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    123        1.1   tsubai 	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    124        1.1   tsubai 	0x01, 0x01,   -1,   -1, 0x00, 0x00,   -1,   -1,
    125        1.1   tsubai 	  -1, 0x04, 0x00,   -1,   -1,   -1,   -1,   -1,
    126        1.1   tsubai 	0x03,   -1, 0x00,   -1, 0x00,   -1,   -1, 0x00,
    127        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    128        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1
    129        1.1   tsubai };
    130        1.1   tsubai 
    131        1.1   tsubai /* these values shows that number of data returned after 'receive' cmd is sent */
    132        1.1   tsubai signed char pm_receive_cmd_type[] = {
    133        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    134        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    135        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    136        1.1   tsubai 	0x02, 0x02,   -1,   -1,   -1,   -1,   -1, 0x00,
    137        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    138        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    139        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    140        1.5   tsubai 	0x05, 0x15,   -1, 0x02,   -1,   -1,   -1,   -1,
    141        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    142        1.1   tsubai 	0x02, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
    143        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    144        1.1   tsubai 	0x02, 0x00, 0x03, 0x03,   -1,   -1,   -1,   -1,
    145        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    146        1.1   tsubai 	0x04, 0x04, 0x03, 0x09,   -1,   -1,   -1,   -1,
    147        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    148        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1, 0x01, 0x01,
    149        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    150        1.1   tsubai 	0x06,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    151        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    152        1.1   tsubai 	0x02, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
    153        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    154        1.1   tsubai 	0x02, 0x00, 0x00, 0x00,   -1,   -1,   -1,   -1,
    155        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    156        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    157        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    158        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    159        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    160        1.1   tsubai 	0x02, 0x02,   -1,   -1, 0x02,   -1,   -1,   -1,
    161        1.1   tsubai 	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    162        1.1   tsubai 	  -1,   -1, 0x02,   -1,   -1,   -1,   -1, 0x00,
    163        1.1   tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    164        1.1   tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    165        1.1   tsubai };
    166        1.1   tsubai 
    167        1.1   tsubai 
    168        1.1   tsubai /*
    169        1.1   tsubai  * Define the private functions
    170        1.1   tsubai  */
    171        1.1   tsubai 
    172        1.1   tsubai /* for debugging */
    173        1.1   tsubai #ifdef ADB_DEBUG
    174       1.28     jmmv void	pm_printerr __P((const char *, int, int, const char *));
    175        1.1   tsubai #endif
    176        1.1   tsubai 
    177        1.1   tsubai int	pm_wait_busy __P((int));
    178        1.1   tsubai int	pm_wait_free __P((int));
    179        1.1   tsubai 
    180       1.25   briggs static int	pm_receive __P((u_char *));
    181       1.25   briggs static int	pm_send __P((u_char));
    182        1.1   tsubai 
    183        1.1   tsubai /* these functions are called from adb_direct.c */
    184        1.1   tsubai void	pm_setup_adb __P((void));
    185        1.1   tsubai void	pm_check_adb_devices __P((int));
    186       1.27  nathanw int	pm_adb_op __P((u_char *, adbComp *, volatile int *, int));
    187        1.1   tsubai 
    188        1.1   tsubai /* these functions also use the variables of adb_direct.c */
    189        1.1   tsubai void	pm_adb_get_TALK_result __P((PMData *));
    190        1.1   tsubai void	pm_adb_get_ADB_data __P((PMData *));
    191        1.1   tsubai 
    192        1.1   tsubai 
    193        1.1   tsubai /*
    194        1.1   tsubai  * These variables are in adb_direct.c.
    195        1.1   tsubai  */
    196        1.1   tsubai extern u_char	*adbBuffer;	/* pointer to user data area */
    197       1.27  nathanw extern adbComp	*adbCompRout;	/* pointer to the completion routine */
    198       1.27  nathanw extern volatile int *adbCompData;	/* pointer to the completion routine data */
    199        1.1   tsubai extern int	adbWaiting;	/* waiting for return data from the device */
    200        1.1   tsubai extern int	adbWaitingCmd;	/* ADB command we are waiting for */
    201        1.1   tsubai extern int	adbStarting;	/* doing ADB reinit, so do "polling" differently */
    202        1.1   tsubai 
    203        1.1   tsubai #define	ADB_MAX_MSG_LENGTH	16
    204        1.1   tsubai #define	ADB_MAX_HDR_LENGTH	8
    205        1.1   tsubai struct adbCommand {
    206        1.1   tsubai 	u_char	header[ADB_MAX_HDR_LENGTH];	/* not used yet */
    207        1.1   tsubai 	u_char	data[ADB_MAX_MSG_LENGTH];	/* packet data only */
    208        1.1   tsubai 	u_char	*saveBuf;	/* where to save result */
    209       1.27  nathanw 	adbComp	*compRout;	/* completion routine pointer */
    210       1.27  nathanw 	volatile int	*compData;	/* completion routine data pointer */
    211        1.1   tsubai 	u_int	cmd;		/* the original command for this data */
    212        1.1   tsubai 	u_int	unsol;		/* 1 if packet was unsolicited */
    213        1.1   tsubai 	u_int	ack_only;	/* 1 for no special processing */
    214        1.1   tsubai };
    215        1.1   tsubai extern	void	adb_pass_up __P((struct adbCommand *));
    216        1.1   tsubai 
    217        1.1   tsubai #if 0
    218        1.1   tsubai /*
    219        1.1   tsubai  * Define the external functions
    220        1.1   tsubai  */
    221        1.1   tsubai extern int	zshard __P((int));		/* from zs.c */
    222        1.1   tsubai #endif
    223        1.1   tsubai 
    224        1.1   tsubai #ifdef ADB_DEBUG
    225        1.1   tsubai /*
    226        1.1   tsubai  * This function dumps contents of the PMData
    227        1.1   tsubai  */
    228        1.1   tsubai void
    229        1.1   tsubai pm_printerr(ttl, rval, num, data)
    230       1.28     jmmv 	const char *ttl;
    231        1.1   tsubai 	int rval;
    232        1.1   tsubai 	int num;
    233       1.28     jmmv 	const char *data;
    234        1.1   tsubai {
    235        1.1   tsubai 	int i;
    236        1.1   tsubai 
    237        1.1   tsubai 	printf("pm: %s:%04x %02x ", ttl, rval, num);
    238        1.1   tsubai 	for (i = 0; i < num; i++)
    239        1.1   tsubai 		printf("%02x ", data[i]);
    240        1.1   tsubai 	printf("\n");
    241        1.1   tsubai }
    242        1.1   tsubai #endif
    243        1.1   tsubai 
    244        1.1   tsubai 
    245        1.1   tsubai 
    246        1.1   tsubai /*
    247        1.1   tsubai  * Check the hardware type of the Power Manager
    248        1.1   tsubai  */
    249        1.1   tsubai void
    250        1.1   tsubai pm_setup_adb()
    251        1.1   tsubai {
    252        1.1   tsubai }
    253        1.1   tsubai 
    254       1.26   briggs /*
    255       1.26   briggs  * Search for targ in list.  list is an area of listlen bytes
    256       1.26   briggs  * containing null-terminated strings.
    257       1.26   briggs  */
    258       1.23   briggs static int
    259       1.27  nathanw strinlist(const char *targ, char *list, int listlen)
    260       1.23   briggs {
    261       1.23   briggs 	char	*str;
    262       1.23   briggs 	int	sl;
    263       1.26   briggs 	int	targlen;
    264       1.23   briggs 
    265       1.23   briggs 	str = list;
    266       1.26   briggs 	targlen = strlen(targ);
    267       1.23   briggs 	while (listlen > 0) {
    268       1.23   briggs 		sl = strlen(str);
    269       1.26   briggs 		if (sl == targlen && (strncmp(targ, str, sl) == 0))
    270       1.23   briggs 			return 1;
    271       1.23   briggs 		str += sl+1;
    272       1.23   briggs 		listlen -= sl+1;
    273       1.23   briggs 	}
    274       1.23   briggs 	return 0;
    275       1.23   briggs }
    276       1.23   briggs 
    277       1.23   briggs /*
    278       1.23   briggs  * Check the hardware type of the Power Manager
    279       1.23   briggs  */
    280       1.23   briggs void
    281       1.23   briggs pm_init(void)
    282       1.23   briggs {
    283       1.23   briggs 	uint32_t	regs[10];
    284       1.23   briggs 	PMData		pmdata;
    285       1.23   briggs 	char		compat[128];
    286       1.27  nathanw 	int		clen, node, pm_imask;
    287       1.23   briggs 
    288       1.23   briggs 	node = OF_peer(0);
    289       1.23   briggs 	if (node == -1) {
    290       1.23   briggs 		printf("pmu: Failed to get root");
    291       1.23   briggs 		return;
    292       1.23   briggs 	}
    293       1.23   briggs 	clen = OF_getprop(node, "compatible", compat, sizeof(compat));
    294       1.23   briggs 	if (clen <= 0) {
    295       1.23   briggs 		printf("pmu: failed to read root compatible data %d\n", clen);
    296       1.23   briggs 		return;
    297       1.23   briggs 	}
    298       1.23   briggs 
    299       1.27  nathanw 	pm_imask =
    300       1.27  nathanw 	    PMU_INT_PCEJECT | PMU_INT_SNDBRT | PMU_INT_ADB | PMU_INT_TICK;
    301       1.23   briggs 
    302       1.23   briggs 	if (strinlist("AAPL,3500", compat, clen) ||
    303       1.23   briggs 	    strinlist("AAPL,3400/2400", compat, clen)) {
    304       1.23   briggs 		/* How to distinguish BATT_COMET? */
    305       1.23   briggs 		pmu_nbatt = 1;
    306       1.23   briggs 		pmu_batt_type = BATT_HOOPER;
    307       1.23   briggs 		pmu_type = PMU_OHARE;
    308       1.23   briggs 	} else if (strinlist("AAPL,PowerBook1998", compat, clen) ||
    309       1.23   briggs 		   strinlist("PowerBook1,1", compat, clen)) {
    310       1.23   briggs 		pmu_nbatt = 2;
    311       1.23   briggs 		pmu_batt_type = BATT_SMART;
    312       1.23   briggs 		pmu_type = PMU_G3;
    313       1.23   briggs 	} else {
    314       1.23   briggs 		pmu_nbatt = 1;
    315       1.23   briggs 		pmu_batt_type = BATT_SMART;
    316       1.23   briggs 		pmu_type = PMU_KEYLARGO;
    317       1.23   briggs 		node = getnodebyname(0, "power-mgt");
    318       1.23   briggs 		if (node == -1) {
    319       1.23   briggs 			printf("pmu: can't find power-mgt\n");
    320       1.23   briggs 			return;
    321       1.23   briggs 		}
    322       1.23   briggs 		clen = OF_getprop(node, "prim-info", regs, sizeof(regs));
    323       1.23   briggs 		if (clen < 24) {
    324       1.23   briggs 			printf("pmu: failed to read prim-info\n");
    325       1.23   briggs 			return;
    326       1.23   briggs 		}
    327       1.23   briggs 		pmu_nbatt = regs[6] >> 16;
    328       1.23   briggs 	}
    329       1.23   briggs 
    330       1.23   briggs 	pmdata.command = PMU_SET_IMASK;
    331       1.23   briggs 	pmdata.num_data = 1;
    332       1.23   briggs 	pmdata.s_buf = pmdata.data;
    333       1.23   briggs 	pmdata.r_buf = pmdata.data;
    334       1.27  nathanw 	pmdata.data[0] = pm_imask;
    335       1.23   briggs 	pmgrop(&pmdata);
    336       1.23   briggs }
    337       1.23   briggs 
    338        1.1   tsubai 
    339        1.1   tsubai /*
    340        1.1   tsubai  * Check the existent ADB devices
    341        1.1   tsubai  */
    342        1.1   tsubai void
    343        1.1   tsubai pm_check_adb_devices(id)
    344        1.1   tsubai 	int id;
    345        1.1   tsubai {
    346        1.1   tsubai 	u_short ed = 0x1;
    347        1.1   tsubai 
    348        1.1   tsubai 	ed <<= id;
    349        1.1   tsubai 	pm_existent_ADB_devices |= ed;
    350        1.1   tsubai }
    351        1.1   tsubai 
    352        1.1   tsubai 
    353        1.1   tsubai /*
    354        1.1   tsubai  * Wait until PM IC is busy
    355        1.1   tsubai  */
    356        1.1   tsubai int
    357       1.27  nathanw pm_wait_busy(delaycycles)
    358       1.27  nathanw 	int delaycycles;
    359        1.1   tsubai {
    360        1.1   tsubai 	while (PM_IS_ON) {
    361        1.1   tsubai #ifdef PM_GRAB_SI
    362        1.1   tsubai #if 0
    363        1.1   tsubai 		zshard(0);		/* grab any serial interrupts */
    364        1.1   tsubai #else
    365        1.1   tsubai 		(void)intr_dispatch(0x70);
    366        1.1   tsubai #endif
    367        1.1   tsubai #endif
    368       1.27  nathanw 		if ((--delaycycles) < 0)
    369        1.1   tsubai 			return 1;	/* timeout */
    370        1.1   tsubai 	}
    371        1.1   tsubai 	return 0;
    372        1.1   tsubai }
    373        1.1   tsubai 
    374        1.1   tsubai 
    375        1.1   tsubai /*
    376        1.1   tsubai  * Wait until PM IC is free
    377        1.1   tsubai  */
    378        1.1   tsubai int
    379       1.27  nathanw pm_wait_free(delaycycles)
    380       1.27  nathanw 	int delaycycles;
    381        1.1   tsubai {
    382        1.1   tsubai 	while (PM_IS_OFF) {
    383        1.1   tsubai #ifdef PM_GRAB_SI
    384        1.1   tsubai #if 0
    385        1.1   tsubai 		zshard(0);		/* grab any serial interrupts */
    386        1.1   tsubai #else
    387        1.1   tsubai 		(void)intr_dispatch(0x70);
    388        1.1   tsubai #endif
    389        1.1   tsubai #endif
    390       1.27  nathanw 		if ((--delaycycles) < 0)
    391        1.1   tsubai 			return 0;	/* timeout */
    392        1.1   tsubai 	}
    393        1.1   tsubai 	return 1;
    394        1.1   tsubai }
    395        1.1   tsubai 
    396        1.1   tsubai 
    397        1.1   tsubai 
    398        1.1   tsubai /*
    399       1.25   briggs  * Receive data from PMU
    400        1.1   tsubai  */
    401       1.25   briggs static int
    402       1.25   briggs pm_receive(data)
    403        1.1   tsubai 	u_char *data;
    404        1.1   tsubai {
    405        1.1   tsubai 	int i;
    406        1.1   tsubai 	int rval;
    407        1.1   tsubai 
    408        1.1   tsubai 	rval = 0xffffcd34;
    409        1.1   tsubai 
    410        1.1   tsubai 	switch (1) {
    411       1.18   itojun 	default:
    412       1.18   itojun 		/* set VIA SR to input mode */
    413       1.18   itojun 		via_reg_or(VIA1, vACR, 0x0c);
    414       1.18   itojun 		via_reg_and(VIA1, vACR, ~0x10);
    415       1.18   itojun 		i = PM_SR();
    416       1.18   itojun 
    417       1.18   itojun 		PM_SET_STATE_ACKOFF();
    418       1.18   itojun 		if (pm_wait_busy((int)ADBDelay*32) != 0)
    419       1.18   itojun 			break;		/* timeout */
    420        1.1   tsubai 
    421       1.18   itojun 		PM_SET_STATE_ACKON();
    422       1.18   itojun 		rval = 0xffffcd33;
    423       1.18   itojun 		if (pm_wait_free((int)ADBDelay*32) == 0)
    424       1.18   itojun 			break;		/* timeout */
    425        1.1   tsubai 
    426       1.18   itojun 		*data = PM_SR();
    427       1.18   itojun 		rval = 0;
    428        1.1   tsubai 
    429       1.18   itojun 		break;
    430        1.1   tsubai 	}
    431        1.1   tsubai 
    432        1.1   tsubai 	PM_SET_STATE_ACKON();
    433        1.1   tsubai 	via_reg_or(VIA1, vACR, 0x1c);
    434        1.1   tsubai 
    435        1.1   tsubai 	return rval;
    436        1.1   tsubai }
    437        1.1   tsubai 
    438        1.1   tsubai 
    439        1.1   tsubai 
    440        1.1   tsubai /*
    441       1.25   briggs  * Send data to PMU
    442        1.1   tsubai  */
    443       1.25   briggs static int
    444       1.25   briggs pm_send(data)
    445        1.1   tsubai 	u_char data;
    446        1.1   tsubai {
    447        1.1   tsubai 	int rval;
    448        1.1   tsubai 
    449        1.1   tsubai 	via_reg_or(VIA1, vACR, 0x1c);
    450        1.1   tsubai 	write_via_reg(VIA1, vSR, data);	/* PM_SR() = data; */
    451        1.1   tsubai 
    452        1.1   tsubai 	PM_SET_STATE_ACKOFF();
    453        1.1   tsubai 	rval = 0xffffcd36;
    454        1.1   tsubai 	if (pm_wait_busy((int)ADBDelay*32) != 0) {
    455        1.1   tsubai 		PM_SET_STATE_ACKON();
    456        1.1   tsubai 
    457        1.1   tsubai 		via_reg_or(VIA1, vACR, 0x1c);
    458        1.1   tsubai 
    459        1.1   tsubai 		return rval;
    460        1.1   tsubai 	}
    461        1.1   tsubai 
    462        1.1   tsubai 	PM_SET_STATE_ACKON();
    463        1.1   tsubai 	rval = 0xffffcd35;
    464        1.1   tsubai 	if (pm_wait_free((int)ADBDelay*32) != 0)
    465        1.1   tsubai 		rval = 0;
    466        1.1   tsubai 
    467        1.1   tsubai 	PM_SET_STATE_ACKON();
    468        1.1   tsubai 	via_reg_or(VIA1, vACR, 0x1c);
    469        1.1   tsubai 
    470        1.1   tsubai 	return rval;
    471        1.1   tsubai }
    472        1.1   tsubai 
    473        1.1   tsubai 
    474        1.1   tsubai 
    475        1.1   tsubai /*
    476       1.25   briggs  * The PMgrOp routine
    477        1.1   tsubai  */
    478        1.1   tsubai int
    479       1.25   briggs pmgrop(pmdata)
    480        1.1   tsubai 	PMData *pmdata;
    481        1.1   tsubai {
    482        1.1   tsubai 	int i;
    483        1.1   tsubai 	int s;
    484        1.1   tsubai 	u_char via1_vIER;
    485        1.1   tsubai 	int rval = 0;
    486        1.1   tsubai 	int num_pm_data = 0;
    487        1.1   tsubai 	u_char pm_cmd;
    488        1.1   tsubai 	short pm_num_rx_data;
    489        1.1   tsubai 	u_char pm_data;
    490        1.1   tsubai 	u_char *pm_buf;
    491        1.1   tsubai 
    492        1.1   tsubai 	s = splhigh();
    493        1.1   tsubai 
    494        1.1   tsubai 	/* disable all inetrrupts but PM */
    495        1.1   tsubai 	via1_vIER = 0x10;
    496        1.1   tsubai 	via1_vIER &= read_via_reg(VIA1, vIER);
    497        1.1   tsubai 	write_via_reg(VIA1, vIER, via1_vIER);
    498        1.1   tsubai 	if (via1_vIER != 0x0)
    499        1.1   tsubai 		via1_vIER |= 0x80;
    500        1.1   tsubai 
    501        1.1   tsubai 	switch (pmdata->command) {
    502       1.18   itojun 	default:
    503       1.18   itojun 		/* wait until PM is free */
    504       1.18   itojun 		pm_cmd = (u_char)(pmdata->command & 0xff);
    505       1.18   itojun 		rval = 0xcd38;
    506       1.18   itojun 		if (pm_wait_free(ADBDelay * 4) == 0)
    507       1.18   itojun 			break;			/* timeout */
    508       1.18   itojun 
    509       1.18   itojun 		/* send PM command */
    510       1.25   briggs 		if ((rval = pm_send((u_char)(pm_cmd & 0xff))))
    511       1.18   itojun 			break;				/* timeout */
    512       1.18   itojun 
    513       1.18   itojun 		/* send number of PM data */
    514       1.18   itojun 		num_pm_data = pmdata->num_data;
    515       1.25   briggs 		if (pm_send_cmd_type[pm_cmd] < 0) {
    516       1.25   briggs 			if ((rval = pm_send((u_char)(num_pm_data & 0xff))) != 0)
    517       1.25   briggs 				break;		/* timeout */
    518       1.25   briggs 			pmdata->command = 0;
    519       1.25   briggs 		}
    520       1.18   itojun 		/* send PM data */
    521       1.18   itojun 		pm_buf = (u_char *)pmdata->s_buf;
    522       1.18   itojun 		for (i = 0 ; i < num_pm_data; i++)
    523       1.25   briggs 			if ((rval = pm_send(pm_buf[i])) != 0)
    524       1.18   itojun 				break;			/* timeout */
    525       1.18   itojun 		if (i != num_pm_data)
    526       1.18   itojun 			break;				/* timeout */
    527        1.1   tsubai 
    528        1.1   tsubai 
    529       1.18   itojun 		/* check if PM will send me data  */
    530       1.18   itojun 		pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
    531       1.18   itojun 		pmdata->num_data = pm_num_rx_data;
    532       1.18   itojun 		if (pm_num_rx_data == 0) {
    533       1.18   itojun 			rval = 0;
    534       1.18   itojun 			break;				/* no return data */
    535       1.18   itojun 		}
    536       1.18   itojun 
    537       1.18   itojun 		/* receive PM command */
    538       1.18   itojun 		pm_data = pmdata->command;
    539       1.25   briggs 		pm_num_rx_data--;
    540       1.25   briggs 		if (pm_num_rx_data == 0)
    541       1.25   briggs 			if ((rval = pm_receive(&pm_data)) != 0) {
    542       1.18   itojun 				rval = 0xffffcd37;
    543       1.18   itojun 				break;
    544        1.1   tsubai 			}
    545       1.25   briggs 		pmdata->command = pm_data;
    546        1.1   tsubai 
    547       1.18   itojun 		/* receive number of PM data */
    548       1.25   briggs 		if (pm_num_rx_data < 0) {
    549       1.25   briggs 			if ((rval = pm_receive(&pm_data)) != 0)
    550       1.25   briggs 				break;		/* timeout */
    551       1.18   itojun 			num_pm_data = pm_data;
    552       1.25   briggs 		} else
    553       1.25   briggs 			num_pm_data = pm_num_rx_data;
    554       1.25   briggs 		pmdata->num_data = num_pm_data;
    555        1.1   tsubai 
    556       1.18   itojun 		/* receive PM data */
    557       1.18   itojun 		pm_buf = (u_char *)pmdata->r_buf;
    558       1.18   itojun 		for (i = 0; i < num_pm_data; i++) {
    559       1.25   briggs 			if ((rval = pm_receive(&pm_data)) != 0)
    560       1.18   itojun 				break;			/* timeout */
    561       1.18   itojun 			pm_buf[i] = pm_data;
    562       1.18   itojun 		}
    563        1.1   tsubai 
    564       1.18   itojun 		rval = 0;
    565        1.1   tsubai 	}
    566        1.1   tsubai 
    567        1.1   tsubai 	/* restore former value */
    568        1.1   tsubai 	write_via_reg(VIA1, vIER, via1_vIER);
    569        1.1   tsubai 	splx(s);
    570        1.1   tsubai 
    571        1.1   tsubai 	return rval;
    572        1.1   tsubai }
    573        1.1   tsubai 
    574        1.1   tsubai 
    575        1.1   tsubai /*
    576       1.25   briggs  * My PMU interrupt routine
    577        1.1   tsubai  */
    578       1.24   briggs int
    579       1.25   briggs pm_intr(void *arg)
    580        1.1   tsubai {
    581        1.1   tsubai 	int s;
    582        1.1   tsubai 	int rval;
    583        1.1   tsubai 	PMData pmdata;
    584        1.1   tsubai 
    585        1.1   tsubai 	s = splhigh();
    586        1.1   tsubai 
    587        1.1   tsubai 	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
    588        1.1   tsubai 						/* ask PM what happend */
    589       1.23   briggs 	pmdata.command = PMU_INT_ACK;
    590        1.1   tsubai 	pmdata.num_data = 0;
    591        1.1   tsubai 	pmdata.s_buf = &pmdata.data[2];
    592        1.1   tsubai 	pmdata.r_buf = &pmdata.data[2];
    593       1.25   briggs 	rval = pmgrop(&pmdata);
    594        1.1   tsubai 	if (rval != 0) {
    595        1.1   tsubai #ifdef ADB_DEBUG
    596        1.1   tsubai 		if (adb_debug)
    597        1.1   tsubai 			printf("pm: PM is not ready. error code: %08x\n", rval);
    598        1.1   tsubai #endif
    599        1.1   tsubai 		splx(s);
    600       1.24   briggs 		return 0;
    601        1.1   tsubai 	}
    602        1.1   tsubai 
    603        1.1   tsubai 	switch ((u_int)(pmdata.data[2] & 0xff)) {
    604       1.21   briggs 	case 0x00:		/* no event pending? */
    605       1.18   itojun 		break;
    606       1.18   itojun 	case 0x80:		/* 1 sec interrupt? */
    607       1.18   itojun 		pm_counter++;
    608       1.18   itojun 		break;
    609       1.18   itojun 	case 0x08:		/* Brightness/Contrast button on LCD panel */
    610       1.18   itojun 		/* get brightness and contrast of the LCD */
    611       1.18   itojun 		pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
    612       1.18   itojun 		pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
    613       1.25   briggs 
    614       1.25   briggs 		/* this is experimental code */
    615       1.23   briggs 		pmdata.command = PMU_SET_BRIGHTNESS;
    616       1.18   itojun 		pmdata.num_data = 1;
    617       1.18   itojun 		pmdata.s_buf = pmdata.data;
    618       1.18   itojun 		pmdata.r_buf = pmdata.data;
    619       1.18   itojun 		pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
    620       1.18   itojun 		if (pm_LCD_brightness < 0x08)
    621       1.18   itojun 			pm_LCD_brightness = 0x08;
    622       1.18   itojun 		if (pm_LCD_brightness > 0x78)
    623       1.18   itojun 			pm_LCD_brightness = 0x78;
    624       1.18   itojun 		pmdata.data[0] = pm_LCD_brightness;
    625       1.25   briggs 		rval = pmgrop(&pmdata);
    626       1.18   itojun 		break;
    627       1.25   briggs 
    628       1.23   briggs 	case 0x10:		/* ADB data requested by TALK command */
    629       1.18   itojun 	case 0x14:
    630       1.18   itojun 		pm_adb_get_TALK_result(&pmdata);
    631       1.18   itojun 		break;
    632       1.18   itojun 	case 0x16:		/* ADB device event */
    633       1.18   itojun 	case 0x18:
    634       1.18   itojun 	case 0x1e:
    635       1.18   itojun 		pm_adb_get_ADB_data(&pmdata);
    636       1.18   itojun 		break;
    637       1.18   itojun 	default:
    638        1.1   tsubai #ifdef ADB_DEBUG
    639       1.18   itojun 		if (adb_debug)
    640       1.23   briggs 			pm_printerr("driver does not support this event.",
    641       1.18   itojun 			    pmdata.data[2], pmdata.num_data,
    642       1.18   itojun 			    pmdata.data);
    643        1.1   tsubai #endif
    644       1.18   itojun 		break;
    645        1.1   tsubai 	}
    646        1.1   tsubai 
    647        1.1   tsubai 	splx(s);
    648       1.24   briggs 
    649       1.24   briggs 	return 1;
    650        1.1   tsubai }
    651        1.1   tsubai 
    652        1.1   tsubai 
    653        1.1   tsubai /*
    654        1.1   tsubai  * Synchronous ADBOp routine for the Power Manager
    655        1.1   tsubai  */
    656        1.1   tsubai int
    657        1.1   tsubai pm_adb_op(buffer, compRout, data, command)
    658        1.1   tsubai 	u_char *buffer;
    659       1.27  nathanw 	adbComp *compRout;
    660       1.27  nathanw 	volatile int *data;
    661        1.1   tsubai 	int command;
    662        1.1   tsubai {
    663        1.1   tsubai 	int i;
    664        1.1   tsubai 	int s;
    665        1.1   tsubai 	int rval;
    666       1.12   tsubai 	int timo;
    667        1.1   tsubai 	PMData pmdata;
    668        1.1   tsubai 	struct adbCommand packet;
    669        1.1   tsubai 
    670        1.1   tsubai 	if (adbWaiting == 1)
    671        1.1   tsubai 		return 1;
    672        1.1   tsubai 
    673        1.1   tsubai 	s = splhigh();
    674        1.1   tsubai 	write_via_reg(VIA1, vIER, 0x10);
    675        1.1   tsubai 
    676        1.1   tsubai  	adbBuffer = buffer;
    677        1.1   tsubai 	adbCompRout = compRout;
    678        1.1   tsubai 	adbCompData = data;
    679        1.1   tsubai 
    680       1.23   briggs 	pmdata.command = PMU_ADB_CMD;
    681        1.1   tsubai 	pmdata.s_buf = pmdata.data;
    682        1.1   tsubai 	pmdata.r_buf = pmdata.data;
    683        1.1   tsubai 
    684        1.1   tsubai 	/* if the command is LISTEN, add number of ADB data to number of PM data */
    685        1.1   tsubai 	if ((command & 0xc) == 0x8) {
    686        1.1   tsubai 		if (buffer != (u_char *)0)
    687        1.1   tsubai 			pmdata.num_data = buffer[0] + 3;
    688        1.1   tsubai 	} else {
    689        1.1   tsubai 		pmdata.num_data = 3;
    690        1.1   tsubai 	}
    691        1.1   tsubai 
    692        1.1   tsubai 	pmdata.data[0] = (u_char)(command & 0xff);
    693        1.1   tsubai 	pmdata.data[1] = 0;
    694        1.1   tsubai 	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
    695        1.1   tsubai 		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
    696        1.1   tsubai 			pmdata.data[2] = buffer[0];		/* number of data */
    697        1.1   tsubai 			for (i = 0; i < buffer[0]; i++)
    698        1.1   tsubai 				pmdata.data[3 + i] = buffer[1 + i];
    699        1.1   tsubai 		} else
    700        1.1   tsubai 			pmdata.data[2] = 0;
    701        1.1   tsubai 	} else
    702        1.1   tsubai 		pmdata.data[2] = 0;
    703        1.1   tsubai 
    704        1.1   tsubai 	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
    705        1.1   tsubai 		/* set up stuff for adb_pass_up */
    706        1.1   tsubai 		packet.data[0] = 1 + pmdata.data[2];
    707        1.1   tsubai 		packet.data[1] = command;
    708        1.1   tsubai 		for (i = 0; i < pmdata.data[2]; i++)
    709        1.1   tsubai 			packet.data[i+2] = pmdata.data[i+3];
    710        1.1   tsubai 		packet.saveBuf = adbBuffer;
    711        1.1   tsubai 		packet.compRout = adbCompRout;
    712        1.1   tsubai 		packet.compData = adbCompData;
    713        1.1   tsubai 		packet.cmd = command;
    714        1.1   tsubai 		packet.unsol = 0;
    715        1.1   tsubai 		packet.ack_only = 1;
    716        1.1   tsubai 		adb_polling = 1;
    717        1.1   tsubai 		adb_pass_up(&packet);
    718        1.1   tsubai 		adb_polling = 0;
    719        1.1   tsubai 	}
    720        1.1   tsubai 
    721        1.1   tsubai 	rval = pmgrop(&pmdata);
    722        1.9   tsubai 	if (rval != 0) {
    723        1.9   tsubai 		splx(s);
    724        1.1   tsubai 		return 1;
    725        1.9   tsubai 	}
    726        1.1   tsubai 
    727       1.12   tsubai 	delay(10000);
    728       1.12   tsubai 
    729        1.1   tsubai 	adbWaiting = 1;
    730        1.1   tsubai 	adbWaitingCmd = command;
    731        1.1   tsubai 
    732        1.1   tsubai 	PM_VIA_INTR_ENABLE();
    733        1.1   tsubai 
    734       1.16      wiz 	/* wait until the PM interrupt has occurred */
    735       1.12   tsubai 	timo = 0x80000;
    736        1.1   tsubai 	while (adbWaiting == 1) {
    737        1.1   tsubai 		if (read_via_reg(VIA1, vIFR) & 0x14)
    738       1.24   briggs 			pm_intr(NULL);
    739        1.1   tsubai #ifdef PM_GRAB_SI
    740        1.1   tsubai #if 0
    741        1.1   tsubai 			zshard(0);		/* grab any serial interrupts */
    742        1.1   tsubai #else
    743        1.1   tsubai 			(void)intr_dispatch(0x70);
    744        1.1   tsubai #endif
    745        1.1   tsubai #endif
    746       1.12   tsubai 		if ((--timo) < 0) {
    747       1.17      dbj 			/* Try to take an interrupt anyway, just in case.
    748       1.17      dbj 			 * This has been observed to happen on my ibook
    749       1.17      dbj 			 * when i press a key after boot and before adb
    750       1.17      dbj 			 * is attached;  For example, when booting with -d.
    751       1.17      dbj 			 */
    752       1.24   briggs 			pm_intr(NULL);
    753       1.17      dbj 			if (adbWaiting) {
    754       1.17      dbj 				printf("pm_adb_op: timeout. command = 0x%x\n",command);
    755       1.17      dbj 				splx(s);
    756       1.17      dbj 				return 1;
    757       1.17      dbj 			}
    758       1.17      dbj #ifdef ADB_DEBUG
    759       1.17      dbj 			else {
    760       1.17      dbj 				printf("pm_adb_op: missed interrupt. cmd=0x%x\n",command);
    761       1.17      dbj 			}
    762       1.17      dbj #endif
    763        1.9   tsubai 		}
    764        1.1   tsubai 	}
    765        1.1   tsubai 
    766        1.1   tsubai 	/* this command enables the interrupt by operating ADB devices */
    767       1.25   briggs 	pmdata.command = PMU_ADB_CMD;
    768       1.25   briggs 	pmdata.num_data = 4;
    769       1.25   briggs 	pmdata.s_buf = pmdata.data;
    770       1.25   briggs 	pmdata.r_buf = pmdata.data;
    771       1.25   briggs 	pmdata.data[0] = 0x00;
    772       1.25   briggs 	pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
    773       1.25   briggs 	pmdata.data[2] = 0x00;
    774       1.25   briggs 	pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
    775        1.1   tsubai 	rval = pmgrop(&pmdata);
    776        1.1   tsubai 
    777        1.1   tsubai 	splx(s);
    778        1.1   tsubai 	return rval;
    779        1.1   tsubai }
    780        1.1   tsubai 
    781        1.1   tsubai 
    782        1.1   tsubai void
    783        1.1   tsubai pm_adb_get_TALK_result(pmdata)
    784        1.1   tsubai 	PMData *pmdata;
    785        1.1   tsubai {
    786        1.1   tsubai 	int i;
    787        1.1   tsubai 	struct adbCommand packet;
    788        1.1   tsubai 
    789        1.1   tsubai 	/* set up data for adb_pass_up */
    790        1.1   tsubai 	packet.data[0] = pmdata->num_data-1;
    791        1.1   tsubai 	packet.data[1] = pmdata->data[3];
    792        1.1   tsubai 	for (i = 0; i <packet.data[0]-1; i++)
    793        1.1   tsubai 		packet.data[i+2] = pmdata->data[i+4];
    794        1.1   tsubai 
    795        1.1   tsubai 	packet.saveBuf = adbBuffer;
    796        1.1   tsubai 	packet.compRout = adbCompRout;
    797        1.1   tsubai 	packet.compData = adbCompData;
    798        1.1   tsubai 	packet.unsol = 0;
    799        1.1   tsubai 	packet.ack_only = 0;
    800        1.1   tsubai 	adb_polling = 1;
    801        1.1   tsubai 	adb_pass_up(&packet);
    802        1.1   tsubai 	adb_polling = 0;
    803        1.1   tsubai 
    804        1.1   tsubai 	adbWaiting = 0;
    805        1.1   tsubai 	adbBuffer = (long)0;
    806        1.1   tsubai 	adbCompRout = (long)0;
    807        1.1   tsubai 	adbCompData = (long)0;
    808        1.1   tsubai }
    809        1.1   tsubai 
    810        1.1   tsubai 
    811        1.1   tsubai void
    812        1.1   tsubai pm_adb_get_ADB_data(pmdata)
    813        1.1   tsubai 	PMData *pmdata;
    814        1.1   tsubai {
    815        1.1   tsubai 	int i;
    816        1.1   tsubai 	struct adbCommand packet;
    817        1.1   tsubai 
    818       1.23   briggs 	if (pmu_type == PMU_OHARE && pmdata->num_data == 4 &&
    819       1.23   briggs 	    pmdata->data[1] == 0x2c && pmdata->data[3] == 0xff &&
    820       1.23   briggs 	    ((pmdata->data[2] & ~1) == 0xf4)) {
    821       1.23   briggs 		if (pmdata->data[2] == 0xf4) {
    822       1.23   briggs 			pm_eject_pcmcia(0);
    823       1.23   briggs 		} else {
    824       1.23   briggs 			pm_eject_pcmcia(1);
    825       1.23   briggs 		}
    826       1.23   briggs 		return;
    827       1.23   briggs 	}
    828        1.1   tsubai 	/* set up data for adb_pass_up */
    829        1.1   tsubai 	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
    830        1.1   tsubai 	packet.data[1] = pmdata->data[3];	/* ADB command */
    831        1.1   tsubai 	for (i = 0; i <packet.data[0]-1; i++)
    832        1.1   tsubai 		packet.data[i+2] = pmdata->data[i+4];
    833        1.1   tsubai 	packet.unsol = 1;
    834        1.1   tsubai 	packet.ack_only = 0;
    835        1.1   tsubai 	adb_pass_up(&packet);
    836        1.1   tsubai }
    837        1.1   tsubai 
    838        1.1   tsubai 
    839        1.1   tsubai void
    840        1.1   tsubai pm_adb_restart()
    841        1.1   tsubai {
    842        1.1   tsubai 	PMData p;
    843        1.1   tsubai 
    844        1.4   tsubai 	p.command = PMU_RESET_CPU;
    845        1.1   tsubai 	p.num_data = 0;
    846        1.1   tsubai 	p.s_buf = p.data;
    847        1.1   tsubai 	p.r_buf = p.data;
    848        1.6   tsubai 	pmgrop(&p);
    849        1.6   tsubai }
    850        1.6   tsubai 
    851        1.6   tsubai void
    852        1.6   tsubai pm_adb_poweroff()
    853        1.6   tsubai {
    854        1.6   tsubai 	PMData p;
    855        1.6   tsubai 
    856        1.6   tsubai 	p.command = PMU_POWER_OFF;
    857        1.6   tsubai 	p.num_data = 4;
    858        1.6   tsubai 	p.s_buf = p.data;
    859        1.6   tsubai 	p.r_buf = p.data;
    860        1.6   tsubai 	strcpy(p.data, "MATT");
    861        1.1   tsubai 	pmgrop(&p);
    862        1.2   tsubai }
    863        1.2   tsubai 
    864        1.2   tsubai void
    865       1.30   kardel pm_read_date_time(t)
    866       1.30   kardel 	u_long *t;
    867        1.2   tsubai {
    868        1.2   tsubai 	PMData p;
    869        1.2   tsubai 
    870        1.4   tsubai 	p.command = PMU_READ_RTC;
    871        1.2   tsubai 	p.num_data = 0;
    872        1.2   tsubai 	p.s_buf = p.data;
    873        1.2   tsubai 	p.r_buf = p.data;
    874        1.2   tsubai 	pmgrop(&p);
    875        1.2   tsubai 
    876       1.30   kardel 	memcpy(t, p.data, 4);
    877        1.4   tsubai }
    878        1.4   tsubai 
    879        1.4   tsubai void
    880       1.30   kardel pm_set_date_time(t)
    881       1.30   kardel 	u_long t;
    882        1.4   tsubai {
    883        1.4   tsubai 	PMData p;
    884        1.4   tsubai 
    885        1.4   tsubai 	p.command = PMU_SET_RTC;
    886        1.4   tsubai 	p.num_data = 4;
    887        1.4   tsubai 	p.s_buf = p.r_buf = p.data;
    888       1.30   kardel 	memcpy(p.data, &t, 4);
    889        1.7   tsubai 	pmgrop(&p);
    890        1.7   tsubai }
    891        1.7   tsubai 
    892        1.7   tsubai int
    893        1.7   tsubai pm_read_brightness()
    894        1.7   tsubai {
    895        1.7   tsubai 	PMData p;
    896        1.7   tsubai 
    897        1.7   tsubai 	p.command = PMU_READ_BRIGHTNESS;
    898        1.7   tsubai 	p.num_data = 1;		/* XXX why 1? */
    899        1.7   tsubai 	p.s_buf = p.r_buf = p.data;
    900        1.7   tsubai 	p.data[0] = 0;
    901        1.7   tsubai 	pmgrop(&p);
    902        1.7   tsubai 
    903        1.7   tsubai 	return p.data[0];
    904        1.7   tsubai }
    905        1.7   tsubai 
    906        1.7   tsubai void
    907        1.7   tsubai pm_set_brightness(val)
    908        1.7   tsubai 	int val;
    909        1.7   tsubai {
    910        1.7   tsubai 	PMData p;
    911        1.7   tsubai 
    912        1.7   tsubai 	val = 0x7f - val / 2;
    913        1.7   tsubai 	if (val < 0x08)
    914        1.7   tsubai 		val = 0x08;
    915        1.7   tsubai 	if (val > 0x78)
    916        1.7   tsubai 		val = 0x78;
    917        1.7   tsubai 
    918        1.7   tsubai 	p.command = PMU_SET_BRIGHTNESS;
    919        1.7   tsubai 	p.num_data = 1;
    920        1.7   tsubai 	p.s_buf = p.r_buf = p.data;
    921        1.7   tsubai 	p.data[0] = val;
    922        1.7   tsubai 	pmgrop(&p);
    923        1.7   tsubai }
    924        1.7   tsubai 
    925        1.7   tsubai void
    926        1.7   tsubai pm_init_brightness()
    927        1.7   tsubai {
    928        1.7   tsubai 	int val;
    929        1.7   tsubai 
    930        1.7   tsubai 	val = pm_read_brightness();
    931        1.7   tsubai 	pm_set_brightness(val);
    932        1.7   tsubai }
    933        1.7   tsubai 
    934        1.7   tsubai void
    935        1.7   tsubai pm_eject_pcmcia(slot)
    936        1.7   tsubai 	int slot;
    937        1.7   tsubai {
    938        1.7   tsubai 	PMData p;
    939        1.7   tsubai 
    940        1.7   tsubai 	if (slot != 0 && slot != 1)
    941        1.7   tsubai 		return;
    942        1.7   tsubai 
    943        1.7   tsubai 	p.command = PMU_EJECT_PCMCIA;
    944        1.7   tsubai 	p.num_data = 1;
    945        1.7   tsubai 	p.s_buf = p.r_buf = p.data;
    946        1.8   tsubai 	p.data[0] = 5 + slot;	/* XXX */
    947        1.5   tsubai 	pmgrop(&p);
    948       1.19   itojun }
    949       1.19   itojun 
    950       1.19   itojun /*
    951       1.19   itojun  * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation
    952       1.19   itojun  * for a clear description of the PMU results.
    953       1.19   itojun  */
    954       1.23   briggs static int
    955       1.23   briggs pm_battery_info_smart(int battery, struct pmu_battery_info *info)
    956       1.19   itojun {
    957       1.19   itojun 	PMData p;
    958       1.19   itojun 
    959       1.19   itojun 	p.command = PMU_SMART_BATTERY_STATE;
    960       1.19   itojun 	p.num_data = 1;
    961       1.19   itojun 	p.s_buf = p.r_buf = p.data;
    962       1.19   itojun 	p.data[0] = battery + 1;
    963       1.19   itojun 	pmgrop(&p);
    964       1.19   itojun 
    965       1.19   itojun 	info->flags = p.data[1];
    966       1.19   itojun 
    967       1.22   briggs 	info->secs_remaining = 0;
    968       1.19   itojun 	switch (p.data[0]) {
    969       1.19   itojun 	case 3:
    970       1.19   itojun 	case 4:
    971       1.19   itojun 		info->cur_charge = p.data[2];
    972       1.19   itojun 		info->max_charge = p.data[3];
    973       1.19   itojun 		info->draw = *((signed char *)&p.data[4]);
    974       1.19   itojun 		info->voltage = p.data[5];
    975       1.19   itojun 		break;
    976       1.19   itojun 	case 5:
    977       1.19   itojun 		info->cur_charge = ((p.data[2] << 8) | (p.data[3]));
    978       1.19   itojun 		info->max_charge = ((p.data[4] << 8) | (p.data[5]));
    979       1.19   itojun 		info->draw = *((signed short *)&p.data[6]);
    980       1.19   itojun 		info->voltage = ((p.data[8] << 8) | (p.data[7]));
    981       1.19   itojun 		break;
    982       1.19   itojun 	default:
    983       1.19   itojun 		/* XXX - Error condition */
    984       1.19   itojun 		info->cur_charge = 0;
    985       1.19   itojun 		info->max_charge = 0;
    986       1.19   itojun 		info->draw = 0;
    987       1.19   itojun 		info->voltage = 0;
    988       1.19   itojun 		break;
    989       1.19   itojun 	}
    990       1.22   briggs 	if (info->draw) {
    991       1.22   briggs 		if (info->flags & PMU_PWR_AC_PRESENT && info->draw > 0) {
    992       1.22   briggs 			info->secs_remaining =
    993       1.22   briggs 				((info->max_charge - info->cur_charge) * 3600)
    994       1.22   briggs 				/ info->draw;
    995       1.22   briggs 		} else {
    996       1.22   briggs 			info->secs_remaining =
    997       1.22   briggs 				(info->cur_charge * 3600) / -info->draw;
    998       1.22   briggs 		}
    999       1.22   briggs 	}
   1000       1.19   itojun 
   1001       1.19   itojun 	return 1;
   1002        1.5   tsubai }
   1003        1.5   tsubai 
   1004       1.23   briggs static int
   1005       1.23   briggs pm_battery_info_legacy(int battery, struct pmu_battery_info *info, int ty)
   1006       1.23   briggs {
   1007       1.23   briggs 	PMData p;
   1008       1.27  nathanw 	long pcharge=0, charge, vb, vmax, chargemax;
   1009       1.23   briggs 	long vmax_charging, vmax_charged, amperage, voltage;
   1010       1.23   briggs 
   1011       1.23   briggs 	p.command = PMU_BATTERY_STATE;
   1012       1.23   briggs 	p.num_data = 0;
   1013       1.23   briggs 	p.s_buf = p.r_buf = p.data;
   1014       1.23   briggs 	pmgrop(&p);
   1015       1.23   briggs 
   1016       1.23   briggs 	info->flags = p.data[0];
   1017       1.23   briggs 
   1018       1.23   briggs 	if (info->flags & PMU_PWR_BATT_PRESENT) {
   1019       1.23   briggs 		if (ty == BATT_COMET) {
   1020       1.23   briggs 			vmax_charging = 213;
   1021       1.23   briggs 			vmax_charged = 189;
   1022       1.27  nathanw 			chargemax = 6500;
   1023       1.23   briggs 		} else {
   1024       1.23   briggs 			/* Experimental values */
   1025       1.23   briggs 			vmax_charging = 365;
   1026       1.23   briggs 			vmax_charged = 365;
   1027       1.27  nathanw 			chargemax = 6500;
   1028       1.23   briggs 		}
   1029       1.23   briggs 		vmax = vmax_charged;
   1030       1.23   briggs 		vb = (p.data[1] << 8) | p.data[2];
   1031       1.23   briggs 		voltage = (vb * 256 + 72665) / 10;
   1032       1.23   briggs 		amperage = (unsigned char) p.data[5];
   1033       1.23   briggs 		if ((info->flags & PMU_PWR_AC_PRESENT) == 0) {
   1034       1.23   briggs 			if (amperage > 200)
   1035       1.23   briggs 				vb += ((amperage - 200) * 15)/100;
   1036       1.23   briggs 		} else if (info->flags & PMU_PWR_BATT_CHARGING) {
   1037       1.23   briggs 			vb = (vb * 97) / 100;
   1038       1.23   briggs 			vmax = vmax_charging;
   1039       1.23   briggs 		}
   1040       1.23   briggs 		charge = (100 * vb) / vmax;
   1041       1.23   briggs 		if (info->flags & PMU_PWR_PCHARGE_RESET) {
   1042       1.23   briggs 			pcharge = (p.data[6] << 8) | p.data[7];
   1043       1.27  nathanw 			if (pcharge > chargemax)
   1044       1.27  nathanw 				pcharge = chargemax;
   1045       1.23   briggs 			pcharge *= 100;
   1046       1.27  nathanw 			pcharge = 100 - pcharge / chargemax;
   1047       1.23   briggs 			if (pcharge < charge)
   1048       1.23   briggs 				charge = pcharge;
   1049       1.23   briggs 		}
   1050       1.23   briggs 		info->cur_charge = charge;
   1051       1.23   briggs 		info->max_charge = 100;
   1052       1.23   briggs 		info->draw = -amperage;
   1053       1.23   briggs 		info->voltage = voltage;
   1054       1.23   briggs 		if (amperage > 0)
   1055       1.23   briggs 			info->secs_remaining = (charge * 16440) / amperage;
   1056       1.23   briggs 		else
   1057       1.23   briggs 			info->secs_remaining = 0;
   1058       1.23   briggs 	} else {
   1059       1.23   briggs 		info->cur_charge = 0;
   1060       1.23   briggs 		info->max_charge = 0;
   1061       1.23   briggs 		info->draw = 0;
   1062       1.23   briggs 		info->voltage = 0;
   1063       1.23   briggs 		info->secs_remaining = 0;
   1064       1.23   briggs 	}
   1065       1.23   briggs 
   1066       1.23   briggs 	return 1;
   1067       1.23   briggs }
   1068       1.23   briggs 
   1069       1.23   briggs int
   1070       1.23   briggs pm_battery_info(int battery, struct pmu_battery_info *info)
   1071       1.23   briggs {
   1072       1.23   briggs 
   1073       1.23   briggs 	if (battery > pmu_nbatt)
   1074       1.23   briggs 		return 0;
   1075       1.23   briggs 
   1076       1.23   briggs 	switch (pmu_batt_type) {
   1077       1.23   briggs 	case BATT_COMET:
   1078       1.23   briggs 	case BATT_HOOPER:
   1079       1.23   briggs 		return pm_battery_info_legacy(battery, info, pmu_batt_type);
   1080       1.23   briggs 
   1081       1.23   briggs 	case BATT_SMART:
   1082       1.23   briggs 		return pm_battery_info_smart(battery, info);
   1083       1.23   briggs 	}
   1084       1.23   briggs 
   1085       1.23   briggs 	return 0;
   1086       1.23   briggs }
   1087       1.23   briggs 
   1088        1.5   tsubai int
   1089        1.5   tsubai pm_read_nvram(addr)
   1090        1.5   tsubai 	int addr;
   1091        1.5   tsubai {
   1092        1.5   tsubai 	PMData p;
   1093        1.5   tsubai 
   1094        1.5   tsubai 	p.command = PMU_READ_NVRAM;
   1095        1.5   tsubai 	p.num_data = 2;
   1096        1.5   tsubai 	p.s_buf = p.r_buf = p.data;
   1097        1.5   tsubai 	p.data[0] = addr >> 8;
   1098        1.5   tsubai 	p.data[1] = addr;
   1099        1.5   tsubai 	pmgrop(&p);
   1100        1.5   tsubai 
   1101        1.5   tsubai 	return p.data[0];
   1102        1.5   tsubai }
   1103        1.5   tsubai 
   1104        1.5   tsubai void
   1105        1.5   tsubai pm_write_nvram(addr, val)
   1106        1.5   tsubai 	int addr, val;
   1107        1.5   tsubai {
   1108        1.5   tsubai 	PMData p;
   1109        1.5   tsubai 
   1110        1.5   tsubai 	p.command = PMU_WRITE_NVRAM;
   1111        1.5   tsubai 	p.num_data = 3;
   1112        1.5   tsubai 	p.s_buf = p.r_buf = p.data;
   1113        1.5   tsubai 	p.data[0] = addr >> 8;
   1114        1.5   tsubai 	p.data[1] = addr;
   1115        1.5   tsubai 	p.data[2] = val;
   1116        1.4   tsubai 	pmgrop(&p);
   1117        1.1   tsubai }
   1118