svn commit: r195046 - head/sys/dev/asmc

Rui Paulo rpaulo at FreeBSD.org
Fri Jun 26 10:23:18 UTC 2009


Author: rpaulo
Date: Fri Jun 26 10:23:17 2009
New Revision: 195046
URL: http://svn.freebsd.org/changeset/base/195046

Log:
  Add support for MacBook4,1.
  
  Submitted by:	Christoph Langguth <christoph at rosenkeller.org>
  MFC after:	2 weeks
  Approved by:	re (kib)

Modified:
  head/sys/dev/asmc/asmc.c
  head/sys/dev/asmc/asmcvar.h

Modified: head/sys/dev/asmc/asmc.c
==============================================================================
--- head/sys/dev/asmc/asmc.c	Fri Jun 26 09:32:31 2009	(r195045)
+++ head/sys/dev/asmc/asmc.c	Fri Jun 26 10:23:17 2009	(r195046)
@@ -68,7 +68,9 @@ static int 	asmc_detach(device_t dev);
  * SMC functions.
  */
 static int 	asmc_init(device_t dev);
+static int 	asmc_command(device_t dev, uint8_t command);
 static int 	asmc_wait(device_t dev, uint8_t val);
+static int 	asmc_wait_ack(device_t dev, uint8_t val, int amount);
 static int 	asmc_key_write(device_t dev, const char *key, uint8_t *buf,
     uint8_t len);
 static int 	asmc_key_read(device_t dev, const char *key, uint8_t *buf,
@@ -99,6 +101,7 @@ static int 	asmc_mb_sysctl_sms_y(SYSCTL_
 static int 	asmc_mb_sysctl_sms_z(SYSCTL_HANDLER_ARGS);
 static int 	asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS);
 static int 	asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS);
+static int 	asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS);
 
 struct asmc_model {
 	const char 	 *smc_model;	/* smbios.system.product env var. */
@@ -115,6 +118,7 @@ struct asmc_model {
 	int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS);
 	int (*smc_light_left)(SYSCTL_HANDLER_ARGS);
 	int (*smc_light_right)(SYSCTL_HANDLER_ARGS);
+	int (*smc_light_control)(SYSCTL_HANDLER_ARGS);
 
 	const char 	*smc_temps[ASMC_TEMP_MAX];
 	const char 	*smc_tempnames[ASMC_TEMP_MAX];
@@ -131,18 +135,19 @@ static struct asmc_model *asmc_match(dev
 			asmc_mb_sysctl_fanmaxspeed, \
 			asmc_mb_sysctl_fantargetspeed
 #define ASMC_LIGHT_FUNCS asmc_mbp_sysctl_light_left, \
-			 asmc_mbp_sysctl_light_right
+			 asmc_mbp_sysctl_light_right, \
+			 asmc_mbp_sysctl_light_control
 
 struct asmc_model asmc_models[] = {
 	{ 
 	  "MacBook1,1", "Apple SMC MacBook Core Duo",
-	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL,
+	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
 	  ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
 	},
 
 	{ 
 	  "MacBook2,1", "Apple SMC MacBook Core 2 Duo",
-	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL,
+	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
 	  ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS
 	},
 
@@ -182,12 +187,18 @@ struct asmc_model asmc_models[] = {
 	  ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS
 	},
 	
+	{ 
+	  "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)",
+	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS,
+	  ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS
+	},
+	
 	/* The Mac Mini has no SMS */
 	{ 
 	  "Macmini1,1", "Apple SMC Mac Mini",
 	  NULL, NULL, NULL,
 	  ASMC_FAN_FUNCS,
-	  NULL, NULL,
+	  NULL, NULL, NULL,
 	  ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS
 	},
 
@@ -196,13 +207,13 @@ struct asmc_model asmc_models[] = {
 	  "MacPro2", "Apple SMC Mac Pro (8-core)",
 	  NULL, NULL, NULL,
 	  ASMC_FAN_FUNCS,
-	  NULL, NULL,
+	  NULL, NULL, NULL,
 	  ASMC_MP_TEMPS, ASMC_MP_TEMPNAMES, ASMC_MP_TEMPDESCS
 	},
 
 	{
 	  "MacBookAir1,1", "Apple SMC MacBook Air",
-	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL,
+	  ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, NULL, NULL, NULL,
 	  ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS
 	},	
 
@@ -242,6 +253,7 @@ ACPI_MODULE_NAME("ASMC")
 #define ASMC_DPRINTF(str)	
 #endif
 
+/* NB: can't be const */
 static char *asmc_ids[] = { "APP0001", NULL };
 
 static devclass_t asmc_devclass;
@@ -385,6 +397,33 @@ asmc_attach(device_t dev)
 		    model->smc_tempdescs[i]);
 	}
 
+	/*
+	 * dev.asmc.n.light
+	 */
+	if (model->smc_light_left) {
+		sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
+		    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
+		    CTLFLAG_RD, 0, "Keyboard backlight sensors");
+		
+		SYSCTL_ADD_PROC(sysctlctx,
+		    SYSCTL_CHILDREN(sc->sc_light_tree),
+		    OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RD,
+		    dev, 0, model->smc_light_left, "I",
+		    "Keyboard backlight left sensor");
+	
+		SYSCTL_ADD_PROC(sysctlctx,
+		    SYSCTL_CHILDREN(sc->sc_light_tree),
+		    OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RD,
+		    dev, 0, model->smc_light_right, "I",
+		    "Keyboard backlight right sensor");
+
+		SYSCTL_ADD_PROC(sysctlctx,
+		    SYSCTL_CHILDREN(sc->sc_light_tree),
+		    OID_AUTO, "control", CTLTYPE_INT | CTLFLAG_RW,
+		    dev, 0, model->smc_light_control, "I",
+		    "Keyboard backlight brightness control");
+	}
+
 	if (model->smc_sms_x == NULL)
 		goto nosms;
 
@@ -414,27 +453,6 @@ asmc_attach(device_t dev)
 	    "Sudden Motion Sensor Z value");
 
 	/*
-	 * dev.asmc.n.light
-	 */
-	if (model->smc_light_left) {
-		sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx,
-		    SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light",
-		    CTLFLAG_RD, 0, "Keyboard backlight sensors");
-		
-		SYSCTL_ADD_PROC(sysctlctx,
-		    SYSCTL_CHILDREN(sc->sc_light_tree),
-		    OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RW,
-		    dev, 0, model->smc_light_left, "I",
-		    "Keyboard backlight left sensor");
-	
-		SYSCTL_ADD_PROC(sysctlctx,
-		    SYSCTL_CHILDREN(sc->sc_light_tree),
-		    OID_AUTO, "right", CTLTYPE_INT | CTLFLAG_RW,
-		    dev, 0, model->smc_light_right, "I",
-		    "Keyboard backlight right sensor");
-	}
-
-	/*
 	 * Need a taskqueue to send devctl_notify() events
 	 * when the SMS interrupt us.
 	 *
@@ -606,38 +624,81 @@ nosms:
 
 /*
  * We need to make sure that the SMC acks the byte sent.
- * Just wait up to 100 ms.
+ * Just wait up to (amount * 10)  ms.
  */
 static int
-asmc_wait(device_t dev, uint8_t val)
+asmc_wait_ack(device_t dev, uint8_t val, int amount)
 {
 	struct asmc_softc *sc = device_get_softc(dev);
 	u_int i;
 
 	val = val & ASMC_STATUS_MASK;
 
-	for (i = 0; i < 1000; i++) {
+	for (i = 0; i < amount; i++) {
 		if ((ASMC_CMDPORT_READ(sc) & ASMC_STATUS_MASK) == val)
 			return (0);
 		DELAY(10);
 	}
 
+	return (1);
+}
+
+/*
+ * We need to make sure that the SMC acks the byte sent.
+ * Just wait up to 100 ms.
+ */
+static int
+asmc_wait(device_t dev, uint8_t val)
+{
+	struct asmc_softc *sc;
+
+	if (asmc_wait_ack(dev, val, 1000) == 0)
+		return (0);
+
+	sc = device_get_softc(dev);
+	val = val & ASMC_STATUS_MASK;
+
+#ifdef DEBUG
 	device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, val,
 	    ASMC_CMDPORT_READ(sc));
+#endif	
+	return (1);
+}
 	
+/*
+ * Send the given command, retrying up to 10 times if
+ * the acknowledgement fails.
+ */
+static int
+asmc_command(device_t dev, uint8_t command) {
+
+	int i;
+	struct asmc_softc *sc = device_get_softc(dev);
+
+	for (i=0; i < 10; i++) {
+		ASMC_CMDPORT_WRITE(sc, command);
+		if (asmc_wait_ack(dev, 0x0c, 100) == 0) {
+			return (0);
+		}
+	}
+
+#ifdef DEBUG
+	device_printf(dev, "%s failed: 0x%x, 0x%x\n", __func__, command,
+	    ASMC_CMDPORT_READ(sc));
+#endif
 	return (1);
 }
 
 static int
 asmc_key_read(device_t dev, const char *key, uint8_t *buf, uint8_t len)
 {
-	int i, error = 1;
+	int i, error = 1, try = 0;
 	struct asmc_softc *sc = device_get_softc(dev);
 
 	mtx_lock_spin(&sc->sc_mtx);
 
-	ASMC_CMDPORT_WRITE(sc, ASMC_CMDREAD);
-	if (asmc_wait(dev, 0x0c))
+begin:
+	if (asmc_command(dev, ASMC_CMDREAD))
 		goto out;
 
 	for (i = 0; i < 4; i++) {
@@ -656,6 +717,12 @@ asmc_key_read(device_t dev, const char *
 
 	error = 0;
 out:
+	if (error) {
+		if (++try < 10) goto begin;
+		device_printf(dev,"%s for key %s failed %d times, giving up\n",
+			__func__, key, try);
+	}
+
 	mtx_unlock_spin(&sc->sc_mtx);
 
 	return (error);
@@ -664,14 +731,14 @@ out:
 static int
 asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len)
 {
-	int i, error = -1;
+	int i, error = -1, try = 0;
 	struct asmc_softc *sc = device_get_softc(dev);
 
 	mtx_lock_spin(&sc->sc_mtx);
 
+begin:
 	ASMC_DPRINTF(("cmd port: cmd write\n"));
-	ASMC_CMDPORT_WRITE(sc, ASMC_CMDWRITE);
-	if (asmc_wait(dev, 0x0c))
+	if (asmc_command(dev, ASMC_CMDWRITE))
 		goto out;
 
 	ASMC_DPRINTF(("data port: key\n"));
@@ -692,6 +759,12 @@ asmc_key_write(device_t dev, const char 
 
 	error = 0;
 out:
+	if (error) {
+		if (++try < 10) goto begin;
+		device_printf(dev,"%s for key %s failed %d times, giving up\n",
+			__func__, key, try);
+	}
+
 	mtx_unlock_spin(&sc->sc_mtx);
 
 	return (error);
@@ -993,20 +1066,11 @@ asmc_mbp_sysctl_light_left(SYSCTL_HANDLE
 	device_t dev = (device_t) arg1;
 	uint8_t buf[6];
 	int error;
-	unsigned int level;
 	int32_t v;
 
 	asmc_key_read(dev, ASMC_KEY_LIGHTLEFT, buf, 6);
 	v = buf[2];
 	error = sysctl_handle_int(oidp, &v, sizeof(v), req);
-	if (error == 0 && req->newptr != NULL) {
-		level = *(unsigned int *)req->newptr;
-		if (level > 255)
-			return (EINVAL);
-		buf[0] = level;
-		buf[1] = 0x00;
-		asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, 2);
-	}
 
 	return (error);
 }
@@ -1017,16 +1081,30 @@ asmc_mbp_sysctl_light_right(SYSCTL_HANDL
 	device_t dev = (device_t) arg1;
 	uint8_t buf[6];
 	int error;
-	unsigned int level;
 	int32_t v;
 	
 	asmc_key_read(dev, ASMC_KEY_LIGHTRIGHT, buf, 6);
 	v = buf[2];
 	error = sysctl_handle_int(oidp, &v, sizeof(v), req);
+	
+	return (error);
+}
+
+static int
+asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS)
+{
+	device_t dev = (device_t) arg1;
+	uint8_t buf[2];
+	int error;
+	unsigned int level;
+	static int32_t v;
+	
+	error = sysctl_handle_int(oidp, &v, sizeof(v), req);
 	if (error == 0 && req->newptr != NULL) {
 		level = *(unsigned int *)req->newptr;
 		if (level > 255)
 			return (EINVAL);
+		v = level;
 		buf[0] = level;
 		buf[1] = 0x00;
 		asmc_key_write(dev, ASMC_KEY_LIGHTVALUE, buf, 2);

Modified: head/sys/dev/asmc/asmcvar.h
==============================================================================
--- head/sys/dev/asmc/asmcvar.h	Fri Jun 26 09:32:31 2009	(r195045)
+++ head/sys/dev/asmc/asmcvar.h	Fri Jun 26 10:23:17 2009	(r195046)
@@ -155,6 +155,25 @@ struct asmc_softc {
 				  "Graphics Chip", "Graphics Heatsink", \
 				  "Unknown", } 
 
+#define ASMC_MBP4_TEMPS		{ "TB0T", "Th0H", "Th1H", "Th2H", "Tm0P", \
+				  "TG0H", "TG0D", "TC0D", "TC0P", "Ts0P", \
+				  "TTF0", "TW0P", NULL }
+
+#define ASMC_MBP4_TEMPNAMES	{ "enclosure", "heatsink1", "heatsink2", \
+				  "heatsink3", "memory", "graphicssink", \
+				  "graphics", "cpu", "cpu2", "unknown1", \
+				  "unknown2", "wireless", }
+
+#define ASMC_MBP4_TEMPDESCS	{ "Enclosure Bottomside", \
+				  "Main Heatsink 1", "Main Heatsink 2", \
+				  "Main Heatsink 3", \
+				  "Memory Controller", \
+				  "Graphics Chip Heatsink", \
+				  "Graphics Chip Diode", \
+				  "CPU Temperature Diode", "CPU Point 2", \
+				  "Unknown", "Unknown", \
+				  "Wireless Module", } 
+
 #define ASMC_MM_TEMPS		{ "TN0P", "TN1P", NULL }
 #define ASMC_MM_TEMPNAMES	{ "northbridge1", "northbridge2" }
 #define ASMC_MM_TEMPDESCS	{ "Northbridge Point 1", \


More information about the svn-src-head mailing list