0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0011
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/init.h>
0015 #include <linux/types.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/backlight.h>
0018 #include <linux/fb.h>
0019 #include <linux/hwmon.h>
0020 #include <linux/hwmon-sysfs.h>
0021 #include <linux/slab.h>
0022 #include <linux/acpi.h>
0023 #include <linux/uaccess.h>
0024 #include <linux/input.h>
0025 #include <linux/input/sparse-keymap.h>
0026 #include <linux/rfkill.h>
0027 #include <linux/pci.h>
0028 #include <linux/pci_hotplug.h>
0029 #include <linux/leds.h>
0030 #include <linux/dmi.h>
0031 #include <acpi/video.h>
0032
0033 #define EEEPC_LAPTOP_VERSION "0.1"
0034 #define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver"
0035 #define EEEPC_LAPTOP_FILE "eeepc"
0036
0037 #define EEEPC_ACPI_CLASS "hotkey"
0038 #define EEEPC_ACPI_DEVICE_NAME "Hotkey"
0039 #define EEEPC_ACPI_HID "ASUS010"
0040
0041 MODULE_AUTHOR("Corentin Chary, Eric Cooper");
0042 MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME);
0043 MODULE_LICENSE("GPL");
0044
0045 static bool hotplug_disabled;
0046
0047 module_param(hotplug_disabled, bool, 0444);
0048 MODULE_PARM_DESC(hotplug_disabled,
0049 "Disable hotplug for wireless device. "
0050 "If your laptop need that, please report to "
0051 "acpi4asus-user@lists.sourceforge.net.");
0052
0053
0054
0055
0056 #define NOTIFY_BRN_MIN 0x20
0057 #define NOTIFY_BRN_MAX 0x2f
0058
0059 enum {
0060 DISABLE_ASL_WLAN = 0x0001,
0061 DISABLE_ASL_BLUETOOTH = 0x0002,
0062 DISABLE_ASL_IRDA = 0x0004,
0063 DISABLE_ASL_CAMERA = 0x0008,
0064 DISABLE_ASL_TV = 0x0010,
0065 DISABLE_ASL_GPS = 0x0020,
0066 DISABLE_ASL_DISPLAYSWITCH = 0x0040,
0067 DISABLE_ASL_MODEM = 0x0080,
0068 DISABLE_ASL_CARDREADER = 0x0100,
0069 DISABLE_ASL_3G = 0x0200,
0070 DISABLE_ASL_WIMAX = 0x0400,
0071 DISABLE_ASL_HWCF = 0x0800
0072 };
0073
0074 enum {
0075 CM_ASL_WLAN = 0,
0076 CM_ASL_BLUETOOTH,
0077 CM_ASL_IRDA,
0078 CM_ASL_1394,
0079 CM_ASL_CAMERA,
0080 CM_ASL_TV,
0081 CM_ASL_GPS,
0082 CM_ASL_DVDROM,
0083 CM_ASL_DISPLAYSWITCH,
0084 CM_ASL_PANELBRIGHT,
0085 CM_ASL_BIOSFLASH,
0086 CM_ASL_ACPIFLASH,
0087 CM_ASL_CPUFV,
0088 CM_ASL_CPUTEMPERATURE,
0089 CM_ASL_FANCPU,
0090 CM_ASL_FANCHASSIS,
0091 CM_ASL_USBPORT1,
0092 CM_ASL_USBPORT2,
0093 CM_ASL_USBPORT3,
0094 CM_ASL_MODEM,
0095 CM_ASL_CARDREADER,
0096 CM_ASL_3G,
0097 CM_ASL_WIMAX,
0098 CM_ASL_HWCF,
0099 CM_ASL_LID,
0100 CM_ASL_TYPE,
0101 CM_ASL_PANELPOWER,
0102 CM_ASL_TPD
0103 };
0104
0105 static const char *cm_getv[] = {
0106 "WLDG", "BTHG", NULL, NULL,
0107 "CAMG", NULL, NULL, NULL,
0108 NULL, "PBLG", NULL, NULL,
0109 "CFVG", NULL, NULL, NULL,
0110 "USBG", NULL, NULL, "MODG",
0111 "CRDG", "M3GG", "WIMG", "HWCF",
0112 "LIDG", "TYPE", "PBPG", "TPDG"
0113 };
0114
0115 static const char *cm_setv[] = {
0116 "WLDS", "BTHS", NULL, NULL,
0117 "CAMS", NULL, NULL, NULL,
0118 "SDSP", "PBLS", "HDPS", NULL,
0119 "CFVS", NULL, NULL, NULL,
0120 "USBG", NULL, NULL, "MODS",
0121 "CRDS", "M3GS", "WIMS", NULL,
0122 NULL, NULL, "PBPS", "TPDS"
0123 };
0124
0125 static const struct key_entry eeepc_keymap[] = {
0126 { KE_KEY, 0x10, { KEY_WLAN } },
0127 { KE_KEY, 0x11, { KEY_WLAN } },
0128 { KE_KEY, 0x12, { KEY_PROG1 } },
0129 { KE_KEY, 0x13, { KEY_MUTE } },
0130 { KE_KEY, 0x14, { KEY_VOLUMEDOWN } },
0131 { KE_KEY, 0x15, { KEY_VOLUMEUP } },
0132 { KE_KEY, 0x16, { KEY_DISPLAY_OFF } },
0133 { KE_KEY, 0x1a, { KEY_COFFEE } },
0134 { KE_KEY, 0x1b, { KEY_ZOOM } },
0135 { KE_KEY, 0x1c, { KEY_PROG2 } },
0136 { KE_KEY, 0x1d, { KEY_PROG3 } },
0137 { KE_KEY, NOTIFY_BRN_MIN, { KEY_BRIGHTNESSDOWN } },
0138 { KE_KEY, NOTIFY_BRN_MAX, { KEY_BRIGHTNESSUP } },
0139 { KE_KEY, 0x30, { KEY_SWITCHVIDEOMODE } },
0140 { KE_KEY, 0x31, { KEY_SWITCHVIDEOMODE } },
0141 { KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } },
0142 { KE_KEY, 0x37, { KEY_F13 } },
0143 { KE_KEY, 0x38, { KEY_F14 } },
0144 { KE_IGNORE, 0x50, { KEY_RESERVED } },
0145 { KE_IGNORE, 0x51, { KEY_RESERVED } },
0146 { KE_END, 0 },
0147 };
0148
0149
0150
0151
0152 struct eeepc_laptop {
0153 acpi_handle handle;
0154 u32 cm_supported;
0155
0156 bool cpufv_disabled;
0157 bool hotplug_disabled;
0158 u16 event_count[128];
0159
0160 struct platform_device *platform_device;
0161 struct acpi_device *device;
0162 struct backlight_device *backlight_device;
0163
0164 struct input_dev *inputdev;
0165
0166 struct rfkill *wlan_rfkill;
0167 struct rfkill *bluetooth_rfkill;
0168 struct rfkill *wwan3g_rfkill;
0169 struct rfkill *wimax_rfkill;
0170
0171 struct hotplug_slot hotplug_slot;
0172 struct mutex hotplug_lock;
0173
0174 struct led_classdev tpd_led;
0175 int tpd_led_wk;
0176 struct workqueue_struct *led_workqueue;
0177 struct work_struct tpd_led_work;
0178 };
0179
0180
0181
0182
0183 static int write_acpi_int(acpi_handle handle, const char *method, int val)
0184 {
0185 acpi_status status;
0186
0187 status = acpi_execute_simple_method(handle, (char *)method, val);
0188
0189 return (status == AE_OK ? 0 : -1);
0190 }
0191
0192 static int read_acpi_int(acpi_handle handle, const char *method, int *val)
0193 {
0194 acpi_status status;
0195 unsigned long long result;
0196
0197 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
0198 if (ACPI_FAILURE(status)) {
0199 *val = -1;
0200 return -1;
0201 } else {
0202 *val = result;
0203 return 0;
0204 }
0205 }
0206
0207 static int set_acpi(struct eeepc_laptop *eeepc, int cm, int value)
0208 {
0209 const char *method = cm_setv[cm];
0210
0211 if (method == NULL)
0212 return -ENODEV;
0213 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
0214 return -ENODEV;
0215
0216 if (write_acpi_int(eeepc->handle, method, value))
0217 pr_warn("Error writing %s\n", method);
0218 return 0;
0219 }
0220
0221 static int get_acpi(struct eeepc_laptop *eeepc, int cm)
0222 {
0223 const char *method = cm_getv[cm];
0224 int value;
0225
0226 if (method == NULL)
0227 return -ENODEV;
0228 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
0229 return -ENODEV;
0230
0231 if (read_acpi_int(eeepc->handle, method, &value))
0232 pr_warn("Error reading %s\n", method);
0233 return value;
0234 }
0235
0236 static int acpi_setter_handle(struct eeepc_laptop *eeepc, int cm,
0237 acpi_handle *handle)
0238 {
0239 const char *method = cm_setv[cm];
0240 acpi_status status;
0241
0242 if (method == NULL)
0243 return -ENODEV;
0244 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
0245 return -ENODEV;
0246
0247 status = acpi_get_handle(eeepc->handle, (char *)method,
0248 handle);
0249 if (status != AE_OK) {
0250 pr_warn("Error finding %s\n", method);
0251 return -ENODEV;
0252 }
0253 return 0;
0254 }
0255
0256
0257
0258
0259
0260 static int parse_arg(const char *buf, int *val)
0261 {
0262 if (sscanf(buf, "%i", val) != 1)
0263 return -EINVAL;
0264 return 0;
0265 }
0266
0267 static ssize_t store_sys_acpi(struct device *dev, int cm,
0268 const char *buf, size_t count)
0269 {
0270 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
0271 int rv, value;
0272
0273 rv = parse_arg(buf, &value);
0274 if (rv < 0)
0275 return rv;
0276 rv = set_acpi(eeepc, cm, value);
0277 if (rv < 0)
0278 return -EIO;
0279 return count;
0280 }
0281
0282 static ssize_t show_sys_acpi(struct device *dev, int cm, char *buf)
0283 {
0284 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
0285 int value = get_acpi(eeepc, cm);
0286
0287 if (value < 0)
0288 return -EIO;
0289 return sprintf(buf, "%d\n", value);
0290 }
0291
0292 #define EEEPC_ACPI_SHOW_FUNC(_name, _cm) \
0293 static ssize_t _name##_show(struct device *dev, \
0294 struct device_attribute *attr, \
0295 char *buf) \
0296 { \
0297 return show_sys_acpi(dev, _cm, buf); \
0298 }
0299
0300 #define EEEPC_ACPI_STORE_FUNC(_name, _cm) \
0301 static ssize_t _name##_store(struct device *dev, \
0302 struct device_attribute *attr, \
0303 const char *buf, size_t count) \
0304 { \
0305 return store_sys_acpi(dev, _cm, buf, count); \
0306 }
0307
0308 #define EEEPC_CREATE_DEVICE_ATTR_RW(_name, _cm) \
0309 EEEPC_ACPI_SHOW_FUNC(_name, _cm) \
0310 EEEPC_ACPI_STORE_FUNC(_name, _cm) \
0311 static DEVICE_ATTR_RW(_name)
0312
0313 #define EEEPC_CREATE_DEVICE_ATTR_WO(_name, _cm) \
0314 EEEPC_ACPI_STORE_FUNC(_name, _cm) \
0315 static DEVICE_ATTR_WO(_name)
0316
0317 EEEPC_CREATE_DEVICE_ATTR_RW(camera, CM_ASL_CAMERA);
0318 EEEPC_CREATE_DEVICE_ATTR_RW(cardr, CM_ASL_CARDREADER);
0319 EEEPC_CREATE_DEVICE_ATTR_WO(disp, CM_ASL_DISPLAYSWITCH);
0320
0321 struct eeepc_cpufv {
0322 int num;
0323 int cur;
0324 };
0325
0326 static int get_cpufv(struct eeepc_laptop *eeepc, struct eeepc_cpufv *c)
0327 {
0328 c->cur = get_acpi(eeepc, CM_ASL_CPUFV);
0329 if (c->cur < 0)
0330 return -ENODEV;
0331
0332 c->num = (c->cur >> 8) & 0xff;
0333 c->cur &= 0xff;
0334 if (c->num == 0 || c->num > 12)
0335 return -ENODEV;
0336 return 0;
0337 }
0338
0339 static ssize_t available_cpufv_show(struct device *dev,
0340 struct device_attribute *attr,
0341 char *buf)
0342 {
0343 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
0344 struct eeepc_cpufv c;
0345 int i;
0346 ssize_t len = 0;
0347
0348 if (get_cpufv(eeepc, &c))
0349 return -ENODEV;
0350 for (i = 0; i < c.num; i++)
0351 len += sprintf(buf + len, "%d ", i);
0352 len += sprintf(buf + len, "\n");
0353 return len;
0354 }
0355
0356 static ssize_t cpufv_show(struct device *dev,
0357 struct device_attribute *attr,
0358 char *buf)
0359 {
0360 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
0361 struct eeepc_cpufv c;
0362
0363 if (get_cpufv(eeepc, &c))
0364 return -ENODEV;
0365 return sprintf(buf, "%#x\n", (c.num << 8) | c.cur);
0366 }
0367
0368 static ssize_t cpufv_store(struct device *dev,
0369 struct device_attribute *attr,
0370 const char *buf, size_t count)
0371 {
0372 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
0373 struct eeepc_cpufv c;
0374 int rv, value;
0375
0376 if (eeepc->cpufv_disabled)
0377 return -EPERM;
0378 if (get_cpufv(eeepc, &c))
0379 return -ENODEV;
0380 rv = parse_arg(buf, &value);
0381 if (rv < 0)
0382 return rv;
0383 if (value < 0 || value >= c.num)
0384 return -EINVAL;
0385 rv = set_acpi(eeepc, CM_ASL_CPUFV, value);
0386 if (rv)
0387 return rv;
0388 return count;
0389 }
0390
0391 static ssize_t cpufv_disabled_show(struct device *dev,
0392 struct device_attribute *attr,
0393 char *buf)
0394 {
0395 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
0396
0397 return sprintf(buf, "%d\n", eeepc->cpufv_disabled);
0398 }
0399
0400 static ssize_t cpufv_disabled_store(struct device *dev,
0401 struct device_attribute *attr,
0402 const char *buf, size_t count)
0403 {
0404 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
0405 int rv, value;
0406
0407 rv = parse_arg(buf, &value);
0408 if (rv < 0)
0409 return rv;
0410
0411 switch (value) {
0412 case 0:
0413 if (eeepc->cpufv_disabled)
0414 pr_warn("cpufv enabled (not officially supported on this model)\n");
0415 eeepc->cpufv_disabled = false;
0416 return count;
0417 case 1:
0418 return -EPERM;
0419 default:
0420 return -EINVAL;
0421 }
0422 }
0423
0424
0425 static DEVICE_ATTR_RW(cpufv);
0426 static DEVICE_ATTR_RO(available_cpufv);
0427 static DEVICE_ATTR_RW(cpufv_disabled);
0428
0429 static struct attribute *platform_attributes[] = {
0430 &dev_attr_camera.attr,
0431 &dev_attr_cardr.attr,
0432 &dev_attr_disp.attr,
0433 &dev_attr_cpufv.attr,
0434 &dev_attr_available_cpufv.attr,
0435 &dev_attr_cpufv_disabled.attr,
0436 NULL
0437 };
0438
0439 static const struct attribute_group platform_attribute_group = {
0440 .attrs = platform_attributes
0441 };
0442
0443 static int eeepc_platform_init(struct eeepc_laptop *eeepc)
0444 {
0445 int result;
0446
0447 eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, -1);
0448 if (!eeepc->platform_device)
0449 return -ENOMEM;
0450 platform_set_drvdata(eeepc->platform_device, eeepc);
0451
0452 result = platform_device_add(eeepc->platform_device);
0453 if (result)
0454 goto fail_platform_device;
0455
0456 result = sysfs_create_group(&eeepc->platform_device->dev.kobj,
0457 &platform_attribute_group);
0458 if (result)
0459 goto fail_sysfs;
0460 return 0;
0461
0462 fail_sysfs:
0463 platform_device_del(eeepc->platform_device);
0464 fail_platform_device:
0465 platform_device_put(eeepc->platform_device);
0466 return result;
0467 }
0468
0469 static void eeepc_platform_exit(struct eeepc_laptop *eeepc)
0470 {
0471 sysfs_remove_group(&eeepc->platform_device->dev.kobj,
0472 &platform_attribute_group);
0473 platform_device_unregister(eeepc->platform_device);
0474 }
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485 static void tpd_led_update(struct work_struct *work)
0486 {
0487 struct eeepc_laptop *eeepc;
0488
0489 eeepc = container_of(work, struct eeepc_laptop, tpd_led_work);
0490
0491 set_acpi(eeepc, CM_ASL_TPD, eeepc->tpd_led_wk);
0492 }
0493
0494 static void tpd_led_set(struct led_classdev *led_cdev,
0495 enum led_brightness value)
0496 {
0497 struct eeepc_laptop *eeepc;
0498
0499 eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
0500
0501 eeepc->tpd_led_wk = (value > 0) ? 1 : 0;
0502 queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
0503 }
0504
0505 static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
0506 {
0507 struct eeepc_laptop *eeepc;
0508
0509 eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
0510
0511 return get_acpi(eeepc, CM_ASL_TPD);
0512 }
0513
0514 static int eeepc_led_init(struct eeepc_laptop *eeepc)
0515 {
0516 int rv;
0517
0518 if (get_acpi(eeepc, CM_ASL_TPD) == -ENODEV)
0519 return 0;
0520
0521 eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");
0522 if (!eeepc->led_workqueue)
0523 return -ENOMEM;
0524 INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);
0525
0526 eeepc->tpd_led.name = "eeepc::touchpad";
0527 eeepc->tpd_led.brightness_set = tpd_led_set;
0528 if (get_acpi(eeepc, CM_ASL_TPD) >= 0)
0529 eeepc->tpd_led.brightness_get = tpd_led_get;
0530 eeepc->tpd_led.max_brightness = 1;
0531
0532 rv = led_classdev_register(&eeepc->platform_device->dev,
0533 &eeepc->tpd_led);
0534 if (rv) {
0535 destroy_workqueue(eeepc->led_workqueue);
0536 return rv;
0537 }
0538
0539 return 0;
0540 }
0541
0542 static void eeepc_led_exit(struct eeepc_laptop *eeepc)
0543 {
0544 led_classdev_unregister(&eeepc->tpd_led);
0545 if (eeepc->led_workqueue)
0546 destroy_workqueue(eeepc->led_workqueue);
0547 }
0548
0549
0550
0551
0552 static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc)
0553 {
0554 if (get_acpi(eeepc, CM_ASL_WLAN) == 1)
0555 return false;
0556 return true;
0557 }
0558
0559 static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
0560 {
0561 struct pci_dev *port;
0562 struct pci_dev *dev;
0563 struct pci_bus *bus;
0564 bool blocked = eeepc_wlan_rfkill_blocked(eeepc);
0565 bool absent;
0566 u32 l;
0567
0568 if (eeepc->wlan_rfkill)
0569 rfkill_set_sw_state(eeepc->wlan_rfkill, blocked);
0570
0571 mutex_lock(&eeepc->hotplug_lock);
0572 pci_lock_rescan_remove();
0573
0574 if (!eeepc->hotplug_slot.ops)
0575 goto out_unlock;
0576
0577 port = acpi_get_pci_dev(handle);
0578 if (!port) {
0579 pr_warn("Unable to find port\n");
0580 goto out_unlock;
0581 }
0582
0583 bus = port->subordinate;
0584
0585 if (!bus) {
0586 pr_warn("Unable to find PCI bus 1?\n");
0587 goto out_put_dev;
0588 }
0589
0590 if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
0591 pr_err("Unable to read PCI config space?\n");
0592 goto out_put_dev;
0593 }
0594
0595 absent = (l == 0xffffffff);
0596
0597 if (blocked != absent) {
0598 pr_warn("BIOS says wireless lan is %s, but the pci device is %s\n",
0599 blocked ? "blocked" : "unblocked",
0600 absent ? "absent" : "present");
0601 pr_warn("skipped wireless hotplug as probably inappropriate for this model\n");
0602 goto out_put_dev;
0603 }
0604
0605 if (!blocked) {
0606 dev = pci_get_slot(bus, 0);
0607 if (dev) {
0608
0609 pci_dev_put(dev);
0610 goto out_put_dev;
0611 }
0612 dev = pci_scan_single_device(bus, 0);
0613 if (dev) {
0614 pci_bus_assign_resources(bus);
0615 pci_bus_add_device(dev);
0616 }
0617 } else {
0618 dev = pci_get_slot(bus, 0);
0619 if (dev) {
0620 pci_stop_and_remove_bus_device(dev);
0621 pci_dev_put(dev);
0622 }
0623 }
0624 out_put_dev:
0625 pci_dev_put(port);
0626
0627 out_unlock:
0628 pci_unlock_rescan_remove();
0629 mutex_unlock(&eeepc->hotplug_lock);
0630 }
0631
0632 static void eeepc_rfkill_hotplug_update(struct eeepc_laptop *eeepc, char *node)
0633 {
0634 acpi_status status = AE_OK;
0635 acpi_handle handle;
0636
0637 status = acpi_get_handle(NULL, node, &handle);
0638
0639 if (ACPI_SUCCESS(status))
0640 eeepc_rfkill_hotplug(eeepc, handle);
0641 }
0642
0643 static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
0644 {
0645 struct eeepc_laptop *eeepc = data;
0646
0647 if (event != ACPI_NOTIFY_BUS_CHECK)
0648 return;
0649
0650 eeepc_rfkill_hotplug(eeepc, handle);
0651 }
0652
0653 static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc,
0654 char *node)
0655 {
0656 acpi_status status;
0657 acpi_handle handle;
0658
0659 status = acpi_get_handle(NULL, node, &handle);
0660
0661 if (ACPI_FAILURE(status))
0662 return -ENODEV;
0663
0664 status = acpi_install_notify_handler(handle,
0665 ACPI_SYSTEM_NOTIFY,
0666 eeepc_rfkill_notify,
0667 eeepc);
0668 if (ACPI_FAILURE(status))
0669 pr_warn("Failed to register notify on %s\n", node);
0670
0671
0672
0673
0674
0675 eeepc_rfkill_hotplug(eeepc, handle);
0676 return 0;
0677 }
0678
0679 static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc,
0680 char *node)
0681 {
0682 acpi_status status = AE_OK;
0683 acpi_handle handle;
0684
0685 status = acpi_get_handle(NULL, node, &handle);
0686
0687 if (ACPI_FAILURE(status))
0688 return;
0689
0690 status = acpi_remove_notify_handler(handle,
0691 ACPI_SYSTEM_NOTIFY,
0692 eeepc_rfkill_notify);
0693 if (ACPI_FAILURE(status))
0694 pr_err("Error removing rfkill notify handler %s\n",
0695 node);
0696
0697
0698
0699
0700
0701 eeepc_rfkill_hotplug(eeepc, handle);
0702 }
0703
0704 static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
0705 u8 *value)
0706 {
0707 struct eeepc_laptop *eeepc;
0708 int val;
0709
0710 eeepc = container_of(hotplug_slot, struct eeepc_laptop, hotplug_slot);
0711 val = get_acpi(eeepc, CM_ASL_WLAN);
0712
0713 if (val == 1 || val == 0)
0714 *value = val;
0715 else
0716 return -EINVAL;
0717
0718 return 0;
0719 }
0720
0721 static const struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
0722 .get_adapter_status = eeepc_get_adapter_status,
0723 .get_power_status = eeepc_get_adapter_status,
0724 };
0725
0726 static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc)
0727 {
0728 int ret = -ENOMEM;
0729 struct pci_bus *bus = pci_find_bus(0, 1);
0730
0731 if (!bus) {
0732 pr_err("Unable to find wifi PCI bus\n");
0733 return -ENODEV;
0734 }
0735
0736 eeepc->hotplug_slot.ops = &eeepc_hotplug_slot_ops;
0737
0738 ret = pci_hp_register(&eeepc->hotplug_slot, bus, 0, "eeepc-wifi");
0739 if (ret) {
0740 pr_err("Unable to register hotplug slot - %d\n", ret);
0741 goto error_register;
0742 }
0743
0744 return 0;
0745
0746 error_register:
0747 eeepc->hotplug_slot.ops = NULL;
0748 return ret;
0749 }
0750
0751
0752
0753
0754 static int eeepc_rfkill_set(void *data, bool blocked)
0755 {
0756 acpi_handle handle = data;
0757
0758 return write_acpi_int(handle, NULL, !blocked);
0759 }
0760
0761 static const struct rfkill_ops eeepc_rfkill_ops = {
0762 .set_block = eeepc_rfkill_set,
0763 };
0764
0765 static int eeepc_new_rfkill(struct eeepc_laptop *eeepc,
0766 struct rfkill **rfkill,
0767 const char *name,
0768 enum rfkill_type type, int cm)
0769 {
0770 acpi_handle handle;
0771 int result;
0772
0773 result = acpi_setter_handle(eeepc, cm, &handle);
0774 if (result < 0)
0775 return result;
0776
0777 *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
0778 &eeepc_rfkill_ops, handle);
0779
0780 if (!*rfkill)
0781 return -EINVAL;
0782
0783 rfkill_init_sw_state(*rfkill, get_acpi(eeepc, cm) != 1);
0784 result = rfkill_register(*rfkill);
0785 if (result) {
0786 rfkill_destroy(*rfkill);
0787 *rfkill = NULL;
0788 return result;
0789 }
0790 return 0;
0791 }
0792
0793 static char EEEPC_RFKILL_NODE_1[] = "\\_SB.PCI0.P0P5";
0794 static char EEEPC_RFKILL_NODE_2[] = "\\_SB.PCI0.P0P6";
0795 static char EEEPC_RFKILL_NODE_3[] = "\\_SB.PCI0.P0P7";
0796
0797 static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc)
0798 {
0799 eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_1);
0800 eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_2);
0801 eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_3);
0802 if (eeepc->wlan_rfkill) {
0803 rfkill_unregister(eeepc->wlan_rfkill);
0804 rfkill_destroy(eeepc->wlan_rfkill);
0805 eeepc->wlan_rfkill = NULL;
0806 }
0807
0808 if (eeepc->hotplug_slot.ops)
0809 pci_hp_deregister(&eeepc->hotplug_slot);
0810
0811 if (eeepc->bluetooth_rfkill) {
0812 rfkill_unregister(eeepc->bluetooth_rfkill);
0813 rfkill_destroy(eeepc->bluetooth_rfkill);
0814 eeepc->bluetooth_rfkill = NULL;
0815 }
0816 if (eeepc->wwan3g_rfkill) {
0817 rfkill_unregister(eeepc->wwan3g_rfkill);
0818 rfkill_destroy(eeepc->wwan3g_rfkill);
0819 eeepc->wwan3g_rfkill = NULL;
0820 }
0821 if (eeepc->wimax_rfkill) {
0822 rfkill_unregister(eeepc->wimax_rfkill);
0823 rfkill_destroy(eeepc->wimax_rfkill);
0824 eeepc->wimax_rfkill = NULL;
0825 }
0826 }
0827
0828 static int eeepc_rfkill_init(struct eeepc_laptop *eeepc)
0829 {
0830 int result = 0;
0831
0832 mutex_init(&eeepc->hotplug_lock);
0833
0834 result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
0835 "eeepc-wlan", RFKILL_TYPE_WLAN,
0836 CM_ASL_WLAN);
0837
0838 if (result && result != -ENODEV)
0839 goto exit;
0840
0841 result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
0842 "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
0843 CM_ASL_BLUETOOTH);
0844
0845 if (result && result != -ENODEV)
0846 goto exit;
0847
0848 result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
0849 "eeepc-wwan3g", RFKILL_TYPE_WWAN,
0850 CM_ASL_3G);
0851
0852 if (result && result != -ENODEV)
0853 goto exit;
0854
0855 result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill,
0856 "eeepc-wimax", RFKILL_TYPE_WIMAX,
0857 CM_ASL_WIMAX);
0858
0859 if (result && result != -ENODEV)
0860 goto exit;
0861
0862 if (eeepc->hotplug_disabled)
0863 return 0;
0864
0865 result = eeepc_setup_pci_hotplug(eeepc);
0866
0867
0868
0869
0870 if (result == -EBUSY)
0871 result = 0;
0872
0873 eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_1);
0874 eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_2);
0875 eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_3);
0876
0877 exit:
0878 if (result && result != -ENODEV)
0879 eeepc_rfkill_exit(eeepc);
0880 return result;
0881 }
0882
0883
0884
0885
0886 static int eeepc_hotk_thaw(struct device *device)
0887 {
0888 struct eeepc_laptop *eeepc = dev_get_drvdata(device);
0889
0890 if (eeepc->wlan_rfkill) {
0891 int wlan;
0892
0893
0894
0895
0896
0897
0898 wlan = get_acpi(eeepc, CM_ASL_WLAN);
0899 if (wlan >= 0)
0900 set_acpi(eeepc, CM_ASL_WLAN, wlan);
0901 }
0902
0903 return 0;
0904 }
0905
0906 static int eeepc_hotk_restore(struct device *device)
0907 {
0908 struct eeepc_laptop *eeepc = dev_get_drvdata(device);
0909
0910
0911 if (eeepc->wlan_rfkill) {
0912 eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_1);
0913 eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_2);
0914 eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_3);
0915 }
0916
0917 if (eeepc->bluetooth_rfkill)
0918 rfkill_set_sw_state(eeepc->bluetooth_rfkill,
0919 get_acpi(eeepc, CM_ASL_BLUETOOTH) != 1);
0920 if (eeepc->wwan3g_rfkill)
0921 rfkill_set_sw_state(eeepc->wwan3g_rfkill,
0922 get_acpi(eeepc, CM_ASL_3G) != 1);
0923 if (eeepc->wimax_rfkill)
0924 rfkill_set_sw_state(eeepc->wimax_rfkill,
0925 get_acpi(eeepc, CM_ASL_WIMAX) != 1);
0926
0927 return 0;
0928 }
0929
0930 static const struct dev_pm_ops eeepc_pm_ops = {
0931 .thaw = eeepc_hotk_thaw,
0932 .restore = eeepc_hotk_restore,
0933 };
0934
0935 static struct platform_driver platform_driver = {
0936 .driver = {
0937 .name = EEEPC_LAPTOP_FILE,
0938 .pm = &eeepc_pm_ops,
0939 }
0940 };
0941
0942
0943
0944
0945
0946 #define EEEPC_EC_SC00 0x61
0947 #define EEEPC_EC_FAN_PWM (EEEPC_EC_SC00 + 2)
0948 #define EEEPC_EC_FAN_HRPM (EEEPC_EC_SC00 + 5)
0949 #define EEEPC_EC_FAN_LRPM (EEEPC_EC_SC00 + 6)
0950
0951 #define EEEPC_EC_SFB0 0xD0
0952 #define EEEPC_EC_FAN_CTRL (EEEPC_EC_SFB0 + 3)
0953
0954 static inline int eeepc_pwm_to_lmsensors(int value)
0955 {
0956 return value * 255 / 100;
0957 }
0958
0959 static inline int eeepc_lmsensors_to_pwm(int value)
0960 {
0961 value = clamp_val(value, 0, 255);
0962 return value * 100 / 255;
0963 }
0964
0965 static int eeepc_get_fan_pwm(void)
0966 {
0967 u8 value = 0;
0968
0969 ec_read(EEEPC_EC_FAN_PWM, &value);
0970 return eeepc_pwm_to_lmsensors(value);
0971 }
0972
0973 static void eeepc_set_fan_pwm(int value)
0974 {
0975 value = eeepc_lmsensors_to_pwm(value);
0976 ec_write(EEEPC_EC_FAN_PWM, value);
0977 }
0978
0979 static int eeepc_get_fan_rpm(void)
0980 {
0981 u8 high = 0;
0982 u8 low = 0;
0983
0984 ec_read(EEEPC_EC_FAN_HRPM, &high);
0985 ec_read(EEEPC_EC_FAN_LRPM, &low);
0986 return high << 8 | low;
0987 }
0988
0989 #define EEEPC_EC_FAN_CTRL_BIT 0x02
0990 #define EEEPC_FAN_CTRL_MANUAL 1
0991 #define EEEPC_FAN_CTRL_AUTO 2
0992
0993 static int eeepc_get_fan_ctrl(void)
0994 {
0995 u8 value = 0;
0996
0997 ec_read(EEEPC_EC_FAN_CTRL, &value);
0998 if (value & EEEPC_EC_FAN_CTRL_BIT)
0999 return EEEPC_FAN_CTRL_MANUAL;
1000 else
1001 return EEEPC_FAN_CTRL_AUTO;
1002 }
1003
1004 static void eeepc_set_fan_ctrl(int manual)
1005 {
1006 u8 value = 0;
1007
1008 ec_read(EEEPC_EC_FAN_CTRL, &value);
1009 if (manual == EEEPC_FAN_CTRL_MANUAL)
1010 value |= EEEPC_EC_FAN_CTRL_BIT;
1011 else
1012 value &= ~EEEPC_EC_FAN_CTRL_BIT;
1013 ec_write(EEEPC_EC_FAN_CTRL, value);
1014 }
1015
1016 static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
1017 {
1018 int rv, value;
1019
1020 rv = parse_arg(buf, &value);
1021 if (rv < 0)
1022 return rv;
1023 set(value);
1024 return count;
1025 }
1026
1027 static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
1028 {
1029 return sprintf(buf, "%d\n", get());
1030 }
1031
1032 #define EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
1033 static ssize_t _name##_show(struct device *dev, \
1034 struct device_attribute *attr, \
1035 char *buf) \
1036 { \
1037 return show_sys_hwmon(_get, buf); \
1038 }
1039
1040 #define EEEPC_SENSOR_STORE_FUNC(_name, _set) \
1041 static ssize_t _name##_store(struct device *dev, \
1042 struct device_attribute *attr, \
1043 const char *buf, size_t count) \
1044 { \
1045 return store_sys_hwmon(_set, buf, count); \
1046 }
1047
1048 #define EEEPC_CREATE_SENSOR_ATTR_RW(_name, _get, _set) \
1049 EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
1050 EEEPC_SENSOR_STORE_FUNC(_name, _set) \
1051 static DEVICE_ATTR_RW(_name)
1052
1053 #define EEEPC_CREATE_SENSOR_ATTR_RO(_name, _get) \
1054 EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
1055 static DEVICE_ATTR_RO(_name)
1056
1057 EEEPC_CREATE_SENSOR_ATTR_RO(fan1_input, eeepc_get_fan_rpm);
1058 EEEPC_CREATE_SENSOR_ATTR_RW(pwm1, eeepc_get_fan_pwm,
1059 eeepc_set_fan_pwm);
1060 EEEPC_CREATE_SENSOR_ATTR_RW(pwm1_enable, eeepc_get_fan_ctrl,
1061 eeepc_set_fan_ctrl);
1062
1063 static struct attribute *hwmon_attrs[] = {
1064 &dev_attr_pwm1.attr,
1065 &dev_attr_fan1_input.attr,
1066 &dev_attr_pwm1_enable.attr,
1067 NULL
1068 };
1069 ATTRIBUTE_GROUPS(hwmon);
1070
1071 static int eeepc_hwmon_init(struct eeepc_laptop *eeepc)
1072 {
1073 struct device *dev = &eeepc->platform_device->dev;
1074 struct device *hwmon;
1075
1076 hwmon = devm_hwmon_device_register_with_groups(dev, "eeepc", NULL,
1077 hwmon_groups);
1078 if (IS_ERR(hwmon)) {
1079 pr_err("Could not register eeepc hwmon device\n");
1080 return PTR_ERR(hwmon);
1081 }
1082 return 0;
1083 }
1084
1085
1086
1087
1088 static int read_brightness(struct backlight_device *bd)
1089 {
1090 struct eeepc_laptop *eeepc = bl_get_data(bd);
1091
1092 return get_acpi(eeepc, CM_ASL_PANELBRIGHT);
1093 }
1094
1095 static int set_brightness(struct backlight_device *bd, int value)
1096 {
1097 struct eeepc_laptop *eeepc = bl_get_data(bd);
1098
1099 return set_acpi(eeepc, CM_ASL_PANELBRIGHT, value);
1100 }
1101
1102 static int update_bl_status(struct backlight_device *bd)
1103 {
1104 return set_brightness(bd, bd->props.brightness);
1105 }
1106
1107 static const struct backlight_ops eeepcbl_ops = {
1108 .get_brightness = read_brightness,
1109 .update_status = update_bl_status,
1110 };
1111
1112 static int eeepc_backlight_notify(struct eeepc_laptop *eeepc)
1113 {
1114 struct backlight_device *bd = eeepc->backlight_device;
1115 int old = bd->props.brightness;
1116
1117 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
1118
1119 return old;
1120 }
1121
1122 static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
1123 {
1124 struct backlight_properties props;
1125 struct backlight_device *bd;
1126
1127 memset(&props, 0, sizeof(struct backlight_properties));
1128 props.type = BACKLIGHT_PLATFORM;
1129 props.max_brightness = 15;
1130 bd = backlight_device_register(EEEPC_LAPTOP_FILE,
1131 &eeepc->platform_device->dev, eeepc,
1132 &eeepcbl_ops, &props);
1133 if (IS_ERR(bd)) {
1134 pr_err("Could not register eeepc backlight device\n");
1135 eeepc->backlight_device = NULL;
1136 return PTR_ERR(bd);
1137 }
1138 eeepc->backlight_device = bd;
1139 bd->props.brightness = read_brightness(bd);
1140 bd->props.power = FB_BLANK_UNBLANK;
1141 backlight_update_status(bd);
1142 return 0;
1143 }
1144
1145 static void eeepc_backlight_exit(struct eeepc_laptop *eeepc)
1146 {
1147 backlight_device_unregister(eeepc->backlight_device);
1148 eeepc->backlight_device = NULL;
1149 }
1150
1151
1152
1153
1154
1155 static int eeepc_input_init(struct eeepc_laptop *eeepc)
1156 {
1157 struct input_dev *input;
1158 int error;
1159
1160 input = input_allocate_device();
1161 if (!input)
1162 return -ENOMEM;
1163
1164 input->name = "Asus EeePC extra buttons";
1165 input->phys = EEEPC_LAPTOP_FILE "/input0";
1166 input->id.bustype = BUS_HOST;
1167 input->dev.parent = &eeepc->platform_device->dev;
1168
1169 error = sparse_keymap_setup(input, eeepc_keymap, NULL);
1170 if (error) {
1171 pr_err("Unable to setup input device keymap\n");
1172 goto err_free_dev;
1173 }
1174
1175 error = input_register_device(input);
1176 if (error) {
1177 pr_err("Unable to register input device\n");
1178 goto err_free_dev;
1179 }
1180
1181 eeepc->inputdev = input;
1182 return 0;
1183
1184 err_free_dev:
1185 input_free_device(input);
1186 return error;
1187 }
1188
1189 static void eeepc_input_exit(struct eeepc_laptop *eeepc)
1190 {
1191 if (eeepc->inputdev)
1192 input_unregister_device(eeepc->inputdev);
1193 eeepc->inputdev = NULL;
1194 }
1195
1196
1197
1198
1199 static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
1200 {
1201 if (!eeepc->inputdev)
1202 return;
1203 if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))
1204 pr_info("Unknown key %x pressed\n", event);
1205 }
1206
1207 static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
1208 {
1209 struct eeepc_laptop *eeepc = acpi_driver_data(device);
1210 int old_brightness, new_brightness;
1211 u16 count;
1212
1213 if (event > ACPI_MAX_SYS_NOTIFY)
1214 return;
1215 count = eeepc->event_count[event % 128]++;
1216 acpi_bus_generate_netlink_event(device->pnp.device_class,
1217 dev_name(&device->dev), event,
1218 count);
1219
1220
1221 if (event < NOTIFY_BRN_MIN || event > NOTIFY_BRN_MAX) {
1222 eeepc_input_notify(eeepc, event);
1223 return;
1224 }
1225
1226
1227 if (!eeepc->backlight_device)
1228 return;
1229
1230
1231 old_brightness = eeepc_backlight_notify(eeepc);
1232
1233
1234 new_brightness = event - NOTIFY_BRN_MIN;
1235
1236 if (new_brightness < old_brightness) {
1237 event = NOTIFY_BRN_MIN;
1238 } else if (new_brightness > old_brightness) {
1239 event = NOTIFY_BRN_MAX;
1240 } else {
1241
1242
1243
1244
1245 }
1246 eeepc_input_notify(eeepc, event);
1247 }
1248
1249 static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
1250 {
1251 const char *model;
1252
1253 model = dmi_get_system_info(DMI_PRODUCT_NAME);
1254 if (!model)
1255 return;
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276 if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
1277 eeepc->cpufv_disabled = true;
1278 pr_info("model %s does not officially support setting cpu speed\n",
1279 model);
1280 pr_info("cpufv disabled to avoid instability\n");
1281 }
1282
1283
1284
1285
1286
1287
1288
1289
1290 if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 ||
1291 strcmp(model, "1005PE") == 0) {
1292 eeepc->hotplug_disabled = true;
1293 pr_info("wlan hotplug disabled\n");
1294 }
1295 }
1296
1297 static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)
1298 {
1299 int dummy;
1300
1301
1302
1303 if (!(eeepc->cm_supported & (1 << cm))
1304 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {
1305 pr_info("%s (%x) not reported by BIOS, enabling anyway\n",
1306 name, 1 << cm);
1307 eeepc->cm_supported |= 1 << cm;
1308 }
1309 }
1310
1311 static void cmsg_quirks(struct eeepc_laptop *eeepc)
1312 {
1313 cmsg_quirk(eeepc, CM_ASL_LID, "LID");
1314 cmsg_quirk(eeepc, CM_ASL_TYPE, "TYPE");
1315 cmsg_quirk(eeepc, CM_ASL_PANELPOWER, "PANELPOWER");
1316 cmsg_quirk(eeepc, CM_ASL_TPD, "TPD");
1317 }
1318
1319 static int eeepc_acpi_init(struct eeepc_laptop *eeepc)
1320 {
1321 unsigned int init_flags;
1322 int result;
1323
1324 result = acpi_bus_get_status(eeepc->device);
1325 if (result)
1326 return result;
1327 if (!eeepc->device->status.present) {
1328 pr_err("Hotkey device not present, aborting\n");
1329 return -ENODEV;
1330 }
1331
1332 init_flags = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
1333 pr_notice("Hotkey init flags 0x%x\n", init_flags);
1334
1335 if (write_acpi_int(eeepc->handle, "INIT", init_flags)) {
1336 pr_err("Hotkey initialization failed\n");
1337 return -ENODEV;
1338 }
1339
1340
1341 if (read_acpi_int(eeepc->handle, "CMSG", &eeepc->cm_supported)) {
1342 pr_err("Get control methods supported failed\n");
1343 return -ENODEV;
1344 }
1345 cmsg_quirks(eeepc);
1346 pr_info("Get control methods supported: 0x%x\n", eeepc->cm_supported);
1347
1348 return 0;
1349 }
1350
1351 static void eeepc_enable_camera(struct eeepc_laptop *eeepc)
1352 {
1353
1354
1355
1356
1357 if (get_acpi(eeepc, CM_ASL_CAMERA) == 0)
1358 set_acpi(eeepc, CM_ASL_CAMERA, 1);
1359 }
1360
1361 static bool eeepc_device_present;
1362
1363 static int eeepc_acpi_add(struct acpi_device *device)
1364 {
1365 struct eeepc_laptop *eeepc;
1366 int result;
1367
1368 pr_notice(EEEPC_LAPTOP_NAME "\n");
1369 eeepc = kzalloc(sizeof(struct eeepc_laptop), GFP_KERNEL);
1370 if (!eeepc)
1371 return -ENOMEM;
1372 eeepc->handle = device->handle;
1373 strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);
1374 strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
1375 device->driver_data = eeepc;
1376 eeepc->device = device;
1377
1378 eeepc->hotplug_disabled = hotplug_disabled;
1379
1380 eeepc_dmi_check(eeepc);
1381
1382 result = eeepc_acpi_init(eeepc);
1383 if (result)
1384 goto fail_platform;
1385 eeepc_enable_camera(eeepc);
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399 result = eeepc_platform_init(eeepc);
1400 if (result)
1401 goto fail_platform;
1402
1403 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1404 result = eeepc_backlight_init(eeepc);
1405 if (result)
1406 goto fail_backlight;
1407 }
1408
1409 result = eeepc_input_init(eeepc);
1410 if (result)
1411 goto fail_input;
1412
1413 result = eeepc_hwmon_init(eeepc);
1414 if (result)
1415 goto fail_hwmon;
1416
1417 result = eeepc_led_init(eeepc);
1418 if (result)
1419 goto fail_led;
1420
1421 result = eeepc_rfkill_init(eeepc);
1422 if (result)
1423 goto fail_rfkill;
1424
1425 eeepc_device_present = true;
1426 return 0;
1427
1428 fail_rfkill:
1429 eeepc_led_exit(eeepc);
1430 fail_led:
1431 fail_hwmon:
1432 eeepc_input_exit(eeepc);
1433 fail_input:
1434 eeepc_backlight_exit(eeepc);
1435 fail_backlight:
1436 eeepc_platform_exit(eeepc);
1437 fail_platform:
1438 kfree(eeepc);
1439
1440 return result;
1441 }
1442
1443 static int eeepc_acpi_remove(struct acpi_device *device)
1444 {
1445 struct eeepc_laptop *eeepc = acpi_driver_data(device);
1446
1447 eeepc_backlight_exit(eeepc);
1448 eeepc_rfkill_exit(eeepc);
1449 eeepc_input_exit(eeepc);
1450 eeepc_led_exit(eeepc);
1451 eeepc_platform_exit(eeepc);
1452
1453 kfree(eeepc);
1454 return 0;
1455 }
1456
1457
1458 static const struct acpi_device_id eeepc_device_ids[] = {
1459 {EEEPC_ACPI_HID, 0},
1460 {"", 0},
1461 };
1462 MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
1463
1464 static struct acpi_driver eeepc_acpi_driver = {
1465 .name = EEEPC_LAPTOP_NAME,
1466 .class = EEEPC_ACPI_CLASS,
1467 .owner = THIS_MODULE,
1468 .ids = eeepc_device_ids,
1469 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
1470 .ops = {
1471 .add = eeepc_acpi_add,
1472 .remove = eeepc_acpi_remove,
1473 .notify = eeepc_acpi_notify,
1474 },
1475 };
1476
1477
1478 static int __init eeepc_laptop_init(void)
1479 {
1480 int result;
1481
1482 result = platform_driver_register(&platform_driver);
1483 if (result < 0)
1484 return result;
1485
1486 result = acpi_bus_register_driver(&eeepc_acpi_driver);
1487 if (result < 0)
1488 goto fail_acpi_driver;
1489
1490 if (!eeepc_device_present) {
1491 result = -ENODEV;
1492 goto fail_no_device;
1493 }
1494
1495 return 0;
1496
1497 fail_no_device:
1498 acpi_bus_unregister_driver(&eeepc_acpi_driver);
1499 fail_acpi_driver:
1500 platform_driver_unregister(&platform_driver);
1501 return result;
1502 }
1503
1504 static void __exit eeepc_laptop_exit(void)
1505 {
1506 acpi_bus_unregister_driver(&eeepc_acpi_driver);
1507 platform_driver_unregister(&platform_driver);
1508 }
1509
1510 module_init(eeepc_laptop_init);
1511 module_exit(eeepc_laptop_exit);