[lm-sensors] [PATCH 1/2] Apple SMC driver - standardize and sanitize sysfs tree + minor features addition

Nicolas Boichat nicolas at boichat.ch
Fri Apr 13 07:33:20 CEST 2007


Hi again,

Jean Delvare wrote:
>>
>> However, I'm not really satisfied with the way sysfs files are created:
>> I use a lot of preprocessor macros to avoid repetition of code.
>> The files created with these macros in /sys/devices/platform/applesmc are
>> the following (on a Macbook Pro):
>> fan0_actual_speed
>> fan0_manual
>> fan0_maximum_speed
>> fan0_minimum_speed
>> fan0_safe_speed
>> fan0_target_speed
>> fan1_actual_speed
>> fan1_manual
>> fan1_maximum_speed
>> fan1_minimum_speed
>> fan1_safe_speed
>> fan1_target_speed
>> temperature_0
>> temperature_1
>> temperature_2
>> temperature_3
>> temperature_4
>> temperature_5
>> temperature_6
>>     
>
> First of all, please read Documentation/hwmon/sysfs-documentation, and
> rename the entries to match the standard names whenever possible. Also
> make sure that you use the standard units. If you use the standard
> names and units and if you register your device with the hwmon class,
> standard monitoring application will be able to support your driver.
>   

Fixed.

[snip]

>> Also, I never call any sysfs_remove_* function, as the files are
>> deleted when the module is unloaded. Is it safe to do so? Doesn't it
>> cause any memory leak?
>>     
>
> This is considered a bad practice, as in theory you driver shouldn't
> create the device by itself, and the files are associated to the device,
> not the driver. All hardware monitoring drivers have been fixed now, so
> please add the file removal calls in your driver too. You might find it
> easier to use file groups rather than individual files. Again, see for
> example the f71805f driver, and in particular the f71805f_attributes
> array and f71805f_group structure, and the sysfs_create_group() and
> sysfs_remove_group() calls.
>   

Fixed too.

I also added some sanity checks, and some minor features I discovered
using key enumeration (see next patch).

Best regards,

Nicolas

- Standardize applesmc to use sysfs filenames recommended by
  Documentation/hwmon/sysfs-interface, and register the device with the hwmon
  class.
- Use snprintf instead of sprintf in sysfs show handlers.
- Remove the sysfs files properly in case of initialisation problem, and when
  the driver is unloaded.
- Add data buffer length sanity checks.
- Improvements of SMC keys' comments (add data type reported by the device).
- Add temperature sensors to Macbook Pro.
- Add support for reading fan physical position (e.g. "Left Side")

Signed-off-by: Nicolas Boichat <nicolas at boichat.ch>
---

 drivers/hwmon/applesmc.c |  280 ++++++++++++++++++++++++++++++++--------------
 1 files changed, 192 insertions(+), 88 deletions(-)

diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index f7b59fc..531bc9a 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -37,40 +37,48 @@
 #include <linux/hwmon-sysfs.h>
 #include <asm/io.h>
 #include <linux/leds.h>
+#include <linux/hwmon.h>
 
-/* data port used by apple SMC */
+/* data port used by Apple SMC */
 #define APPLESMC_DATA_PORT	0x300
-/* command/status port used by apple SMC */
+/* command/status port used by Apple SMC */
 #define APPLESMC_CMD_PORT	0x304
 
-#define APPLESMC_NR_PORTS	5 /* 0x300-0x304 */
+#define APPLESMC_NR_PORTS	32 /* 0x300-0x31f */
+
+#define APPLESMC_MAX_DATA_LENGTH 32
 
 #define APPLESMC_STATUS_MASK	0x0f
 #define APPLESMC_READ_CMD	0x10
 #define APPLESMC_WRITE_CMD	0x11
 
-#define LIGHT_SENSOR_LEFT_KEY	"ALV0" /* r-o length 6 */
-#define LIGHT_SENSOR_RIGHT_KEY	"ALV1" /* r-o length 6 */
-#define BACKLIGHT_KEY 		"LKSB" /* w-o */
+#define LIGHT_SENSOR_LEFT_KEY	"ALV0" /* r-o {alv (6 bytes) */
+#define LIGHT_SENSOR_RIGHT_KEY	"ALV1" /* r-o {alv (6 bytes) */
+#define BACKLIGHT_KEY 		"LKSB" /* w-o {lkb (2 bytes) */
 
-#define CLAMSHELL_KEY 		"MSLD" /* r-o length 1 (unused) */
+#define CLAMSHELL_KEY 		"MSLD" /* r-o ui8 (unused) */
 
-#define MOTION_SENSOR_X_KEY	"MO_X" /* r-o length 2 */
-#define MOTION_SENSOR_Y_KEY	"MO_Y" /* r-o length 2 */
-#define MOTION_SENSOR_Z_KEY	"MO_Z" /* r-o length 2 */
-#define MOTION_SENSOR_KEY	"MOCN" /* r/w length 2 */
+#define MOTION_SENSOR_X_KEY	"MO_X" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_Y_KEY	"MO_Y" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_Z_KEY	"MO_Z" /* r-o sp78 (2 bytes) */
+#define MOTION_SENSOR_KEY	"MOCN" /* r/w ui16 */
 
-#define FANS_COUNT		"FNum" /* r-o length 1 */
-#define FANS_MANUAL		"FS! " /* r-w length 2 */
-#define FAN_ACTUAL_SPEED	"F0Ac" /* r-o length 2 */
-#define FAN_MIN_SPEED		"F0Mn" /* r-o length 2 */
-#define FAN_MAX_SPEED		"F0Mx" /* r-o length 2 */
-#define FAN_SAFE_SPEED		"F0Sf" /* r-o length 2 */
-#define FAN_TARGET_SPEED	"F0Tg" /* r-w length 2 */
+#define FANS_COUNT		"FNum" /* r-o ui8 */
+#define FANS_MANUAL		"FS! " /* r-w ui16 */
+#define FAN_ACTUAL_SPEED	"F0Ac" /* r-o fpe2 (2 bytes) */
+#define FAN_MIN_SPEED		"F0Mn" /* r-o fpe2 (2 bytes) */
+#define FAN_MAX_SPEED		"F0Mx" /* r-o fpe2 (2 bytes) */
+#define FAN_SAFE_SPEED		"F0Sf" /* r-o fpe2 (2 bytes) */
+#define FAN_TARGET_SPEED	"F0Tg" /* r-w fpe2 (2 bytes) */
+#define FAN_POSITION		"F0ID" /* r-o char[16] */
 
-/* Temperature sensors keys. First set for Macbook(Pro), second for Macmini */
-static const char* temperature_sensors_sets[][8] = {
-	{ "TB0T", "TC0D", "TC0P", "Th0H", "Ts0P", "Th1H", "Ts1P", NULL },
+/*
+ * Temperature sensors keys (sp78 - 2 bytes).
+ * First set for Macbook(Pro), second for Macmini.
+ */
+static const char* temperature_sensors_sets[][13] = {
+	{ "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
+	  "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
 	{ "TC0D", "TC0P", NULL }
 };
 
@@ -110,6 +118,7 @@ static s16 rest_x;
 static s16 rest_y;
 static struct timer_list applesmc_timer;
 static struct input_dev *applesmc_idev;
+static struct class_device *hwmon_class_dev;
 
 /* Indicates whether this computer has an accelerometer. */
 static unsigned int applesmc_accelerometer;
@@ -152,17 +161,22 @@ static int __wait_status(u8 val)
  */
 static int applesmc_read_key(const char* key, u8* buffer, u8 len)
 {
-	int ret = -EIO;
 	int i;
 
+	if (len > APPLESMC_MAX_DATA_LENGTH) {
+		printk(KERN_ERR	"applesmc_read_key: cannot read more than "
+					"%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
+		return -EINVAL;
+	}
+
 	outb(APPLESMC_READ_CMD, APPLESMC_CMD_PORT);
 	if (__wait_status(0x0c))
-		goto out;
+		return -EIO;
 	
 	for (i = 0; i < 4; i++) {
 		outb(key[i], APPLESMC_DATA_PORT);
 		if (__wait_status(0x04))
-			goto out;
+			return -EIO;
 	}
 	if (debug)
 		printk(KERN_DEBUG "<%s", key);
@@ -173,7 +187,7 @@ static int applesmc_read_key(const char* key, u8* buffer, u8 len)
 
 	for (i = 0; i < len; i++) {
 		if (__wait_status(0x05))
-			goto out;
+			return -EIO;
 		buffer[i] = inb(APPLESMC_DATA_PORT);
 		if (debug)
 			printk(KERN_DEBUG "<%x", buffer[i]);
@@ -181,10 +195,7 @@ static int applesmc_read_key(const char* key, u8* buffer, u8 len)
 	if (debug)
 		printk(KERN_DEBUG "\n");
 
-	ret = 0;
-
-out:
-	return ret;
+	return 0;
 }
 
 /*
@@ -194,30 +205,33 @@ out:
  */
 static int applesmc_write_key(const char* key, u8* buffer, u8 len)
 {
-	int ret = -EIO;
 	int i;
 
+	if (len > APPLESMC_MAX_DATA_LENGTH) {
+		printk(KERN_ERR	"applesmc_write_key: cannot write more than "
+					"%d bytes\n", APPLESMC_MAX_DATA_LENGTH);
+		return -EINVAL;
+	}
+
 	outb(APPLESMC_WRITE_CMD, APPLESMC_CMD_PORT);
 	if (__wait_status(0x0c))
-		goto out;
+		return -EIO;
 	
 	for (i = 0; i < 4; i++) {
 		outb(key[i], APPLESMC_DATA_PORT);
 		if (__wait_status(0x04))
-			goto out;
+			return -EIO;
 	}
 
 	outb(len, APPLESMC_DATA_PORT);
 
 	for (i = 0; i < len; i++) {
 		if (__wait_status(0x04))
-			goto out;
+			return -EIO;
 		outb(buffer[i], APPLESMC_DATA_PORT);
 	}
 
-	ret = 0;
-out:
-	return ret;
+	return 0;
 }
 
 /*
@@ -415,7 +429,7 @@ out:
 	if (ret)
 		return ret;
 	else
-		return sprintf(buf, "(%d,%d,%d)\n", x, y, z);
+		return snprintf(buf, PAGE_SIZE, "(%d,%d,%d)\n", x, y, z);
 }
 
 static ssize_t applesmc_light_show(struct device *dev,
@@ -439,10 +453,10 @@ out:
 	if (ret)
 		return ret;
 	else
-		return sprintf(sysfsbuf, "(%d,%d)\n", left, right);
+		return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", left, right);
 }
 
-/* Displays degree Celsius * 100 */
+/* Displays degree Celsius * 1000 */
 static ssize_t applesmc_show_temperature(struct device *dev,
 			struct device_attribute *devattr, char *sysfsbuf)
 {
@@ -456,15 +470,15 @@ static ssize_t applesmc_show_temperature(struct device *dev,
 	mutex_lock(&applesmc_lock);
 
 	ret = applesmc_read_key(key, buffer, 2);
-	temp = buffer[0]*100;
-	temp += (buffer[1] >> 6) * 25;
+	temp = buffer[0]*1000;
+	temp += (buffer[1] >> 6) * 250;
 
 	mutex_unlock(&applesmc_lock);
 
 	if (ret)
 		return ret;
 	else
-		return sprintf(sysfsbuf, "%u\n", temp);
+		return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", temp);
 }
 
 static ssize_t applesmc_show_fan_speed(struct device *dev,
@@ -492,7 +506,7 @@ static ssize_t applesmc_show_fan_speed(struct device *dev,
 	if (ret)
 		return ret;
 	else
-		return sprintf(sysfsbuf, "%u\n", speed);
+		return snprintf(sysfsbuf, PAGE_SIZE, "%u\n", speed);
 }
 
 static ssize_t applesmc_store_fan_speed(struct device *dev,
@@ -547,7 +561,7 @@ static ssize_t applesmc_show_fan_manual(struct device *dev,
 	if (ret)
 		return ret;
 	else
-		return sprintf(sysfsbuf, "%d\n", manual);
+		return snprintf(sysfsbuf, PAGE_SIZE, "%d\n", manual);
 }
 
 static ssize_t applesmc_store_fan_manual(struct device *dev,
@@ -587,10 +601,37 @@ out:
 		return count;
 }
 
+static ssize_t applesmc_show_fan_position(struct device *dev,
+				struct device_attribute *attr, char *sysfsbuf)
+{
+	int ret;
+	char newkey[5];
+	u8 buffer[17];
+	struct sensor_device_attribute_2 *sensor_attr =
+						to_sensor_dev_attr_2(attr);
+
+	newkey[0] = FAN_POSITION[0];
+	newkey[1] = '0' + sensor_attr->index;
+	newkey[2] = FAN_POSITION[2];
+	newkey[3] = FAN_POSITION[3];
+	newkey[4] = 0;
+
+	mutex_lock(&applesmc_lock);
+
+	ret = applesmc_read_key(newkey, buffer, 16);
+	buffer[16] = 0;
+
+	mutex_unlock(&applesmc_lock);
+	if (ret)
+		return ret;
+	else
+		return snprintf(sysfsbuf, PAGE_SIZE, "%s\n", buffer+4);
+}
+
 static ssize_t applesmc_calibrate_show(struct device *dev,
 				struct device_attribute *attr, char *sysfsbuf)
 {
-	return sprintf(sysfsbuf, "(%d,%d)\n", rest_x, rest_y);
+	return snprintf(sysfsbuf, PAGE_SIZE, "(%d,%d)\n", rest_x, rest_y);
 }
 
 static ssize_t applesmc_calibrate_store(struct device *dev,
@@ -625,6 +666,15 @@ static DEVICE_ATTR(position, 0444, applesmc_position_show, NULL);
 static DEVICE_ATTR(calibrate, 0644,
 			applesmc_calibrate_show, applesmc_calibrate_store);
 
+static struct attribute *accelerometer_attributes[] = {
+	&dev_attr_position.attr,
+	&dev_attr_calibrate.attr,
+	NULL
+};
+
+static const struct attribute_group accelerometer_attributes_group =
+	{ .attrs = accelerometer_attributes };
+
 static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
 
 /*
@@ -637,31 +687,35 @@ static DEVICE_ATTR(light, 0444, applesmc_light_show, NULL);
  *  - show/store manual mode
  */
 #define sysfs_fan_speeds_offset(offset) \
-static SENSOR_DEVICE_ATTR_2(fan##offset##_actual_speed, S_IRUGO, \
-			applesmc_show_fan_speed, NULL, 0, offset); \
+static SENSOR_DEVICE_ATTR_2(fan##offset##_input, S_IRUGO, \
+			applesmc_show_fan_speed, NULL, 0, offset-1); \
 \
-static SENSOR_DEVICE_ATTR_2(fan##offset##_minimum_speed, S_IRUGO | S_IWUSR, \
-	applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset); \
+static SENSOR_DEVICE_ATTR_2(fan##offset##_min, S_IRUGO | S_IWUSR, \
+	applesmc_show_fan_speed, applesmc_store_fan_speed, 1, offset-1); \
 \
-static SENSOR_DEVICE_ATTR_2(fan##offset##_maximum_speed, S_IRUGO, \
-			applesmc_show_fan_speed, NULL, 2, offset); \
+static SENSOR_DEVICE_ATTR_2(fan##offset##_max, S_IRUGO, \
+			applesmc_show_fan_speed, NULL, 2, offset-1); \
 \
-static SENSOR_DEVICE_ATTR_2(fan##offset##_safe_speed, S_IRUGO, \
-			applesmc_show_fan_speed, NULL, 3, offset); \
+static SENSOR_DEVICE_ATTR_2(fan##offset##_safe, S_IRUGO, \
+			applesmc_show_fan_speed, NULL, 3, offset-1); \
 \
-static SENSOR_DEVICE_ATTR_2(fan##offset##_target_speed, S_IRUGO | S_IWUSR, \
-	applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset); \
+static SENSOR_DEVICE_ATTR_2(fan##offset##_output, S_IRUGO | S_IWUSR, \
+	applesmc_show_fan_speed, applesmc_store_fan_speed, 4, offset-1); \
 \
 static SENSOR_DEVICE_ATTR(fan##offset##_manual, S_IRUGO | S_IWUSR, \
-	applesmc_show_fan_manual, applesmc_store_fan_manual, offset); \
+	applesmc_show_fan_manual, applesmc_store_fan_manual, offset-1); \
+\
+static SENSOR_DEVICE_ATTR(fan##offset##_position, S_IRUGO, \
+	applesmc_show_fan_position, NULL, offset-1); \
 \
 static struct attribute *fan##offset##_attributes[] = { \
-	&sensor_dev_attr_fan##offset##_actual_speed.dev_attr.attr, \
-	&sensor_dev_attr_fan##offset##_minimum_speed.dev_attr.attr, \
-	&sensor_dev_attr_fan##offset##_maximum_speed.dev_attr.attr, \
-	&sensor_dev_attr_fan##offset##_safe_speed.dev_attr.attr, \
-	&sensor_dev_attr_fan##offset##_target_speed.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_input.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_min.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_max.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_safe.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_output.dev_attr.attr, \
 	&sensor_dev_attr_fan##offset##_manual.dev_attr.attr, \
+	&sensor_dev_attr_fan##offset##_position.dev_attr.attr, \
 	NULL \
 };
 
@@ -669,42 +723,61 @@ static struct attribute *fan##offset##_attributes[] = { \
  * Create the needed functions for each fan using the macro defined above 
  * (2 fans are supported)
  */
-sysfs_fan_speeds_offset(0);
 sysfs_fan_speeds_offset(1);
+sysfs_fan_speeds_offset(2);
 
 static const struct attribute_group fan_attribute_groups[] = {
-	{ .attrs = fan0_attributes },
-	{ .attrs = fan1_attributes }
+	{ .attrs = fan1_attributes },
+	{ .attrs = fan2_attributes }
 };
 
 /*
  * Temperature sensors sysfs entries.
  */
-static SENSOR_DEVICE_ATTR(temperature_0, S_IRUGO,
+static SENSOR_DEVICE_ATTR(temp_1_input, S_IRUGO,
 					applesmc_show_temperature, NULL, 0);
-static SENSOR_DEVICE_ATTR(temperature_1, S_IRUGO,
+static SENSOR_DEVICE_ATTR(temp_2_input, S_IRUGO,
 					applesmc_show_temperature, NULL, 1);
-static SENSOR_DEVICE_ATTR(temperature_2, S_IRUGO,
+static SENSOR_DEVICE_ATTR(temp_3_input, S_IRUGO,
 					applesmc_show_temperature, NULL, 2);
-static SENSOR_DEVICE_ATTR(temperature_3, S_IRUGO,
+static SENSOR_DEVICE_ATTR(temp_4_input, S_IRUGO,
 					applesmc_show_temperature, NULL, 3);
-static SENSOR_DEVICE_ATTR(temperature_4, S_IRUGO,
+static SENSOR_DEVICE_ATTR(temp_5_input, S_IRUGO,
 					applesmc_show_temperature, NULL, 4);
-static SENSOR_DEVICE_ATTR(temperature_5, S_IRUGO,
+static SENSOR_DEVICE_ATTR(temp_6_input, S_IRUGO,
 					applesmc_show_temperature, NULL, 5);
-static SENSOR_DEVICE_ATTR(temperature_6, S_IRUGO,
+static SENSOR_DEVICE_ATTR(temp_7_input, S_IRUGO,
 					applesmc_show_temperature, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp_8_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 7);
+static SENSOR_DEVICE_ATTR(temp_9_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp_10_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp_11_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp_12_input, S_IRUGO,
+					applesmc_show_temperature, NULL, 11);
 
 static struct attribute *temperature_attributes[] = {
-	&sensor_dev_attr_temperature_0.dev_attr.attr,
-	&sensor_dev_attr_temperature_1.dev_attr.attr,
-	&sensor_dev_attr_temperature_2.dev_attr.attr,
-	&sensor_dev_attr_temperature_3.dev_attr.attr,
-	&sensor_dev_attr_temperature_4.dev_attr.attr,
-	&sensor_dev_attr_temperature_5.dev_attr.attr,
-	&sensor_dev_attr_temperature_6.dev_attr.attr,
+	&sensor_dev_attr_temp_1_input.dev_attr.attr,
+	&sensor_dev_attr_temp_2_input.dev_attr.attr,
+	&sensor_dev_attr_temp_3_input.dev_attr.attr,
+	&sensor_dev_attr_temp_4_input.dev_attr.attr,
+	&sensor_dev_attr_temp_5_input.dev_attr.attr,
+	&sensor_dev_attr_temp_6_input.dev_attr.attr,
+	&sensor_dev_attr_temp_7_input.dev_attr.attr,
+	&sensor_dev_attr_temp_8_input.dev_attr.attr,
+	&sensor_dev_attr_temp_9_input.dev_attr.attr,
+	&sensor_dev_attr_temp_10_input.dev_attr.attr,
+	&sensor_dev_attr_temp_11_input.dev_attr.attr,
+	&sensor_dev_attr_temp_12_input.dev_attr.attr,
+	NULL
 };
 
+static const struct attribute_group temperature_attributes_group =
+	{ .attrs = temperature_attributes };
+
 /* Module stuff */
 
 /* 
@@ -734,18 +807,15 @@ static int applesmc_create_accelerometer(void)
 {
 	int ret;
 
-	ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_position.attr);
-	if (ret)
-		goto out;
-
-	ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_calibrate.attr);
+	ret = sysfs_create_group(&pdev->dev.kobj,
+					&accelerometer_attributes_group);
 	if (ret)
 		goto out;
 
 	applesmc_idev = input_allocate_device();
 	if (!applesmc_idev) {
 		ret = -ENOMEM;
-		goto out;
+		goto out_sysfs;
 	}
 
 	/* initial calibrate for the input device */
@@ -777,6 +847,9 @@ static int applesmc_create_accelerometer(void)
 out_idev:
 	input_free_device(applesmc_idev);
 
+out_sysfs:
+	sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);	
+
 out:
 	printk(KERN_WARNING "applesmc: driver init failed (ret=%d)!\n", ret);
 	return ret;
@@ -787,6 +860,7 @@ static void applesmc_release_accelerometer(void)
 {
 	del_timer_sync(&applesmc_timer);
 	input_unregister_device(applesmc_idev);
+	sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group);
 }
 
 static __initdata struct dmi_match_data applesmc_dmi_data[] = {
@@ -867,7 +941,7 @@ static int __init applesmc_init(void)
 			ret = sysfs_create_group(&pdev->dev.kobj,
 						 &fan_attribute_groups[0]);
 			if (ret)
-				goto out_device;
+				goto out_fan_1;
 		case 0:
 			;
 		}
@@ -876,16 +950,24 @@ static int __init applesmc_init(void)
 	for (i = 0;
 	     temperature_sensors_sets[applesmc_temperature_set][i] != NULL;
 	     i++) {
+		if (temperature_attributes[i] == NULL) {
+			printk(KERN_ERR "applesmc: More temperature sensors "
+				"in temperature_sensors_sets (at least %i)"
+				"than available sysfs files in "
+				"temperature_attributes (%i), please report "
+				"this bug.\n", i, i-1);
+			goto out_temperature;
+		}
 		ret = sysfs_create_file(&pdev->dev.kobj,
 						temperature_attributes[i]);
 		if (ret)
-			goto out_device;
+			goto out_temperature;
 	}
 
 	if (applesmc_accelerometer) {
 		ret = applesmc_create_accelerometer();
 		if (ret)
-			goto out_device;
+			goto out_temperature;
 	}
 
 	if (applesmc_light) {
@@ -897,15 +979,33 @@ static int __init applesmc_init(void)
 		/* register as a led device */
 		ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
 		if (ret < 0)
-			goto out_accelerometer;
+			goto out_light_sysfs;
+	}
+
+	hwmon_class_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(hwmon_class_dev)) {
+		ret = PTR_ERR(hwmon_class_dev);
+		goto out_light;
 	}
 
 	printk(KERN_INFO "applesmc: driver successfully loaded.\n");
+
 	return 0;
 
+out_light:
+	if (applesmc_light)
+		led_classdev_unregister(&applesmc_backlight);
+out_light_sysfs:
+	if (applesmc_light)
+		sysfs_remove_file(&pdev->dev.kobj, &dev_attr_light.attr);
 out_accelerometer:
 	if (applesmc_accelerometer)
 		applesmc_release_accelerometer();
+out_temperature:
+	sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
+	sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
+out_fan_1:
+	sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
 out_device:
 	platform_device_unregister(pdev);
 out_driver:
@@ -919,10 +1019,14 @@ out:
 
 static void __exit applesmc_exit(void)
 {
+	hwmon_device_unregister(hwmon_class_dev);	
 	if (applesmc_light)
 		led_classdev_unregister(&applesmc_backlight);
 	if (applesmc_accelerometer)
 		applesmc_release_accelerometer();
+	sysfs_remove_group(&pdev->dev.kobj, &temperature_attributes_group);
+	sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[0]);
+	sysfs_remove_group(&pdev->dev.kobj, &fan_attribute_groups[1]);
 	platform_device_unregister(pdev);
 	platform_driver_unregister(&applesmc_driver);
 	release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);





More information about the lm-sensors mailing list