Commit 52bbe3c7 authored by Alan Jenkins's avatar Alan Jenkins Committed by Len Brown

eeepc-laptop: code movement

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: default avatarAlan Jenkins <alan-jenkins@tuffmail.co.uk>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 9db106be
......@@ -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;
......@@ -190,47 +142,39 @@ static struct key_entry eeepc_keymap[] = {
{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_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;
}
return -EINVAL;
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 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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment