diff options
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
| -rw-r--r-- | drivers/misc/thinkpad_acpi.c | 496 | 
1 files changed, 260 insertions, 236 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 3f28f6eabdbf..b5969298f3d3 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1293,7 +1293,7 @@ static void tpacpi_input_send_radiosw(void)  		mutex_lock(&tpacpi_inputdev_send_mutex);  		input_report_switch(tpacpi_inputdev, -				    SW_RADIO, !!wlsw); +				    SW_RFKILL_ALL, !!wlsw);  		input_sync(tpacpi_inputdev);  		mutex_unlock(&tpacpi_inputdev_send_mutex); @@ -1921,6 +1921,29 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {  	&dev_attr_hotkey_wakeup_hotunplug_complete.attr,  }; +static void hotkey_exit(void) +{ +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL +	hotkey_poll_stop_sync(); +#endif + +	if (hotkey_dev_attributes) +		delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); + +	kfree(hotkey_keycode_map); + +	if (tp_features.hotkey) { +		dbg_printk(TPACPI_DBG_EXIT, +			   "restoring original hot key mask\n"); +		/* no short-circuit boolean operator below! */ +		if ((hotkey_mask_set(hotkey_orig_mask) | +		     hotkey_status_set(hotkey_orig_status)) != 0) +			printk(TPACPI_ERR +			       "failed to restore hot key mask " +			       "to BIOS defaults\n"); +	} +} +  static int __init hotkey_init(struct ibm_init_struct *iibm)  {  	/* Requirements for changing the default keymaps: @@ -2060,226 +2083,220 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)  	vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",  		str_supported(tp_features.hotkey)); -	if (tp_features.hotkey) { -		hotkey_dev_attributes = create_attr_set(13, NULL); -		if (!hotkey_dev_attributes) -			return -ENOMEM; -		res = add_many_to_attr_set(hotkey_dev_attributes, -				hotkey_attributes, -				ARRAY_SIZE(hotkey_attributes)); -		if (res) -			return res; +	if (!tp_features.hotkey) +		return 1; -		/* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, -		   A30, R30, R31, T20-22, X20-21, X22-24.  Detected by checking -		   for HKEY interface version 0x100 */ -		if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { -			if ((hkeyv >> 8) != 1) { -				printk(TPACPI_ERR "unknown version of the " -				       "HKEY interface: 0x%x\n", hkeyv); -				printk(TPACPI_ERR "please report this to %s\n", -				       TPACPI_MAIL); -			} else { -				/* -				 * MHKV 0x100 in A31, R40, R40e, -				 * T4x, X31, and later -				 */ -				tp_features.hotkey_mask = 1; -			} +	hotkey_dev_attributes = create_attr_set(13, NULL); +	if (!hotkey_dev_attributes) +		return -ENOMEM; +	res = add_many_to_attr_set(hotkey_dev_attributes, +			hotkey_attributes, +			ARRAY_SIZE(hotkey_attributes)); +	if (res) +		goto err_exit; + +	/* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, +	   A30, R30, R31, T20-22, X20-21, X22-24.  Detected by checking +	   for HKEY interface version 0x100 */ +	if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { +		if ((hkeyv >> 8) != 1) { +			printk(TPACPI_ERR "unknown version of the " +			       "HKEY interface: 0x%x\n", hkeyv); +			printk(TPACPI_ERR "please report this to %s\n", +			       TPACPI_MAIL); +		} else { +			/* +			 * MHKV 0x100 in A31, R40, R40e, +			 * T4x, X31, and later +			 */ +			tp_features.hotkey_mask = 1;  		} +	} -		vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", -			str_supported(tp_features.hotkey_mask)); +	vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", +		str_supported(tp_features.hotkey_mask)); -		if (tp_features.hotkey_mask) { -			if (!acpi_evalf(hkey_handle, &hotkey_all_mask, -					"MHKA", "qd")) { -				printk(TPACPI_ERR -				       "missing MHKA handler, " -				       "please report this to %s\n", -				       TPACPI_MAIL); -				/* FN+F12, FN+F4, FN+F3 */ -				hotkey_all_mask = 0x080cU; -			} +	if (tp_features.hotkey_mask) { +		if (!acpi_evalf(hkey_handle, &hotkey_all_mask, +				"MHKA", "qd")) { +			printk(TPACPI_ERR +			       "missing MHKA handler, " +			       "please report this to %s\n", +			       TPACPI_MAIL); +			/* FN+F12, FN+F4, FN+F3 */ +			hotkey_all_mask = 0x080cU;  		} +	} -		/* hotkey_source_mask *must* be zero for -		 * the first hotkey_mask_get */ -		res = hotkey_status_get(&hotkey_orig_status); -		if (!res && tp_features.hotkey_mask) { -			res = hotkey_mask_get(); -			hotkey_orig_mask = hotkey_mask; -			if (!res) { -				res = add_many_to_attr_set( -					hotkey_dev_attributes, -					hotkey_mask_attributes, -					ARRAY_SIZE(hotkey_mask_attributes)); -			} -		} +	/* hotkey_source_mask *must* be zero for +	 * the first hotkey_mask_get */ +	res = hotkey_status_get(&hotkey_orig_status); +	if (res) +		goto err_exit; + +	if (tp_features.hotkey_mask) { +		res = hotkey_mask_get(); +		if (res) +			goto err_exit; + +		hotkey_orig_mask = hotkey_mask; +		res = add_many_to_attr_set( +				hotkey_dev_attributes, +				hotkey_mask_attributes, +				ARRAY_SIZE(hotkey_mask_attributes)); +		if (res) +			goto err_exit; +	}  #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL -		if (tp_features.hotkey_mask) { -			hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK -						& ~hotkey_all_mask; -		} else { -			hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; -		} +	if (tp_features.hotkey_mask) { +		hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK +					& ~hotkey_all_mask; +	} else { +		hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; +	} -		vdbg_printk(TPACPI_DBG_INIT, -			    "hotkey source mask 0x%08x, polling freq %d\n", -			    hotkey_source_mask, hotkey_poll_freq); +	vdbg_printk(TPACPI_DBG_INIT, +		    "hotkey source mask 0x%08x, polling freq %d\n", +		    hotkey_source_mask, hotkey_poll_freq);  #endif -		/* Not all thinkpads have a hardware radio switch */ -		if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { -			tp_features.hotkey_wlsw = 1; -			printk(TPACPI_INFO -				"radio switch found; radios are %s\n", -				enabled(status, 0)); -			res = add_to_attr_set(hotkey_dev_attributes, -					&dev_attr_hotkey_radio_sw.attr); -		} +	/* Not all thinkpads have a hardware radio switch */ +	if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { +		tp_features.hotkey_wlsw = 1; +		printk(TPACPI_INFO +			"radio switch found; radios are %s\n", +			enabled(status, 0)); +		res = add_to_attr_set(hotkey_dev_attributes, +				&dev_attr_hotkey_radio_sw.attr); +	} -		/* For X41t, X60t, X61t Tablets... */ -		if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { -			tp_features.hotkey_tablet = 1; -			printk(TPACPI_INFO -				"possible tablet mode switch found; " -				"ThinkPad in %s mode\n", -				(status & TP_HOTKEY_TABLET_MASK)? -					"tablet" : "laptop"); -			res = add_to_attr_set(hotkey_dev_attributes, -					&dev_attr_hotkey_tablet_mode.attr); -		} +	/* For X41t, X60t, X61t Tablets... */ +	if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { +		tp_features.hotkey_tablet = 1; +		printk(TPACPI_INFO +			"possible tablet mode switch found; " +			"ThinkPad in %s mode\n", +			(status & TP_HOTKEY_TABLET_MASK)? +				"tablet" : "laptop"); +		res = add_to_attr_set(hotkey_dev_attributes, +				&dev_attr_hotkey_tablet_mode.attr); +	} -		if (!res) -			res = register_attr_set_with_sysfs( -					hotkey_dev_attributes, -					&tpacpi_pdev->dev.kobj); -		if (res) -			return res; +	if (!res) +		res = register_attr_set_with_sysfs( +				hotkey_dev_attributes, +				&tpacpi_pdev->dev.kobj); +	if (res) +		goto err_exit; -		/* Set up key map */ +	/* Set up key map */ -		hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, -						GFP_KERNEL); -		if (!hotkey_keycode_map) { -			printk(TPACPI_ERR -				"failed to allocate memory for key map\n"); -			return -ENOMEM; -		} +	hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, +					GFP_KERNEL); +	if (!hotkey_keycode_map) { +		printk(TPACPI_ERR +			"failed to allocate memory for key map\n"); +		res = -ENOMEM; +		goto err_exit; +	} -		if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { -			dbg_printk(TPACPI_DBG_INIT, -				   "using Lenovo default hot key map\n"); -			memcpy(hotkey_keycode_map, &lenovo_keycode_map, -				TPACPI_HOTKEY_MAP_SIZE); +	if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { +		dbg_printk(TPACPI_DBG_INIT, +			   "using Lenovo default hot key map\n"); +		memcpy(hotkey_keycode_map, &lenovo_keycode_map, +			TPACPI_HOTKEY_MAP_SIZE); +	} else { +		dbg_printk(TPACPI_DBG_INIT, +			   "using IBM default hot key map\n"); +		memcpy(hotkey_keycode_map, &ibm_keycode_map, +			TPACPI_HOTKEY_MAP_SIZE); +	} + +	set_bit(EV_KEY, tpacpi_inputdev->evbit); +	set_bit(EV_MSC, tpacpi_inputdev->evbit); +	set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); +	tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; +	tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; +	tpacpi_inputdev->keycode = hotkey_keycode_map; +	for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { +		if (hotkey_keycode_map[i] != KEY_RESERVED) { +			set_bit(hotkey_keycode_map[i], +				tpacpi_inputdev->keybit);  		} else { -			dbg_printk(TPACPI_DBG_INIT, -				   "using IBM default hot key map\n"); -			memcpy(hotkey_keycode_map, &ibm_keycode_map, -				TPACPI_HOTKEY_MAP_SIZE); -		} - -		set_bit(EV_KEY, tpacpi_inputdev->evbit); -		set_bit(EV_MSC, tpacpi_inputdev->evbit); -		set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); -		tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; -		tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; -		tpacpi_inputdev->keycode = hotkey_keycode_map; -		for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { -			if (hotkey_keycode_map[i] != KEY_RESERVED) { -				set_bit(hotkey_keycode_map[i], -					tpacpi_inputdev->keybit); -			} else { -				if (i < sizeof(hotkey_reserved_mask)*8) -					hotkey_reserved_mask |= 1 << i; -			} -		} - -		if (tp_features.hotkey_wlsw) { -			set_bit(EV_SW, tpacpi_inputdev->evbit); -			set_bit(SW_RADIO, tpacpi_inputdev->swbit); -		} -		if (tp_features.hotkey_tablet) { -			set_bit(EV_SW, tpacpi_inputdev->evbit); -			set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); +			if (i < sizeof(hotkey_reserved_mask)*8) +				hotkey_reserved_mask |= 1 << i;  		} +	} -		/* Do not issue duplicate brightness change events to -		 * userspace */ -		if (!tp_features.bright_acpimode) -			/* update bright_acpimode... */ -			tpacpi_check_std_acpi_brightness_support(); - -		if (tp_features.bright_acpimode) { -			printk(TPACPI_INFO -			       "This ThinkPad has standard ACPI backlight " -			       "brightness control, supported by the ACPI " -			       "video driver\n"); -			printk(TPACPI_NOTICE -			       "Disabling thinkpad-acpi brightness events " -			       "by default...\n"); - -			/* The hotkey_reserved_mask change below is not -			 * necessary while the keys are at KEY_RESERVED in the -			 * default map, but better safe than sorry, leave it -			 * here as a marker of what we have to do, especially -			 * when we finally become able to set this at runtime -			 * on response to X.org requests */ -			hotkey_reserved_mask |= -				(1 << TP_ACPI_HOTKEYSCAN_FNHOME) -				| (1 << TP_ACPI_HOTKEYSCAN_FNEND); -		} +	if (tp_features.hotkey_wlsw) { +		set_bit(EV_SW, tpacpi_inputdev->evbit); +		set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit); +	} +	if (tp_features.hotkey_tablet) { +		set_bit(EV_SW, tpacpi_inputdev->evbit); +		set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); +	} -		dbg_printk(TPACPI_DBG_INIT, -				"enabling hot key handling\n"); -		res = hotkey_status_set(1); -		if (res) -			return res; -		res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) -					& ~hotkey_reserved_mask) -					| hotkey_orig_mask); -		if (res < 0 && res != -ENXIO) -			return res; +	/* Do not issue duplicate brightness change events to +	 * userspace */ +	if (!tp_features.bright_acpimode) +		/* update bright_acpimode... */ +		tpacpi_check_std_acpi_brightness_support(); -		dbg_printk(TPACPI_DBG_INIT, -				"legacy hot key reporting over procfs %s\n", -				(hotkey_report_mode < 2) ? -					"enabled" : "disabled"); +	if (tp_features.bright_acpimode) { +		printk(TPACPI_INFO +		       "This ThinkPad has standard ACPI backlight " +		       "brightness control, supported by the ACPI " +		       "video driver\n"); +		printk(TPACPI_NOTICE +		       "Disabling thinkpad-acpi brightness events " +		       "by default...\n"); + +		/* The hotkey_reserved_mask change below is not +		 * necessary while the keys are at KEY_RESERVED in the +		 * default map, but better safe than sorry, leave it +		 * here as a marker of what we have to do, especially +		 * when we finally become able to set this at runtime +		 * on response to X.org requests */ +		hotkey_reserved_mask |= +			(1 << TP_ACPI_HOTKEYSCAN_FNHOME) +			| (1 << TP_ACPI_HOTKEYSCAN_FNEND); +	} + +	dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); +	res = hotkey_status_set(1); +	if (res) { +		hotkey_exit(); +		return res; +	} +	res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) +				& ~hotkey_reserved_mask) +				| hotkey_orig_mask); +	if (res < 0 && res != -ENXIO) { +		hotkey_exit(); +		return res; +	} -		tpacpi_inputdev->open = &hotkey_inputdev_open; -		tpacpi_inputdev->close = &hotkey_inputdev_close; +	dbg_printk(TPACPI_DBG_INIT, +			"legacy hot key reporting over procfs %s\n", +			(hotkey_report_mode < 2) ? +				"enabled" : "disabled"); -		hotkey_poll_setup_safe(1); -		tpacpi_input_send_radiosw(); -		tpacpi_input_send_tabletsw(); -	} +	tpacpi_inputdev->open = &hotkey_inputdev_open; +	tpacpi_inputdev->close = &hotkey_inputdev_close; -	return (tp_features.hotkey)? 0 : 1; -} +	hotkey_poll_setup_safe(1); +	tpacpi_input_send_radiosw(); +	tpacpi_input_send_tabletsw(); -static void hotkey_exit(void) -{ -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL -	hotkey_poll_stop_sync(); -#endif +	return 0; -	if (tp_features.hotkey) { -		dbg_printk(TPACPI_DBG_EXIT, -			   "restoring original hot key mask\n"); -		/* no short-circuit boolean operator below! */ -		if ((hotkey_mask_set(hotkey_orig_mask) | -		     hotkey_status_set(hotkey_orig_status)) != 0) -			printk(TPACPI_ERR -			       "failed to restore hot key mask " -			       "to BIOS defaults\n"); -	} +err_exit: +	delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); +	hotkey_dev_attributes = NULL; -	if (hotkey_dev_attributes) { -		delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); -		hotkey_dev_attributes = NULL; -	} +	return (res < 0)? res : 1;  }  static void hotkey_notify(struct ibm_struct *ibm, u32 event) @@ -3319,7 +3336,7 @@ static struct tpacpi_led_classdev tpacpi_led_thinklight = {  static int __init light_init(struct ibm_init_struct *iibm)  { -	int rc = 0; +	int rc;  	vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); @@ -3337,20 +3354,23 @@ static int __init light_init(struct ibm_init_struct *iibm)  		tp_features.light_status =  			acpi_evalf(ec_handle, NULL, "KBLT", "qv"); -	vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", -		str_supported(tp_features.light)); +	vdbg_printk(TPACPI_DBG_INIT, "light is %s, light status is %s\n", +		str_supported(tp_features.light), +		str_supported(tp_features.light_status)); -	if (tp_features.light) { -		rc = led_classdev_register(&tpacpi_pdev->dev, -					   &tpacpi_led_thinklight.led_classdev); -	} +	if (!tp_features.light) +		return 1; + +	rc = led_classdev_register(&tpacpi_pdev->dev, +				   &tpacpi_led_thinklight.led_classdev);  	if (rc < 0) {  		tp_features.light = 0;  		tp_features.light_status = 0; -	} else { -		rc = (tp_features.light)? 0 : 1; +	} else  { +		rc = 0;  	} +  	return rc;  } @@ -3821,7 +3841,7 @@ TPACPI_HANDLE(led, ec, "SLED",	/* 570 */  #define TPACPI_LED_NUMLEDS 8  static struct tpacpi_led_classdev *tpacpi_leds;  static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS]; -static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = { +static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {  	/* there's a limit of 19 chars + NULL before 2.6.26 */  	"tpacpi::power",  	"tpacpi:orange:batt", @@ -3833,7 +3853,7 @@ static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = {  	"tpacpi::standby",  }; -static int led_get_status(unsigned int led) +static int led_get_status(const unsigned int led)  {  	int status;  	enum led_status_t led_s; @@ -3857,41 +3877,42 @@ static int led_get_status(unsigned int led)  	/* not reached */  } -static int led_set_status(unsigned int led, enum led_status_t ledstatus) +static int led_set_status(const unsigned int led, +			  const enum led_status_t ledstatus)  {  	/* off, on, blink. Index is led_status_t */ -	static const int const led_sled_arg1[] = { 0, 1, 3 }; -	static const int const led_exp_hlbl[] = { 0, 0, 1 };	/* led# * */ -	static const int const led_exp_hlcl[] = { 0, 1, 1 };	/* led# * */ -	static const int const led_led_arg1[] = { 0, 0x80, 0xc0 }; +	static const unsigned int led_sled_arg1[] = { 0, 1, 3 }; +	static const unsigned int led_led_arg1[] = { 0, 0x80, 0xc0 };  	int rc = 0;  	switch (led_supported) {  	case TPACPI_LED_570: -			/* 570 */ -			led = 1 << led; -			if (!acpi_evalf(led_handle, NULL, NULL, "vdd", -					led, led_sled_arg1[ledstatus])) -				rc = -EIO; -			break; +		/* 570 */ +		if (led > 7) +			return -EINVAL; +		if (!acpi_evalf(led_handle, NULL, NULL, "vdd", +				(1 << led), led_sled_arg1[ledstatus])) +			rc = -EIO; +		break;  	case TPACPI_LED_OLD: -			/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ -			led = 1 << led; -			rc = ec_write(TPACPI_LED_EC_HLMS, led); -			if (rc >= 0) -				rc = ec_write(TPACPI_LED_EC_HLBL, -					      led * led_exp_hlbl[ledstatus]); -			if (rc >= 0) -				rc = ec_write(TPACPI_LED_EC_HLCL, -					      led * led_exp_hlcl[ledstatus]); -			break; +		/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ +		if (led > 7) +			return -EINVAL; +		rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led)); +		if (rc >= 0) +			rc = ec_write(TPACPI_LED_EC_HLBL, +				      (ledstatus == TPACPI_LED_BLINK) << led); +		if (rc >= 0) +			rc = ec_write(TPACPI_LED_EC_HLCL, +				      (ledstatus != TPACPI_LED_OFF) << led); +		break;  	case TPACPI_LED_NEW: -			/* all others */ -			if (!acpi_evalf(led_handle, NULL, NULL, "vdd", -					led, led_led_arg1[ledstatus])) -				rc = -EIO; -			break; +		/* all others */ +		if (!acpi_evalf(led_handle, NULL, NULL, "vdd", +				led, led_led_arg1[ledstatus])) +			rc = -EIO; +		break;  	default:  		rc = -ENXIO;  	} @@ -3978,7 +3999,6 @@ static void led_exit(void)  	}  	kfree(tpacpi_leds); -	tpacpi_leds = NULL;  }  static int __init led_init(struct ibm_init_struct *iibm) @@ -4802,7 +4822,6 @@ static void brightness_exit(void)  		vdbg_printk(TPACPI_DBG_EXIT,  			    "calling backlight_device_unregister()\n");  		backlight_device_unregister(ibm_backlight_device); -		ibm_backlight_device = NULL;  	}  } @@ -5764,11 +5783,16 @@ static int __init fan_init(struct ibm_init_struct *iibm)  	    fan_control_access_mode != TPACPI_FAN_WR_NONE) {  		rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj,  					 &fan_attr_group); -		if (!(rc < 0)) -			rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, -					&driver_attr_fan_watchdog);  		if (rc < 0)  			return rc; + +		rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, +					&driver_attr_fan_watchdog); +		if (rc < 0) { +			sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, +					&fan_attr_group); +			return rc; +		}  		return 0;  	} else  		return 1;  | 
