Subject: Changes for review
To: None <port-macppc@netbsd.org>
From: Allen Briggs <briggs@wasabisystems.com>
List: port-macppc
Date: 02/17/2003 10:44:07
--tNQTSEo8WG/FKZ8E
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,

I've added support for the O'Hare-based 2400/3400 batteries in apm(4)
for macppc.  I have also made changes to force detection of an ADB
console keyboard on the later tibooks (do the new iBooks need this,
too?).

To make these changes, I added a couple of new functions to machdep.c--
one to initially probe the model name and compatibility list from open
firmware, and another to match a passed-in string against the compatible
list.

I would appreciate any comments on the changes.

Thanks,
-allen

-- 
 Allen Briggs                     briggs@wasabisystems.com
 Wasabi Systems, Inc.             http://www.wasabisystems.com/

--tNQTSEo8WG/FKZ8E
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diffs

Index: include/macppc.h
===================================================================
--- /dev/null	Mon Feb 17 05:04:46 2003
+++ include/macppc.h	Mon Feb 17 05:31:21 2003
@@ -0,0 +1,17 @@
+/*	$NetBSD$	*/
+
+#ifndef _MACHINE_MACPPC_H_
+#define _MACHINE_MACPPC_H_
+
+/*
+ * XXX - provide vectors for platform-specific functions that can not
+ *	 be auto-detected or easily hooked in via normal OFW probes --
+ *	 like brightness control, volume control, sleep, etc.
+ */
+
+/*
+ * macppc-specific glue;
+ */
+int macppc_iscompatible(const char *);
+
+#endif /* _MACHINE_MACPPC_H_ */
Index: dev/pm_direct.c
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/dev/pm_direct.c,v
retrieving revision 1.19
diff -u -p -r1.19 pm_direct.c
--- dev/pm_direct.c	2002/06/18 05:22:51	1.19
+++ dev/pm_direct.c	2003/02/17 15:34:03
@@ -46,6 +46,7 @@
 
 #include <machine/adbsys.h>
 #include <machine/cpu.h>
+#include <machine/macppc.h>
 
 #include <macppc/dev/adbvar.h>
 #include <macppc/dev/pm_direct.h>
@@ -88,6 +89,11 @@ u_int	pm_LCD_brightness = 0x0;
 u_int	pm_LCD_contrast = 0x0;
 u_int	pm_counter = 0;			/* clock count */
 
+u_int	pm_battery_type = 0;
+#define PM_BATTERY_2400		0x01
+#define PM_BATTERY_3400		0x02
+#define PM_BATTERY_SMART	0x03
+
 /* these values shows that number of data returned after 'send' cmd is sent */
 signed char pm_send_cmd_type[] = {
 	  -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
@@ -257,6 +263,22 @@ void
 pm_setup_adb()
 {
 	pmHardware = PM_HW_PB5XX;	/* XXX */
+
+	/*
+	 * This is pulled from Linux.  Apparently the "Comet" and "Hooper"
+	 * variants are distinguished by the magic value.
+	 */
+	if (macppc_iscompatible("AAPL,3400/2400")) {
+		uint32_t *mach_id_ptr = (uint32_t *) mapiodev(0xf3000034, 4);
+
+		if (mach_id_ptr && ((*mach_id_ptr) & 0x20000000)) {
+			pm_battery_type = PM_BATTERY_2400;
+		} else {
+			pm_battery_type = PM_BATTERY_3400;
+		}
+	} else {
+		pm_battery_type = PM_BATTERY_SMART;
+	}
 }
 
 
@@ -1269,40 +1291,124 @@ pm_eject_pcmcia(slot)
 /*
  * Thanks to Paul Mackerras and Fabio Riccardi's Linux implementation
  * for a clear description of the PMU results.
+ *
+ * Thanks to Linux implementation of done_battery_state_ohare for
+ * information on handling ohare batteries in the [23]400.
  */
 int
 pm_battery_info(int battery, struct pmu_battery_info *info)
 {
 	PMData p;
+	long vchgd_max, vchging_max, lmax;
+	long vmax, current, charge, pcharge, vb;
 
-	p.command = PMU_SMART_BATTERY_STATE;
-	p.num_data = 1;
+	switch (pm_battery_type) {
+	case PM_BATTERY_2400:
+	case PM_BATTERY_3400:
+		p.command = PMU_BATTERY_STATE;
+		p.num_data = 0;
+		break;
+	default:
+		p.command = PMU_SMART_BATTERY_STATE;
+		p.num_data = 1;
+		p.data[0] = battery + 1;
+		break;
+	}
 	p.s_buf = p.r_buf = p.data;
-	p.data[0] = battery + 1;
 	pmgrop(&p);
+
+	switch (pm_battery_type) {
+	case PM_BATTERY_2400:
+	case PM_BATTERY_3400:
+		/*
+		 * p.data[0]     ==  flags
+		 *    1 << 0          plugged in
+		 *    1 << 1          charging
+		 *    1 << 2          battery present
+		 *    1 << 5          fully charged
+		 *    1 << 6          pcharge reset
+		 *    1 << 7          battery exists (?)
+		 * p.data[1][2]  ==  battery voltage
+		 * p.data[3]     ==  CPU temperature
+		 * p.data[4]     ==  battery temperature
+		 * p.data[5]     ==  current
+		 * p.data[6][7]  ==  pcharge
+		 * Linux code attributes this information as
+		 *			--tkoba
+		 * XXX -- it would be nice to get the temps out in
+		 *	  envsys so they're user-visible, too.  Don't
+		 *	  know units or anything there.
+		 */
+		info->flags = p.data[0];
+
+		/* If battery isn't present, zero result and go */
+		if (!(info->flags & PMU_PWR_BATT_PRESENT)) {
+			info->cur_charge = 0;
+			info->max_charge = 0;
+			info->draw = 0;
+			info->voltage = 0;
+			break;
+		}
 
-	info->flags = p.data[1];
+		if (pm_battery_type == PM_BATTERY_2400) {
+			vchgd_max = 189;
+			vchging_max = 189; /* Linux has 213 ? */
+		} else {
+			vchgd_max = 330;
+			vchging_max = 330;
+		}
 
-	switch (p.data[0]) {
-	case 3:
-	case 4:
-		info->cur_charge = p.data[2];
-		info->max_charge = p.data[3];
-		info->draw = *((signed char *)&p.data[4]);
-		info->voltage = p.data[5];
-		break;
-	case 5:
-		info->cur_charge = ((p.data[2] << 8) | (p.data[3]));
-		info->max_charge = ((p.data[4] << 8) | (p.data[5]));
-		info->draw = *((signed short *)&p.data[6]);
-		info->voltage = ((p.data[8] << 8) | (p.data[7]));
+		lmax = 6500;
+		vb = (p.data[1] << 8) | p.data[2];
+		info->voltage = (vb * 265 + 72665) / 10;
+		current = p.data[5];
+
+		vmax = vchgd_max;
+		if (!(info->flags & PMU_PWR_AC_PRESENT)) {
+			if (current > 200)
+				vb += ((current - 200) * 15) / 100;
+		} else if (info->flags & PMU_PWR_BATT_CHARGING) {
+			vb = (vb * 97) / 100;
+			vmax = vchging_max;
+		}
+		charge = (100 * vb) / vmax;
+		if (info->flags & PMU_PWR_PCHARGE_RESET) {
+			pcharge = (p.data[6] << 8) | p.data[7];
+			if (pcharge > lmax)
+				pcharge = lmax;
+			pcharge = 100 - (pcharge * 100) / lmax;
+			if (pcharge < charge)
+				charge = pcharge;
+		}
+		info->cur_charge = charge;
+		info->draw = -current;
+		info->max_charge = 100;
 		break;
 	default:
-		/* XXX - Error condition */
-		info->cur_charge = 0;
-		info->max_charge = 0;
-		info->draw = 0;
-		info->voltage = 0;
+		info->flags = p.data[1];
+
+		switch (p.data[0]) {
+		case 3:
+		case 4:
+			info->cur_charge = p.data[2];
+			info->max_charge = p.data[3];
+			info->draw = *((signed char *)&p.data[4]);
+			info->voltage = p.data[5];
+			break;
+		case 5:
+			info->cur_charge = ((p.data[2] << 8) | (p.data[3]));
+			info->max_charge = ((p.data[4] << 8) | (p.data[5]));
+			info->draw = *((signed short *)&p.data[6]);
+			info->voltage = ((p.data[8] << 8) | (p.data[7]));
+			break;
+		default:
+			/* XXX - Error condition */
+			info->cur_charge = 0;
+			info->max_charge = 0;
+			info->draw = 0;
+			info->voltage = 0;
+			break;
+		}
 		break;
 	}
 
Index: dev/pm_direct.h
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/dev/pm_direct.h,v
retrieving revision 1.6
diff -u -p -r1.6 pm_direct.h
--- dev/pm_direct.h	2002/06/18 05:22:51	1.6
+++ dev/pm_direct.h	2003/02/17 15:34:03
@@ -89,6 +89,7 @@ void pm_eject_pcmcia __P((int));
 #define PMU_POWER_EVENTS        0x8f    /* Send power-event commands to PMU */
 #define PMU_SYSTEM_READY        0xdf    /* tell PMU we are awake */
 
+#define PMU_BATTERY_STATE	0x6b	/* Read battery state (older pmacs) */
 #define PMU_SMART_BATTERY_STATE	0x6f	/* Read battery state */
 
 /* Bits in PMU interrupt and interrupt mask bytes */
@@ -125,5 +126,7 @@ enum {
 /* PMU Power Information */
 
 #define PMU_PWR_AC_PRESENT	(1 << 0)
+#define PMU_PWR_BATT_CHARGING	(1 << 1)
 #define PMU_PWR_BATT_PRESENT	(1 << 2)
+#define PMU_PWR_PCHARGE_RESET	(1 << 6)
 
Index: macppc/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/macppc/macppc/machdep.c,v
retrieving revision 1.124
diff -u -p -r1.124 machdep.c
--- macppc/machdep.c	2003/02/03 17:09:57	1.124
+++ macppc/machdep.c	2003/02/17 15:34:04
@@ -76,6 +76,7 @@
 
 #include <machine/autoconf.h>
 #include <machine/bat.h>
+#include <machine/macppc.h>
 #include <machine/powerpc.h>
 #include <machine/trap.h>
 #include <machine/bus.h>
@@ -105,6 +106,10 @@ static int chosen;
 struct pmap ofw_pmap;
 int ofkbd_ihandle;
 
+static int	macppc_forceadb = 0;
+static char	macppc_compat[128];
+static int	macppc_compat_len;
+
 #ifdef DDB
 void *startsym, *endsym;
 #endif
@@ -122,6 +127,7 @@ int lcsplx(int);
 int save_ofmap(struct ofw_translations *, int);
 void restore_ofmap(struct ofw_translations *, int);
 static void dumpsys(void);
+static void macppc_identify(void);
 
 void
 initppc(startkernel, endkernel, args)
@@ -167,8 +173,16 @@ initppc(startkernel, endkernel, args)
 			BOOT_FLAG(*args++, boothowto);
 	}
 
+	/*
+	 * Really would kind of like to do this later, after pmap_bootstrap(),
+	 * but we want to get default keyboard type, which we need for console
+	 * initialization, and console initialization notes that it must be
+	 * done before pmap_bootstrap().
+	 */
+	macppc_identify();
+
 	/*
-	 * i386 port says, that this shouldn't be here,
+	 * i386 port says that this shouldn't be here,
 	 * but I really think the console should be initialized
 	 * as early as possible.
 	 */
@@ -596,6 +610,20 @@ cninit_kd()
 	}
 #endif
 
+	/*
+	 * New firmware does not have any *-kbd-ihandle[s] methods.
+	 * If we've set macppc_forceadb (in macppc_identify()),
+	 * assume ADB; otherwise, assume USB.
+	 */
+#if NAKBD > 0
+	if (macppc_forceadb) {
+		printf("console keyboard type: ADB\n");
+		stdin = akbd;
+		akbd_cnattach();
+		goto kbd_found;
+	}
+#endif
+
 #if NUKBD > 0
 	/*
 	 * XXX Old firmware does not have `usb-kbd-ihandles method.  Assume
@@ -726,3 +754,48 @@ mp_save_vec_lwp(l)
 }
 #endif /* ALTIVEC */
 #endif /* MULTIPROCESSOR */
+
+int
+macppc_iscompatible(const char *comp)
+{
+	char	*str;
+	int	len, l;
+
+	str = macppc_compat;
+	len = macppc_compat_len;
+	while (len > 0) {
+		if (strcmp(str, comp) == 0)
+			return 1;
+		l = strlen(str) + 1;
+		str += l;
+		len -= l;
+	}
+	return 0;
+}
+
+static void
+macppc_identify(void)
+{
+	char	mod[32];
+	int	devtree, modlen;
+
+	devtree = OF_peer(0);
+	modlen = OF_getprop(devtree, "model", mod, sizeof mod);
+	if (modlen >= sizeof mod) {
+		strcpy(mod, "no_fit");
+	}
+
+	macppc_compat_len = OF_getprop(devtree, "compatible",
+	    macppc_compat, sizeof macppc_compat);
+	if (macppc_compat_len >= sizeof macppc_compat) {
+		strcpy(macppc_compat, "no_fit");
+	}
+
+	/*
+	 * Newer PowerBooks have firmware without any obvious ADB/USB
+	 * detection methods available.
+	 */
+	if (   (strcmp(mod, "PowerBook3,4") == 0)
+	    || (strcmp(mod, "PowerBook3,5") == 0))
+		macppc_forceadb = 1;
+}

--tNQTSEo8WG/FKZ8E--