]> git.karo-electronics.de Git - linux-beck.git/commitdiff
eeepc-laptop: code movement
authorAlan Jenkins <alan-jenkins@tuffmail.co.uk>
Thu, 3 Dec 2009 07:45:07 +0000 (07:45 +0000)
committerLen Brown <len.brown@intel.com>
Wed, 9 Dec 2009 20:54:32 +0000 (15:54 -0500)
Move e.g. backlight_init() and backlight_exit() together along with the
other backlight functions, instead of grouping init() and exit()
functions.  Move e.g. backlight_ops to follow the functions it refers
to, and remove the forward declarations.  The code itself should remain
unchanged.

The eeepc-laptop driver implements a number of interfaces like the
backlight class driver.  This change makes it easier to examine the
implementation of one interface at at a time, without having to search
through the file to find init() and exit() functions etc.

Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
Signed-off-by: Len Brown <len.brown@intel.com>
drivers/platform/x86/eeepc-laptop.c

index f4f67967aae2a78785d0e72a84f766caeaae5550..f457587e64d3bdb7c6121e6c9c83fb4986ef3bbd 100644 (file)
@@ -44,6 +44,9 @@
 #define EEEPC_HOTK_DEVICE_NAME "Hotkey"
 #define EEEPC_HOTK_HID         "ASUS010"
 
+MODULE_AUTHOR("Corentin Chary, Eric Cooper");
+MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
+MODULE_LICENSE("GPL");
 
 /*
  * Definitions for Asus EeePC
@@ -118,57 +121,6 @@ static const char *cm_setv[] = {
        NULL, NULL, "PBPS", "TPDS"
 };
 
-#define EEEPC_EC_SC00      0x61
-#define EEEPC_EC_FAN_PWM   (EEEPC_EC_SC00 + 2) /* Fan PWM duty cycle (%) */
-#define EEEPC_EC_FAN_HRPM  (EEEPC_EC_SC00 + 5) /* High byte, fan speed (RPM) */
-#define EEEPC_EC_FAN_LRPM  (EEEPC_EC_SC00 + 6) /* Low byte, fan speed (RPM) */
-
-#define EEEPC_EC_SFB0      0xD0
-#define EEEPC_EC_FAN_CTRL  (EEEPC_EC_SFB0 + 3) /* Byte containing SF25  */
-
-
-/*
- * This is the main structure, we can use it to store useful information
- * about the hotk device
- */
-struct eeepc_hotk {
-       struct acpi_device *device;     /* the device we are in */
-       acpi_handle handle;             /* the handle of the hotk device */
-       u32 cm_supported;               /* the control methods supported
-                                          by this BIOS */
-       u16 event_count[128];           /* count for each event */
-       struct input_dev *inputdev;
-       u16 *keycode_map;
-       struct rfkill *wlan_rfkill;
-       struct rfkill *bluetooth_rfkill;
-       struct rfkill *wwan3g_rfkill;
-       struct rfkill *wimax_rfkill;
-       struct hotplug_slot *hotplug_slot;
-       struct mutex hotplug_lock;
-};
-
-/* The actual device the driver binds to */
-static struct eeepc_hotk *ehotk;
-
-/* Platform device/driver */
-static int eeepc_hotk_thaw(struct device *device);
-static int eeepc_hotk_restore(struct device *device);
-
-static struct dev_pm_ops eeepc_pm_ops = {
-       .thaw = eeepc_hotk_thaw,
-       .restore = eeepc_hotk_restore,
-};
-
-static struct platform_driver platform_driver = {
-       .driver = {
-               .name = EEEPC_HOTK_FILE,
-               .owner = THIS_MODULE,
-               .pm = &eeepc_pm_ops,
-       }
-};
-
-static struct platform_device *platform_device;
-
 struct key_entry {
        char type;
        u8 code;
@@ -189,48 +141,40 @@ static struct key_entry eeepc_keymap[] = {
        {KE_KEY, 0x1b, KEY_ZOOM },
        {KE_KEY, 0x1c, KEY_PROG2 },
        {KE_KEY, 0x1d, KEY_PROG3 },
-       {KE_KEY, NOTIFY_BRN_MIN,     KEY_BRIGHTNESSDOWN },
-       {KE_KEY, NOTIFY_BRN_MIN + 2, KEY_BRIGHTNESSUP },
+       {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN },
+       {KE_KEY, NOTIFY_BRN_MAX, KEY_BRIGHTNESSUP },
        {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
        {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
        {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
        {KE_END, 0},
 };
 
+
 /*
- * The hotkey driver declaration
+ * This is the main structure, we can use it to store useful information
+ * about the hotk device
  */
-static int eeepc_hotk_add(struct acpi_device *device);
-static int eeepc_hotk_remove(struct acpi_device *device, int type);
-static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
-
-static const struct acpi_device_id eeepc_device_ids[] = {
-       {EEEPC_HOTK_HID, 0},
-       {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
-
-static struct acpi_driver eeepc_hotk_driver = {
-       .name = EEEPC_HOTK_NAME,
-       .class = EEEPC_HOTK_CLASS,
-       .owner = THIS_MODULE,
-       .ids = eeepc_device_ids,
-       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
-       .ops = {
-               .add = eeepc_hotk_add,
-               .remove = eeepc_hotk_remove,
-               .notify = eeepc_hotk_notify,
-       },
+struct eeepc_hotk {
+       struct acpi_device *device;     /* the device we are in */
+       acpi_handle handle;             /* the handle of the hotk device */
+       u32 cm_supported;               /* the control methods supported
+                                          by this BIOS */
+       u16 event_count[128];           /* count for each event */
+       struct input_dev *inputdev;
+       u16 *keycode_map;
+       struct rfkill *wlan_rfkill;
+       struct rfkill *bluetooth_rfkill;
+       struct rfkill *wwan3g_rfkill;
+       struct rfkill *wimax_rfkill;
+       struct hotplug_slot *hotplug_slot;
+       struct mutex hotplug_lock;
 };
 
-/* PCI hotplug ops */
-static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value);
+/* The actual device the driver binds to */
+static struct eeepc_hotk *ehotk;
 
-static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
-       .owner = THIS_MODULE,
-       .get_adapter_status = eeepc_get_adapter_status,
-       .get_power_status = eeepc_get_adapter_status,
-};
+/* The platform device */
+static struct platform_device *platform_device;
 
 /* The backlight device /sys/class/backlight */
 static struct backlight_device *eeepc_backlight_device;
@@ -238,19 +182,6 @@ static struct backlight_device *eeepc_backlight_device;
 /* The hwmon device */
 static struct device *eeepc_hwmon_device;
 
-/*
- * The backlight class declaration
- */
-static int read_brightness(struct backlight_device *bd);
-static int update_bl_status(struct backlight_device *bd);
-static struct backlight_ops eeepcbl_ops = {
-       .get_brightness = read_brightness,
-       .update_status = update_bl_status,
-};
-
-MODULE_AUTHOR("Corentin Chary, Eric Cooper");
-MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
-MODULE_LICENSE("GPL");
 
 /*
  * ACPI Helpers
@@ -314,55 +245,6 @@ static int get_acpi(int cm)
        return value;
 }
 
-/*
- * Backlight
- */
-static int read_brightness(struct backlight_device *bd)
-{
-       return get_acpi(CM_ASL_PANELBRIGHT);
-}
-
-static int set_brightness(struct backlight_device *bd, int value)
-{
-       return set_acpi(CM_ASL_PANELBRIGHT, value);
-}
-
-static int update_bl_status(struct backlight_device *bd)
-{
-       return set_brightness(bd, bd->props.brightness);
-}
-
-/*
- * Rfkill helpers
- */
-
-static bool eeepc_wlan_rfkill_blocked(void)
-{
-       if (get_acpi(CM_ASL_WLAN) == 1)
-               return false;
-       return true;
-}
-
-static int eeepc_rfkill_set(void *data, bool blocked)
-{
-       unsigned long asl = (unsigned long)data;
-       return set_acpi(asl, !blocked);
-}
-
-static const struct rfkill_ops eeepc_rfkill_ops = {
-       .set_block = eeepc_rfkill_set,
-};
-
-static void __devinit eeepc_enable_camera(void)
-{
-       /*
-        * If the following call to set_acpi() fails, it's because there's no
-        * camera so we can ignore the error.
-        */
-       if (get_acpi(CM_ASL_CAMERA) == 0)
-               set_acpi(CM_ASL_CAMERA, 1);
-}
-
 /*
  * Sys helpers
  */
@@ -574,248 +456,97 @@ static struct led_classdev tpd_led = {
        .max_brightness = 1
 };
 
-/*
- * Hotkey functions
- */
-static struct key_entry *eepc_get_entry_by_scancode(int code)
+static int eeepc_led_init(struct device *dev)
 {
-       struct key_entry *key;
-
-       for (key = eeepc_keymap; key->type != KE_END; key++)
-               if (code == key->code)
-                       return key;
+       int rv;
 
-       return NULL;
-}
+       if (get_acpi(CM_ASL_TPD) == -ENODEV)
+               return 0;
 
-static struct key_entry *eepc_get_entry_by_keycode(int code)
-{
-       struct key_entry *key;
+       led_workqueue = create_singlethread_workqueue("led_workqueue");
+       if (!led_workqueue)
+               return -ENOMEM;
 
-       for (key = eeepc_keymap; key->type != KE_END; key++)
-               if (code == key->keycode && key->type == KE_KEY)
-                       return key;
+       rv = led_classdev_register(dev, &tpd_led);
+       if (rv) {
+               destroy_workqueue(led_workqueue);
+               return rv;
+       }
 
-       return NULL;
+       return 0;
 }
 
-static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+static void eeepc_led_exit(void)
 {
-       struct key_entry *key = eepc_get_entry_by_scancode(scancode);
+       if (tpd_led.dev)
+               led_classdev_unregister(&tpd_led);
+       if (led_workqueue)
+               destroy_workqueue(led_workqueue);
+}
 
-       if (key && key->type == KE_KEY) {
-               *keycode = key->keycode;
-               return 0;
-       }
 
-       return -EINVAL;
+/*
+ * PCI hotplug (for wlan rfkill)
+ */
+static bool eeepc_wlan_rfkill_blocked(void)
+{
+       if (get_acpi(CM_ASL_WLAN) == 1)
+               return false;
+       return true;
 }
 
-static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
+static void eeepc_rfkill_hotplug(void)
 {
-       struct key_entry *key;
-       int old_keycode;
+       struct pci_dev *dev;
+       struct pci_bus *bus;
+       bool blocked = eeepc_wlan_rfkill_blocked();
 
-       if (keycode < 0 || keycode > KEY_MAX)
-               return -EINVAL;
+       if (ehotk->wlan_rfkill)
+               rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
 
-       key = eepc_get_entry_by_scancode(scancode);
-       if (key && key->type == KE_KEY) {
-               old_keycode = key->keycode;
-               key->keycode = keycode;
-               set_bit(keycode, dev->keybit);
-               if (!eepc_get_entry_by_keycode(old_keycode))
-                       clear_bit(old_keycode, dev->keybit);
-               return 0;
+       mutex_lock(&ehotk->hotplug_lock);
+
+       if (ehotk->hotplug_slot) {
+               bus = pci_find_bus(0, 1);
+               if (!bus) {
+                       pr_warning("Unable to find PCI bus 1?\n");
+                       goto out_unlock;
+               }
+
+               if (!blocked) {
+                       dev = pci_get_slot(bus, 0);
+                       if (dev) {
+                               /* Device already present */
+                               pci_dev_put(dev);
+                               goto out_unlock;
+                       }
+                       dev = pci_scan_single_device(bus, 0);
+                       if (dev) {
+                               pci_bus_assign_resources(bus);
+                               if (pci_bus_add_device(dev))
+                                       pr_err("Unable to hotplug wifi\n");
+                       }
+               } else {
+                       dev = pci_get_slot(bus, 0);
+                       if (dev) {
+                               pci_remove_bus_device(dev);
+                               pci_dev_put(dev);
+                       }
+               }
        }
 
-       return -EINVAL;
+out_unlock:
+       mutex_unlock(&ehotk->hotplug_lock);
 }
 
-static void cmsg_quirk(int cm, const char *name)
+static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
 {
-       int dummy;
-
-       /* Some BIOSes do not report cm although it is avaliable.
-          Check if cm_getv[cm] works and, if yes, assume cm should be set. */
-       if (!(ehotk->cm_supported & (1 << cm))
-           && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) {
-               pr_info("%s (%x) not reported by BIOS,"
-                       " enabling anyway\n", name, 1 << cm);
-               ehotk->cm_supported |= 1 << cm;
-       }
-}
-
-static void cmsg_quirks(void)
-{
-       cmsg_quirk(CM_ASL_LID, "LID");
-       cmsg_quirk(CM_ASL_TYPE, "TYPE");
-       cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER");
-       cmsg_quirk(CM_ASL_TPD, "TPD");
-}
-
-static int eeepc_hotk_init(void)
-{
-       unsigned int init_flags;
-       int result;
-
-       result = acpi_bus_get_status(ehotk->device);
-       if (result)
-               return result;
-       if (!ehotk->device->status.present) {
-               pr_err("Hotkey device not present, aborting\n");
-               return -ENODEV;
-       }
-
-       init_flags = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
-       pr_notice("Hotkey init flags 0x%x\n", init_flags);
-
-       if (write_acpi_int(ehotk->handle, "INIT", init_flags)) {
-               pr_err("Hotkey initialization failed\n");
-               return -ENODEV;
-       }
-
-       /* get control methods supported */
-       if (read_acpi_int(ehotk->handle, "CMSG",
-                               &ehotk->cm_supported)) {
-               pr_err("Get control methods supported failed\n");
-               return -ENODEV;
-       }
-       cmsg_quirks();
-       pr_info("Get control methods supported: 0x%x\n", ehotk->cm_supported);
-
-       return 0;
-}
-
-static int eeepc_backlight_notify(void)
-{
-       struct backlight_device *bd = eeepc_backlight_device;
-       int old = bd->props.brightness;
-
-       backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
-
-       return old;
-}
-
-static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
-                                   u8 *value)
-{
-       int val = get_acpi(CM_ASL_WLAN);
-
-       if (val == 1 || val == 0)
-               *value = val;
-       else
-               return -EINVAL;
-
-       return 0;
-}
-
-static void eeepc_rfkill_hotplug(void)
-{
-       struct pci_dev *dev;
-       struct pci_bus *bus;
-       bool blocked = eeepc_wlan_rfkill_blocked();
-
-       if (ehotk->wlan_rfkill)
-               rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
-
-       mutex_lock(&ehotk->hotplug_lock);
-
-       if (ehotk->hotplug_slot) {
-               bus = pci_find_bus(0, 1);
-               if (!bus) {
-                       pr_warning("Unable to find PCI bus 1?\n");
-                       goto out_unlock;
-               }
-
-               if (!blocked) {
-                       dev = pci_get_slot(bus, 0);
-                       if (dev) {
-                               /* Device already present */
-                               pci_dev_put(dev);
-                               goto out_unlock;
-                       }
-                       dev = pci_scan_single_device(bus, 0);
-                       if (dev) {
-                               pci_bus_assign_resources(bus);
-                               if (pci_bus_add_device(dev))
-                                       pr_err("Unable to hotplug wifi\n");
-                       }
-               } else {
-                       dev = pci_get_slot(bus, 0);
-                       if (dev) {
-                               pci_remove_bus_device(dev);
-                               pci_dev_put(dev);
-                       }
-               }
-       }
-
-out_unlock:
-       mutex_unlock(&ehotk->hotplug_lock);
-}
-
-static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
-{
-       if (event != ACPI_NOTIFY_BUS_CHECK)
-               return;
+       if (event != ACPI_NOTIFY_BUS_CHECK)
+               return;
 
        eeepc_rfkill_hotplug();
 }
 
-static void eeepc_input_notify(int event)
-{
-       static struct key_entry *key;
-
-       key = eepc_get_entry_by_scancode(event);
-       if (key) {
-               switch (key->type) {
-               case KE_KEY:
-                       input_report_key(ehotk->inputdev, key->keycode,
-                                               1);
-                       input_sync(ehotk->inputdev);
-                       input_report_key(ehotk->inputdev, key->keycode,
-                                               0);
-                       input_sync(ehotk->inputdev);
-                       break;
-               }
-       }
-}
-
-static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
-{
-       u16 count;
-
-       if (event > ACPI_MAX_SYS_NOTIFY)
-               return;
-       count = ehotk->event_count[event % 128]++;
-       acpi_bus_generate_proc_event(ehotk->device, event, count);
-       acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class,
-                                       dev_name(&ehotk->device->dev), event,
-                                       count);
-
-       if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) {
-               int old_brightness, new_brightness;
-
-               /* Update backlight device. */
-               old_brightness = eeepc_backlight_notify();
-
-               /* Convert brightness event to keypress (obsolescent hack). */
-               new_brightness = event - NOTIFY_BRN_MIN;
-
-               if (new_brightness < old_brightness) {
-                       event = NOTIFY_BRN_MIN; /* brightness down */
-               } else if (new_brightness > old_brightness) {
-                       event = NOTIFY_BRN_MAX; /* brightness up */
-               } else {
-                       /*
-                        * no change in brightness - already at min/max,
-                        * event will be desired value (or else ignored).
-                        */
-               }
-       }
-       eeepc_input_notify(event);
-}
-
 static int eeepc_register_rfkill_notifier(char *node)
 {
        acpi_status status = AE_OK;
@@ -853,12 +584,31 @@ static void eeepc_unregister_rfkill_notifier(char *node)
        }
 }
 
+static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
+                                   u8 *value)
+{
+       int val = get_acpi(CM_ASL_WLAN);
+
+       if (val == 1 || val == 0)
+               *value = val;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
 static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
 {
        kfree(hotplug_slot->info);
        kfree(hotplug_slot);
 }
 
+static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
+       .owner = THIS_MODULE,
+       .get_adapter_status = eeepc_get_adapter_status,
+       .get_power_status = eeepc_get_adapter_status,
+};
+
 static int eeepc_setup_pci_hotplug(void)
 {
        int ret = -ENOMEM;
@@ -901,6 +651,140 @@ error_slot:
        return ret;
 }
 
+/*
+ * Rfkill devices
+ */
+static int eeepc_rfkill_set(void *data, bool blocked)
+{
+       unsigned long asl = (unsigned long)data;
+       return set_acpi(asl, !blocked);
+}
+
+static const struct rfkill_ops eeepc_rfkill_ops = {
+       .set_block = eeepc_rfkill_set,
+};
+
+static int eeepc_new_rfkill(struct rfkill **rfkill,
+                           const char *name, struct device *dev,
+                           enum rfkill_type type, int cm)
+{
+       int result;
+
+       result = get_acpi(cm);
+       if (result < 0)
+               return result;
+
+       *rfkill = rfkill_alloc(name, dev, type,
+                              &eeepc_rfkill_ops, (void *)(unsigned long)cm);
+
+       if (!*rfkill)
+               return -EINVAL;
+
+       rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1);
+       result = rfkill_register(*rfkill);
+       if (result) {
+               rfkill_destroy(*rfkill);
+               *rfkill = NULL;
+               return result;
+       }
+       return 0;
+}
+
+static void eeepc_rfkill_exit(void)
+{
+       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5");
+       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
+       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
+       if (ehotk->wlan_rfkill) {
+               rfkill_unregister(ehotk->wlan_rfkill);
+               rfkill_destroy(ehotk->wlan_rfkill);
+               ehotk->wlan_rfkill = NULL;
+       }
+       /*
+        * Refresh pci hotplug in case the rfkill state was changed after
+        * eeepc_unregister_rfkill_notifier()
+        */
+       eeepc_rfkill_hotplug();
+       if (ehotk->hotplug_slot)
+               pci_hp_deregister(ehotk->hotplug_slot);
+
+       if (ehotk->bluetooth_rfkill) {
+               rfkill_unregister(ehotk->bluetooth_rfkill);
+               rfkill_destroy(ehotk->bluetooth_rfkill);
+               ehotk->bluetooth_rfkill = NULL;
+       }
+       if (ehotk->wwan3g_rfkill) {
+               rfkill_unregister(ehotk->wwan3g_rfkill);
+               rfkill_destroy(ehotk->wwan3g_rfkill);
+               ehotk->wwan3g_rfkill = NULL;
+       }
+       if (ehotk->wimax_rfkill) {
+               rfkill_unregister(ehotk->wimax_rfkill);
+               rfkill_destroy(ehotk->wimax_rfkill);
+               ehotk->wimax_rfkill = NULL;
+       }
+}
+
+static int eeepc_rfkill_init(struct device *dev)
+{
+       int result = 0;
+
+       mutex_init(&ehotk->hotplug_lock);
+
+       result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
+                                 "eeepc-wlan", dev,
+                                 RFKILL_TYPE_WLAN, CM_ASL_WLAN);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill,
+                                 "eeepc-bluetooth", dev,
+                                 RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill,
+                                 "eeepc-wwan3g", dev,
+                                 RFKILL_TYPE_WWAN, CM_ASL_3G);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = eeepc_new_rfkill(&ehotk->wimax_rfkill,
+                                 "eeepc-wimax", dev,
+                                 RFKILL_TYPE_WIMAX, CM_ASL_WIMAX);
+
+       if (result && result != -ENODEV)
+               goto exit;
+
+       result = eeepc_setup_pci_hotplug();
+       /*
+        * If we get -EBUSY then something else is handling the PCI hotplug -
+        * don't fail in this case
+        */
+       if (result == -EBUSY)
+               result = 0;
+
+       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5");
+       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
+       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
+       /*
+        * Refresh pci hotplug in case the rfkill state was changed during
+        * setup.
+        */
+       eeepc_rfkill_hotplug();
+
+exit:
+       if (result && result != -ENODEV)
+               eeepc_rfkill_exit();
+       return result;
+}
+
+/*
+ * Platform driver - hibernate/resume callbacks
+ */
 static int eeepc_hotk_thaw(struct device *device)
 {
        if (ehotk->wlan_rfkill) {
@@ -937,9 +821,31 @@ static int eeepc_hotk_restore(struct device *device)
        return 0;
 }
 
+static struct dev_pm_ops eeepc_pm_ops = {
+       .thaw = eeepc_hotk_thaw,
+       .restore = eeepc_hotk_restore,
+};
+
+static struct platform_driver platform_driver = {
+       .driver = {
+               .name = EEEPC_HOTK_FILE,
+               .owner = THIS_MODULE,
+               .pm = &eeepc_pm_ops,
+       }
+};
+
 /*
- * Hwmon
+ * Hwmon device
  */
+
+#define EEEPC_EC_SC00      0x61
+#define EEEPC_EC_FAN_PWM   (EEEPC_EC_SC00 + 2) /* Fan PWM duty cycle (%) */
+#define EEEPC_EC_FAN_HRPM  (EEEPC_EC_SC00 + 5) /* High byte, fan speed (RPM) */
+#define EEEPC_EC_FAN_LRPM  (EEEPC_EC_SC00 + 6) /* Low byte, fan speed (RPM) */
+
+#define EEEPC_EC_SFB0      0xD0
+#define EEEPC_EC_FAN_CTRL  (EEEPC_EC_SFB0 + 3) /* Byte containing SF25  */
+
 static int eeepc_get_fan_pwm(void)
 {
        u8 value = 0;
@@ -1043,57 +949,6 @@ static struct attribute_group hwmon_attribute_group = {
        .attrs = hwmon_attributes
 };
 
-/*
- * exit/init
- */
-static void eeepc_backlight_exit(void)
-{
-       if (eeepc_backlight_device)
-               backlight_device_unregister(eeepc_backlight_device);
-       eeepc_backlight_device = NULL;
-}
-
-static void eeepc_rfkill_exit(void)
-{
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5");
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
-       eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
-       if (ehotk->wlan_rfkill) {
-               rfkill_unregister(ehotk->wlan_rfkill);
-               rfkill_destroy(ehotk->wlan_rfkill);
-               ehotk->wlan_rfkill = NULL;
-       }
-       /*
-        * Refresh pci hotplug in case the rfkill state was changed after
-        * eeepc_unregister_rfkill_notifier()
-        */
-       eeepc_rfkill_hotplug();
-       if (ehotk->hotplug_slot)
-               pci_hp_deregister(ehotk->hotplug_slot);
-
-       if (ehotk->bluetooth_rfkill) {
-               rfkill_unregister(ehotk->bluetooth_rfkill);
-               rfkill_destroy(ehotk->bluetooth_rfkill);
-               ehotk->bluetooth_rfkill = NULL;
-       }
-       if (ehotk->wwan3g_rfkill) {
-               rfkill_unregister(ehotk->wwan3g_rfkill);
-               rfkill_destroy(ehotk->wwan3g_rfkill);
-               ehotk->wwan3g_rfkill = NULL;
-       }
-       if (ehotk->wimax_rfkill) {
-               rfkill_unregister(ehotk->wimax_rfkill);
-               rfkill_destroy(ehotk->wimax_rfkill);
-               ehotk->wimax_rfkill = NULL;
-       }
-}
-
-static void eeepc_input_exit(void)
-{
-       if (ehotk->inputdev)
-               input_unregister_device(ehotk->inputdev);
-}
-
 static void eeepc_hwmon_exit(void)
 {
        struct device *hwmon;
@@ -1107,96 +962,56 @@ static void eeepc_hwmon_exit(void)
        eeepc_hwmon_device = NULL;
 }
 
-static void eeepc_led_exit(void)
-{
-       if (tpd_led.dev)
-               led_classdev_unregister(&tpd_led);
-       if (led_workqueue)
-               destroy_workqueue(led_workqueue);
-}
-
-static int eeepc_new_rfkill(struct rfkill **rfkill,
-                           const char *name, struct device *dev,
-                           enum rfkill_type type, int cm)
+static int eeepc_hwmon_init(struct device *dev)
 {
+       struct device *hwmon;
        int result;
 
-       result = get_acpi(cm);
-       if (result < 0)
-               return result;
-
-       *rfkill = rfkill_alloc(name, dev, type,
-                              &eeepc_rfkill_ops, (void *)(unsigned long)cm);
-
-       if (!*rfkill)
-               return -EINVAL;
-
-       rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1);
-       result = rfkill_register(*rfkill);
-       if (result) {
-               rfkill_destroy(*rfkill);
-               *rfkill = NULL;
-               return result;
+       hwmon = hwmon_device_register(dev);
+       if (IS_ERR(hwmon)) {
+               pr_err("Could not register eeepc hwmon device\n");
+               eeepc_hwmon_device = NULL;
+               return PTR_ERR(hwmon);
        }
-       return 0;
+       eeepc_hwmon_device = hwmon;
+       result = sysfs_create_group(&hwmon->kobj,
+                                   &hwmon_attribute_group);
+       if (result)
+               eeepc_hwmon_exit();
+       return result;
 }
 
-
-static int eeepc_rfkill_init(struct device *dev)
+/*
+ * Backlight device
+ */
+static int read_brightness(struct backlight_device *bd)
 {
-       int result = 0;
-
-       mutex_init(&ehotk->hotplug_lock);
-
-       result = eeepc_new_rfkill(&ehotk->wlan_rfkill,
-                                 "eeepc-wlan", dev,
-                                 RFKILL_TYPE_WLAN, CM_ASL_WLAN);
-
-       if (result && result != -ENODEV)
-               goto exit;
-
-       result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill,
-                                 "eeepc-bluetooth", dev,
-                                 RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH);
-
-       if (result && result != -ENODEV)
-               goto exit;
-
-       result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill,
-                                 "eeepc-wwan3g", dev,
-                                 RFKILL_TYPE_WWAN, CM_ASL_3G);
+       return get_acpi(CM_ASL_PANELBRIGHT);
+}
 
-       if (result && result != -ENODEV)
-               goto exit;
+static int set_brightness(struct backlight_device *bd, int value)
+{
+       return set_acpi(CM_ASL_PANELBRIGHT, value);
+}
 
-       result = eeepc_new_rfkill(&ehotk->wimax_rfkill,
-                                 "eeepc-wimax", dev,
-                                 RFKILL_TYPE_WIMAX, CM_ASL_WIMAX);
+static int update_bl_status(struct backlight_device *bd)
+{
+       return set_brightness(bd, bd->props.brightness);
+}
 
-       if (result && result != -ENODEV)
-               goto exit;
+static struct backlight_ops eeepcbl_ops = {
+       .get_brightness = read_brightness,
+       .update_status = update_bl_status,
+};
 
-       result = eeepc_setup_pci_hotplug();
-       /*
-        * If we get -EBUSY then something else is handling the PCI hotplug -
-        * don't fail in this case
-        */
-       if (result == -EBUSY)
-               result = 0;
+static int eeepc_backlight_notify(void)
+{
+       struct backlight_device *bd = eeepc_backlight_device;
+       int old = bd->props.brightness;
 
-       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5");
-       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
-       eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
-       /*
-        * Refresh pci hotplug in case the rfkill state was changed during
-        * setup.
-        */
-       eeepc_rfkill_hotplug();
+       backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
 
-exit:
-       if (result && result != -ENODEV)
-               eeepc_rfkill_exit();
-       return result;
+       return old;
 }
 
 static int eeepc_backlight_init(struct device *dev)
@@ -1218,23 +1033,89 @@ static int eeepc_backlight_init(struct device *dev)
        return 0;
 }
 
-static int eeepc_hwmon_init(struct device *dev)
+static void eeepc_backlight_exit(void)
 {
-       struct device *hwmon;
-       int result;
+       if (eeepc_backlight_device)
+               backlight_device_unregister(eeepc_backlight_device);
+       eeepc_backlight_device = NULL;
+}
 
-       hwmon = hwmon_device_register(dev);
-       if (IS_ERR(hwmon)) {
-               pr_err("Could not register eeepc hwmon device\n");
-               eeepc_hwmon_device = NULL;
-               return PTR_ERR(hwmon);
+
+/*
+ * Input device (i.e. hotkeys)
+ */
+static struct key_entry *eeepc_get_entry_by_scancode(int code)
+{
+       struct key_entry *key;
+
+       for (key = eeepc_keymap; key->type != KE_END; key++)
+               if (code == key->code)
+                       return key;
+
+       return NULL;
+}
+
+static void eeepc_input_notify(int event)
+{
+       static struct key_entry *key;
+
+       key = eeepc_get_entry_by_scancode(event);
+       if (key) {
+               switch (key->type) {
+               case KE_KEY:
+                       input_report_key(ehotk->inputdev, key->keycode,
+                                               1);
+                       input_sync(ehotk->inputdev);
+                       input_report_key(ehotk->inputdev, key->keycode,
+                                               0);
+                       input_sync(ehotk->inputdev);
+                       break;
+               }
        }
-       eeepc_hwmon_device = hwmon;
-       result = sysfs_create_group(&hwmon->kobj,
-                                   &hwmon_attribute_group);
-       if (result)
-               eeepc_hwmon_exit();
-       return result;
+}
+
+static struct key_entry *eepc_get_entry_by_keycode(int code)
+{
+       struct key_entry *key;
+
+       for (key = eeepc_keymap; key->type != KE_END; key++)
+               if (code == key->keycode && key->type == KE_KEY)
+                       return key;
+
+       return NULL;
+}
+
+static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
+{
+       struct key_entry *key = eeepc_get_entry_by_scancode(scancode);
+
+       if (key && key->type == KE_KEY) {
+               *keycode = key->keycode;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
+{
+       struct key_entry *key;
+       int old_keycode;
+
+       if (keycode < 0 || keycode > KEY_MAX)
+               return -EINVAL;
+
+       key = eeepc_get_entry_by_scancode(scancode);
+       if (key && key->type == KE_KEY) {
+               old_keycode = key->keycode;
+               key->keycode = keycode;
+               set_bit(keycode, dev->keybit);
+               if (!eepc_get_entry_by_keycode(old_keycode))
+                       clear_bit(old_keycode, dev->keybit);
+               return 0;
+       }
+
+       return -EINVAL;
 }
 
 static int eeepc_input_init(struct device *dev)
@@ -1271,26 +1152,114 @@ static int eeepc_input_init(struct device *dev)
        return 0;
 }
 
-static int eeepc_led_init(struct device *dev)
+static void eeepc_input_exit(void)
 {
-       int rv;
+       if (ehotk->inputdev)
+               input_unregister_device(ehotk->inputdev);
+}
 
-       if (get_acpi(CM_ASL_TPD) == -ENODEV)
-               return 0;
+/*
+ * ACPI driver
+ */
+static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
+{
+       u16 count;
 
-       led_workqueue = create_singlethread_workqueue("led_workqueue");
-       if (!led_workqueue)
-               return -ENOMEM;
+       if (event > ACPI_MAX_SYS_NOTIFY)
+               return;
+       count = ehotk->event_count[event % 128]++;
+       acpi_bus_generate_proc_event(ehotk->device, event, count);
+       acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class,
+                                       dev_name(&ehotk->device->dev), event,
+                                       count);
 
-       rv = led_classdev_register(dev, &tpd_led);
-       if (rv) {
-               destroy_workqueue(led_workqueue);
-               return rv;
+       if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) {
+               int old_brightness, new_brightness;
+
+               /* Update backlight device. */
+               old_brightness = eeepc_backlight_notify();
+
+               /* Convert brightness event to keypress (obsolescent hack). */
+               new_brightness = event - NOTIFY_BRN_MIN;
+
+               if (new_brightness < old_brightness) {
+                       event = NOTIFY_BRN_MIN; /* brightness down */
+               } else if (new_brightness > old_brightness) {
+                       event = NOTIFY_BRN_MAX; /* brightness up */
+               } else {
+                       /*
+                        * no change in brightness - already at min/max,
+                        * event will be desired value (or else ignored).
+                        */
+               }
+       }
+       eeepc_input_notify(event);
+}
+
+static void cmsg_quirk(int cm, const char *name)
+{
+       int dummy;
+
+       /* Some BIOSes do not report cm although it is avaliable.
+          Check if cm_getv[cm] works and, if yes, assume cm should be set. */
+       if (!(ehotk->cm_supported & (1 << cm))
+           && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) {
+               pr_info("%s (%x) not reported by BIOS,"
+                       " enabling anyway\n", name, 1 << cm);
+               ehotk->cm_supported |= 1 << cm;
+       }
+}
+
+static void cmsg_quirks(void)
+{
+       cmsg_quirk(CM_ASL_LID, "LID");
+       cmsg_quirk(CM_ASL_TYPE, "TYPE");
+       cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER");
+       cmsg_quirk(CM_ASL_TPD, "TPD");
+}
+
+static int eeepc_hotk_init(void)
+{
+       unsigned int init_flags;
+       int result;
+
+       result = acpi_bus_get_status(ehotk->device);
+       if (result)
+               return result;
+       if (!ehotk->device->status.present) {
+               pr_err("Hotkey device not present, aborting\n");
+               return -ENODEV;
+       }
+
+       init_flags = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
+       pr_notice("Hotkey init flags 0x%x\n", init_flags);
+
+       if (write_acpi_int(ehotk->handle, "INIT", init_flags)) {
+               pr_err("Hotkey initialization failed\n");
+               return -ENODEV;
+       }
+
+       /* get control methods supported */
+       if (read_acpi_int(ehotk->handle, "CMSG", &ehotk->cm_supported)) {
+               pr_err("Get control methods supported failed\n");
+               return -ENODEV;
        }
+       cmsg_quirks();
+       pr_info("Get control methods supported: 0x%x\n", ehotk->cm_supported);
 
        return 0;
 }
 
+static void __devinit eeepc_enable_camera(void)
+{
+       /*
+        * If the following call to set_acpi() fails, it's because there's no
+        * camera so we can ignore the error.
+        */
+       if (get_acpi(CM_ASL_CAMERA) == 0)
+               set_acpi(CM_ASL_CAMERA, 1);
+}
+
 static int __devinit eeepc_hotk_add(struct acpi_device *device)
 {
        struct device *dev;
@@ -1371,6 +1340,27 @@ static int eeepc_hotk_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+
+static const struct acpi_device_id eeepc_device_ids[] = {
+       {EEEPC_HOTK_HID, 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
+
+static struct acpi_driver eeepc_hotk_driver = {
+       .name = EEEPC_HOTK_NAME,
+       .class = EEEPC_HOTK_CLASS,
+       .owner = THIS_MODULE,
+       .ids = eeepc_device_ids,
+       .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
+       .ops = {
+               .add = eeepc_hotk_add,
+               .remove = eeepc_hotk_remove,
+               .notify = eeepc_hotk_notify,
+       },
+};
+
+
 static int __init eeepc_laptop_init(void)
 {
        int result;