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

From: Nicolas Boichat
Date: Fri Apr 13 2007 - 01:38:07 EST


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@xxxxxxxxxx>
---

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);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/