Home | History | Annotate | Line # | Download | only in dev
pm_direct.c revision 1.33.26.1
      1  1.33.26.1    skrll /*	$NetBSD: pm_direct.c,v 1.33.26.1 2009/04/28 07:34:20 skrll 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.33.26.1    skrll __KERNEL_RCSID(0, "$NetBSD: pm_direct.c,v 1.33.26.1 2009/04/28 07:34:20 skrll 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.32  garbled #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.33.26.1    skrll void	pm_printerr(const char *, int, int, const char *);
    175        1.1   tsubai #endif
    176        1.1   tsubai 
    177  1.33.26.1    skrll int	pm_wait_busy(int);
    178  1.33.26.1    skrll int	pm_wait_free(int);
    179        1.1   tsubai 
    180  1.33.26.1    skrll static int	pm_receive(u_char *);
    181  1.33.26.1    skrll static int	pm_send(u_char);
    182        1.1   tsubai 
    183        1.1   tsubai /* these functions are called from adb_direct.c */
    184  1.33.26.1    skrll void	pm_setup_adb(void);
    185  1.33.26.1    skrll void	pm_check_adb_devices(int);
    186  1.33.26.1    skrll int	pm_adb_op(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.33.26.1    skrll void	pm_adb_get_TALK_result(PMData *);
    190  1.33.26.1    skrll void	pm_adb_get_ADB_data(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.33.26.1    skrll extern	void	adb_pass_up(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.33.26.1    skrll extern int	zshard(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.33.26.1    skrll pm_printerr(const char *ttl, int rval, int num, const char *data)
    230        1.1   tsubai {
    231        1.1   tsubai 	int i;
    232        1.1   tsubai 
    233        1.1   tsubai 	printf("pm: %s:%04x %02x ", ttl, rval, num);
    234        1.1   tsubai 	for (i = 0; i < num; i++)
    235        1.1   tsubai 		printf("%02x ", data[i]);
    236        1.1   tsubai 	printf("\n");
    237        1.1   tsubai }
    238        1.1   tsubai #endif
    239        1.1   tsubai 
    240        1.1   tsubai 
    241        1.1   tsubai 
    242        1.1   tsubai /*
    243        1.1   tsubai  * Check the hardware type of the Power Manager
    244        1.1   tsubai  */
    245        1.1   tsubai void
    246  1.33.26.1    skrll pm_setup_adb(void)
    247        1.1   tsubai {
    248        1.1   tsubai }
    249        1.1   tsubai 
    250       1.26   briggs /*
    251       1.26   briggs  * Search for targ in list.  list is an area of listlen bytes
    252       1.26   briggs  * containing null-terminated strings.
    253       1.26   briggs  */
    254       1.23   briggs static int
    255       1.27  nathanw strinlist(const char *targ, char *list, int listlen)
    256       1.23   briggs {
    257       1.23   briggs 	char	*str;
    258       1.23   briggs 	int	sl;
    259       1.26   briggs 	int	targlen;
    260       1.23   briggs 
    261       1.23   briggs 	str = list;
    262       1.26   briggs 	targlen = strlen(targ);
    263       1.23   briggs 	while (listlen > 0) {
    264       1.23   briggs 		sl = strlen(str);
    265       1.26   briggs 		if (sl == targlen && (strncmp(targ, str, sl) == 0))
    266       1.23   briggs 			return 1;
    267       1.23   briggs 		str += sl+1;
    268       1.23   briggs 		listlen -= sl+1;
    269       1.23   briggs 	}
    270       1.23   briggs 	return 0;
    271       1.23   briggs }
    272       1.23   briggs 
    273       1.23   briggs /*
    274       1.23   briggs  * Check the hardware type of the Power Manager
    275       1.23   briggs  */
    276       1.23   briggs void
    277       1.23   briggs pm_init(void)
    278       1.23   briggs {
    279       1.23   briggs 	uint32_t	regs[10];
    280       1.23   briggs 	PMData		pmdata;
    281       1.23   briggs 	char		compat[128];
    282       1.27  nathanw 	int		clen, node, pm_imask;
    283       1.23   briggs 
    284       1.23   briggs 	node = OF_peer(0);
    285       1.23   briggs 	if (node == -1) {
    286       1.23   briggs 		printf("pmu: Failed to get root");
    287       1.23   briggs 		return;
    288       1.23   briggs 	}
    289       1.23   briggs 	clen = OF_getprop(node, "compatible", compat, sizeof(compat));
    290       1.23   briggs 	if (clen <= 0) {
    291       1.23   briggs 		printf("pmu: failed to read root compatible data %d\n", clen);
    292       1.23   briggs 		return;
    293       1.23   briggs 	}
    294       1.23   briggs 
    295       1.27  nathanw 	pm_imask =
    296       1.27  nathanw 	    PMU_INT_PCEJECT | PMU_INT_SNDBRT | PMU_INT_ADB | PMU_INT_TICK;
    297       1.23   briggs 
    298       1.23   briggs 	if (strinlist("AAPL,3500", compat, clen) ||
    299       1.23   briggs 	    strinlist("AAPL,3400/2400", compat, clen)) {
    300       1.23   briggs 		/* How to distinguish BATT_COMET? */
    301       1.23   briggs 		pmu_nbatt = 1;
    302       1.23   briggs 		pmu_batt_type = BATT_HOOPER;
    303       1.23   briggs 		pmu_type = PMU_OHARE;
    304       1.23   briggs 	} else if (strinlist("AAPL,PowerBook1998", compat, clen) ||
    305       1.23   briggs 		   strinlist("PowerBook1,1", compat, clen)) {
    306       1.23   briggs 		pmu_nbatt = 2;
    307       1.23   briggs 		pmu_batt_type = BATT_SMART;
    308       1.23   briggs 		pmu_type = PMU_G3;
    309       1.23   briggs 	} else {
    310       1.23   briggs 		pmu_nbatt = 1;
    311       1.23   briggs 		pmu_batt_type = BATT_SMART;
    312       1.23   briggs 		pmu_type = PMU_KEYLARGO;
    313       1.33  garbled 		node = of_getnode_byname(0, "power-mgt");
    314       1.23   briggs 		if (node == -1) {
    315       1.23   briggs 			printf("pmu: can't find power-mgt\n");
    316       1.23   briggs 			return;
    317       1.23   briggs 		}
    318       1.23   briggs 		clen = OF_getprop(node, "prim-info", regs, sizeof(regs));
    319       1.23   briggs 		if (clen < 24) {
    320       1.23   briggs 			printf("pmu: failed to read prim-info\n");
    321       1.23   briggs 			return;
    322       1.23   briggs 		}
    323       1.23   briggs 		pmu_nbatt = regs[6] >> 16;
    324       1.23   briggs 	}
    325       1.23   briggs 
    326       1.23   briggs 	pmdata.command = PMU_SET_IMASK;
    327       1.23   briggs 	pmdata.num_data = 1;
    328       1.23   briggs 	pmdata.s_buf = pmdata.data;
    329       1.23   briggs 	pmdata.r_buf = pmdata.data;
    330       1.27  nathanw 	pmdata.data[0] = pm_imask;
    331       1.23   briggs 	pmgrop(&pmdata);
    332       1.23   briggs }
    333       1.23   briggs 
    334        1.1   tsubai 
    335        1.1   tsubai /*
    336        1.1   tsubai  * Check the existent ADB devices
    337        1.1   tsubai  */
    338        1.1   tsubai void
    339  1.33.26.1    skrll pm_check_adb_devices(int id)
    340        1.1   tsubai {
    341        1.1   tsubai 	u_short ed = 0x1;
    342        1.1   tsubai 
    343        1.1   tsubai 	ed <<= id;
    344        1.1   tsubai 	pm_existent_ADB_devices |= ed;
    345        1.1   tsubai }
    346        1.1   tsubai 
    347        1.1   tsubai 
    348        1.1   tsubai /*
    349        1.1   tsubai  * Wait until PM IC is busy
    350        1.1   tsubai  */
    351        1.1   tsubai int
    352  1.33.26.1    skrll pm_wait_busy(int delaycycles)
    353        1.1   tsubai {
    354        1.1   tsubai 	while (PM_IS_ON) {
    355        1.1   tsubai #ifdef PM_GRAB_SI
    356        1.1   tsubai #if 0
    357        1.1   tsubai 		zshard(0);		/* grab any serial interrupts */
    358        1.1   tsubai #else
    359        1.1   tsubai 		(void)intr_dispatch(0x70);
    360        1.1   tsubai #endif
    361        1.1   tsubai #endif
    362       1.27  nathanw 		if ((--delaycycles) < 0)
    363        1.1   tsubai 			return 1;	/* timeout */
    364        1.1   tsubai 	}
    365        1.1   tsubai 	return 0;
    366        1.1   tsubai }
    367        1.1   tsubai 
    368        1.1   tsubai 
    369        1.1   tsubai /*
    370        1.1   tsubai  * Wait until PM IC is free
    371        1.1   tsubai  */
    372        1.1   tsubai int
    373  1.33.26.1    skrll pm_wait_free(int delaycycles)
    374        1.1   tsubai {
    375        1.1   tsubai 	while (PM_IS_OFF) {
    376        1.1   tsubai #ifdef PM_GRAB_SI
    377        1.1   tsubai #if 0
    378        1.1   tsubai 		zshard(0);		/* grab any serial interrupts */
    379        1.1   tsubai #else
    380        1.1   tsubai 		(void)intr_dispatch(0x70);
    381        1.1   tsubai #endif
    382        1.1   tsubai #endif
    383       1.27  nathanw 		if ((--delaycycles) < 0)
    384        1.1   tsubai 			return 0;	/* timeout */
    385        1.1   tsubai 	}
    386        1.1   tsubai 	return 1;
    387        1.1   tsubai }
    388        1.1   tsubai 
    389        1.1   tsubai 
    390        1.1   tsubai 
    391        1.1   tsubai /*
    392       1.25   briggs  * Receive data from PMU
    393        1.1   tsubai  */
    394       1.25   briggs static int
    395  1.33.26.1    skrll pm_receive(u_char *data)
    396        1.1   tsubai {
    397        1.1   tsubai 	int i;
    398        1.1   tsubai 	int rval;
    399        1.1   tsubai 
    400        1.1   tsubai 	rval = 0xffffcd34;
    401        1.1   tsubai 
    402        1.1   tsubai 	switch (1) {
    403       1.18   itojun 	default:
    404       1.18   itojun 		/* set VIA SR to input mode */
    405       1.18   itojun 		via_reg_or(VIA1, vACR, 0x0c);
    406       1.18   itojun 		via_reg_and(VIA1, vACR, ~0x10);
    407       1.18   itojun 		i = PM_SR();
    408       1.18   itojun 
    409       1.18   itojun 		PM_SET_STATE_ACKOFF();
    410       1.18   itojun 		if (pm_wait_busy((int)ADBDelay*32) != 0)
    411       1.18   itojun 			break;		/* timeout */
    412        1.1   tsubai 
    413       1.18   itojun 		PM_SET_STATE_ACKON();
    414       1.18   itojun 		rval = 0xffffcd33;
    415       1.18   itojun 		if (pm_wait_free((int)ADBDelay*32) == 0)
    416       1.18   itojun 			break;		/* timeout */
    417        1.1   tsubai 
    418       1.18   itojun 		*data = PM_SR();
    419       1.18   itojun 		rval = 0;
    420        1.1   tsubai 
    421       1.18   itojun 		break;
    422        1.1   tsubai 	}
    423        1.1   tsubai 
    424        1.1   tsubai 	PM_SET_STATE_ACKON();
    425        1.1   tsubai 	via_reg_or(VIA1, vACR, 0x1c);
    426        1.1   tsubai 
    427        1.1   tsubai 	return rval;
    428        1.1   tsubai }
    429        1.1   tsubai 
    430        1.1   tsubai 
    431        1.1   tsubai 
    432        1.1   tsubai /*
    433       1.25   briggs  * Send data to PMU
    434        1.1   tsubai  */
    435       1.25   briggs static int
    436  1.33.26.1    skrll pm_send(u_char data)
    437        1.1   tsubai {
    438        1.1   tsubai 	int rval;
    439        1.1   tsubai 
    440        1.1   tsubai 	via_reg_or(VIA1, vACR, 0x1c);
    441        1.1   tsubai 	write_via_reg(VIA1, vSR, data);	/* PM_SR() = data; */
    442        1.1   tsubai 
    443        1.1   tsubai 	PM_SET_STATE_ACKOFF();
    444        1.1   tsubai 	rval = 0xffffcd36;
    445        1.1   tsubai 	if (pm_wait_busy((int)ADBDelay*32) != 0) {
    446        1.1   tsubai 		PM_SET_STATE_ACKON();
    447        1.1   tsubai 
    448        1.1   tsubai 		via_reg_or(VIA1, vACR, 0x1c);
    449        1.1   tsubai 
    450        1.1   tsubai 		return rval;
    451        1.1   tsubai 	}
    452        1.1   tsubai 
    453        1.1   tsubai 	PM_SET_STATE_ACKON();
    454        1.1   tsubai 	rval = 0xffffcd35;
    455        1.1   tsubai 	if (pm_wait_free((int)ADBDelay*32) != 0)
    456        1.1   tsubai 		rval = 0;
    457        1.1   tsubai 
    458        1.1   tsubai 	PM_SET_STATE_ACKON();
    459        1.1   tsubai 	via_reg_or(VIA1, vACR, 0x1c);
    460        1.1   tsubai 
    461        1.1   tsubai 	return rval;
    462        1.1   tsubai }
    463        1.1   tsubai 
    464        1.1   tsubai 
    465        1.1   tsubai 
    466        1.1   tsubai /*
    467       1.25   briggs  * The PMgrOp routine
    468        1.1   tsubai  */
    469        1.1   tsubai int
    470  1.33.26.1    skrll pmgrop(PMData *pmdata)
    471        1.1   tsubai {
    472        1.1   tsubai 	int i;
    473        1.1   tsubai 	int s;
    474        1.1   tsubai 	u_char via1_vIER;
    475        1.1   tsubai 	int rval = 0;
    476        1.1   tsubai 	int num_pm_data = 0;
    477        1.1   tsubai 	u_char pm_cmd;
    478        1.1   tsubai 	short pm_num_rx_data;
    479        1.1   tsubai 	u_char pm_data;
    480        1.1   tsubai 	u_char *pm_buf;
    481        1.1   tsubai 
    482        1.1   tsubai 	s = splhigh();
    483        1.1   tsubai 
    484        1.1   tsubai 	/* disable all inetrrupts but PM */
    485        1.1   tsubai 	via1_vIER = 0x10;
    486        1.1   tsubai 	via1_vIER &= read_via_reg(VIA1, vIER);
    487        1.1   tsubai 	write_via_reg(VIA1, vIER, via1_vIER);
    488        1.1   tsubai 	if (via1_vIER != 0x0)
    489        1.1   tsubai 		via1_vIER |= 0x80;
    490        1.1   tsubai 
    491        1.1   tsubai 	switch (pmdata->command) {
    492       1.18   itojun 	default:
    493       1.18   itojun 		/* wait until PM is free */
    494       1.18   itojun 		pm_cmd = (u_char)(pmdata->command & 0xff);
    495       1.18   itojun 		rval = 0xcd38;
    496       1.18   itojun 		if (pm_wait_free(ADBDelay * 4) == 0)
    497       1.18   itojun 			break;			/* timeout */
    498       1.18   itojun 
    499       1.18   itojun 		/* send PM command */
    500       1.25   briggs 		if ((rval = pm_send((u_char)(pm_cmd & 0xff))))
    501       1.18   itojun 			break;				/* timeout */
    502       1.18   itojun 
    503       1.18   itojun 		/* send number of PM data */
    504       1.18   itojun 		num_pm_data = pmdata->num_data;
    505       1.25   briggs 		if (pm_send_cmd_type[pm_cmd] < 0) {
    506       1.25   briggs 			if ((rval = pm_send((u_char)(num_pm_data & 0xff))) != 0)
    507       1.25   briggs 				break;		/* timeout */
    508       1.25   briggs 			pmdata->command = 0;
    509       1.25   briggs 		}
    510       1.18   itojun 		/* send PM data */
    511       1.18   itojun 		pm_buf = (u_char *)pmdata->s_buf;
    512       1.18   itojun 		for (i = 0 ; i < num_pm_data; i++)
    513       1.25   briggs 			if ((rval = pm_send(pm_buf[i])) != 0)
    514       1.18   itojun 				break;			/* timeout */
    515       1.18   itojun 		if (i != num_pm_data)
    516       1.18   itojun 			break;				/* timeout */
    517        1.1   tsubai 
    518        1.1   tsubai 
    519       1.18   itojun 		/* check if PM will send me data  */
    520       1.18   itojun 		pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
    521       1.18   itojun 		pmdata->num_data = pm_num_rx_data;
    522       1.18   itojun 		if (pm_num_rx_data == 0) {
    523       1.18   itojun 			rval = 0;
    524       1.18   itojun 			break;				/* no return data */
    525       1.18   itojun 		}
    526       1.18   itojun 
    527       1.18   itojun 		/* receive PM command */
    528       1.18   itojun 		pm_data = pmdata->command;
    529       1.25   briggs 		pm_num_rx_data--;
    530       1.25   briggs 		if (pm_num_rx_data == 0)
    531       1.25   briggs 			if ((rval = pm_receive(&pm_data)) != 0) {
    532       1.18   itojun 				rval = 0xffffcd37;
    533       1.18   itojun 				break;
    534        1.1   tsubai 			}
    535       1.25   briggs 		pmdata->command = pm_data;
    536        1.1   tsubai 
    537       1.18   itojun 		/* receive number of PM data */
    538       1.25   briggs 		if (pm_num_rx_data < 0) {
    539       1.25   briggs 			if ((rval = pm_receive(&pm_data)) != 0)
    540       1.25   briggs 				break;		/* timeout */
    541       1.18   itojun 			num_pm_data = pm_data;
    542       1.25   briggs 		} else
    543       1.25   briggs 			num_pm_data = pm_num_rx_data;
    544       1.25   briggs 		pmdata->num_data = num_pm_data;
    545        1.1   tsubai 
    546       1.18   itojun 		/* receive PM data */
    547       1.18   itojun 		pm_buf = (u_char *)pmdata->r_buf;
    548       1.18   itojun 		for (i = 0; i < num_pm_data; i++) {
    549       1.25   briggs 			if ((rval = pm_receive(&pm_data)) != 0)
    550       1.18   itojun 				break;			/* timeout */
    551       1.18   itojun 			pm_buf[i] = pm_data;
    552       1.18   itojun 		}
    553        1.1   tsubai 
    554       1.18   itojun 		rval = 0;
    555        1.1   tsubai 	}
    556        1.1   tsubai 
    557        1.1   tsubai 	/* restore former value */
    558        1.1   tsubai 	write_via_reg(VIA1, vIER, via1_vIER);
    559        1.1   tsubai 	splx(s);
    560        1.1   tsubai 
    561        1.1   tsubai 	return rval;
    562        1.1   tsubai }
    563        1.1   tsubai 
    564        1.1   tsubai 
    565        1.1   tsubai /*
    566       1.25   briggs  * My PMU interrupt routine
    567        1.1   tsubai  */
    568       1.24   briggs int
    569       1.25   briggs pm_intr(void *arg)
    570        1.1   tsubai {
    571        1.1   tsubai 	int s;
    572        1.1   tsubai 	int rval;
    573        1.1   tsubai 	PMData pmdata;
    574        1.1   tsubai 
    575        1.1   tsubai 	s = splhigh();
    576        1.1   tsubai 
    577        1.1   tsubai 	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
    578        1.1   tsubai 						/* ask PM what happend */
    579       1.23   briggs 	pmdata.command = PMU_INT_ACK;
    580        1.1   tsubai 	pmdata.num_data = 0;
    581        1.1   tsubai 	pmdata.s_buf = &pmdata.data[2];
    582        1.1   tsubai 	pmdata.r_buf = &pmdata.data[2];
    583       1.25   briggs 	rval = pmgrop(&pmdata);
    584        1.1   tsubai 	if (rval != 0) {
    585        1.1   tsubai #ifdef ADB_DEBUG
    586        1.1   tsubai 		if (adb_debug)
    587        1.1   tsubai 			printf("pm: PM is not ready. error code: %08x\n", rval);
    588        1.1   tsubai #endif
    589        1.1   tsubai 		splx(s);
    590       1.24   briggs 		return 0;
    591        1.1   tsubai 	}
    592        1.1   tsubai 
    593        1.1   tsubai 	switch ((u_int)(pmdata.data[2] & 0xff)) {
    594       1.21   briggs 	case 0x00:		/* no event pending? */
    595       1.18   itojun 		break;
    596       1.18   itojun 	case 0x80:		/* 1 sec interrupt? */
    597       1.18   itojun 		pm_counter++;
    598       1.18   itojun 		break;
    599       1.18   itojun 	case 0x08:		/* Brightness/Contrast button on LCD panel */
    600       1.18   itojun 		/* get brightness and contrast of the LCD */
    601       1.18   itojun 		pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
    602       1.18   itojun 		pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
    603       1.25   briggs 
    604       1.25   briggs 		/* this is experimental code */
    605       1.23   briggs 		pmdata.command = PMU_SET_BRIGHTNESS;
    606       1.18   itojun 		pmdata.num_data = 1;
    607       1.18   itojun 		pmdata.s_buf = pmdata.data;
    608       1.18   itojun 		pmdata.r_buf = pmdata.data;
    609       1.18   itojun 		pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
    610       1.18   itojun 		if (pm_LCD_brightness < 0x08)
    611       1.18   itojun 			pm_LCD_brightness = 0x08;
    612       1.18   itojun 		if (pm_LCD_brightness > 0x78)
    613       1.18   itojun 			pm_LCD_brightness = 0x78;
    614       1.18   itojun 		pmdata.data[0] = pm_LCD_brightness;
    615       1.25   briggs 		rval = pmgrop(&pmdata);
    616       1.18   itojun 		break;
    617       1.25   briggs 
    618       1.23   briggs 	case 0x10:		/* ADB data requested by TALK command */
    619       1.18   itojun 	case 0x14:
    620       1.18   itojun 		pm_adb_get_TALK_result(&pmdata);
    621       1.18   itojun 		break;
    622       1.18   itojun 	case 0x16:		/* ADB device event */
    623       1.18   itojun 	case 0x18:
    624       1.18   itojun 	case 0x1e:
    625       1.18   itojun 		pm_adb_get_ADB_data(&pmdata);
    626       1.18   itojun 		break;
    627       1.18   itojun 	default:
    628        1.1   tsubai #ifdef ADB_DEBUG
    629       1.18   itojun 		if (adb_debug)
    630       1.23   briggs 			pm_printerr("driver does not support this event.",
    631       1.18   itojun 			    pmdata.data[2], pmdata.num_data,
    632       1.18   itojun 			    pmdata.data);
    633        1.1   tsubai #endif
    634       1.18   itojun 		break;
    635        1.1   tsubai 	}
    636        1.1   tsubai 
    637        1.1   tsubai 	splx(s);
    638       1.24   briggs 
    639       1.24   briggs 	return 1;
    640        1.1   tsubai }
    641        1.1   tsubai 
    642        1.1   tsubai 
    643        1.1   tsubai /*
    644        1.1   tsubai  * Synchronous ADBOp routine for the Power Manager
    645        1.1   tsubai  */
    646        1.1   tsubai int
    647  1.33.26.1    skrll pm_adb_op(u_char *buffer, adbComp *compRout, volatile int *data, int command)
    648        1.1   tsubai {
    649        1.1   tsubai 	int i;
    650        1.1   tsubai 	int s;
    651        1.1   tsubai 	int rval;
    652       1.12   tsubai 	int timo;
    653        1.1   tsubai 	PMData pmdata;
    654        1.1   tsubai 	struct adbCommand packet;
    655        1.1   tsubai 
    656        1.1   tsubai 	if (adbWaiting == 1)
    657        1.1   tsubai 		return 1;
    658        1.1   tsubai 
    659        1.1   tsubai 	s = splhigh();
    660        1.1   tsubai 	write_via_reg(VIA1, vIER, 0x10);
    661        1.1   tsubai 
    662        1.1   tsubai  	adbBuffer = buffer;
    663        1.1   tsubai 	adbCompRout = compRout;
    664        1.1   tsubai 	adbCompData = data;
    665        1.1   tsubai 
    666       1.23   briggs 	pmdata.command = PMU_ADB_CMD;
    667        1.1   tsubai 	pmdata.s_buf = pmdata.data;
    668        1.1   tsubai 	pmdata.r_buf = pmdata.data;
    669        1.1   tsubai 
    670        1.1   tsubai 	/* if the command is LISTEN, add number of ADB data to number of PM data */
    671        1.1   tsubai 	if ((command & 0xc) == 0x8) {
    672        1.1   tsubai 		if (buffer != (u_char *)0)
    673        1.1   tsubai 			pmdata.num_data = buffer[0] + 3;
    674        1.1   tsubai 	} else {
    675        1.1   tsubai 		pmdata.num_data = 3;
    676        1.1   tsubai 	}
    677        1.1   tsubai 
    678        1.1   tsubai 	pmdata.data[0] = (u_char)(command & 0xff);
    679        1.1   tsubai 	pmdata.data[1] = 0;
    680        1.1   tsubai 	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
    681        1.1   tsubai 		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
    682        1.1   tsubai 			pmdata.data[2] = buffer[0];		/* number of data */
    683        1.1   tsubai 			for (i = 0; i < buffer[0]; i++)
    684        1.1   tsubai 				pmdata.data[3 + i] = buffer[1 + i];
    685        1.1   tsubai 		} else
    686        1.1   tsubai 			pmdata.data[2] = 0;
    687        1.1   tsubai 	} else
    688        1.1   tsubai 		pmdata.data[2] = 0;
    689        1.1   tsubai 
    690        1.1   tsubai 	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
    691        1.1   tsubai 		/* set up stuff for adb_pass_up */
    692        1.1   tsubai 		packet.data[0] = 1 + pmdata.data[2];
    693        1.1   tsubai 		packet.data[1] = command;
    694        1.1   tsubai 		for (i = 0; i < pmdata.data[2]; i++)
    695        1.1   tsubai 			packet.data[i+2] = pmdata.data[i+3];
    696        1.1   tsubai 		packet.saveBuf = adbBuffer;
    697        1.1   tsubai 		packet.compRout = adbCompRout;
    698        1.1   tsubai 		packet.compData = adbCompData;
    699        1.1   tsubai 		packet.cmd = command;
    700        1.1   tsubai 		packet.unsol = 0;
    701        1.1   tsubai 		packet.ack_only = 1;
    702        1.1   tsubai 		adb_polling = 1;
    703        1.1   tsubai 		adb_pass_up(&packet);
    704        1.1   tsubai 		adb_polling = 0;
    705        1.1   tsubai 	}
    706        1.1   tsubai 
    707        1.1   tsubai 	rval = pmgrop(&pmdata);
    708        1.9   tsubai 	if (rval != 0) {
    709        1.9   tsubai 		splx(s);
    710        1.1   tsubai 		return 1;
    711        1.9   tsubai 	}
    712        1.1   tsubai 
    713       1.12   tsubai 	delay(10000);
    714       1.12   tsubai 
    715        1.1   tsubai 	adbWaiting = 1;
    716        1.1   tsubai 	adbWaitingCmd = command;
    717        1.1   tsubai 
    718        1.1   tsubai 	PM_VIA_INTR_ENABLE();
    719        1.1   tsubai 
    720       1.16      wiz 	/* wait until the PM interrupt has occurred */
    721       1.12   tsubai 	timo = 0x80000;
    722        1.1   tsubai 	while (adbWaiting == 1) {
    723        1.1   tsubai 		if (read_via_reg(VIA1, vIFR) & 0x14)
    724       1.24   briggs 			pm_intr(NULL);
    725        1.1   tsubai #ifdef PM_GRAB_SI
    726        1.1   tsubai #if 0
    727        1.1   tsubai 			zshard(0);		/* grab any serial interrupts */
    728        1.1   tsubai #else
    729        1.1   tsubai 			(void)intr_dispatch(0x70);
    730        1.1   tsubai #endif
    731        1.1   tsubai #endif
    732       1.12   tsubai 		if ((--timo) < 0) {
    733       1.17      dbj 			/* Try to take an interrupt anyway, just in case.
    734       1.17      dbj 			 * This has been observed to happen on my ibook
    735       1.17      dbj 			 * when i press a key after boot and before adb
    736       1.17      dbj 			 * is attached;  For example, when booting with -d.
    737       1.17      dbj 			 */
    738       1.24   briggs 			pm_intr(NULL);
    739       1.17      dbj 			if (adbWaiting) {
    740       1.17      dbj 				printf("pm_adb_op: timeout. command = 0x%x\n",command);
    741       1.17      dbj 				splx(s);
    742       1.17      dbj 				return 1;
    743       1.17      dbj 			}
    744       1.17      dbj #ifdef ADB_DEBUG
    745       1.17      dbj 			else {
    746       1.17      dbj 				printf("pm_adb_op: missed interrupt. cmd=0x%x\n",command);
    747       1.17      dbj 			}
    748       1.17      dbj #endif
    749        1.9   tsubai 		}
    750        1.1   tsubai 	}
    751        1.1   tsubai 
    752        1.1   tsubai 	/* this command enables the interrupt by operating ADB devices */
    753       1.25   briggs 	pmdata.command = PMU_ADB_CMD;
    754       1.25   briggs 	pmdata.num_data = 4;
    755       1.25   briggs 	pmdata.s_buf = pmdata.data;
    756       1.25   briggs 	pmdata.r_buf = pmdata.data;
    757       1.25   briggs 	pmdata.data[0] = 0x00;
    758       1.25   briggs 	pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
    759       1.25   briggs 	pmdata.data[2] = 0x00;
    760       1.25   briggs 	pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
    761        1.1   tsubai 	rval = pmgrop(&pmdata);
    762        1.1   tsubai 
    763        1.1   tsubai 	splx(s);
    764        1.1   tsubai 	return rval;
    765        1.1   tsubai }
    766        1.1   tsubai 
    767        1.1   tsubai 
    768        1.1   tsubai void
    769  1.33.26.1    skrll pm_adb_get_TALK_result(PMData *pmdata)
    770        1.1   tsubai {
    771        1.1   tsubai 	int i;
    772        1.1   tsubai 	struct adbCommand packet;
    773        1.1   tsubai 
    774        1.1   tsubai 	/* set up data for adb_pass_up */
    775        1.1   tsubai 	packet.data[0] = pmdata->num_data-1;
    776        1.1   tsubai 	packet.data[1] = pmdata->data[3];
    777        1.1   tsubai 	for (i = 0; i <packet.data[0]-1; i++)
    778        1.1   tsubai 		packet.data[i+2] = pmdata->data[i+4];
    779        1.1   tsubai 
    780        1.1   tsubai 	packet.saveBuf = adbBuffer;
    781        1.1   tsubai 	packet.compRout = adbCompRout;
    782        1.1   tsubai 	packet.compData = adbCompData;
    783        1.1   tsubai 	packet.unsol = 0;
    784        1.1   tsubai 	packet.ack_only = 0;
    785        1.1   tsubai 	adb_polling = 1;
    786        1.1   tsubai 	adb_pass_up(&packet);
    787        1.1   tsubai 	adb_polling = 0;
    788        1.1   tsubai 
    789        1.1   tsubai 	adbWaiting = 0;
    790        1.1   tsubai 	adbBuffer = (long)0;
    791        1.1   tsubai 	adbCompRout = (long)0;
    792        1.1   tsubai 	adbCompData = (long)0;
    793        1.1   tsubai }
    794        1.1   tsubai 
    795        1.1   tsubai 
    796        1.1   tsubai void
    797  1.33.26.1    skrll pm_adb_get_ADB_data(PMData *pmdata)
    798        1.1   tsubai {
    799        1.1   tsubai 	int i;
    800        1.1   tsubai 	struct adbCommand packet;
    801        1.1   tsubai 
    802       1.23   briggs 	if (pmu_type == PMU_OHARE && pmdata->num_data == 4 &&
    803       1.23   briggs 	    pmdata->data[1] == 0x2c && pmdata->data[3] == 0xff &&
    804       1.23   briggs 	    ((pmdata->data[2] & ~1) == 0xf4)) {
    805       1.23   briggs 		if (pmdata->data[2] == 0xf4) {
    806       1.23   briggs 			pm_eject_pcmcia(0);
    807       1.23   briggs 		} else {
    808       1.23   briggs 			pm_eject_pcmcia(1);
    809       1.23   briggs 		}
    810       1.23   briggs 		return;
    811       1.23   briggs 	}
    812        1.1   tsubai 	/* set up data for adb_pass_up */
    813        1.1   tsubai 	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
    814        1.1   tsubai 	packet.data[1] = pmdata->data[3];	/* ADB command */
    815        1.1   tsubai 	for (i = 0; i <packet.data[0]-1; i++)
    816        1.1   tsubai 		packet.data[i+2] = pmdata->data[i+4];
    817        1.1   tsubai 	packet.unsol = 1;
    818        1.1   tsubai 	packet.ack_only = 0;
    819        1.1   tsubai 	adb_pass_up(&packet);
    820        1.1   tsubai }
    821        1.1   tsubai 
    822        1.1   tsubai 
    823        1.1   tsubai void
    824  1.33.26.1    skrll pm_adb_restart(void)
    825        1.1   tsubai {
    826        1.1   tsubai 	PMData p;
    827        1.1   tsubai 
    828        1.4   tsubai 	p.command = PMU_RESET_CPU;
    829        1.1   tsubai 	p.num_data = 0;
    830        1.1   tsubai 	p.s_buf = p.data;
    831        1.1   tsubai 	p.r_buf = p.data;
    832        1.6   tsubai 	pmgrop(&p);
    833        1.6   tsubai }
    834        1.6   tsubai 
    835        1.6   tsubai void
    836  1.33.26.1    skrll pm_adb_poweroff(void)
    837        1.6   tsubai {
    838        1.6   tsubai 	PMData p;
    839        1.6   tsubai 
    840        1.6   tsubai 	p.command = PMU_POWER_OFF;
    841        1.6   tsubai 	p.num_data = 4;
    842        1.6   tsubai 	p.s_buf = p.data;
    843        1.6   tsubai 	p.r_buf = p.data;
    844        1.6   tsubai 	strcpy(p.data, "MATT");
    845        1.1   tsubai 	pmgrop(&p);
    846        1.2   tsubai }
    847        1.2   tsubai 
    848        1.2   tsubai void
    849  1.33.26.1    skrll pm_read_date_time(u_long *t)
    850        1.2   tsubai {
    851        1.2   tsubai 	PMData p;
    852        1.2   tsubai 
    853        1.4   tsubai 	p.command = PMU_READ_RTC;
    854        1.2   tsubai 	p.num_data = 0;
    855        1.2   tsubai 	p.s_buf = p.data;
    856        1.2   tsubai 	p.r_buf = p.data;
    857        1.2   tsubai 	pmgrop(&p);
    858        1.2   tsubai 
    859       1.30   kardel 	memcpy(t, p.data, 4);
    860        1.4   tsubai }
    861        1.4   tsubai 
    862        1.4   tsubai void
    863  1.33.26.1    skrll pm_set_date_time(u_long t)
    864        1.4   tsubai {
    865        1.4   tsubai 	PMData p;
    866        1.4   tsubai 
    867        1.4   tsubai 	p.command = PMU_SET_RTC;
    868        1.4   tsubai 	p.num_data = 4;
    869        1.4   tsubai 	p.s_buf = p.r_buf = p.data;
    870       1.30   kardel 	memcpy(p.data, &t, 4);
    871        1.7   tsubai 	pmgrop(&p);
    872        1.7   tsubai }
    873        1.7   tsubai 
    874        1.7   tsubai int
    875  1.33.26.1    skrll pm_read_brightness(void)
    876        1.7   tsubai {
    877        1.7   tsubai 	PMData p;
    878        1.7   tsubai 
    879        1.7   tsubai 	p.command = PMU_READ_BRIGHTNESS;
    880        1.7   tsubai 	p.num_data = 1;		/* XXX why 1? */
    881        1.7   tsubai 	p.s_buf = p.r_buf = p.data;
    882        1.7   tsubai 	p.data[0] = 0;
    883        1.7   tsubai 	pmgrop(&p);
    884        1.7   tsubai 
    885        1.7   tsubai 	return p.data[0];
    886        1.7   tsubai }
    887        1.7   tsubai 
    888        1.7   tsubai void
    889  1.33.26.1    skrll pm_set_brightness(int val)
    890        1.7   tsubai {
    891        1.7   tsubai 	PMData p;
    892        1.7   tsubai 
    893        1.7   tsubai 	val = 0x7f - val / 2;
    894        1.7   tsubai 	if (val < 0x08)
    895        1.7   tsubai 		val = 0x08;
    896        1.7   tsubai 	if (val > 0x78)
    897        1.7   tsubai 		val = 0x78;
    898        1.7   tsubai 
    899        1.7   tsubai 	p.command = PMU_SET_BRIGHTNESS;
    900        1.7   tsubai 	p.num_data = 1;
    901        1.7   tsubai 	p.s_buf = p.r_buf = p.data;
    902        1.7   tsubai 	p.data[0] = val;
    903        1.7   tsubai 	pmgrop(&p);
    904        1.7   tsubai }
    905        1.7   tsubai 
    906        1.7   tsubai void
    907  1.33.26.1    skrll pm_init_brightness(void)
    908        1.7   tsubai {
    909        1.7   tsubai 	int val;
    910        1.7   tsubai 
    911        1.7   tsubai 	val = pm_read_brightness();
    912        1.7   tsubai 	pm_set_brightness(val);
    913        1.7   tsubai }
    914        1.7   tsubai 
    915        1.7   tsubai void
    916  1.33.26.1    skrll pm_eject_pcmcia(int slot)
    917        1.7   tsubai {
    918        1.7   tsubai 	PMData p;
    919        1.7   tsubai 
    920        1.7   tsubai 	if (slot != 0 && slot != 1)
    921        1.7   tsubai 		return;
    922        1.7   tsubai 
    923        1.7   tsubai 	p.command = PMU_EJECT_PCMCIA;
    924        1.7   tsubai 	p.num_data = 1;
    925        1.7   tsubai 	p.s_buf = p.r_buf = p.data;
    926        1.8   tsubai 	p.data[0] = 5 + slot;	/* XXX */
    927        1.5   tsubai 	pmgrop(&p);
    928       1.19   itojun }
    929       1.19   itojun 
    930       1.19   itojun /*
    931       1.19   itojun  * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation
    932       1.19   itojun  * for a clear description of the PMU results.
    933       1.19   itojun  */
    934       1.23   briggs static int
    935       1.23   briggs pm_battery_info_smart(int battery, struct pmu_battery_info *info)
    936       1.19   itojun {
    937       1.19   itojun 	PMData p;
    938       1.19   itojun 
    939       1.19   itojun 	p.command = PMU_SMART_BATTERY_STATE;
    940       1.19   itojun 	p.num_data = 1;
    941       1.19   itojun 	p.s_buf = p.r_buf = p.data;
    942       1.19   itojun 	p.data[0] = battery + 1;
    943       1.19   itojun 	pmgrop(&p);
    944       1.19   itojun 
    945       1.19   itojun 	info->flags = p.data[1];
    946       1.19   itojun 
    947       1.22   briggs 	info->secs_remaining = 0;
    948       1.19   itojun 	switch (p.data[0]) {
    949       1.19   itojun 	case 3:
    950       1.19   itojun 	case 4:
    951       1.19   itojun 		info->cur_charge = p.data[2];
    952       1.19   itojun 		info->max_charge = p.data[3];
    953       1.19   itojun 		info->draw = *((signed char *)&p.data[4]);
    954       1.19   itojun 		info->voltage = p.data[5];
    955       1.19   itojun 		break;
    956       1.19   itojun 	case 5:
    957       1.19   itojun 		info->cur_charge = ((p.data[2] << 8) | (p.data[3]));
    958       1.19   itojun 		info->max_charge = ((p.data[4] << 8) | (p.data[5]));
    959       1.19   itojun 		info->draw = *((signed short *)&p.data[6]);
    960       1.19   itojun 		info->voltage = ((p.data[8] << 8) | (p.data[7]));
    961       1.19   itojun 		break;
    962       1.19   itojun 	default:
    963       1.19   itojun 		/* XXX - Error condition */
    964       1.19   itojun 		info->cur_charge = 0;
    965       1.19   itojun 		info->max_charge = 0;
    966       1.19   itojun 		info->draw = 0;
    967       1.19   itojun 		info->voltage = 0;
    968       1.19   itojun 		break;
    969       1.19   itojun 	}
    970       1.22   briggs 	if (info->draw) {
    971       1.22   briggs 		if (info->flags & PMU_PWR_AC_PRESENT && info->draw > 0) {
    972       1.22   briggs 			info->secs_remaining =
    973       1.22   briggs 				((info->max_charge - info->cur_charge) * 3600)
    974       1.22   briggs 				/ info->draw;
    975       1.22   briggs 		} else {
    976       1.22   briggs 			info->secs_remaining =
    977       1.22   briggs 				(info->cur_charge * 3600) / -info->draw;
    978       1.22   briggs 		}
    979       1.22   briggs 	}
    980       1.19   itojun 
    981       1.19   itojun 	return 1;
    982        1.5   tsubai }
    983        1.5   tsubai 
    984       1.23   briggs static int
    985       1.23   briggs pm_battery_info_legacy(int battery, struct pmu_battery_info *info, int ty)
    986       1.23   briggs {
    987       1.23   briggs 	PMData p;
    988       1.27  nathanw 	long pcharge=0, charge, vb, vmax, chargemax;
    989       1.23   briggs 	long vmax_charging, vmax_charged, amperage, voltage;
    990       1.23   briggs 
    991       1.23   briggs 	p.command = PMU_BATTERY_STATE;
    992       1.23   briggs 	p.num_data = 0;
    993       1.23   briggs 	p.s_buf = p.r_buf = p.data;
    994       1.23   briggs 	pmgrop(&p);
    995       1.23   briggs 
    996       1.23   briggs 	info->flags = p.data[0];
    997       1.23   briggs 
    998       1.23   briggs 	if (info->flags & PMU_PWR_BATT_PRESENT) {
    999       1.23   briggs 		if (ty == BATT_COMET) {
   1000       1.23   briggs 			vmax_charging = 213;
   1001       1.23   briggs 			vmax_charged = 189;
   1002       1.27  nathanw 			chargemax = 6500;
   1003       1.23   briggs 		} else {
   1004       1.23   briggs 			/* Experimental values */
   1005       1.23   briggs 			vmax_charging = 365;
   1006       1.23   briggs 			vmax_charged = 365;
   1007       1.27  nathanw 			chargemax = 6500;
   1008       1.23   briggs 		}
   1009       1.23   briggs 		vmax = vmax_charged;
   1010       1.23   briggs 		vb = (p.data[1] << 8) | p.data[2];
   1011       1.23   briggs 		voltage = (vb * 256 + 72665) / 10;
   1012       1.23   briggs 		amperage = (unsigned char) p.data[5];
   1013       1.23   briggs 		if ((info->flags & PMU_PWR_AC_PRESENT) == 0) {
   1014       1.23   briggs 			if (amperage > 200)
   1015       1.23   briggs 				vb += ((amperage - 200) * 15)/100;
   1016       1.23   briggs 		} else if (info->flags & PMU_PWR_BATT_CHARGING) {
   1017       1.23   briggs 			vb = (vb * 97) / 100;
   1018       1.23   briggs 			vmax = vmax_charging;
   1019       1.23   briggs 		}
   1020       1.23   briggs 		charge = (100 * vb) / vmax;
   1021       1.23   briggs 		if (info->flags & PMU_PWR_PCHARGE_RESET) {
   1022       1.23   briggs 			pcharge = (p.data[6] << 8) | p.data[7];
   1023       1.27  nathanw 			if (pcharge > chargemax)
   1024       1.27  nathanw 				pcharge = chargemax;
   1025       1.23   briggs 			pcharge *= 100;
   1026       1.27  nathanw 			pcharge = 100 - pcharge / chargemax;
   1027       1.23   briggs 			if (pcharge < charge)
   1028       1.23   briggs 				charge = pcharge;
   1029       1.23   briggs 		}
   1030       1.23   briggs 		info->cur_charge = charge;
   1031       1.23   briggs 		info->max_charge = 100;
   1032       1.23   briggs 		info->draw = -amperage;
   1033       1.23   briggs 		info->voltage = voltage;
   1034       1.23   briggs 		if (amperage > 0)
   1035       1.23   briggs 			info->secs_remaining = (charge * 16440) / amperage;
   1036       1.23   briggs 		else
   1037       1.23   briggs 			info->secs_remaining = 0;
   1038       1.23   briggs 	} else {
   1039       1.23   briggs 		info->cur_charge = 0;
   1040       1.23   briggs 		info->max_charge = 0;
   1041       1.23   briggs 		info->draw = 0;
   1042       1.23   briggs 		info->voltage = 0;
   1043       1.23   briggs 		info->secs_remaining = 0;
   1044       1.23   briggs 	}
   1045       1.23   briggs 
   1046       1.23   briggs 	return 1;
   1047       1.23   briggs }
   1048       1.23   briggs 
   1049       1.23   briggs int
   1050       1.23   briggs pm_battery_info(int battery, struct pmu_battery_info *info)
   1051       1.23   briggs {
   1052       1.23   briggs 
   1053       1.23   briggs 	if (battery > pmu_nbatt)
   1054       1.23   briggs 		return 0;
   1055       1.23   briggs 
   1056       1.23   briggs 	switch (pmu_batt_type) {
   1057       1.23   briggs 	case BATT_COMET:
   1058       1.23   briggs 	case BATT_HOOPER:
   1059       1.23   briggs 		return pm_battery_info_legacy(battery, info, pmu_batt_type);
   1060       1.23   briggs 
   1061       1.23   briggs 	case BATT_SMART:
   1062       1.23   briggs 		return pm_battery_info_smart(battery, info);
   1063       1.23   briggs 	}
   1064       1.23   briggs 
   1065       1.23   briggs 	return 0;
   1066       1.23   briggs }
   1067       1.23   briggs 
   1068        1.5   tsubai int
   1069  1.33.26.1    skrll pm_read_nvram(int addr)
   1070        1.5   tsubai {
   1071        1.5   tsubai 	PMData p;
   1072        1.5   tsubai 
   1073        1.5   tsubai 	p.command = PMU_READ_NVRAM;
   1074        1.5   tsubai 	p.num_data = 2;
   1075        1.5   tsubai 	p.s_buf = p.r_buf = p.data;
   1076        1.5   tsubai 	p.data[0] = addr >> 8;
   1077        1.5   tsubai 	p.data[1] = addr;
   1078        1.5   tsubai 	pmgrop(&p);
   1079        1.5   tsubai 
   1080        1.5   tsubai 	return p.data[0];
   1081        1.5   tsubai }
   1082        1.5   tsubai 
   1083        1.5   tsubai void
   1084  1.33.26.1    skrll pm_write_nvram(int addr, int val)
   1085        1.5   tsubai {
   1086        1.5   tsubai 	PMData p;
   1087        1.5   tsubai 
   1088        1.5   tsubai 	p.command = PMU_WRITE_NVRAM;
   1089        1.5   tsubai 	p.num_data = 3;
   1090        1.5   tsubai 	p.s_buf = p.r_buf = p.data;
   1091        1.5   tsubai 	p.data[0] = addr >> 8;
   1092        1.5   tsubai 	p.data[1] = addr;
   1093        1.5   tsubai 	p.data[2] = val;
   1094        1.4   tsubai 	pmgrop(&p);
   1095        1.1   tsubai }
   1096