Home | History | Annotate | Line # | Download | only in dev
pm_direct.c revision 1.23
      1  1.23  briggs /*	$NetBSD: pm_direct.c,v 1.23 2005/02/01 02:46:00 briggs 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.23  briggs __KERNEL_RCSID(0, "$NetBSD: pm_direct.c,v 1.23 2005/02/01 02:46:00 briggs 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/cdefs.h>
     53   1.1  tsubai #include <sys/device.h>
     54   1.1  tsubai #include <sys/systm.h>
     55   1.1  tsubai 
     56   1.1  tsubai #include <machine/adbsys.h>
     57  1.23  briggs #include <machine/autoconf.h>
     58   1.1  tsubai #include <machine/cpu.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 #define HwCfgFlags3 0x20000	/* XXX */
     71   1.1  tsubai 
     72   1.1  tsubai /* define the types of the Power Manager */
     73   1.1  tsubai #define PM_HW_UNKNOWN		0x00	/* don't know */
     74   1.1  tsubai #define PM_HW_PB1XX		0x01	/* PowerBook 1XX series */
     75   1.1  tsubai #define	PM_HW_PB5XX		0x02	/* PowerBook Duo and 5XX series */
     76   1.1  tsubai 
     77   1.1  tsubai /* useful macros */
     78   1.1  tsubai #define PM_SR()			read_via_reg(VIA1, vSR)
     79   1.1  tsubai #define PM_VIA_INTR_ENABLE()	write_via_reg(VIA1, vIER, 0x90)
     80   1.1  tsubai #define PM_VIA_INTR_DISABLE()	write_via_reg(VIA1, vIER, 0x10)
     81   1.1  tsubai #define PM_VIA_CLR_INTR()	write_via_reg(VIA1, vIFR, 0x90)
     82   1.1  tsubai #if 0
     83   1.1  tsubai #define PM_SET_STATE_ACKON()	via_reg_or(VIA2, vBufB, 0x04)
     84   1.1  tsubai #define PM_SET_STATE_ACKOFF()	via_reg_and(VIA2, vBufB, ~0x04)
     85   1.1  tsubai #define PM_IS_ON		(0x02 == (read_via_reg(VIA2, vBufB) & 0x02))
     86   1.1  tsubai #define PM_IS_OFF		(0x00 == (read_via_reg(VIA2, vBufB) & 0x02))
     87   1.1  tsubai #else
     88   1.1  tsubai #define PM_SET_STATE_ACKON()	via_reg_or(VIA2, vBufB, 0x10)
     89   1.1  tsubai #define PM_SET_STATE_ACKOFF()	via_reg_and(VIA2, vBufB, ~0x10)
     90   1.1  tsubai #define PM_IS_ON		(0x08 == (read_via_reg(VIA2, vBufB) & 0x08))
     91   1.1  tsubai #define PM_IS_OFF		(0x00 == (read_via_reg(VIA2, vBufB) & 0x08))
     92   1.1  tsubai #endif
     93   1.1  tsubai 
     94   1.1  tsubai /*
     95   1.1  tsubai  * Variables for internal use
     96   1.1  tsubai  */
     97   1.1  tsubai int	pmHardware = PM_HW_UNKNOWN;
     98   1.1  tsubai u_short	pm_existent_ADB_devices = 0x0;	/* each bit expresses the existent ADB device */
     99   1.1  tsubai u_int	pm_LCD_brightness = 0x0;
    100   1.1  tsubai u_int	pm_LCD_contrast = 0x0;
    101   1.1  tsubai u_int	pm_counter = 0;			/* clock count */
    102   1.1  tsubai 
    103  1.23  briggs static enum batt_type { BATT_COMET, BATT_HOOPER, BATT_SMART } pmu_batt_type;
    104  1.23  briggs static int	pmu_nbatt;
    105  1.23  briggs static int	strinlist(char *, char *, int);
    106  1.23  briggs static enum pmu_type { PMU_UNKNOWN, PMU_OHARE, PMU_G3, PMU_KEYLARGO } pmu_type;
    107  1.23  briggs 
    108   1.1  tsubai /* these values shows that number of data returned after 'send' cmd is sent */
    109   1.1  tsubai signed char pm_send_cmd_type[] = {
    110   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    111   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    112   1.1  tsubai 	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
    113   1.1  tsubai 	0x00, 0x00,   -1,   -1,   -1,   -1,   -1, 0x00,
    114   1.1  tsubai 	  -1, 0x00, 0x02, 0x01, 0x01,   -1,   -1,   -1,
    115   1.1  tsubai 	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    116   1.5  tsubai 	0x04, 0x14,   -1, 0x03,   -1,   -1,   -1,   -1,
    117   1.5  tsubai 	0x00, 0x00, 0x02, 0x02,   -1,   -1,   -1,   -1,
    118   1.1  tsubai 	0x01, 0x01,   -1,   -1,   -1,   -1,   -1,   -1,
    119   1.7  tsubai 	0x00, 0x00,   -1,   -1, 0x01,   -1,   -1,   -1,
    120   1.1  tsubai 	0x01, 0x00, 0x02, 0x02,   -1, 0x01, 0x03, 0x01,
    121   1.1  tsubai 	0x00, 0x01, 0x00, 0x00, 0x00,   -1,   -1,   -1,
    122   1.1  tsubai 	0x02,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    123   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   -1,   -1,
    124   1.1  tsubai 	0x01, 0x01, 0x01,   -1,   -1,   -1,   -1,   -1,
    125   1.1  tsubai 	0x00, 0x00,   -1,   -1,   -1,   -1, 0x04, 0x04,
    126   1.1  tsubai 	0x04,   -1, 0x00,   -1,   -1,   -1,   -1,   -1,
    127   1.1  tsubai 	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    128   1.1  tsubai 	0x01, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
    129   1.1  tsubai 	0x00, 0x00,   -1,   -1,   -1,   -1,   -1,   -1,
    130   1.1  tsubai 	0x02, 0x02, 0x02, 0x04,   -1, 0x00,   -1,   -1,
    131   1.1  tsubai 	0x01, 0x01, 0x03, 0x02,   -1,   -1,   -1,   -1,
    132   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    133   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    134   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    135   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    136   1.1  tsubai 	0x00,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    137   1.1  tsubai 	0x01, 0x01,   -1,   -1, 0x00, 0x00,   -1,   -1,
    138   1.1  tsubai 	  -1, 0x04, 0x00,   -1,   -1,   -1,   -1,   -1,
    139   1.1  tsubai 	0x03,   -1, 0x00,   -1, 0x00,   -1,   -1, 0x00,
    140   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    141   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1
    142   1.1  tsubai };
    143   1.1  tsubai 
    144   1.1  tsubai /* these values shows that number of data returned after 'receive' cmd is sent */
    145   1.1  tsubai signed char pm_receive_cmd_type[] = {
    146   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    147   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    148   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    149   1.1  tsubai 	0x02, 0x02,   -1,   -1,   -1,   -1,   -1, 0x00,
    150   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    151   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    152   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    153   1.5  tsubai 	0x05, 0x15,   -1, 0x02,   -1,   -1,   -1,   -1,
    154   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    155   1.1  tsubai 	0x02, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
    156   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    157   1.1  tsubai 	0x02, 0x00, 0x03, 0x03,   -1,   -1,   -1,   -1,
    158   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    159   1.1  tsubai 	0x04, 0x04, 0x03, 0x09,   -1,   -1,   -1,   -1,
    160   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    161   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1, 0x01, 0x01,
    162   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    163   1.1  tsubai 	0x06,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    164   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    165   1.1  tsubai 	0x02, 0x02,   -1,   -1,   -1,   -1,   -1,   -1,
    166   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    167   1.1  tsubai 	0x02, 0x00, 0x00, 0x00,   -1,   -1,   -1,   -1,
    168   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    169   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    170   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    171   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    172   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    173   1.1  tsubai 	0x02, 0x02,   -1,   -1, 0x02,   -1,   -1,   -1,
    174   1.1  tsubai 	0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
    175   1.1  tsubai 	  -1,   -1, 0x02,   -1,   -1,   -1,   -1, 0x00,
    176   1.1  tsubai 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    177   1.1  tsubai 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
    178   1.1  tsubai };
    179   1.1  tsubai 
    180   1.1  tsubai 
    181   1.1  tsubai /*
    182   1.1  tsubai  * Define the private functions
    183   1.1  tsubai  */
    184   1.1  tsubai 
    185   1.1  tsubai /* for debugging */
    186   1.1  tsubai #ifdef ADB_DEBUG
    187   1.1  tsubai void	pm_printerr __P((char *, int, int, char *));
    188   1.1  tsubai #endif
    189   1.1  tsubai 
    190   1.1  tsubai int	pm_wait_busy __P((int));
    191   1.1  tsubai int	pm_wait_free __P((int));
    192   1.1  tsubai 
    193   1.1  tsubai /* these functions are for the PB1XX series */
    194   1.1  tsubai int	pm_receive_pm1 __P((u_char *));
    195   1.1  tsubai int	pm_send_pm1 __P((u_char,int));
    196   1.1  tsubai int	pm_pmgrop_pm1 __P((PMData *));
    197   1.1  tsubai void	pm_intr_pm1 __P((void));
    198   1.1  tsubai 
    199   1.1  tsubai /* these functions are for the PB Duo series and the PB 5XX series */
    200   1.1  tsubai int	pm_receive_pm2 __P((u_char *));
    201   1.1  tsubai int	pm_send_pm2 __P((u_char));
    202   1.1  tsubai int	pm_pmgrop_pm2 __P((PMData *));
    203   1.1  tsubai void	pm_intr_pm2 __P((void));
    204   1.1  tsubai 
    205   1.1  tsubai /* these functions are called from adb_direct.c */
    206   1.1  tsubai void	pm_setup_adb __P((void));
    207   1.1  tsubai void	pm_check_adb_devices __P((int));
    208   1.1  tsubai void	pm_intr __P((void));
    209   1.1  tsubai int	pm_adb_op __P((u_char *, void *, void *, int));
    210   1.1  tsubai 
    211   1.1  tsubai /* these functions also use the variables of adb_direct.c */
    212   1.1  tsubai void	pm_adb_get_TALK_result __P((PMData *));
    213   1.1  tsubai void	pm_adb_get_ADB_data __P((PMData *));
    214   1.1  tsubai void	pm_adb_poll_next_device_pm1 __P((PMData *));
    215   1.1  tsubai 
    216   1.1  tsubai 
    217   1.1  tsubai /*
    218   1.1  tsubai  * These variables are in adb_direct.c.
    219   1.1  tsubai  */
    220   1.1  tsubai extern u_char	*adbBuffer;	/* pointer to user data area */
    221   1.1  tsubai extern void	*adbCompRout;	/* pointer to the completion routine */
    222   1.1  tsubai extern void	*adbCompData;	/* pointer to the completion routine data */
    223   1.1  tsubai extern int	adbWaiting;	/* waiting for return data from the device */
    224   1.1  tsubai extern int	adbWaitingCmd;	/* ADB command we are waiting for */
    225   1.1  tsubai extern int	adbStarting;	/* doing ADB reinit, so do "polling" differently */
    226   1.1  tsubai 
    227   1.1  tsubai #define	ADB_MAX_MSG_LENGTH	16
    228   1.1  tsubai #define	ADB_MAX_HDR_LENGTH	8
    229   1.1  tsubai struct adbCommand {
    230   1.1  tsubai 	u_char	header[ADB_MAX_HDR_LENGTH];	/* not used yet */
    231   1.1  tsubai 	u_char	data[ADB_MAX_MSG_LENGTH];	/* packet data only */
    232   1.1  tsubai 	u_char	*saveBuf;	/* where to save result */
    233   1.1  tsubai 	u_char	*compRout;	/* completion routine pointer */
    234   1.1  tsubai 	u_char	*compData;	/* completion routine data pointer */
    235   1.1  tsubai 	u_int	cmd;		/* the original command for this data */
    236   1.1  tsubai 	u_int	unsol;		/* 1 if packet was unsolicited */
    237   1.1  tsubai 	u_int	ack_only;	/* 1 for no special processing */
    238   1.1  tsubai };
    239   1.1  tsubai extern	void	adb_pass_up __P((struct adbCommand *));
    240   1.1  tsubai 
    241   1.1  tsubai #if 0
    242   1.1  tsubai /*
    243   1.1  tsubai  * Define the external functions
    244   1.1  tsubai  */
    245   1.1  tsubai extern int	zshard __P((int));		/* from zs.c */
    246   1.1  tsubai #endif
    247   1.1  tsubai 
    248   1.1  tsubai #ifdef ADB_DEBUG
    249   1.1  tsubai /*
    250   1.1  tsubai  * This function dumps contents of the PMData
    251   1.1  tsubai  */
    252   1.1  tsubai void
    253   1.1  tsubai pm_printerr(ttl, rval, num, data)
    254   1.1  tsubai 	char *ttl;
    255   1.1  tsubai 	int rval;
    256   1.1  tsubai 	int num;
    257   1.1  tsubai 	char *data;
    258   1.1  tsubai {
    259   1.1  tsubai 	int i;
    260   1.1  tsubai 
    261   1.1  tsubai 	printf("pm: %s:%04x %02x ", ttl, rval, num);
    262   1.1  tsubai 	for (i = 0; i < num; i++)
    263   1.1  tsubai 		printf("%02x ", data[i]);
    264   1.1  tsubai 	printf("\n");
    265   1.1  tsubai }
    266   1.1  tsubai #endif
    267   1.1  tsubai 
    268   1.1  tsubai 
    269   1.1  tsubai 
    270   1.1  tsubai /*
    271   1.1  tsubai  * Check the hardware type of the Power Manager
    272   1.1  tsubai  */
    273   1.1  tsubai void
    274   1.1  tsubai pm_setup_adb()
    275   1.1  tsubai {
    276   1.1  tsubai 	pmHardware = PM_HW_PB5XX;	/* XXX */
    277   1.1  tsubai }
    278   1.1  tsubai 
    279  1.23  briggs static int
    280  1.23  briggs strinlist(char *targ, char *list, int listlen)
    281  1.23  briggs {
    282  1.23  briggs 	char	*str;
    283  1.23  briggs 	int	sl;
    284  1.23  briggs 
    285  1.23  briggs 	str = list;
    286  1.23  briggs 	while (listlen > 0) {
    287  1.23  briggs 		sl = strlen(str);
    288  1.23  briggs 		if (strncmp(targ, str, sl) == 0)
    289  1.23  briggs 			return 1;
    290  1.23  briggs 		str += sl+1;
    291  1.23  briggs 		listlen -= sl+1;
    292  1.23  briggs 	}
    293  1.23  briggs 	return 0;
    294  1.23  briggs }
    295  1.23  briggs 
    296  1.23  briggs /*
    297  1.23  briggs  * Check the hardware type of the Power Manager
    298  1.23  briggs  */
    299  1.23  briggs void
    300  1.23  briggs pm_init(void)
    301  1.23  briggs {
    302  1.23  briggs 	uint32_t	regs[10];
    303  1.23  briggs 	PMData		pmdata;
    304  1.23  briggs 	char		compat[128];
    305  1.23  briggs 	int		clen, node, imask;
    306  1.23  briggs 
    307  1.23  briggs 	node = OF_peer(0);
    308  1.23  briggs 	if (node == -1) {
    309  1.23  briggs 		printf("pmu: Failed to get root");
    310  1.23  briggs 		return;
    311  1.23  briggs 	}
    312  1.23  briggs 	clen = OF_getprop(node, "compatible", compat, sizeof(compat));
    313  1.23  briggs 	if (clen <= 0) {
    314  1.23  briggs 		printf("pmu: failed to read root compatible data %d\n", clen);
    315  1.23  briggs 		return;
    316  1.23  briggs 	}
    317  1.23  briggs 
    318  1.23  briggs 	imask = PMU_INT_PCEJECT | PMU_INT_SNDBRT | PMU_INT_ADB | PMU_INT_TICK;
    319  1.23  briggs 
    320  1.23  briggs 	if (strinlist("AAPL,3500", compat, clen) ||
    321  1.23  briggs 	    strinlist("AAPL,3400/2400", compat, clen)) {
    322  1.23  briggs 		/* How to distinguish BATT_COMET? */
    323  1.23  briggs 		pmu_nbatt = 1;
    324  1.23  briggs 		pmu_batt_type = BATT_HOOPER;
    325  1.23  briggs 		pmu_type = PMU_OHARE;
    326  1.23  briggs 	} else if (strinlist("AAPL,PowerBook1998", compat, clen) ||
    327  1.23  briggs 		   strinlist("PowerBook1,1", compat, clen)) {
    328  1.23  briggs 		pmu_nbatt = 2;
    329  1.23  briggs 		pmu_batt_type = BATT_SMART;
    330  1.23  briggs 		pmu_type = PMU_G3;
    331  1.23  briggs 	} else {
    332  1.23  briggs 		pmu_nbatt = 1;
    333  1.23  briggs 		pmu_batt_type = BATT_SMART;
    334  1.23  briggs 		pmu_type = PMU_KEYLARGO;
    335  1.23  briggs 		node = getnodebyname(0, "power-mgt");
    336  1.23  briggs 		if (node == -1) {
    337  1.23  briggs 			printf("pmu: can't find power-mgt\n");
    338  1.23  briggs 			return;
    339  1.23  briggs 		}
    340  1.23  briggs 		clen = OF_getprop(node, "prim-info", regs, sizeof(regs));
    341  1.23  briggs 		if (clen < 24) {
    342  1.23  briggs 			printf("pmu: failed to read prim-info\n");
    343  1.23  briggs 			return;
    344  1.23  briggs 		}
    345  1.23  briggs 		pmu_nbatt = regs[6] >> 16;
    346  1.23  briggs 	}
    347  1.23  briggs 
    348  1.23  briggs 	pmdata.command = PMU_SET_IMASK;
    349  1.23  briggs 	pmdata.num_data = 1;
    350  1.23  briggs 	pmdata.s_buf = pmdata.data;
    351  1.23  briggs 	pmdata.r_buf = pmdata.data;
    352  1.23  briggs 	pmdata.data[0] = imask;
    353  1.23  briggs 	pmgrop(&pmdata);
    354  1.23  briggs }
    355  1.23  briggs 
    356   1.1  tsubai 
    357   1.1  tsubai /*
    358   1.1  tsubai  * Check the existent ADB devices
    359   1.1  tsubai  */
    360   1.1  tsubai void
    361   1.1  tsubai pm_check_adb_devices(id)
    362   1.1  tsubai 	int id;
    363   1.1  tsubai {
    364   1.1  tsubai 	u_short ed = 0x1;
    365   1.1  tsubai 
    366   1.1  tsubai 	ed <<= id;
    367   1.1  tsubai 	pm_existent_ADB_devices |= ed;
    368   1.1  tsubai }
    369   1.1  tsubai 
    370   1.1  tsubai 
    371   1.1  tsubai /*
    372   1.1  tsubai  * Wait until PM IC is busy
    373   1.1  tsubai  */
    374   1.1  tsubai int
    375   1.1  tsubai pm_wait_busy(delay)
    376   1.1  tsubai 	int delay;
    377   1.1  tsubai {
    378   1.1  tsubai 	while (PM_IS_ON) {
    379   1.1  tsubai #ifdef PM_GRAB_SI
    380   1.1  tsubai #if 0
    381   1.1  tsubai 		zshard(0);		/* grab any serial interrupts */
    382   1.1  tsubai #else
    383   1.1  tsubai 		(void)intr_dispatch(0x70);
    384   1.1  tsubai #endif
    385   1.1  tsubai #endif
    386   1.1  tsubai 		if ((--delay) < 0)
    387   1.1  tsubai 			return 1;	/* timeout */
    388   1.1  tsubai 	}
    389   1.1  tsubai 	return 0;
    390   1.1  tsubai }
    391   1.1  tsubai 
    392   1.1  tsubai 
    393   1.1  tsubai /*
    394   1.1  tsubai  * Wait until PM IC is free
    395   1.1  tsubai  */
    396   1.1  tsubai int
    397   1.1  tsubai pm_wait_free(delay)
    398   1.1  tsubai 	int delay;
    399   1.1  tsubai {
    400   1.1  tsubai 	while (PM_IS_OFF) {
    401   1.1  tsubai #ifdef PM_GRAB_SI
    402   1.1  tsubai #if 0
    403   1.1  tsubai 		zshard(0);		/* grab any serial interrupts */
    404   1.1  tsubai #else
    405   1.1  tsubai 		(void)intr_dispatch(0x70);
    406   1.1  tsubai #endif
    407   1.1  tsubai #endif
    408   1.1  tsubai 		if ((--delay) < 0)
    409   1.1  tsubai 			return 0;	/* timeout */
    410   1.1  tsubai 	}
    411   1.1  tsubai 	return 1;
    412   1.1  tsubai }
    413   1.1  tsubai 
    414   1.1  tsubai 
    415   1.1  tsubai 
    416   1.1  tsubai /*
    417   1.1  tsubai  * Functions for the PB1XX series
    418   1.1  tsubai  */
    419   1.1  tsubai 
    420   1.1  tsubai /*
    421   1.1  tsubai  * Receive data from PM for the PB1XX series
    422   1.1  tsubai  */
    423   1.1  tsubai int
    424   1.1  tsubai pm_receive_pm1(data)
    425   1.1  tsubai 	u_char *data;
    426   1.1  tsubai {
    427   1.1  tsubai #if 0
    428   1.1  tsubai 	int rval = 0xffffcd34;
    429   1.1  tsubai 
    430   1.1  tsubai 	via_reg(VIA2, vDirA) = 0x00;
    431   1.1  tsubai 
    432   1.1  tsubai 	switch (1) {
    433  1.18  itojun 	default:
    434  1.18  itojun 		if (pm_wait_busy(0x40) != 0)
    435  1.18  itojun 			break;			/* timeout */
    436  1.18  itojun 
    437  1.18  itojun 		PM_SET_STATE_ACKOFF();
    438  1.18  itojun 		*data = via_reg(VIA2, 0x200);
    439  1.18  itojun 
    440  1.18  itojun 		rval = 0xffffcd33;
    441  1.18  itojun 		if (pm_wait_free(0x40) == 0)
    442  1.18  itojun 			break;			/* timeout */
    443   1.1  tsubai 
    444  1.18  itojun 		rval = 0x00;
    445  1.18  itojun 		break;
    446   1.1  tsubai 	}
    447   1.1  tsubai 
    448   1.1  tsubai 	PM_SET_STATE_ACKON();
    449   1.1  tsubai 	via_reg(VIA2, vDirA) = 0x00;
    450   1.1  tsubai 
    451   1.1  tsubai 	return rval;
    452   1.1  tsubai #else
    453   1.1  tsubai 	panic("pm_receive_pm1");
    454   1.1  tsubai #endif
    455   1.1  tsubai }
    456   1.1  tsubai 
    457   1.1  tsubai 
    458   1.1  tsubai 
    459   1.1  tsubai /*
    460   1.1  tsubai  * Send data to PM for the PB1XX series
    461   1.1  tsubai  */
    462   1.1  tsubai int
    463   1.1  tsubai pm_send_pm1(data, delay)
    464   1.1  tsubai 	u_char data;
    465   1.1  tsubai 	int delay;
    466   1.1  tsubai {
    467   1.1  tsubai #if 0
    468   1.1  tsubai 	int rval;
    469   1.1  tsubai 
    470   1.1  tsubai 	via_reg(VIA2, vDirA) = 0xff;
    471   1.1  tsubai 	via_reg(VIA2, 0x200) = data;
    472   1.1  tsubai 
    473   1.1  tsubai 	PM_SET_STATE_ACKOFF();
    474   1.1  tsubai 	if (pm_wait_busy(0x400) != 0) {
    475   1.1  tsubai 		PM_SET_STATE_ACKON();
    476   1.1  tsubai 		via_reg(VIA2, vDirA) = 0x00;
    477   1.1  tsubai 
    478   1.1  tsubai 		return 0xffffcd36;
    479   1.1  tsubai 	}
    480   1.1  tsubai 
    481   1.1  tsubai 	rval = 0x0;
    482   1.1  tsubai 	PM_SET_STATE_ACKON();
    483   1.1  tsubai 	if (pm_wait_free(0x40) == 0)
    484   1.1  tsubai 		rval = 0xffffcd35;
    485   1.1  tsubai 
    486   1.1  tsubai 	PM_SET_STATE_ACKON();
    487   1.1  tsubai 	via_reg(VIA2, vDirA) = 0x00;
    488   1.1  tsubai 
    489   1.1  tsubai 	return rval;
    490   1.1  tsubai #else
    491   1.1  tsubai 	panic("pm_send_pm1");
    492   1.1  tsubai #endif
    493   1.1  tsubai }
    494   1.1  tsubai 
    495   1.1  tsubai 
    496   1.1  tsubai /*
    497   1.1  tsubai  * My PMgrOp routine for the PB1XX series
    498   1.1  tsubai  */
    499   1.1  tsubai int
    500   1.1  tsubai pm_pmgrop_pm1(pmdata)
    501   1.1  tsubai 	PMData *pmdata;
    502   1.1  tsubai {
    503   1.1  tsubai #if 0
    504   1.1  tsubai 	int i;
    505   1.1  tsubai 	int s = 0x81815963;
    506   1.1  tsubai 	u_char via1_vIER, via1_vDirA;
    507   1.1  tsubai 	int rval = 0;
    508   1.1  tsubai 	int num_pm_data = 0;
    509   1.1  tsubai 	u_char pm_cmd;
    510   1.1  tsubai 	u_char pm_data;
    511   1.1  tsubai 	u_char *pm_buf;
    512   1.1  tsubai 
    513   1.1  tsubai 	/* disable all inetrrupts but PM */
    514   1.1  tsubai 	via1_vIER = via_reg(VIA1, vIER);
    515   1.1  tsubai 	PM_VIA_INTR_DISABLE();
    516   1.1  tsubai 
    517   1.1  tsubai 	via1_vDirA = via_reg(VIA1, vDirA);
    518   1.1  tsubai 
    519   1.1  tsubai 	switch (pmdata->command) {
    520  1.18  itojun 	default:
    521  1.18  itojun 		for (i = 0; i < 7; i++) {
    522  1.18  itojun 			via_reg(VIA2, vDirA) = 0x00;
    523  1.18  itojun 
    524  1.18  itojun 			/* wait until PM is free */
    525  1.18  itojun 			if (pm_wait_free(ADBDelay) == 0) {	/* timeout */
    526  1.18  itojun 				via_reg(VIA2, vDirA) = 0x00;
    527  1.18  itojun 				/* restore formar value */
    528  1.18  itojun 				via_reg(VIA1, vDirA) = via1_vDirA;
    529  1.18  itojun 				via_reg(VIA1, vIER) = via1_vIER;
    530  1.18  itojun 				return 0xffffcd38;
    531  1.18  itojun 			}
    532   1.1  tsubai 
    533  1.18  itojun 			switch (mac68k_machine.machineid) {
    534  1.18  itojun 				case MACH_MACPB160:
    535  1.18  itojun 				case MACH_MACPB165:
    536  1.18  itojun 				case MACH_MACPB165C:
    537  1.18  itojun 				case MACH_MACPB180:
    538  1.18  itojun 				case MACH_MACPB180C:
    539  1.18  itojun 					{
    540  1.18  itojun 						int delay = ADBDelay * 16;
    541  1.18  itojun 
    542  1.18  itojun 						via_reg(VIA2, vDirA) = 0x00;
    543  1.18  itojun 						while ((via_reg(VIA2, 0x200) == 0x7f) && (delay >= 0))
    544  1.18  itojun 							delay--;
    545   1.1  tsubai 
    546  1.18  itojun 						if (delay < 0) {	/* timeout */
    547   1.1  tsubai 							via_reg(VIA2, vDirA) = 0x00;
    548  1.18  itojun 							/* restore formar value */
    549  1.18  itojun 							via_reg(VIA1, vIER) = via1_vIER;
    550  1.18  itojun 							return 0xffffcd38;
    551   1.1  tsubai 						}
    552  1.18  itojun 					}
    553  1.18  itojun 			} /* end switch */
    554   1.1  tsubai 
    555  1.18  itojun 			s = splhigh();
    556   1.1  tsubai 
    557  1.18  itojun 			via1_vDirA = via_reg(VIA1, vDirA);
    558  1.18  itojun 			via_reg(VIA1, vDirA) &= 0x7f;
    559   1.1  tsubai 
    560  1.18  itojun 			pm_cmd = (u_char)(pmdata->command & 0xff);
    561  1.18  itojun 			if ((rval = pm_send_pm1(pm_cmd, ADBDelay * 8)) == 0)
    562  1.18  itojun 				break;	/* send command succeeded */
    563   1.1  tsubai 
    564  1.18  itojun 			via_reg(VIA1, vDirA) = via1_vDirA;
    565  1.18  itojun 			splx(s);
    566  1.18  itojun 		} /* end for */
    567  1.18  itojun 
    568  1.18  itojun 		/* failed to send a command */
    569  1.18  itojun 		if (i == 7) {
    570  1.18  itojun 			via_reg(VIA2, vDirA) = 0x00;
    571  1.18  itojun 			/* restore formar value */
    572  1.18  itojun 			via_reg(VIA1, vDirA) = via1_vDirA;
    573  1.18  itojun 			via_reg(VIA1, vIER) = via1_vIER;
    574  1.18  itojun 			if (s != 0x81815963)
    575   1.1  tsubai 				splx(s);
    576  1.18  itojun 			return 0xffffcd38;
    577  1.18  itojun 		}
    578   1.1  tsubai 
    579  1.18  itojun 		/* send # of PM data */
    580  1.18  itojun 		num_pm_data = pmdata->num_data;
    581  1.18  itojun 		if ((rval = pm_send_pm1((u_char)(num_pm_data & 0xff), ADBDelay * 8)) != 0)
    582  1.18  itojun 			break;			/* timeout */
    583  1.18  itojun 
    584  1.18  itojun 		/* send PM data */
    585  1.18  itojun 		pm_buf = (u_char *)pmdata->s_buf;
    586  1.18  itojun 		for (i = 0; i < num_pm_data; i++)
    587  1.18  itojun 			if ((rval = pm_send_pm1(pm_buf[i], ADBDelay * 8)) != 0)
    588  1.18  itojun 				break;		/* timeout */
    589  1.18  itojun 		if ((i != num_pm_data) && (num_pm_data != 0))
    590  1.18  itojun 			break;			/* timeout */
    591   1.1  tsubai 
    592  1.18  itojun 		/* Will PM IC return data? */
    593  1.18  itojun 		if ((pm_cmd & 0x08) == 0) {
    594  1.18  itojun 			rval = 0;
    595  1.18  itojun 			break;			/* no returned data */
    596  1.18  itojun 		}
    597   1.1  tsubai 
    598  1.18  itojun 		rval = 0xffffcd37;
    599  1.18  itojun 		if (pm_wait_busy(ADBDelay) != 0)
    600  1.18  itojun 			break;			/* timeout */
    601   1.1  tsubai 
    602  1.18  itojun 		/* receive PM command */
    603  1.18  itojun 		if ((rval = pm_receive_pm1(&pm_data)) != 0)
    604  1.18  itojun 			break;
    605   1.1  tsubai 
    606  1.18  itojun 		pmdata->command = pm_data;
    607   1.1  tsubai 
    608  1.18  itojun 		/* receive number of PM data */
    609  1.18  itojun 		if ((rval = pm_receive_pm1(&pm_data)) != 0)
    610  1.18  itojun 			break;			/* timeout */
    611  1.18  itojun 		num_pm_data = pm_data;
    612  1.18  itojun 		pmdata->num_data = num_pm_data;
    613   1.1  tsubai 
    614  1.18  itojun 		/* receive PM data */
    615  1.18  itojun 		pm_buf = (u_char *)pmdata->r_buf;
    616  1.18  itojun 		for (i = 0; i < num_pm_data; i++) {
    617   1.1  tsubai 			if ((rval = pm_receive_pm1(&pm_data)) != 0)
    618  1.18  itojun 				break;		/* timeout */
    619  1.18  itojun 			pm_buf[i] = pm_data;
    620  1.18  itojun 		}
    621   1.1  tsubai 
    622  1.18  itojun 		rval = 0;
    623   1.1  tsubai 	}
    624   1.1  tsubai 
    625   1.1  tsubai 	via_reg(VIA2, vDirA) = 0x00;
    626   1.1  tsubai 
    627   1.1  tsubai 	/* restore formar value */
    628   1.1  tsubai 	via_reg(VIA1, vDirA) = via1_vDirA;
    629   1.1  tsubai 	via_reg(VIA1, vIER) = via1_vIER;
    630   1.1  tsubai 	if (s != 0x81815963)
    631   1.1  tsubai 		splx(s);
    632   1.1  tsubai 
    633   1.1  tsubai 	return rval;
    634   1.1  tsubai #else
    635   1.1  tsubai 	panic("pm_pmgrop_pm1");
    636   1.1  tsubai #endif
    637   1.1  tsubai }
    638   1.1  tsubai 
    639   1.1  tsubai 
    640   1.1  tsubai /*
    641   1.1  tsubai  * My PM interrupt routine for PB1XX series
    642   1.1  tsubai  */
    643   1.1  tsubai void
    644   1.1  tsubai pm_intr_pm1()
    645   1.1  tsubai {
    646   1.1  tsubai #if 0
    647   1.1  tsubai 	int s;
    648   1.1  tsubai 	int rval;
    649   1.1  tsubai 	PMData pmdata;
    650   1.1  tsubai 
    651   1.1  tsubai 	s = splhigh();
    652   1.1  tsubai 
    653   1.1  tsubai 	PM_VIA_CLR_INTR();				/* clear VIA1 interrupt */
    654   1.1  tsubai 
    655   1.1  tsubai 	/* ask PM what happend */
    656  1.23  briggs 	pmdata.command = PMU_INT_ACK;
    657   1.1  tsubai 	pmdata.num_data = 0;
    658   1.1  tsubai 	pmdata.data[0] = pmdata.data[1] = 0;
    659   1.1  tsubai 	pmdata.s_buf = &pmdata.data[2];
    660   1.1  tsubai 	pmdata.r_buf = &pmdata.data[2];
    661   1.1  tsubai 	rval = pm_pmgrop_pm1(&pmdata);
    662   1.1  tsubai 	if (rval != 0) {
    663   1.1  tsubai #ifdef ADB_DEBUG
    664   1.1  tsubai 		if (adb_debug)
    665   1.1  tsubai 			printf("pm: PM is not ready. error code=%08x\n", rval);
    666   1.1  tsubai #endif
    667   1.1  tsubai 		splx(s);
    668   1.1  tsubai 	}
    669   1.1  tsubai 
    670   1.1  tsubai 	if ((pmdata.data[2] & 0x10) == 0x10) {
    671   1.1  tsubai 		if ((pmdata.data[2] & 0x0f) == 0) {
    672   1.1  tsubai 			/* ADB data that were requested by TALK command */
    673   1.1  tsubai 			pm_adb_get_TALK_result(&pmdata);
    674   1.1  tsubai 		} else if ((pmdata.data[2] & 0x08) == 0x8) {
    675   1.1  tsubai 			/* PM is requesting to poll  */
    676   1.1  tsubai 			pm_adb_poll_next_device_pm1(&pmdata);
    677   1.1  tsubai 		} else if ((pmdata.data[2] & 0x04) == 0x4) {
    678   1.1  tsubai 			/* ADB device event */
    679   1.1  tsubai 			pm_adb_get_ADB_data(&pmdata);
    680   1.1  tsubai 		}
    681   1.1  tsubai 	} else {
    682   1.1  tsubai #ifdef ADB_DEBUG
    683   1.1  tsubai 		if (adb_debug)
    684  1.23  briggs 			pm_printerr("driver does not support this event.",
    685   1.1  tsubai 			    rval, pmdata.num_data, pmdata.data);
    686   1.1  tsubai #endif
    687   1.1  tsubai 	}
    688   1.1  tsubai 
    689   1.1  tsubai 	splx(s);
    690   1.1  tsubai #else
    691   1.1  tsubai 	panic("pm_intr_pm1");
    692   1.1  tsubai #endif
    693   1.1  tsubai }
    694   1.1  tsubai 
    695   1.1  tsubai 
    696   1.1  tsubai 
    697   1.1  tsubai /*
    698   1.1  tsubai  * Functions for the PB Duo series and the PB 5XX series
    699   1.1  tsubai  */
    700   1.1  tsubai 
    701   1.1  tsubai /*
    702   1.1  tsubai  * Receive data from PM for the PB Duo series and the PB 5XX series
    703   1.1  tsubai  */
    704   1.1  tsubai int
    705   1.1  tsubai pm_receive_pm2(data)
    706   1.1  tsubai 	u_char *data;
    707   1.1  tsubai {
    708   1.1  tsubai 	int i;
    709   1.1  tsubai 	int rval;
    710   1.1  tsubai 
    711   1.1  tsubai 	rval = 0xffffcd34;
    712   1.1  tsubai 
    713   1.1  tsubai 	switch (1) {
    714  1.18  itojun 	default:
    715  1.18  itojun 		/* set VIA SR to input mode */
    716  1.18  itojun 		via_reg_or(VIA1, vACR, 0x0c);
    717  1.18  itojun 		via_reg_and(VIA1, vACR, ~0x10);
    718  1.18  itojun 		i = PM_SR();
    719  1.18  itojun 
    720  1.18  itojun 		PM_SET_STATE_ACKOFF();
    721  1.18  itojun 		if (pm_wait_busy((int)ADBDelay*32) != 0)
    722  1.18  itojun 			break;		/* timeout */
    723   1.1  tsubai 
    724  1.18  itojun 		PM_SET_STATE_ACKON();
    725  1.18  itojun 		rval = 0xffffcd33;
    726  1.18  itojun 		if (pm_wait_free((int)ADBDelay*32) == 0)
    727  1.18  itojun 			break;		/* timeout */
    728   1.1  tsubai 
    729  1.18  itojun 		*data = PM_SR();
    730  1.18  itojun 		rval = 0;
    731   1.1  tsubai 
    732  1.18  itojun 		break;
    733   1.1  tsubai 	}
    734   1.1  tsubai 
    735   1.1  tsubai 	PM_SET_STATE_ACKON();
    736   1.1  tsubai 	via_reg_or(VIA1, vACR, 0x1c);
    737   1.1  tsubai 
    738   1.1  tsubai 	return rval;
    739   1.1  tsubai }
    740   1.1  tsubai 
    741   1.1  tsubai 
    742   1.1  tsubai 
    743   1.1  tsubai /*
    744   1.1  tsubai  * Send data to PM for the PB Duo series and the PB 5XX series
    745   1.1  tsubai  */
    746   1.1  tsubai int
    747   1.1  tsubai pm_send_pm2(data)
    748   1.1  tsubai 	u_char data;
    749   1.1  tsubai {
    750   1.1  tsubai 	int rval;
    751   1.1  tsubai 
    752   1.1  tsubai 	via_reg_or(VIA1, vACR, 0x1c);
    753   1.1  tsubai 	write_via_reg(VIA1, vSR, data);	/* PM_SR() = data; */
    754   1.1  tsubai 
    755   1.1  tsubai 	PM_SET_STATE_ACKOFF();
    756   1.1  tsubai 	rval = 0xffffcd36;
    757   1.1  tsubai 	if (pm_wait_busy((int)ADBDelay*32) != 0) {
    758   1.1  tsubai 		PM_SET_STATE_ACKON();
    759   1.1  tsubai 
    760   1.1  tsubai 		via_reg_or(VIA1, vACR, 0x1c);
    761   1.1  tsubai 
    762   1.1  tsubai 		return rval;
    763   1.1  tsubai 	}
    764   1.1  tsubai 
    765   1.1  tsubai 	PM_SET_STATE_ACKON();
    766   1.1  tsubai 	rval = 0xffffcd35;
    767   1.1  tsubai 	if (pm_wait_free((int)ADBDelay*32) != 0)
    768   1.1  tsubai 		rval = 0;
    769   1.1  tsubai 
    770   1.1  tsubai 	PM_SET_STATE_ACKON();
    771   1.1  tsubai 	via_reg_or(VIA1, vACR, 0x1c);
    772   1.1  tsubai 
    773   1.1  tsubai 	return rval;
    774   1.1  tsubai }
    775   1.1  tsubai 
    776   1.1  tsubai 
    777   1.1  tsubai 
    778   1.1  tsubai /*
    779   1.1  tsubai  * My PMgrOp routine for the PB Duo series and the PB 5XX series
    780   1.1  tsubai  */
    781   1.1  tsubai int
    782   1.1  tsubai pm_pmgrop_pm2(pmdata)
    783   1.1  tsubai 	PMData *pmdata;
    784   1.1  tsubai {
    785   1.1  tsubai 	int i;
    786   1.1  tsubai 	int s;
    787   1.1  tsubai 	u_char via1_vIER;
    788   1.1  tsubai 	int rval = 0;
    789   1.1  tsubai 	int num_pm_data = 0;
    790   1.1  tsubai 	u_char pm_cmd;
    791   1.1  tsubai 	short pm_num_rx_data;
    792   1.1  tsubai 	u_char pm_data;
    793   1.1  tsubai 	u_char *pm_buf;
    794   1.1  tsubai 
    795   1.1  tsubai 	s = splhigh();
    796   1.1  tsubai 
    797   1.1  tsubai 	/* disable all inetrrupts but PM */
    798   1.1  tsubai 	via1_vIER = 0x10;
    799   1.1  tsubai 	via1_vIER &= read_via_reg(VIA1, vIER);
    800   1.1  tsubai 	write_via_reg(VIA1, vIER, via1_vIER);
    801   1.1  tsubai 	if (via1_vIER != 0x0)
    802   1.1  tsubai 		via1_vIER |= 0x80;
    803   1.1  tsubai 
    804   1.1  tsubai 	switch (pmdata->command) {
    805  1.18  itojun 	default:
    806  1.18  itojun 		/* wait until PM is free */
    807  1.18  itojun 		pm_cmd = (u_char)(pmdata->command & 0xff);
    808  1.18  itojun 		rval = 0xcd38;
    809  1.18  itojun 		if (pm_wait_free(ADBDelay * 4) == 0)
    810  1.18  itojun 			break;			/* timeout */
    811  1.18  itojun 
    812  1.18  itojun 		if (HwCfgFlags3 & 0x00200000) {
    813  1.18  itojun 			/* PB 160, PB 165(c), PB 180(c)? */
    814  1.18  itojun 			int delay = ADBDelay * 16;
    815  1.18  itojun 
    816  1.18  itojun 			write_via_reg(VIA2, vDirA, 0x00);
    817  1.18  itojun 			while ((read_via_reg(VIA2, 0x200) == 0x07) &&
    818  1.18  itojun 			    (delay >= 0))
    819  1.18  itojun 				delay--;
    820   1.1  tsubai 
    821  1.18  itojun 			if (delay < 0) {
    822  1.18  itojun 				rval = 0xffffcd38;
    823  1.18  itojun 				break;		/* timeout */
    824  1.18  itojun 			}
    825  1.18  itojun 		}
    826   1.1  tsubai 
    827  1.18  itojun 		/* send PM command */
    828  1.18  itojun 		if ((rval = pm_send_pm2((u_char)(pm_cmd & 0xff))))
    829  1.18  itojun 			break;				/* timeout */
    830  1.18  itojun 
    831  1.18  itojun 		/* send number of PM data */
    832  1.18  itojun 		num_pm_data = pmdata->num_data;
    833  1.18  itojun 		if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
    834  1.18  itojun 			if (pm_send_cmd_type[pm_cmd] < 0) {
    835  1.18  itojun 				if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
    836   1.1  tsubai 					break;		/* timeout */
    837  1.18  itojun 				pmdata->command = 0;
    838   1.1  tsubai 			}
    839  1.18  itojun 		} else {				/* PB 1XX series ? */
    840  1.18  itojun 			if ((rval = pm_send_pm2((u_char)(num_pm_data & 0xff))) != 0)
    841  1.18  itojun 				break;			/* timeout */
    842  1.18  itojun 		}
    843  1.18  itojun 		/* send PM data */
    844  1.18  itojun 		pm_buf = (u_char *)pmdata->s_buf;
    845  1.18  itojun 		for (i = 0 ; i < num_pm_data; i++)
    846  1.18  itojun 			if ((rval = pm_send_pm2(pm_buf[i])) != 0)
    847  1.18  itojun 				break;			/* timeout */
    848  1.18  itojun 		if (i != num_pm_data)
    849  1.18  itojun 			break;				/* timeout */
    850   1.1  tsubai 
    851   1.1  tsubai 
    852  1.18  itojun 		/* check if PM will send me data  */
    853  1.18  itojun 		pm_num_rx_data = pm_receive_cmd_type[pm_cmd];
    854  1.18  itojun 		pmdata->num_data = pm_num_rx_data;
    855  1.18  itojun 		if (pm_num_rx_data == 0) {
    856  1.18  itojun 			rval = 0;
    857  1.18  itojun 			break;				/* no return data */
    858  1.18  itojun 		}
    859  1.18  itojun 
    860  1.18  itojun 		/* receive PM command */
    861  1.18  itojun 		pm_data = pmdata->command;
    862  1.18  itojun 		if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
    863  1.18  itojun 			pm_num_rx_data--;
    864  1.18  itojun 			if (pm_num_rx_data == 0)
    865   1.1  tsubai 				if ((rval = pm_receive_pm2(&pm_data)) != 0) {
    866   1.1  tsubai 					rval = 0xffffcd37;
    867   1.1  tsubai 					break;
    868   1.1  tsubai 				}
    869  1.18  itojun 			pmdata->command = pm_data;
    870  1.18  itojun 		} else {				/* PB 1XX series ? */
    871  1.18  itojun 			if ((rval = pm_receive_pm2(&pm_data)) != 0) {
    872  1.18  itojun 				rval = 0xffffcd37;
    873  1.18  itojun 				break;
    874   1.1  tsubai 			}
    875  1.18  itojun 			pmdata->command = pm_data;
    876  1.18  itojun 		}
    877   1.1  tsubai 
    878  1.18  itojun 		/* receive number of PM data */
    879  1.18  itojun 		if (HwCfgFlags3 & 0x00020000) {		/* PB Duo, PB 5XX */
    880  1.18  itojun 			if (pm_num_rx_data < 0) {
    881   1.1  tsubai 				if ((rval = pm_receive_pm2(&pm_data)) != 0)
    882  1.18  itojun 					break;		/* timeout */
    883   1.1  tsubai 				num_pm_data = pm_data;
    884  1.18  itojun 			} else
    885  1.18  itojun 				num_pm_data = pm_num_rx_data;
    886  1.18  itojun 			pmdata->num_data = num_pm_data;
    887  1.18  itojun 		} else {				/* PB 1XX serias ? */
    888  1.18  itojun 			if ((rval = pm_receive_pm2(&pm_data)) != 0)
    889  1.18  itojun 				break;			/* timeout */
    890  1.18  itojun 			num_pm_data = pm_data;
    891  1.18  itojun 			pmdata->num_data = num_pm_data;
    892  1.18  itojun 		}
    893   1.1  tsubai 
    894  1.18  itojun 		/* receive PM data */
    895  1.18  itojun 		pm_buf = (u_char *)pmdata->r_buf;
    896  1.18  itojun 		for (i = 0; i < num_pm_data; i++) {
    897  1.18  itojun 			if ((rval = pm_receive_pm2(&pm_data)) != 0)
    898  1.18  itojun 				break;			/* timeout */
    899  1.18  itojun 			pm_buf[i] = pm_data;
    900  1.18  itojun 		}
    901   1.1  tsubai 
    902  1.18  itojun 		rval = 0;
    903   1.1  tsubai 	}
    904   1.1  tsubai 
    905   1.1  tsubai 	/* restore former value */
    906   1.1  tsubai 	write_via_reg(VIA1, vIER, via1_vIER);
    907   1.1  tsubai 	splx(s);
    908   1.1  tsubai 
    909   1.1  tsubai 	return rval;
    910   1.1  tsubai }
    911   1.1  tsubai 
    912   1.1  tsubai 
    913   1.1  tsubai /*
    914   1.1  tsubai  * My PM interrupt routine for the PB Duo series and the PB 5XX series
    915   1.1  tsubai  */
    916   1.1  tsubai void
    917   1.1  tsubai pm_intr_pm2()
    918   1.1  tsubai {
    919   1.1  tsubai 	int s;
    920   1.1  tsubai 	int rval;
    921   1.1  tsubai 	PMData pmdata;
    922   1.1  tsubai 
    923   1.1  tsubai 	s = splhigh();
    924   1.1  tsubai 
    925   1.1  tsubai 	PM_VIA_CLR_INTR();			/* clear VIA1 interrupt */
    926   1.1  tsubai 						/* ask PM what happend */
    927  1.23  briggs 	pmdata.command = PMU_INT_ACK;
    928   1.1  tsubai 	pmdata.num_data = 0;
    929   1.1  tsubai 	pmdata.s_buf = &pmdata.data[2];
    930   1.1  tsubai 	pmdata.r_buf = &pmdata.data[2];
    931   1.1  tsubai 	rval = pm_pmgrop_pm2(&pmdata);
    932   1.1  tsubai 	if (rval != 0) {
    933   1.1  tsubai #ifdef ADB_DEBUG
    934   1.1  tsubai 		if (adb_debug)
    935   1.1  tsubai 			printf("pm: PM is not ready. error code: %08x\n", rval);
    936   1.1  tsubai #endif
    937   1.1  tsubai 		splx(s);
    938  1.21  briggs 		return;
    939   1.1  tsubai 	}
    940   1.1  tsubai 
    941   1.1  tsubai 	switch ((u_int)(pmdata.data[2] & 0xff)) {
    942  1.21  briggs 	case 0x00:		/* no event pending? */
    943  1.18  itojun 		break;
    944  1.18  itojun 	case 0x80:		/* 1 sec interrupt? */
    945  1.18  itojun 		pm_counter++;
    946  1.18  itojun 		break;
    947  1.18  itojun 	case 0x08:		/* Brightness/Contrast button on LCD panel */
    948  1.18  itojun 		/* get brightness and contrast of the LCD */
    949  1.18  itojun 		pm_LCD_brightness = (u_int)pmdata.data[3] & 0xff;
    950  1.18  itojun 		pm_LCD_contrast = (u_int)pmdata.data[4] & 0xff;
    951  1.18  itojun /*
    952  1.18  itojun 		pm_printerr("#08", rval, pmdata.num_data, pmdata.data);
    953  1.18  itojun 		pmdata.command = 0x33;
    954  1.18  itojun 		pmdata.num_data = 1;
    955  1.18  itojun 		pmdata.s_buf = pmdata.data;
    956  1.18  itojun 		pmdata.r_buf = pmdata.data;
    957  1.18  itojun 		pmdata.data[0] = pm_LCD_contrast;
    958  1.18  itojun 		rval = pm_pmgrop_pm2(&pmdata);
    959  1.18  itojun 		pm_printerr("#33", rval, pmdata.num_data, pmdata.data);
    960   1.1  tsubai */
    961  1.18  itojun 		/* this is an experimental code */
    962  1.23  briggs 		pmdata.command = PMU_SET_BRIGHTNESS;
    963  1.18  itojun 		pmdata.num_data = 1;
    964  1.18  itojun 		pmdata.s_buf = pmdata.data;
    965  1.18  itojun 		pmdata.r_buf = pmdata.data;
    966  1.18  itojun 		pm_LCD_brightness = 0x7f - pm_LCD_brightness / 2;
    967  1.18  itojun 		if (pm_LCD_brightness < 0x08)
    968  1.18  itojun 			pm_LCD_brightness = 0x08;
    969  1.18  itojun 		if (pm_LCD_brightness > 0x78)
    970  1.18  itojun 			pm_LCD_brightness = 0x78;
    971  1.18  itojun 		pmdata.data[0] = pm_LCD_brightness;
    972  1.18  itojun 		rval = pm_pmgrop_pm2(&pmdata);
    973  1.18  itojun 		break;
    974  1.23  briggs 	case 0x10:		/* ADB data requested by TALK command */
    975  1.18  itojun 	case 0x14:
    976  1.18  itojun 		pm_adb_get_TALK_result(&pmdata);
    977  1.18  itojun 		break;
    978  1.18  itojun 	case 0x16:		/* ADB device event */
    979  1.18  itojun 	case 0x18:
    980  1.18  itojun 	case 0x1e:
    981  1.18  itojun 		pm_adb_get_ADB_data(&pmdata);
    982  1.18  itojun 		break;
    983  1.18  itojun 	default:
    984   1.1  tsubai #ifdef ADB_DEBUG
    985  1.18  itojun 		if (adb_debug)
    986  1.23  briggs 			pm_printerr("driver does not support this event.",
    987  1.18  itojun 			    pmdata.data[2], pmdata.num_data,
    988  1.18  itojun 			    pmdata.data);
    989   1.1  tsubai #endif
    990  1.18  itojun 		break;
    991   1.1  tsubai 	}
    992   1.1  tsubai 
    993   1.1  tsubai 	splx(s);
    994   1.1  tsubai }
    995   1.1  tsubai 
    996   1.1  tsubai 
    997   1.1  tsubai /*
    998   1.1  tsubai  * My PMgrOp routine
    999   1.1  tsubai  */
   1000   1.1  tsubai int
   1001   1.1  tsubai pmgrop(pmdata)
   1002   1.1  tsubai 	PMData *pmdata;
   1003   1.1  tsubai {
   1004   1.1  tsubai 	switch (pmHardware) {
   1005  1.18  itojun 	case PM_HW_PB1XX:
   1006  1.18  itojun 		return (pm_pmgrop_pm1(pmdata));
   1007  1.18  itojun 		break;
   1008  1.18  itojun 	case PM_HW_PB5XX:
   1009  1.18  itojun 		return (pm_pmgrop_pm2(pmdata));
   1010  1.18  itojun 		break;
   1011  1.18  itojun 	default:
   1012  1.18  itojun 		/* return (pmgrop_mrg(pmdata)); */
   1013  1.18  itojun 		return 1;
   1014   1.1  tsubai 	}
   1015   1.1  tsubai }
   1016   1.1  tsubai 
   1017   1.1  tsubai 
   1018   1.1  tsubai /*
   1019   1.1  tsubai  * My PM interrupt routine
   1020   1.1  tsubai  */
   1021   1.1  tsubai void
   1022   1.1  tsubai pm_intr()
   1023   1.1  tsubai {
   1024   1.1  tsubai 	switch (pmHardware) {
   1025  1.18  itojun 	case PM_HW_PB1XX:
   1026  1.18  itojun 		pm_intr_pm1();
   1027  1.18  itojun 		break;
   1028  1.18  itojun 	case PM_HW_PB5XX:
   1029  1.18  itojun 		pm_intr_pm2();
   1030  1.18  itojun 		break;
   1031  1.18  itojun 	default:
   1032  1.18  itojun 		break;
   1033   1.1  tsubai 	}
   1034   1.1  tsubai }
   1035   1.1  tsubai 
   1036   1.1  tsubai 
   1037   1.1  tsubai 
   1038   1.1  tsubai /*
   1039   1.1  tsubai  * Synchronous ADBOp routine for the Power Manager
   1040   1.1  tsubai  */
   1041   1.1  tsubai int
   1042   1.1  tsubai pm_adb_op(buffer, compRout, data, command)
   1043   1.1  tsubai 	u_char *buffer;
   1044   1.1  tsubai 	void *compRout;
   1045   1.1  tsubai 	void *data;
   1046   1.1  tsubai 	int command;
   1047   1.1  tsubai {
   1048   1.1  tsubai 	int i;
   1049   1.1  tsubai 	int s;
   1050   1.1  tsubai 	int rval;
   1051  1.12  tsubai 	int timo;
   1052   1.1  tsubai 	PMData pmdata;
   1053   1.1  tsubai 	struct adbCommand packet;
   1054   1.1  tsubai 
   1055   1.1  tsubai 	if (adbWaiting == 1)
   1056   1.1  tsubai 		return 1;
   1057   1.1  tsubai 
   1058   1.1  tsubai 	s = splhigh();
   1059   1.1  tsubai 	write_via_reg(VIA1, vIER, 0x10);
   1060   1.1  tsubai 
   1061   1.1  tsubai  	adbBuffer = buffer;
   1062   1.1  tsubai 	adbCompRout = compRout;
   1063   1.1  tsubai 	adbCompData = data;
   1064   1.1  tsubai 
   1065  1.23  briggs 	pmdata.command = PMU_ADB_CMD;
   1066   1.1  tsubai 	pmdata.s_buf = pmdata.data;
   1067   1.1  tsubai 	pmdata.r_buf = pmdata.data;
   1068   1.1  tsubai 
   1069   1.1  tsubai 	/* if the command is LISTEN, add number of ADB data to number of PM data */
   1070   1.1  tsubai 	if ((command & 0xc) == 0x8) {
   1071   1.1  tsubai 		if (buffer != (u_char *)0)
   1072   1.1  tsubai 			pmdata.num_data = buffer[0] + 3;
   1073   1.1  tsubai 	} else {
   1074   1.1  tsubai 		pmdata.num_data = 3;
   1075   1.1  tsubai 	}
   1076   1.1  tsubai 
   1077   1.1  tsubai 	pmdata.data[0] = (u_char)(command & 0xff);
   1078   1.1  tsubai 	pmdata.data[1] = 0;
   1079   1.1  tsubai 	if ((command & 0xc) == 0x8) {		/* if the command is LISTEN, copy ADB data to PM buffer */
   1080   1.1  tsubai 		if ((buffer != (u_char *)0) && (buffer[0] <= 24)) {
   1081   1.1  tsubai 			pmdata.data[2] = buffer[0];		/* number of data */
   1082   1.1  tsubai 			for (i = 0; i < buffer[0]; i++)
   1083   1.1  tsubai 				pmdata.data[3 + i] = buffer[1 + i];
   1084   1.1  tsubai 		} else
   1085   1.1  tsubai 			pmdata.data[2] = 0;
   1086   1.1  tsubai 	} else
   1087   1.1  tsubai 		pmdata.data[2] = 0;
   1088   1.1  tsubai 
   1089   1.1  tsubai 	if ((command & 0xc) != 0xc) {		/* if the command is not TALK */
   1090   1.1  tsubai 		/* set up stuff for adb_pass_up */
   1091   1.1  tsubai 		packet.data[0] = 1 + pmdata.data[2];
   1092   1.1  tsubai 		packet.data[1] = command;
   1093   1.1  tsubai 		for (i = 0; i < pmdata.data[2]; i++)
   1094   1.1  tsubai 			packet.data[i+2] = pmdata.data[i+3];
   1095   1.1  tsubai 		packet.saveBuf = adbBuffer;
   1096   1.1  tsubai 		packet.compRout = adbCompRout;
   1097   1.1  tsubai 		packet.compData = adbCompData;
   1098   1.1  tsubai 		packet.cmd = command;
   1099   1.1  tsubai 		packet.unsol = 0;
   1100   1.1  tsubai 		packet.ack_only = 1;
   1101   1.1  tsubai 		adb_polling = 1;
   1102   1.1  tsubai 		adb_pass_up(&packet);
   1103   1.1  tsubai 		adb_polling = 0;
   1104   1.1  tsubai 	}
   1105   1.1  tsubai 
   1106   1.1  tsubai 	rval = pmgrop(&pmdata);
   1107   1.9  tsubai 	if (rval != 0) {
   1108   1.9  tsubai 		splx(s);
   1109   1.1  tsubai 		return 1;
   1110   1.9  tsubai 	}
   1111   1.1  tsubai 
   1112  1.12  tsubai 	delay(10000);
   1113  1.12  tsubai 
   1114   1.1  tsubai 	adbWaiting = 1;
   1115   1.1  tsubai 	adbWaitingCmd = command;
   1116   1.1  tsubai 
   1117   1.1  tsubai 	PM_VIA_INTR_ENABLE();
   1118   1.1  tsubai 
   1119  1.16     wiz 	/* wait until the PM interrupt has occurred */
   1120  1.12  tsubai 	timo = 0x80000;
   1121   1.1  tsubai 	while (adbWaiting == 1) {
   1122   1.1  tsubai 		if (read_via_reg(VIA1, vIFR) & 0x14)
   1123   1.1  tsubai 			pm_intr();
   1124   1.1  tsubai #ifdef PM_GRAB_SI
   1125   1.1  tsubai #if 0
   1126   1.1  tsubai 			zshard(0);		/* grab any serial interrupts */
   1127   1.1  tsubai #else
   1128   1.1  tsubai 			(void)intr_dispatch(0x70);
   1129   1.1  tsubai #endif
   1130   1.1  tsubai #endif
   1131  1.12  tsubai 		if ((--timo) < 0) {
   1132  1.17     dbj 			/* Try to take an interrupt anyway, just in case.
   1133  1.17     dbj 			 * This has been observed to happen on my ibook
   1134  1.17     dbj 			 * when i press a key after boot and before adb
   1135  1.17     dbj 			 * is attached;  For example, when booting with -d.
   1136  1.17     dbj 			 */
   1137  1.17     dbj 			pm_intr();
   1138  1.17     dbj 			if (adbWaiting) {
   1139  1.17     dbj 				printf("pm_adb_op: timeout. command = 0x%x\n",command);
   1140  1.17     dbj 				splx(s);
   1141  1.17     dbj 				return 1;
   1142  1.17     dbj 			}
   1143  1.17     dbj #ifdef ADB_DEBUG
   1144  1.17     dbj 			else {
   1145  1.17     dbj 				printf("pm_adb_op: missed interrupt. cmd=0x%x\n",command);
   1146  1.17     dbj 			}
   1147  1.17     dbj #endif
   1148   1.9  tsubai 		}
   1149   1.1  tsubai 	}
   1150   1.1  tsubai 
   1151   1.1  tsubai 	/* this command enables the interrupt by operating ADB devices */
   1152   1.1  tsubai 	if (HwCfgFlags3 & 0x00020000) {		/* PB Duo series, PB 5XX series */
   1153  1.23  briggs 		pmdata.command = PMU_ADB_CMD;
   1154   1.1  tsubai 		pmdata.num_data = 4;
   1155   1.1  tsubai 		pmdata.s_buf = pmdata.data;
   1156   1.1  tsubai 		pmdata.r_buf = pmdata.data;
   1157   1.1  tsubai 		pmdata.data[0] = 0x00;
   1158   1.1  tsubai 		pmdata.data[1] = 0x86;	/* magic spell for awaking the PM */
   1159   1.1  tsubai 		pmdata.data[2] = 0x00;
   1160   1.1  tsubai 		pmdata.data[3] = 0x0c;	/* each bit may express the existent ADB device */
   1161   1.1  tsubai 	} else {				/* PB 1XX series */
   1162  1.23  briggs 		pmdata.command = PMU_ADB_CMD;
   1163   1.1  tsubai 		pmdata.num_data = 3;
   1164   1.1  tsubai 		pmdata.s_buf = pmdata.data;
   1165   1.1  tsubai 		pmdata.r_buf = pmdata.data;
   1166   1.1  tsubai 		pmdata.data[0] = (u_char)(command & 0xf0) | 0xc;
   1167   1.1  tsubai 		pmdata.data[1] = 0x04;
   1168   1.1  tsubai 		pmdata.data[2] = 0x00;
   1169   1.1  tsubai 	}
   1170   1.1  tsubai 	rval = pmgrop(&pmdata);
   1171   1.1  tsubai 
   1172   1.1  tsubai 	splx(s);
   1173   1.1  tsubai 	return rval;
   1174   1.1  tsubai }
   1175   1.1  tsubai 
   1176   1.1  tsubai 
   1177   1.1  tsubai void
   1178   1.1  tsubai pm_adb_get_TALK_result(pmdata)
   1179   1.1  tsubai 	PMData *pmdata;
   1180   1.1  tsubai {
   1181   1.1  tsubai 	int i;
   1182   1.1  tsubai 	struct adbCommand packet;
   1183   1.1  tsubai 
   1184   1.1  tsubai 	/* set up data for adb_pass_up */
   1185   1.1  tsubai 	packet.data[0] = pmdata->num_data-1;
   1186   1.1  tsubai 	packet.data[1] = pmdata->data[3];
   1187   1.1  tsubai 	for (i = 0; i <packet.data[0]-1; i++)
   1188   1.1  tsubai 		packet.data[i+2] = pmdata->data[i+4];
   1189   1.1  tsubai 
   1190   1.1  tsubai 	packet.saveBuf = adbBuffer;
   1191   1.1  tsubai 	packet.compRout = adbCompRout;
   1192   1.1  tsubai 	packet.compData = adbCompData;
   1193   1.1  tsubai 	packet.unsol = 0;
   1194   1.1  tsubai 	packet.ack_only = 0;
   1195   1.1  tsubai 	adb_polling = 1;
   1196   1.1  tsubai 	adb_pass_up(&packet);
   1197   1.1  tsubai 	adb_polling = 0;
   1198   1.1  tsubai 
   1199   1.1  tsubai 	adbWaiting = 0;
   1200   1.1  tsubai 	adbBuffer = (long)0;
   1201   1.1  tsubai 	adbCompRout = (long)0;
   1202   1.1  tsubai 	adbCompData = (long)0;
   1203   1.1  tsubai }
   1204   1.1  tsubai 
   1205   1.1  tsubai 
   1206   1.1  tsubai void
   1207   1.1  tsubai pm_adb_get_ADB_data(pmdata)
   1208   1.1  tsubai 	PMData *pmdata;
   1209   1.1  tsubai {
   1210   1.1  tsubai 	int i;
   1211   1.1  tsubai 	struct adbCommand packet;
   1212   1.1  tsubai 
   1213  1.23  briggs 	if (pmu_type == PMU_OHARE && pmdata->num_data == 4 &&
   1214  1.23  briggs 	    pmdata->data[1] == 0x2c && pmdata->data[3] == 0xff &&
   1215  1.23  briggs 	    ((pmdata->data[2] & ~1) == 0xf4)) {
   1216  1.23  briggs 		if (pmdata->data[2] == 0xf4) {
   1217  1.23  briggs 			pm_eject_pcmcia(0);
   1218  1.23  briggs 		} else {
   1219  1.23  briggs 			pm_eject_pcmcia(1);
   1220  1.23  briggs 		}
   1221  1.23  briggs 		return;
   1222  1.23  briggs 	}
   1223   1.1  tsubai 	/* set up data for adb_pass_up */
   1224   1.1  tsubai 	packet.data[0] = pmdata->num_data-1;	/* number of raw data */
   1225   1.1  tsubai 	packet.data[1] = pmdata->data[3];	/* ADB command */
   1226   1.1  tsubai 	for (i = 0; i <packet.data[0]-1; i++)
   1227   1.1  tsubai 		packet.data[i+2] = pmdata->data[i+4];
   1228   1.1  tsubai 	packet.unsol = 1;
   1229   1.1  tsubai 	packet.ack_only = 0;
   1230   1.1  tsubai 	adb_pass_up(&packet);
   1231   1.1  tsubai }
   1232   1.1  tsubai 
   1233   1.1  tsubai 
   1234   1.1  tsubai void
   1235   1.1  tsubai pm_adb_poll_next_device_pm1(pmdata)
   1236   1.1  tsubai 	PMData *pmdata;
   1237   1.1  tsubai {
   1238   1.1  tsubai 	int i;
   1239   1.1  tsubai 	int ndid;
   1240   1.1  tsubai 	u_short bendid = 0x1;
   1241   1.1  tsubai 	int rval;
   1242   1.1  tsubai 	PMData tmp_pmdata;
   1243   1.1  tsubai 
   1244   1.1  tsubai 	/* find another existent ADB device to poll */
   1245   1.1  tsubai 	for (i = 1; i < 16; i++) {
   1246   1.9  tsubai 		ndid = (ADB_CMDADDR(pmdata->data[3]) + i) & 0xf;
   1247   1.1  tsubai 		bendid <<= ndid;
   1248   1.1  tsubai 		if ((pm_existent_ADB_devices & bendid) != 0)
   1249   1.1  tsubai 			break;
   1250   1.1  tsubai 	}
   1251   1.1  tsubai 
   1252   1.1  tsubai 	/* poll the other device */
   1253  1.23  briggs 	tmp_pmdata.command = PMU_ADB_CMD;
   1254   1.1  tsubai 	tmp_pmdata.num_data = 3;
   1255   1.1  tsubai 	tmp_pmdata.s_buf = tmp_pmdata.data;
   1256   1.1  tsubai 	tmp_pmdata.r_buf = tmp_pmdata.data;
   1257   1.1  tsubai 	tmp_pmdata.data[0] = (u_char)(ndid << 4) | 0xc;
   1258   1.1  tsubai 	tmp_pmdata.data[1] = 0x04;	/* magic spell for awaking the PM */
   1259   1.1  tsubai 	tmp_pmdata.data[2] = 0x00;
   1260   1.1  tsubai 	rval = pmgrop(&tmp_pmdata);
   1261   1.1  tsubai }
   1262   1.1  tsubai 
   1263   1.1  tsubai void
   1264   1.1  tsubai pm_adb_restart()
   1265   1.1  tsubai {
   1266   1.1  tsubai 	PMData p;
   1267   1.1  tsubai 
   1268   1.4  tsubai 	p.command = PMU_RESET_CPU;
   1269   1.1  tsubai 	p.num_data = 0;
   1270   1.1  tsubai 	p.s_buf = p.data;
   1271   1.1  tsubai 	p.r_buf = p.data;
   1272   1.6  tsubai 	pmgrop(&p);
   1273   1.6  tsubai }
   1274   1.6  tsubai 
   1275   1.6  tsubai void
   1276   1.6  tsubai pm_adb_poweroff()
   1277   1.6  tsubai {
   1278   1.6  tsubai 	PMData p;
   1279   1.6  tsubai 
   1280   1.6  tsubai 	p.command = PMU_POWER_OFF;
   1281   1.6  tsubai 	p.num_data = 4;
   1282   1.6  tsubai 	p.s_buf = p.data;
   1283   1.6  tsubai 	p.r_buf = p.data;
   1284   1.6  tsubai 	strcpy(p.data, "MATT");
   1285   1.1  tsubai 	pmgrop(&p);
   1286   1.2  tsubai }
   1287   1.2  tsubai 
   1288   1.2  tsubai void
   1289   1.2  tsubai pm_read_date_time(time)
   1290   1.2  tsubai 	u_long *time;
   1291   1.2  tsubai {
   1292   1.2  tsubai 	PMData p;
   1293   1.2  tsubai 
   1294   1.4  tsubai 	p.command = PMU_READ_RTC;
   1295   1.2  tsubai 	p.num_data = 0;
   1296   1.2  tsubai 	p.s_buf = p.data;
   1297   1.2  tsubai 	p.r_buf = p.data;
   1298   1.2  tsubai 	pmgrop(&p);
   1299   1.2  tsubai 
   1300  1.13     wiz 	memcpy(time, p.data, 4);
   1301   1.4  tsubai }
   1302   1.4  tsubai 
   1303   1.4  tsubai void
   1304   1.4  tsubai pm_set_date_time(time)
   1305   1.4  tsubai 	u_long time;
   1306   1.4  tsubai {
   1307   1.4  tsubai 	PMData p;
   1308   1.4  tsubai 
   1309   1.4  tsubai 	p.command = PMU_SET_RTC;
   1310   1.4  tsubai 	p.num_data = 4;
   1311   1.4  tsubai 	p.s_buf = p.r_buf = p.data;
   1312  1.13     wiz 	memcpy(p.data, &time, 4);
   1313   1.7  tsubai 	pmgrop(&p);
   1314   1.7  tsubai }
   1315   1.7  tsubai 
   1316   1.7  tsubai int
   1317   1.7  tsubai pm_read_brightness()
   1318   1.7  tsubai {
   1319   1.7  tsubai 	PMData p;
   1320   1.7  tsubai 
   1321   1.7  tsubai 	p.command = PMU_READ_BRIGHTNESS;
   1322   1.7  tsubai 	p.num_data = 1;		/* XXX why 1? */
   1323   1.7  tsubai 	p.s_buf = p.r_buf = p.data;
   1324   1.7  tsubai 	p.data[0] = 0;
   1325   1.7  tsubai 	pmgrop(&p);
   1326   1.7  tsubai 
   1327   1.7  tsubai 	return p.data[0];
   1328   1.7  tsubai }
   1329   1.7  tsubai 
   1330   1.7  tsubai void
   1331   1.7  tsubai pm_set_brightness(val)
   1332   1.7  tsubai 	int val;
   1333   1.7  tsubai {
   1334   1.7  tsubai 	PMData p;
   1335   1.7  tsubai 
   1336   1.7  tsubai 	val = 0x7f - val / 2;
   1337   1.7  tsubai 	if (val < 0x08)
   1338   1.7  tsubai 		val = 0x08;
   1339   1.7  tsubai 	if (val > 0x78)
   1340   1.7  tsubai 		val = 0x78;
   1341   1.7  tsubai 
   1342   1.7  tsubai 	p.command = PMU_SET_BRIGHTNESS;
   1343   1.7  tsubai 	p.num_data = 1;
   1344   1.7  tsubai 	p.s_buf = p.r_buf = p.data;
   1345   1.7  tsubai 	p.data[0] = val;
   1346   1.7  tsubai 	pmgrop(&p);
   1347   1.7  tsubai }
   1348   1.7  tsubai 
   1349   1.7  tsubai void
   1350   1.7  tsubai pm_init_brightness()
   1351   1.7  tsubai {
   1352   1.7  tsubai 	int val;
   1353   1.7  tsubai 
   1354   1.7  tsubai 	val = pm_read_brightness();
   1355   1.7  tsubai 	pm_set_brightness(val);
   1356   1.7  tsubai }
   1357   1.7  tsubai 
   1358   1.7  tsubai void
   1359   1.7  tsubai pm_eject_pcmcia(slot)
   1360   1.7  tsubai 	int slot;
   1361   1.7  tsubai {
   1362   1.7  tsubai 	PMData p;
   1363   1.7  tsubai 
   1364   1.7  tsubai 	if (slot != 0 && slot != 1)
   1365   1.7  tsubai 		return;
   1366   1.7  tsubai 
   1367   1.7  tsubai 	p.command = PMU_EJECT_PCMCIA;
   1368   1.7  tsubai 	p.num_data = 1;
   1369   1.7  tsubai 	p.s_buf = p.r_buf = p.data;
   1370   1.8  tsubai 	p.data[0] = 5 + slot;	/* XXX */
   1371   1.5  tsubai 	pmgrop(&p);
   1372  1.19  itojun }
   1373  1.19  itojun 
   1374  1.19  itojun /*
   1375  1.19  itojun  * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation
   1376  1.19  itojun  * for a clear description of the PMU results.
   1377  1.19  itojun  */
   1378  1.23  briggs static int
   1379  1.23  briggs pm_battery_info_smart(int battery, struct pmu_battery_info *info)
   1380  1.19  itojun {
   1381  1.19  itojun 	PMData p;
   1382  1.19  itojun 
   1383  1.19  itojun 	p.command = PMU_SMART_BATTERY_STATE;
   1384  1.19  itojun 	p.num_data = 1;
   1385  1.19  itojun 	p.s_buf = p.r_buf = p.data;
   1386  1.19  itojun 	p.data[0] = battery + 1;
   1387  1.19  itojun 	pmgrop(&p);
   1388  1.19  itojun 
   1389  1.19  itojun 	info->flags = p.data[1];
   1390  1.19  itojun 
   1391  1.22  briggs 	info->secs_remaining = 0;
   1392  1.19  itojun 	switch (p.data[0]) {
   1393  1.19  itojun 	case 3:
   1394  1.19  itojun 	case 4:
   1395  1.19  itojun 		info->cur_charge = p.data[2];
   1396  1.19  itojun 		info->max_charge = p.data[3];
   1397  1.19  itojun 		info->draw = *((signed char *)&p.data[4]);
   1398  1.19  itojun 		info->voltage = p.data[5];
   1399  1.19  itojun 		break;
   1400  1.19  itojun 	case 5:
   1401  1.19  itojun 		info->cur_charge = ((p.data[2] << 8) | (p.data[3]));
   1402  1.19  itojun 		info->max_charge = ((p.data[4] << 8) | (p.data[5]));
   1403  1.19  itojun 		info->draw = *((signed short *)&p.data[6]);
   1404  1.19  itojun 		info->voltage = ((p.data[8] << 8) | (p.data[7]));
   1405  1.19  itojun 		break;
   1406  1.19  itojun 	default:
   1407  1.19  itojun 		/* XXX - Error condition */
   1408  1.19  itojun 		info->cur_charge = 0;
   1409  1.19  itojun 		info->max_charge = 0;
   1410  1.19  itojun 		info->draw = 0;
   1411  1.19  itojun 		info->voltage = 0;
   1412  1.19  itojun 		break;
   1413  1.19  itojun 	}
   1414  1.22  briggs 	if (info->draw) {
   1415  1.22  briggs 		if (info->flags & PMU_PWR_AC_PRESENT && info->draw > 0) {
   1416  1.22  briggs 			info->secs_remaining =
   1417  1.22  briggs 				((info->max_charge - info->cur_charge) * 3600)
   1418  1.22  briggs 				/ info->draw;
   1419  1.22  briggs 		} else {
   1420  1.22  briggs 			info->secs_remaining =
   1421  1.22  briggs 				(info->cur_charge * 3600) / -info->draw;
   1422  1.22  briggs 		}
   1423  1.22  briggs 	}
   1424  1.19  itojun 
   1425  1.19  itojun 	return 1;
   1426   1.5  tsubai }
   1427   1.5  tsubai 
   1428  1.23  briggs static int
   1429  1.23  briggs pm_battery_info_legacy(int battery, struct pmu_battery_info *info, int ty)
   1430  1.23  briggs {
   1431  1.23  briggs 	PMData p;
   1432  1.23  briggs 	long pcharge=0, charge, vb, vmax, lmax;
   1433  1.23  briggs 	long vmax_charging, vmax_charged, amperage, voltage;
   1434  1.23  briggs 
   1435  1.23  briggs 	p.command = PMU_BATTERY_STATE;
   1436  1.23  briggs 	p.num_data = 0;
   1437  1.23  briggs 	p.s_buf = p.r_buf = p.data;
   1438  1.23  briggs 	pmgrop(&p);
   1439  1.23  briggs 
   1440  1.23  briggs 	info->flags = p.data[0];
   1441  1.23  briggs 
   1442  1.23  briggs 	if (info->flags & PMU_PWR_BATT_PRESENT) {
   1443  1.23  briggs 		if (ty == BATT_COMET) {
   1444  1.23  briggs 			vmax_charging = 213;
   1445  1.23  briggs 			vmax_charged = 189;
   1446  1.23  briggs 			lmax = 6500;
   1447  1.23  briggs 		} else {
   1448  1.23  briggs 			/* Experimental values */
   1449  1.23  briggs 			vmax_charging = 365;
   1450  1.23  briggs 			vmax_charged = 365;
   1451  1.23  briggs 			lmax = 6500;
   1452  1.23  briggs 		}
   1453  1.23  briggs 		vmax = vmax_charged;
   1454  1.23  briggs 		vb = (p.data[1] << 8) | p.data[2];
   1455  1.23  briggs 		voltage = (vb * 256 + 72665) / 10;
   1456  1.23  briggs 		amperage = (unsigned char) p.data[5];
   1457  1.23  briggs 		if ((info->flags & PMU_PWR_AC_PRESENT) == 0) {
   1458  1.23  briggs 			if (amperage > 200)
   1459  1.23  briggs 				vb += ((amperage - 200) * 15)/100;
   1460  1.23  briggs 		} else if (info->flags & PMU_PWR_BATT_CHARGING) {
   1461  1.23  briggs 			vb = (vb * 97) / 100;
   1462  1.23  briggs 			vmax = vmax_charging;
   1463  1.23  briggs 		}
   1464  1.23  briggs 		charge = (100 * vb) / vmax;
   1465  1.23  briggs 		if (info->flags & PMU_PWR_PCHARGE_RESET) {
   1466  1.23  briggs 			pcharge = (p.data[6] << 8) | p.data[7];
   1467  1.23  briggs 			if (pcharge > lmax)
   1468  1.23  briggs 				pcharge = lmax;
   1469  1.23  briggs 			pcharge *= 100;
   1470  1.23  briggs 			pcharge = 100 - pcharge / lmax;
   1471  1.23  briggs 			if (pcharge < charge)
   1472  1.23  briggs 				charge = pcharge;
   1473  1.23  briggs 		}
   1474  1.23  briggs 		info->cur_charge = charge;
   1475  1.23  briggs 		info->max_charge = 100;
   1476  1.23  briggs 		info->draw = -amperage;
   1477  1.23  briggs 		info->voltage = voltage;
   1478  1.23  briggs 		if (amperage > 0)
   1479  1.23  briggs 			info->secs_remaining = (charge * 16440) / amperage;
   1480  1.23  briggs 		else
   1481  1.23  briggs 			info->secs_remaining = 0;
   1482  1.23  briggs 	} else {
   1483  1.23  briggs 		info->cur_charge = 0;
   1484  1.23  briggs 		info->max_charge = 0;
   1485  1.23  briggs 		info->draw = 0;
   1486  1.23  briggs 		info->voltage = 0;
   1487  1.23  briggs 		info->secs_remaining = 0;
   1488  1.23  briggs 	}
   1489  1.23  briggs 
   1490  1.23  briggs 	return 1;
   1491  1.23  briggs }
   1492  1.23  briggs 
   1493  1.23  briggs int
   1494  1.23  briggs pm_battery_info(int battery, struct pmu_battery_info *info)
   1495  1.23  briggs {
   1496  1.23  briggs 
   1497  1.23  briggs 	if (battery > pmu_nbatt)
   1498  1.23  briggs 		return 0;
   1499  1.23  briggs 
   1500  1.23  briggs 	switch (pmu_batt_type) {
   1501  1.23  briggs 	case BATT_COMET:
   1502  1.23  briggs 	case BATT_HOOPER:
   1503  1.23  briggs 		return pm_battery_info_legacy(battery, info, pmu_batt_type);
   1504  1.23  briggs 
   1505  1.23  briggs 	case BATT_SMART:
   1506  1.23  briggs 		return pm_battery_info_smart(battery, info);
   1507  1.23  briggs 	}
   1508  1.23  briggs 
   1509  1.23  briggs 	return 0;
   1510  1.23  briggs }
   1511  1.23  briggs 
   1512   1.5  tsubai int
   1513   1.5  tsubai pm_read_nvram(addr)
   1514   1.5  tsubai 	int addr;
   1515   1.5  tsubai {
   1516   1.5  tsubai 	PMData p;
   1517   1.5  tsubai 
   1518   1.5  tsubai 	p.command = PMU_READ_NVRAM;
   1519   1.5  tsubai 	p.num_data = 2;
   1520   1.5  tsubai 	p.s_buf = p.r_buf = p.data;
   1521   1.5  tsubai 	p.data[0] = addr >> 8;
   1522   1.5  tsubai 	p.data[1] = addr;
   1523   1.5  tsubai 	pmgrop(&p);
   1524   1.5  tsubai 
   1525   1.5  tsubai 	return p.data[0];
   1526   1.5  tsubai }
   1527   1.5  tsubai 
   1528   1.5  tsubai void
   1529   1.5  tsubai pm_write_nvram(addr, val)
   1530   1.5  tsubai 	int addr, val;
   1531   1.5  tsubai {
   1532   1.5  tsubai 	PMData p;
   1533   1.5  tsubai 
   1534   1.5  tsubai 	p.command = PMU_WRITE_NVRAM;
   1535   1.5  tsubai 	p.num_data = 3;
   1536   1.5  tsubai 	p.s_buf = p.r_buf = p.data;
   1537   1.5  tsubai 	p.data[0] = addr >> 8;
   1538   1.5  tsubai 	p.data[1] = addr;
   1539   1.5  tsubai 	p.data[2] = val;
   1540   1.4  tsubai 	pmgrop(&p);
   1541   1.1  tsubai }
   1542