brintos

brintos / linux-shallow public Read only

0
0
Text · 35.2 KiB · 03319a8 Raw
1509 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  eeepc-laptop.c - Asus Eee PC extras4 *5 *  Based on asus_acpi.c as patched for the Eee PC by Asus:6 *  ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar7 *  Based on eee.c from eeepc-linux8 */9 10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt11 12#include <linux/kernel.h>13#include <linux/module.h>14#include <linux/init.h>15#include <linux/types.h>16#include <linux/platform_device.h>17#include <linux/backlight.h>18#include <linux/hwmon.h>19#include <linux/hwmon-sysfs.h>20#include <linux/slab.h>21#include <linux/acpi.h>22#include <linux/uaccess.h>23#include <linux/input.h>24#include <linux/input/sparse-keymap.h>25#include <linux/rfkill.h>26#include <linux/pci.h>27#include <linux/pci_hotplug.h>28#include <linux/leds.h>29#include <linux/dmi.h>30#include <acpi/video.h>31 32#define EEEPC_LAPTOP_VERSION	"0.1"33#define EEEPC_LAPTOP_NAME	"Eee PC Hotkey Driver"34#define EEEPC_LAPTOP_FILE	"eeepc"35 36#define EEEPC_ACPI_CLASS	"hotkey"37#define EEEPC_ACPI_DEVICE_NAME	"Hotkey"38#define EEEPC_ACPI_HID		"ASUS010"39 40MODULE_AUTHOR("Corentin Chary, Eric Cooper");41MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME);42MODULE_LICENSE("GPL");43 44static bool hotplug_disabled;45 46module_param(hotplug_disabled, bool, 0444);47MODULE_PARM_DESC(hotplug_disabled,48		 "Disable hotplug for wireless device. "49		 "If your laptop need that, please report to "50		 "acpi4asus-user@lists.sourceforge.net.");51 52/*53 * Definitions for Asus EeePC54 */55#define NOTIFY_BRN_MIN	0x2056#define NOTIFY_BRN_MAX	0x2f57 58enum {59	DISABLE_ASL_WLAN = 0x0001,60	DISABLE_ASL_BLUETOOTH = 0x0002,61	DISABLE_ASL_IRDA = 0x0004,62	DISABLE_ASL_CAMERA = 0x0008,63	DISABLE_ASL_TV = 0x0010,64	DISABLE_ASL_GPS = 0x0020,65	DISABLE_ASL_DISPLAYSWITCH = 0x0040,66	DISABLE_ASL_MODEM = 0x0080,67	DISABLE_ASL_CARDREADER = 0x0100,68	DISABLE_ASL_3G = 0x0200,69	DISABLE_ASL_WIMAX = 0x0400,70	DISABLE_ASL_HWCF = 0x080071};72 73enum {74	CM_ASL_WLAN = 0,75	CM_ASL_BLUETOOTH,76	CM_ASL_IRDA,77	CM_ASL_1394,78	CM_ASL_CAMERA,79	CM_ASL_TV,80	CM_ASL_GPS,81	CM_ASL_DVDROM,82	CM_ASL_DISPLAYSWITCH,83	CM_ASL_PANELBRIGHT,84	CM_ASL_BIOSFLASH,85	CM_ASL_ACPIFLASH,86	CM_ASL_CPUFV,87	CM_ASL_CPUTEMPERATURE,88	CM_ASL_FANCPU,89	CM_ASL_FANCHASSIS,90	CM_ASL_USBPORT1,91	CM_ASL_USBPORT2,92	CM_ASL_USBPORT3,93	CM_ASL_MODEM,94	CM_ASL_CARDREADER,95	CM_ASL_3G,96	CM_ASL_WIMAX,97	CM_ASL_HWCF,98	CM_ASL_LID,99	CM_ASL_TYPE,100	CM_ASL_PANELPOWER,	/*P901*/101	CM_ASL_TPD102};103 104static const char *cm_getv[] = {105	"WLDG", "BTHG", NULL, NULL,106	"CAMG", NULL, NULL, NULL,107	NULL, "PBLG", NULL, NULL,108	"CFVG", NULL, NULL, NULL,109	"USBG", NULL, NULL, "MODG",110	"CRDG", "M3GG", "WIMG", "HWCF",111	"LIDG",	"TYPE", "PBPG",	"TPDG"112};113 114static const char *cm_setv[] = {115	"WLDS", "BTHS", NULL, NULL,116	"CAMS", NULL, NULL, NULL,117	"SDSP", "PBLS", "HDPS", NULL,118	"CFVS", NULL, NULL, NULL,119	"USBG", NULL, NULL, "MODS",120	"CRDS", "M3GS", "WIMS", NULL,121	NULL, NULL, "PBPS", "TPDS"122};123 124static const struct key_entry eeepc_keymap[] = {125	{ KE_KEY, 0x10, { KEY_WLAN } },126	{ KE_KEY, 0x11, { KEY_WLAN } },127	{ KE_KEY, 0x12, { KEY_PROG1 } },128	{ KE_KEY, 0x13, { KEY_MUTE } },129	{ KE_KEY, 0x14, { KEY_VOLUMEDOWN } },130	{ KE_KEY, 0x15, { KEY_VOLUMEUP } },131	{ KE_KEY, 0x16, { KEY_DISPLAY_OFF } },132	{ KE_KEY, 0x1a, { KEY_COFFEE } },133	{ KE_KEY, 0x1b, { KEY_ZOOM } },134	{ KE_KEY, 0x1c, { KEY_PROG2 } },135	{ KE_KEY, 0x1d, { KEY_PROG3 } },136	{ KE_KEY, NOTIFY_BRN_MIN, { KEY_BRIGHTNESSDOWN } },137	{ KE_KEY, NOTIFY_BRN_MAX, { KEY_BRIGHTNESSUP } },138	{ KE_KEY, 0x30, { KEY_SWITCHVIDEOMODE } },139	{ KE_KEY, 0x31, { KEY_SWITCHVIDEOMODE } },140	{ KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } },141	{ KE_KEY, 0x37, { KEY_F13 } }, /* Disable Touchpad */142	{ KE_KEY, 0x38, { KEY_F14 } },143	{ KE_IGNORE, 0x50, { KEY_RESERVED } }, /* AC plugged */144	{ KE_IGNORE, 0x51, { KEY_RESERVED } }, /* AC unplugged */145	{ KE_END, 0 },146};147 148/*149 * This is the main structure, we can use it to store useful information150 */151struct eeepc_laptop {152	acpi_handle handle;		/* the handle of the acpi device */153	u32 cm_supported;		/* the control methods supported154					   by this BIOS */155	bool cpufv_disabled;156	bool hotplug_disabled;157	u16 event_count[128];		/* count for each event */158 159	struct platform_device *platform_device;160	struct acpi_device *device;		/* the device we are in */161	struct backlight_device *backlight_device;162 163	struct input_dev *inputdev;164 165	struct rfkill *wlan_rfkill;166	struct rfkill *bluetooth_rfkill;167	struct rfkill *wwan3g_rfkill;168	struct rfkill *wimax_rfkill;169 170	struct hotplug_slot hotplug_slot;171	struct mutex hotplug_lock;172 173	struct led_classdev tpd_led;174	int tpd_led_wk;175	struct workqueue_struct *led_workqueue;176	struct work_struct tpd_led_work;177};178 179/*180 * ACPI Helpers181 */182static int write_acpi_int(acpi_handle handle, const char *method, int val)183{184	acpi_status status;185 186	status = acpi_execute_simple_method(handle, (char *)method, val);187 188	return (status == AE_OK ? 0 : -1);189}190 191static int read_acpi_int(acpi_handle handle, const char *method, int *val)192{193	acpi_status status;194	unsigned long long result;195 196	status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);197	if (ACPI_FAILURE(status)) {198		*val = -1;199		return -1;200	} else {201		*val = result;202		return 0;203	}204}205 206static int set_acpi(struct eeepc_laptop *eeepc, int cm, int value)207{208	const char *method = cm_setv[cm];209 210	if (method == NULL)211		return -ENODEV;212	if ((eeepc->cm_supported & (0x1 << cm)) == 0)213		return -ENODEV;214 215	if (write_acpi_int(eeepc->handle, method, value))216		pr_warn("Error writing %s\n", method);217	return 0;218}219 220static int get_acpi(struct eeepc_laptop *eeepc, int cm)221{222	const char *method = cm_getv[cm];223	int value;224 225	if (method == NULL)226		return -ENODEV;227	if ((eeepc->cm_supported & (0x1 << cm)) == 0)228		return -ENODEV;229 230	if (read_acpi_int(eeepc->handle, method, &value))231		pr_warn("Error reading %s\n", method);232	return value;233}234 235static int acpi_setter_handle(struct eeepc_laptop *eeepc, int cm,236			      acpi_handle *handle)237{238	const char *method = cm_setv[cm];239	acpi_status status;240 241	if (method == NULL)242		return -ENODEV;243	if ((eeepc->cm_supported & (0x1 << cm)) == 0)244		return -ENODEV;245 246	status = acpi_get_handle(eeepc->handle, (char *)method,247				 handle);248	if (status != AE_OK) {249		pr_warn("Error finding %s\n", method);250		return -ENODEV;251	}252	return 0;253}254 255 256/*257 * Sys helpers258 */259static int parse_arg(const char *buf, int *val)260{261	if (sscanf(buf, "%i", val) != 1)262		return -EINVAL;263	return 0;264}265 266static ssize_t store_sys_acpi(struct device *dev, int cm,267			      const char *buf, size_t count)268{269	struct eeepc_laptop *eeepc = dev_get_drvdata(dev);270	int rv, value;271 272	rv = parse_arg(buf, &value);273	if (rv < 0)274		return rv;275	rv = set_acpi(eeepc, cm, value);276	if (rv < 0)277		return -EIO;278	return count;279}280 281static ssize_t show_sys_acpi(struct device *dev, int cm, char *buf)282{283	struct eeepc_laptop *eeepc = dev_get_drvdata(dev);284	int value = get_acpi(eeepc, cm);285 286	if (value < 0)287		return -EIO;288	return sprintf(buf, "%d\n", value);289}290 291#define EEEPC_ACPI_SHOW_FUNC(_name, _cm)				\292	static ssize_t _name##_show(struct device *dev,			\293				    struct device_attribute *attr,	\294				    char *buf)				\295	{								\296		return show_sys_acpi(dev, _cm, buf);			\297	}298 299#define EEEPC_ACPI_STORE_FUNC(_name, _cm)				\300	static ssize_t _name##_store(struct device *dev,		\301				     struct device_attribute *attr,	\302				     const char *buf, size_t count)	\303	{								\304		return store_sys_acpi(dev, _cm, buf, count);		\305	}306 307#define EEEPC_CREATE_DEVICE_ATTR_RW(_name, _cm)				\308	EEEPC_ACPI_SHOW_FUNC(_name, _cm)				\309	EEEPC_ACPI_STORE_FUNC(_name, _cm)				\310	static DEVICE_ATTR_RW(_name)311 312#define EEEPC_CREATE_DEVICE_ATTR_WO(_name, _cm)				\313	EEEPC_ACPI_STORE_FUNC(_name, _cm)				\314	static DEVICE_ATTR_WO(_name)315 316EEEPC_CREATE_DEVICE_ATTR_RW(camera, CM_ASL_CAMERA);317EEEPC_CREATE_DEVICE_ATTR_RW(cardr, CM_ASL_CARDREADER);318EEEPC_CREATE_DEVICE_ATTR_WO(disp, CM_ASL_DISPLAYSWITCH);319 320struct eeepc_cpufv {321	int num;322	int cur;323};324 325static int get_cpufv(struct eeepc_laptop *eeepc, struct eeepc_cpufv *c)326{327	c->cur = get_acpi(eeepc, CM_ASL_CPUFV);328	if (c->cur < 0)329		return -ENODEV;330 331	c->num = (c->cur >> 8) & 0xff;332	c->cur &= 0xff;333	if (c->num == 0 || c->num > 12)334		return -ENODEV;335	return 0;336}337 338static ssize_t available_cpufv_show(struct device *dev,339				    struct device_attribute *attr,340				    char *buf)341{342	struct eeepc_laptop *eeepc = dev_get_drvdata(dev);343	struct eeepc_cpufv c;344	int i;345	ssize_t len = 0;346 347	if (get_cpufv(eeepc, &c))348		return -ENODEV;349	for (i = 0; i < c.num; i++)350		len += sprintf(buf + len, "%d ", i);351	len += sprintf(buf + len, "\n");352	return len;353}354 355static ssize_t cpufv_show(struct device *dev,356			  struct device_attribute *attr,357			  char *buf)358{359	struct eeepc_laptop *eeepc = dev_get_drvdata(dev);360	struct eeepc_cpufv c;361 362	if (get_cpufv(eeepc, &c))363		return -ENODEV;364	return sprintf(buf, "%#x\n", (c.num << 8) | c.cur);365}366 367static ssize_t cpufv_store(struct device *dev,368			   struct device_attribute *attr,369			   const char *buf, size_t count)370{371	struct eeepc_laptop *eeepc = dev_get_drvdata(dev);372	struct eeepc_cpufv c;373	int rv, value;374 375	if (eeepc->cpufv_disabled)376		return -EPERM;377	if (get_cpufv(eeepc, &c))378		return -ENODEV;379	rv = parse_arg(buf, &value);380	if (rv < 0)381		return rv;382	if (value < 0 || value >= c.num)383		return -EINVAL;384	rv = set_acpi(eeepc, CM_ASL_CPUFV, value);385	if (rv)386		return rv;387	return count;388}389 390static ssize_t cpufv_disabled_show(struct device *dev,391			  struct device_attribute *attr,392			  char *buf)393{394	struct eeepc_laptop *eeepc = dev_get_drvdata(dev);395 396	return sprintf(buf, "%d\n", eeepc->cpufv_disabled);397}398 399static ssize_t cpufv_disabled_store(struct device *dev,400			   struct device_attribute *attr,401			   const char *buf, size_t count)402{403	struct eeepc_laptop *eeepc = dev_get_drvdata(dev);404	int rv, value;405 406	rv = parse_arg(buf, &value);407	if (rv < 0)408		return rv;409 410	switch (value) {411	case 0:412		if (eeepc->cpufv_disabled)413			pr_warn("cpufv enabled (not officially supported on this model)\n");414		eeepc->cpufv_disabled = false;415		return count;416	case 1:417		return -EPERM;418	default:419		return -EINVAL;420	}421}422 423 424static DEVICE_ATTR_RW(cpufv);425static DEVICE_ATTR_RO(available_cpufv);426static DEVICE_ATTR_RW(cpufv_disabled);427 428static struct attribute *platform_attributes[] = {429	&dev_attr_camera.attr,430	&dev_attr_cardr.attr,431	&dev_attr_disp.attr,432	&dev_attr_cpufv.attr,433	&dev_attr_available_cpufv.attr,434	&dev_attr_cpufv_disabled.attr,435	NULL436};437 438static const struct attribute_group platform_attribute_group = {439	.attrs = platform_attributes440};441 442static int eeepc_platform_init(struct eeepc_laptop *eeepc)443{444	int result;445 446	eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, PLATFORM_DEVID_NONE);447	if (!eeepc->platform_device)448		return -ENOMEM;449	platform_set_drvdata(eeepc->platform_device, eeepc);450 451	result = platform_device_add(eeepc->platform_device);452	if (result)453		goto fail_platform_device;454 455	result = sysfs_create_group(&eeepc->platform_device->dev.kobj,456				    &platform_attribute_group);457	if (result)458		goto fail_sysfs;459	return 0;460 461fail_sysfs:462	platform_device_del(eeepc->platform_device);463fail_platform_device:464	platform_device_put(eeepc->platform_device);465	return result;466}467 468static void eeepc_platform_exit(struct eeepc_laptop *eeepc)469{470	sysfs_remove_group(&eeepc->platform_device->dev.kobj,471			   &platform_attribute_group);472	platform_device_unregister(eeepc->platform_device);473}474 475/*476 * LEDs477 */478/*479 * These functions actually update the LED's, and are called from a480 * workqueue. By doing this as separate work rather than when the LED481 * subsystem asks, we avoid messing with the Asus ACPI stuff during a482 * potentially bad time, such as a timer interrupt.483 */484static void tpd_led_update(struct work_struct *work)485{486	struct eeepc_laptop *eeepc;487 488	eeepc = container_of(work, struct eeepc_laptop, tpd_led_work);489 490	set_acpi(eeepc, CM_ASL_TPD, eeepc->tpd_led_wk);491}492 493static void tpd_led_set(struct led_classdev *led_cdev,494			enum led_brightness value)495{496	struct eeepc_laptop *eeepc;497 498	eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);499 500	eeepc->tpd_led_wk = (value > 0) ? 1 : 0;501	queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);502}503 504static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)505{506	struct eeepc_laptop *eeepc;507 508	eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);509 510	return get_acpi(eeepc, CM_ASL_TPD);511}512 513static int eeepc_led_init(struct eeepc_laptop *eeepc)514{515	int rv;516 517	if (get_acpi(eeepc, CM_ASL_TPD) == -ENODEV)518		return 0;519 520	eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");521	if (!eeepc->led_workqueue)522		return -ENOMEM;523	INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);524 525	eeepc->tpd_led.name = "eeepc::touchpad";526	eeepc->tpd_led.brightness_set = tpd_led_set;527	if (get_acpi(eeepc, CM_ASL_TPD) >= 0) /* if method is available */528		eeepc->tpd_led.brightness_get = tpd_led_get;529	eeepc->tpd_led.max_brightness = 1;530 531	rv = led_classdev_register(&eeepc->platform_device->dev,532				   &eeepc->tpd_led);533	if (rv) {534		destroy_workqueue(eeepc->led_workqueue);535		return rv;536	}537 538	return 0;539}540 541static void eeepc_led_exit(struct eeepc_laptop *eeepc)542{543	led_classdev_unregister(&eeepc->tpd_led);544	if (eeepc->led_workqueue)545		destroy_workqueue(eeepc->led_workqueue);546}547 548/*549 * PCI hotplug (for wlan rfkill)550 */551static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc)552{553	if (get_acpi(eeepc, CM_ASL_WLAN) == 1)554		return false;555	return true;556}557 558static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)559{560	struct pci_dev *port;561	struct pci_dev *dev;562	struct pci_bus *bus;563	bool blocked = eeepc_wlan_rfkill_blocked(eeepc);564	bool absent;565	u32 l;566 567	if (eeepc->wlan_rfkill)568		rfkill_set_sw_state(eeepc->wlan_rfkill, blocked);569 570	mutex_lock(&eeepc->hotplug_lock);571	pci_lock_rescan_remove();572 573	if (!eeepc->hotplug_slot.ops)574		goto out_unlock;575 576	port = acpi_get_pci_dev(handle);577	if (!port) {578		pr_warn("Unable to find port\n");579		goto out_unlock;580	}581 582	bus = port->subordinate;583 584	if (!bus) {585		pr_warn("Unable to find PCI bus 1?\n");586		goto out_put_dev;587	}588 589	if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {590		pr_err("Unable to read PCI config space?\n");591		goto out_put_dev;592	}593 594	absent = (l == 0xffffffff);595 596	if (blocked != absent) {597		pr_warn("BIOS says wireless lan is %s, but the pci device is %s\n",598			blocked ? "blocked" : "unblocked",599			absent ? "absent" : "present");600		pr_warn("skipped wireless hotplug as probably inappropriate for this model\n");601		goto out_put_dev;602	}603 604	if (!blocked) {605		dev = pci_get_slot(bus, 0);606		if (dev) {607			/* Device already present */608			pci_dev_put(dev);609			goto out_put_dev;610		}611		dev = pci_scan_single_device(bus, 0);612		if (dev) {613			pci_bus_assign_resources(bus);614			pci_bus_add_device(dev);615		}616	} else {617		dev = pci_get_slot(bus, 0);618		if (dev) {619			pci_stop_and_remove_bus_device(dev);620			pci_dev_put(dev);621		}622	}623out_put_dev:624	pci_dev_put(port);625 626out_unlock:627	pci_unlock_rescan_remove();628	mutex_unlock(&eeepc->hotplug_lock);629}630 631static void eeepc_rfkill_hotplug_update(struct eeepc_laptop *eeepc, char *node)632{633	acpi_status status = AE_OK;634	acpi_handle handle;635 636	status = acpi_get_handle(NULL, node, &handle);637 638	if (ACPI_SUCCESS(status))639		eeepc_rfkill_hotplug(eeepc, handle);640}641 642static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)643{644	struct eeepc_laptop *eeepc = data;645 646	if (event != ACPI_NOTIFY_BUS_CHECK)647		return;648 649	eeepc_rfkill_hotplug(eeepc, handle);650}651 652static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc,653					  char *node)654{655	acpi_status status;656	acpi_handle handle;657 658	status = acpi_get_handle(NULL, node, &handle);659 660	if (ACPI_FAILURE(status))661		return -ENODEV;662 663	status = acpi_install_notify_handler(handle,664					     ACPI_SYSTEM_NOTIFY,665					     eeepc_rfkill_notify,666					     eeepc);667	if (ACPI_FAILURE(status))668		pr_warn("Failed to register notify on %s\n", node);669 670	/*671	 * Refresh pci hotplug in case the rfkill state was672	 * changed during setup.673	 */674	eeepc_rfkill_hotplug(eeepc, handle);675	return 0;676}677 678static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc,679					     char *node)680{681	acpi_status status = AE_OK;682	acpi_handle handle;683 684	status = acpi_get_handle(NULL, node, &handle);685 686	if (ACPI_FAILURE(status))687		return;688 689	status = acpi_remove_notify_handler(handle,690					     ACPI_SYSTEM_NOTIFY,691					     eeepc_rfkill_notify);692	if (ACPI_FAILURE(status))693		pr_err("Error removing rfkill notify handler %s\n",694			node);695		/*696		 * Refresh pci hotplug in case the rfkill697		 * state was changed after698		 * eeepc_unregister_rfkill_notifier()699		 */700	eeepc_rfkill_hotplug(eeepc, handle);701}702 703static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,704				    u8 *value)705{706	struct eeepc_laptop *eeepc;707	int val;708 709	eeepc = container_of(hotplug_slot, struct eeepc_laptop, hotplug_slot);710	val = get_acpi(eeepc, CM_ASL_WLAN);711 712	if (val == 1 || val == 0)713		*value = val;714	else715		return -EINVAL;716 717	return 0;718}719 720static const struct hotplug_slot_ops eeepc_hotplug_slot_ops = {721	.get_adapter_status = eeepc_get_adapter_status,722	.get_power_status = eeepc_get_adapter_status,723};724 725static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc)726{727	int ret = -ENOMEM;728	struct pci_bus *bus = pci_find_bus(0, 1);729 730	if (!bus) {731		pr_err("Unable to find wifi PCI bus\n");732		return -ENODEV;733	}734 735	eeepc->hotplug_slot.ops = &eeepc_hotplug_slot_ops;736 737	ret = pci_hp_register(&eeepc->hotplug_slot, bus, 0, "eeepc-wifi");738	if (ret) {739		pr_err("Unable to register hotplug slot - %d\n", ret);740		goto error_register;741	}742 743	return 0;744 745error_register:746	eeepc->hotplug_slot.ops = NULL;747	return ret;748}749 750/*751 * Rfkill devices752 */753static int eeepc_rfkill_set(void *data, bool blocked)754{755	acpi_handle handle = data;756 757	return write_acpi_int(handle, NULL, !blocked);758}759 760static const struct rfkill_ops eeepc_rfkill_ops = {761	.set_block = eeepc_rfkill_set,762};763 764static int eeepc_new_rfkill(struct eeepc_laptop *eeepc,765			    struct rfkill **rfkill,766			    const char *name,767			    enum rfkill_type type, int cm)768{769	acpi_handle handle;770	int result;771 772	result = acpi_setter_handle(eeepc, cm, &handle);773	if (result < 0)774		return result;775 776	*rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,777			       &eeepc_rfkill_ops, handle);778 779	if (!*rfkill)780		return -EINVAL;781 782	rfkill_init_sw_state(*rfkill, get_acpi(eeepc, cm) != 1);783	result = rfkill_register(*rfkill);784	if (result) {785		rfkill_destroy(*rfkill);786		*rfkill = NULL;787		return result;788	}789	return 0;790}791 792static char EEEPC_RFKILL_NODE_1[] = "\\_SB.PCI0.P0P5";793static char EEEPC_RFKILL_NODE_2[] = "\\_SB.PCI0.P0P6";794static char EEEPC_RFKILL_NODE_3[] = "\\_SB.PCI0.P0P7";795 796static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc)797{798	eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_1);799	eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_2);800	eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_3);801	if (eeepc->wlan_rfkill) {802		rfkill_unregister(eeepc->wlan_rfkill);803		rfkill_destroy(eeepc->wlan_rfkill);804		eeepc->wlan_rfkill = NULL;805	}806 807	if (eeepc->hotplug_slot.ops)808		pci_hp_deregister(&eeepc->hotplug_slot);809 810	if (eeepc->bluetooth_rfkill) {811		rfkill_unregister(eeepc->bluetooth_rfkill);812		rfkill_destroy(eeepc->bluetooth_rfkill);813		eeepc->bluetooth_rfkill = NULL;814	}815	if (eeepc->wwan3g_rfkill) {816		rfkill_unregister(eeepc->wwan3g_rfkill);817		rfkill_destroy(eeepc->wwan3g_rfkill);818		eeepc->wwan3g_rfkill = NULL;819	}820	if (eeepc->wimax_rfkill) {821		rfkill_unregister(eeepc->wimax_rfkill);822		rfkill_destroy(eeepc->wimax_rfkill);823		eeepc->wimax_rfkill = NULL;824	}825}826 827static int eeepc_rfkill_init(struct eeepc_laptop *eeepc)828{829	int result = 0;830 831	mutex_init(&eeepc->hotplug_lock);832 833	result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,834				  "eeepc-wlan", RFKILL_TYPE_WLAN,835				  CM_ASL_WLAN);836 837	if (result && result != -ENODEV)838		goto exit;839 840	result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,841				  "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,842				  CM_ASL_BLUETOOTH);843 844	if (result && result != -ENODEV)845		goto exit;846 847	result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,848				  "eeepc-wwan3g", RFKILL_TYPE_WWAN,849				  CM_ASL_3G);850 851	if (result && result != -ENODEV)852		goto exit;853 854	result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill,855				  "eeepc-wimax", RFKILL_TYPE_WIMAX,856				  CM_ASL_WIMAX);857 858	if (result && result != -ENODEV)859		goto exit;860 861	if (eeepc->hotplug_disabled)862		return 0;863 864	result = eeepc_setup_pci_hotplug(eeepc);865	/*866	 * If we get -EBUSY then something else is handling the PCI hotplug -867	 * don't fail in this case868	 */869	if (result == -EBUSY)870		result = 0;871 872	eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_1);873	eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_2);874	eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_3);875 876exit:877	if (result && result != -ENODEV)878		eeepc_rfkill_exit(eeepc);879	return result;880}881 882/*883 * Platform driver - hibernate/resume callbacks884 */885static int eeepc_hotk_thaw(struct device *device)886{887	struct eeepc_laptop *eeepc = dev_get_drvdata(device);888 889	if (eeepc->wlan_rfkill) {890		int wlan;891 892		/*893		 * Work around bios bug - acpi _PTS turns off the wireless led894		 * during suspend.  Normally it restores it on resume, but895		 * we should kick it ourselves in case hibernation is aborted.896		 */897		wlan = get_acpi(eeepc, CM_ASL_WLAN);898		if (wlan >= 0)899			set_acpi(eeepc, CM_ASL_WLAN, wlan);900	}901 902	return 0;903}904 905static int eeepc_hotk_restore(struct device *device)906{907	struct eeepc_laptop *eeepc = dev_get_drvdata(device);908 909	/* Refresh both wlan rfkill state and pci hotplug */910	if (eeepc->wlan_rfkill) {911		eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_1);912		eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_2);913		eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_3);914	}915 916	if (eeepc->bluetooth_rfkill)917		rfkill_set_sw_state(eeepc->bluetooth_rfkill,918				    get_acpi(eeepc, CM_ASL_BLUETOOTH) != 1);919	if (eeepc->wwan3g_rfkill)920		rfkill_set_sw_state(eeepc->wwan3g_rfkill,921				    get_acpi(eeepc, CM_ASL_3G) != 1);922	if (eeepc->wimax_rfkill)923		rfkill_set_sw_state(eeepc->wimax_rfkill,924				    get_acpi(eeepc, CM_ASL_WIMAX) != 1);925 926	return 0;927}928 929static const struct dev_pm_ops eeepc_pm_ops = {930	.thaw = eeepc_hotk_thaw,931	.restore = eeepc_hotk_restore,932};933 934static struct platform_driver platform_driver = {935	.driver = {936		.name = EEEPC_LAPTOP_FILE,937		.pm = &eeepc_pm_ops,938	}939};940 941/*942 * Hwmon device943 */944 945#define EEEPC_EC_SC00      0x61946#define EEEPC_EC_FAN_PWM   (EEEPC_EC_SC00 + 2) /* Fan PWM duty cycle (%) */947#define EEEPC_EC_FAN_HRPM  (EEEPC_EC_SC00 + 5) /* High byte, fan speed (RPM) */948#define EEEPC_EC_FAN_LRPM  (EEEPC_EC_SC00 + 6) /* Low byte, fan speed (RPM) */949 950#define EEEPC_EC_SFB0      0xD0951#define EEEPC_EC_FAN_CTRL  (EEEPC_EC_SFB0 + 3) /* Byte containing SF25  */952 953static inline int eeepc_pwm_to_lmsensors(int value)954{955	return value * 255 / 100;956}957 958static inline int eeepc_lmsensors_to_pwm(int value)959{960	value = clamp_val(value, 0, 255);961	return value * 100 / 255;962}963 964static int eeepc_get_fan_pwm(void)965{966	u8 value = 0;967 968	ec_read(EEEPC_EC_FAN_PWM, &value);969	return eeepc_pwm_to_lmsensors(value);970}971 972static void eeepc_set_fan_pwm(int value)973{974	value = eeepc_lmsensors_to_pwm(value);975	ec_write(EEEPC_EC_FAN_PWM, value);976}977 978static int eeepc_get_fan_rpm(void)979{980	u8 high = 0;981	u8 low = 0;982 983	ec_read(EEEPC_EC_FAN_HRPM, &high);984	ec_read(EEEPC_EC_FAN_LRPM, &low);985	return high << 8 | low;986}987 988#define EEEPC_EC_FAN_CTRL_BIT	0x02989#define EEEPC_FAN_CTRL_MANUAL	1990#define EEEPC_FAN_CTRL_AUTO	2991 992static int eeepc_get_fan_ctrl(void)993{994	u8 value = 0;995 996	ec_read(EEEPC_EC_FAN_CTRL, &value);997	if (value & EEEPC_EC_FAN_CTRL_BIT)998		return EEEPC_FAN_CTRL_MANUAL;999	else1000		return EEEPC_FAN_CTRL_AUTO;1001}1002 1003static void eeepc_set_fan_ctrl(int manual)1004{1005	u8 value = 0;1006 1007	ec_read(EEEPC_EC_FAN_CTRL, &value);1008	if (manual == EEEPC_FAN_CTRL_MANUAL)1009		value |= EEEPC_EC_FAN_CTRL_BIT;1010	else1011		value &= ~EEEPC_EC_FAN_CTRL_BIT;1012	ec_write(EEEPC_EC_FAN_CTRL, value);1013}1014 1015static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)1016{1017	int rv, value;1018 1019	rv = parse_arg(buf, &value);1020	if (rv < 0)1021		return rv;1022	set(value);1023	return count;1024}1025 1026static ssize_t show_sys_hwmon(int (*get)(void), char *buf)1027{1028	return sprintf(buf, "%d\n", get());1029}1030 1031#define EEEPC_SENSOR_SHOW_FUNC(_name, _get)				\1032	static ssize_t _name##_show(struct device *dev,			\1033				    struct device_attribute *attr,	\1034				    char *buf)				\1035	{								\1036		return show_sys_hwmon(_get, buf);			\1037	}1038 1039#define EEEPC_SENSOR_STORE_FUNC(_name, _set)				\1040	static ssize_t _name##_store(struct device *dev,		\1041				     struct device_attribute *attr,	\1042				     const char *buf, size_t count)	\1043	{								\1044		return store_sys_hwmon(_set, buf, count);		\1045	}1046 1047#define EEEPC_CREATE_SENSOR_ATTR_RW(_name, _get, _set)			\1048	EEEPC_SENSOR_SHOW_FUNC(_name, _get)				\1049	EEEPC_SENSOR_STORE_FUNC(_name, _set)				\1050	static DEVICE_ATTR_RW(_name)1051 1052#define EEEPC_CREATE_SENSOR_ATTR_RO(_name, _get)			\1053	EEEPC_SENSOR_SHOW_FUNC(_name, _get)				\1054	static DEVICE_ATTR_RO(_name)1055 1056EEEPC_CREATE_SENSOR_ATTR_RO(fan1_input, eeepc_get_fan_rpm);1057EEEPC_CREATE_SENSOR_ATTR_RW(pwm1, eeepc_get_fan_pwm,1058			    eeepc_set_fan_pwm);1059EEEPC_CREATE_SENSOR_ATTR_RW(pwm1_enable, eeepc_get_fan_ctrl,1060			    eeepc_set_fan_ctrl);1061 1062static struct attribute *hwmon_attrs[] = {1063	&dev_attr_pwm1.attr,1064	&dev_attr_fan1_input.attr,1065	&dev_attr_pwm1_enable.attr,1066	NULL1067};1068ATTRIBUTE_GROUPS(hwmon);1069 1070static int eeepc_hwmon_init(struct eeepc_laptop *eeepc)1071{1072	struct device *dev = &eeepc->platform_device->dev;1073	struct device *hwmon;1074 1075	hwmon = devm_hwmon_device_register_with_groups(dev, "eeepc", NULL,1076						       hwmon_groups);1077	if (IS_ERR(hwmon)) {1078		pr_err("Could not register eeepc hwmon device\n");1079		return PTR_ERR(hwmon);1080	}1081	return 0;1082}1083 1084/*1085 * Backlight device1086 */1087static int read_brightness(struct backlight_device *bd)1088{1089	struct eeepc_laptop *eeepc = bl_get_data(bd);1090 1091	return get_acpi(eeepc, CM_ASL_PANELBRIGHT);1092}1093 1094static int set_brightness(struct backlight_device *bd, int value)1095{1096	struct eeepc_laptop *eeepc = bl_get_data(bd);1097 1098	return set_acpi(eeepc, CM_ASL_PANELBRIGHT, value);1099}1100 1101static int update_bl_status(struct backlight_device *bd)1102{1103	return set_brightness(bd, bd->props.brightness);1104}1105 1106static const struct backlight_ops eeepcbl_ops = {1107	.get_brightness = read_brightness,1108	.update_status = update_bl_status,1109};1110 1111static int eeepc_backlight_notify(struct eeepc_laptop *eeepc)1112{1113	struct backlight_device *bd = eeepc->backlight_device;1114	int old = bd->props.brightness;1115 1116	backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);1117 1118	return old;1119}1120 1121static int eeepc_backlight_init(struct eeepc_laptop *eeepc)1122{1123	struct backlight_properties props;1124	struct backlight_device *bd;1125 1126	memset(&props, 0, sizeof(struct backlight_properties));1127	props.type = BACKLIGHT_PLATFORM;1128	props.max_brightness = 15;1129	bd = backlight_device_register(EEEPC_LAPTOP_FILE,1130				       &eeepc->platform_device->dev, eeepc,1131				       &eeepcbl_ops, &props);1132	if (IS_ERR(bd)) {1133		pr_err("Could not register eeepc backlight device\n");1134		eeepc->backlight_device = NULL;1135		return PTR_ERR(bd);1136	}1137	eeepc->backlight_device = bd;1138	bd->props.brightness = read_brightness(bd);1139	bd->props.power = BACKLIGHT_POWER_ON;1140	backlight_update_status(bd);1141	return 0;1142}1143 1144static void eeepc_backlight_exit(struct eeepc_laptop *eeepc)1145{1146	backlight_device_unregister(eeepc->backlight_device);1147	eeepc->backlight_device = NULL;1148}1149 1150 1151/*1152 * Input device (i.e. hotkeys)1153 */1154static int eeepc_input_init(struct eeepc_laptop *eeepc)1155{1156	struct input_dev *input;1157	int error;1158 1159	input = input_allocate_device();1160	if (!input)1161		return -ENOMEM;1162 1163	input->name = "Asus EeePC extra buttons";1164	input->phys = EEEPC_LAPTOP_FILE "/input0";1165	input->id.bustype = BUS_HOST;1166	input->dev.parent = &eeepc->platform_device->dev;1167 1168	error = sparse_keymap_setup(input, eeepc_keymap, NULL);1169	if (error) {1170		pr_err("Unable to setup input device keymap\n");1171		goto err_free_dev;1172	}1173 1174	error = input_register_device(input);1175	if (error) {1176		pr_err("Unable to register input device\n");1177		goto err_free_dev;1178	}1179 1180	eeepc->inputdev = input;1181	return 0;1182 1183err_free_dev:1184	input_free_device(input);1185	return error;1186}1187 1188static void eeepc_input_exit(struct eeepc_laptop *eeepc)1189{1190	if (eeepc->inputdev)1191		input_unregister_device(eeepc->inputdev);1192	eeepc->inputdev = NULL;1193}1194 1195/*1196 * ACPI driver1197 */1198static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)1199{1200	if (!eeepc->inputdev)1201		return;1202	if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))1203		pr_info("Unknown key %x pressed\n", event);1204}1205 1206static void eeepc_acpi_notify(struct acpi_device *device, u32 event)1207{1208	struct eeepc_laptop *eeepc = acpi_driver_data(device);1209	int old_brightness, new_brightness;1210	u16 count;1211 1212	if (event > ACPI_MAX_SYS_NOTIFY)1213		return;1214	count = eeepc->event_count[event % 128]++;1215	acpi_bus_generate_netlink_event(device->pnp.device_class,1216					dev_name(&device->dev), event,1217					count);1218 1219	/* Brightness events are special */1220	if (event < NOTIFY_BRN_MIN || event > NOTIFY_BRN_MAX) {1221		eeepc_input_notify(eeepc, event);1222		return;1223	}1224 1225	/* Ignore them completely if the acpi video driver is used */1226	if (!eeepc->backlight_device)1227		return;1228 1229	/* Update the backlight device. */1230	old_brightness = eeepc_backlight_notify(eeepc);1231 1232	/* Convert event to keypress (obsolescent hack) */1233	new_brightness = event - NOTIFY_BRN_MIN;1234 1235	if (new_brightness < old_brightness) {1236		event = NOTIFY_BRN_MIN; /* brightness down */1237	} else if (new_brightness > old_brightness) {1238		event = NOTIFY_BRN_MAX; /* brightness up */1239	} else {1240		/*1241		 * no change in brightness - already at min/max,1242		 * event will be desired value (or else ignored)1243		 */1244	}1245	eeepc_input_notify(eeepc, event);1246}1247 1248static void eeepc_dmi_check(struct eeepc_laptop *eeepc)1249{1250	const char *model;1251 1252	model = dmi_get_system_info(DMI_PRODUCT_NAME);1253	if (!model)1254		return;1255 1256	/*1257	 * Blacklist for setting cpufv (cpu speed).1258	 *1259	 * EeePC 4G ("701") implements CFVS, but it is not supported1260	 * by the pre-installed OS, and the original option to change it1261	 * in the BIOS setup screen was removed in later versions.1262	 *1263	 * Judging by the lack of "Super Hybrid Engine" on Asus product pages,1264	 * this applies to all "701" models (4G/4G Surf/2G Surf).1265	 *1266	 * So Asus made a deliberate decision not to support it on this model.1267	 * We have several reports that using it can cause the system to hang1268	 *1269	 * The hang has also been reported on a "702" (Model name "8G"?).1270	 *1271	 * We avoid dmi_check_system() / dmi_match(), because they use1272	 * substring matching.  We don't want to affect the "701SD"1273	 * and "701SDX" models, because they do support S.H.E.1274	 */1275	if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {1276		eeepc->cpufv_disabled = true;1277		pr_info("model %s does not officially support setting cpu speed\n",1278			model);1279		pr_info("cpufv disabled to avoid instability\n");1280	}1281 1282	/*1283	 * Blacklist for wlan hotplug1284	 *1285	 * Eeepc 1005HA doesn't work like others models and don't need the1286	 * hotplug code. In fact, current hotplug code seems to unplug another1287	 * device...1288	 */1289	if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 ||1290	    strcmp(model, "1005PE") == 0) {1291		eeepc->hotplug_disabled = true;1292		pr_info("wlan hotplug disabled\n");1293	}1294}1295 1296static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)1297{1298	int dummy;1299 1300	/* Some BIOSes do not report cm although it is available.1301	   Check if cm_getv[cm] works and, if yes, assume cm should be set. */1302	if (!(eeepc->cm_supported & (1 << cm))1303	    && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {1304		pr_info("%s (%x) not reported by BIOS, enabling anyway\n",1305			name, 1 << cm);1306		eeepc->cm_supported |= 1 << cm;1307	}1308}1309 1310static void cmsg_quirks(struct eeepc_laptop *eeepc)1311{1312	cmsg_quirk(eeepc, CM_ASL_LID, "LID");1313	cmsg_quirk(eeepc, CM_ASL_TYPE, "TYPE");1314	cmsg_quirk(eeepc, CM_ASL_PANELPOWER, "PANELPOWER");1315	cmsg_quirk(eeepc, CM_ASL_TPD, "TPD");1316}1317 1318static int eeepc_acpi_init(struct eeepc_laptop *eeepc)1319{1320	unsigned int init_flags;1321	int result;1322 1323	result = acpi_bus_get_status(eeepc->device);1324	if (result)1325		return result;1326	if (!eeepc->device->status.present) {1327		pr_err("Hotkey device not present, aborting\n");1328		return -ENODEV;1329	}1330 1331	init_flags = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;1332	pr_notice("Hotkey init flags 0x%x\n", init_flags);1333 1334	if (write_acpi_int(eeepc->handle, "INIT", init_flags)) {1335		pr_err("Hotkey initialization failed\n");1336		return -ENODEV;1337	}1338 1339	/* get control methods supported */1340	if (read_acpi_int(eeepc->handle, "CMSG", &eeepc->cm_supported)) {1341		pr_err("Get control methods supported failed\n");1342		return -ENODEV;1343	}1344	cmsg_quirks(eeepc);1345	pr_info("Get control methods supported: 0x%x\n", eeepc->cm_supported);1346 1347	return 0;1348}1349 1350static void eeepc_enable_camera(struct eeepc_laptop *eeepc)1351{1352	/*1353	 * If the following call to set_acpi() fails, it's because there's no1354	 * camera so we can ignore the error.1355	 */1356	if (get_acpi(eeepc, CM_ASL_CAMERA) == 0)1357		set_acpi(eeepc, CM_ASL_CAMERA, 1);1358}1359 1360static bool eeepc_device_present;1361 1362static int eeepc_acpi_add(struct acpi_device *device)1363{1364	struct eeepc_laptop *eeepc;1365	int result;1366 1367	pr_notice(EEEPC_LAPTOP_NAME "\n");1368	eeepc = kzalloc(sizeof(struct eeepc_laptop), GFP_KERNEL);1369	if (!eeepc)1370		return -ENOMEM;1371	eeepc->handle = device->handle;1372	strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);1373	strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);1374	device->driver_data = eeepc;1375	eeepc->device = device;1376 1377	eeepc->hotplug_disabled = hotplug_disabled;1378 1379	eeepc_dmi_check(eeepc);1380 1381	result = eeepc_acpi_init(eeepc);1382	if (result)1383		goto fail_platform;1384	eeepc_enable_camera(eeepc);1385 1386	/*1387	 * Register the platform device first.  It is used as a parent for the1388	 * sub-devices below.1389	 *1390	 * Note that if there are multiple instances of this ACPI device it1391	 * will bail out, because the platform device is registered with a1392	 * fixed name.  Of course it doesn't make sense to have more than one,1393	 * and machine-specific scripts find the fixed name convenient.  But1394	 * It's also good for us to exclude multiple instances because both1395	 * our hwmon and our wlan rfkill subdevice use global ACPI objects1396	 * (the EC and the PCI wlan slot respectively).1397	 */1398	result = eeepc_platform_init(eeepc);1399	if (result)1400		goto fail_platform;1401 1402	if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {1403		result = eeepc_backlight_init(eeepc);1404		if (result)1405			goto fail_backlight;1406	}1407 1408	result = eeepc_input_init(eeepc);1409	if (result)1410		goto fail_input;1411 1412	result = eeepc_hwmon_init(eeepc);1413	if (result)1414		goto fail_hwmon;1415 1416	result = eeepc_led_init(eeepc);1417	if (result)1418		goto fail_led;1419 1420	result = eeepc_rfkill_init(eeepc);1421	if (result)1422		goto fail_rfkill;1423 1424	eeepc_device_present = true;1425	return 0;1426 1427fail_rfkill:1428	eeepc_led_exit(eeepc);1429fail_led:1430fail_hwmon:1431	eeepc_input_exit(eeepc);1432fail_input:1433	eeepc_backlight_exit(eeepc);1434fail_backlight:1435	eeepc_platform_exit(eeepc);1436fail_platform:1437	kfree(eeepc);1438 1439	return result;1440}1441 1442static void eeepc_acpi_remove(struct acpi_device *device)1443{1444	struct eeepc_laptop *eeepc = acpi_driver_data(device);1445 1446	eeepc_backlight_exit(eeepc);1447	eeepc_rfkill_exit(eeepc);1448	eeepc_input_exit(eeepc);1449	eeepc_led_exit(eeepc);1450	eeepc_platform_exit(eeepc);1451 1452	kfree(eeepc);1453}1454 1455 1456static const struct acpi_device_id eeepc_device_ids[] = {1457	{EEEPC_ACPI_HID, 0},1458	{"", 0},1459};1460MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);1461 1462static struct acpi_driver eeepc_acpi_driver = {1463	.name = EEEPC_LAPTOP_NAME,1464	.class = EEEPC_ACPI_CLASS,1465	.ids = eeepc_device_ids,1466	.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,1467	.ops = {1468		.add = eeepc_acpi_add,1469		.remove = eeepc_acpi_remove,1470		.notify = eeepc_acpi_notify,1471	},1472};1473 1474 1475static int __init eeepc_laptop_init(void)1476{1477	int result;1478 1479	result = platform_driver_register(&platform_driver);1480	if (result < 0)1481		return result;1482 1483	result = acpi_bus_register_driver(&eeepc_acpi_driver);1484	if (result < 0)1485		goto fail_acpi_driver;1486 1487	if (!eeepc_device_present) {1488		result = -ENODEV;1489		goto fail_no_device;1490	}1491 1492	return 0;1493 1494fail_no_device:1495	acpi_bus_unregister_driver(&eeepc_acpi_driver);1496fail_acpi_driver:1497	platform_driver_unregister(&platform_driver);1498	return result;1499}1500 1501static void __exit eeepc_laptop_exit(void)1502{1503	acpi_bus_unregister_driver(&eeepc_acpi_driver);1504	platform_driver_unregister(&platform_driver);1505}1506 1507module_init(eeepc_laptop_init);1508module_exit(eeepc_laptop_exit);1509