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