Merge branch 'acer-wmi' into test

This commit is contained in:
Len Brown 2008-10-22 23:19:47 -04:00
commit aa58329fc8
4 changed files with 176 additions and 105 deletions

View File

@ -1,7 +1,7 @@
Acer Laptop WMI Extras Driver
http://code.google.com/p/aceracpi
Version 0.1
9th February 2008
Version 0.2
18th August 2008
Copyright 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
@ -87,17 +87,7 @@ acer-wmi come with built-in wireless. However, should you feel so inclined to
ever wish to remove the card, or swap it out at some point, please get in touch
with me, as we may well be able to gain some data on wireless card detection.
To read the status of the wireless radio (0=off, 1=on):
cat /sys/devices/platform/acer-wmi/wireless
To enable the wireless radio:
echo 1 > /sys/devices/platform/acer-wmi/wireless
To disable the wireless radio:
echo 0 > /sys/devices/platform/acer-wmi/wireless
To set the state of the wireless radio when loading acer-wmi, pass:
wireless=X (where X is 0 or 1)
The wireless radio is exposed through rfkill.
Bluetooth
*********
@ -117,17 +107,7 @@ For the adventurously minded - if you want to buy an internal bluetooth
module off the internet that is compatible with your laptop and fit it, then
it will work just fine with acer-wmi.
To read the status of the bluetooth module (0=off, 1=on):
cat /sys/devices/platform/acer-wmi/wireless
To enable the bluetooth module:
echo 1 > /sys/devices/platform/acer-wmi/bluetooth
To disable the bluetooth module:
echo 0 > /sys/devices/platform/acer-wmi/bluetooth
To set the state of the bluetooth module when loading acer-wmi, pass:
bluetooth=X (where X is 0 or 1)
Bluetooth is exposed through rfkill.
3G
**

View File

@ -217,6 +217,35 @@ static bool find_guid(const char *guid_string, struct wmi_block **out)
return 0;
}
static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
{
struct guid_block *block = NULL;
char method[5];
struct acpi_object_list input;
union acpi_object params[1];
acpi_status status;
acpi_handle handle;
block = &wblock->gblock;
handle = wblock->handle;
if (!block)
return AE_NOT_EXIST;
input.count = 1;
input.pointer = params;
params[0].type = ACPI_TYPE_INTEGER;
params[0].integer.value = enable;
snprintf(method, 5, "WE%02X", block->notify_id);
status = acpi_evaluate_object(handle, method, &input, NULL);
if (status != AE_OK && status != AE_NOT_FOUND)
return status;
else
return AE_OK;
}
/*
* Exported WMI functions
*/
@ -427,6 +456,7 @@ acpi_status wmi_install_notify_handler(const char *guid,
wmi_notify_handler handler, void *data)
{
struct wmi_block *block;
acpi_status status;
if (!guid || !handler)
return AE_BAD_PARAMETER;
@ -441,7 +471,9 @@ wmi_notify_handler handler, void *data)
block->handler = handler;
block->handler_data = data;
return AE_OK;
status = wmi_method_enable(block, 1);
return status;
}
EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
@ -453,6 +485,7 @@ EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
acpi_status wmi_remove_notify_handler(const char *guid)
{
struct wmi_block *block;
acpi_status status;
if (!guid)
return AE_BAD_PARAMETER;
@ -464,10 +497,12 @@ acpi_status wmi_remove_notify_handler(const char *guid)
if (!block->handler)
return AE_NULL_ENTRY;
status = wmi_method_enable(block, 0);
block->handler = NULL;
block->handler_data = NULL;
return AE_OK;
return status;
}
EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);

View File

@ -145,6 +145,7 @@ config ACER_WMI
depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
depends on RFKILL
select ACPI_WMI
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds

View File

@ -33,6 +33,8 @@
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/i8042.h>
#include <linux/rfkill.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <acpi/acpi_drivers.h>
@ -123,21 +125,15 @@ enum interface_flags {
static int max_brightness = 0xF;
static int wireless = -1;
static int bluetooth = -1;
static int mailled = -1;
static int brightness = -1;
static int threeg = -1;
static int force_series;
module_param(mailled, int, 0444);
module_param(wireless, int, 0444);
module_param(bluetooth, int, 0444);
module_param(brightness, int, 0444);
module_param(threeg, int, 0444);
module_param(force_series, int, 0444);
MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
@ -145,8 +141,6 @@ MODULE_PARM_DESC(force_series, "Force a different laptop series");
struct acer_data {
int mailled;
int wireless;
int bluetooth;
int threeg;
int brightness;
};
@ -157,6 +151,9 @@ struct acer_debug {
u32 wmid_devices;
};
static struct rfkill *wireless_rfkill;
static struct rfkill *bluetooth_rfkill;
/* Each low-level interface must define at least some of the following */
struct wmi_interface {
/* The WMI device type */
@ -846,8 +843,6 @@ static void __init acer_commandline_init(void)
* capability isn't available on the given interface
*/
set_u32(mailled, ACER_CAP_MAILLED);
set_u32(wireless, ACER_CAP_WIRELESS);
set_u32(bluetooth, ACER_CAP_BLUETOOTH);
set_u32(threeg, ACER_CAP_THREEG);
set_u32(brightness, ACER_CAP_BRIGHTNESS);
}
@ -933,40 +928,135 @@ static void acer_backlight_exit(void)
}
/*
* Read/ write bool sysfs macro
* Rfkill devices
*/
#define show_set_bool(value, cap) \
static ssize_t \
show_bool_##value(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
u32 result; \
acpi_status status = get_u32(&result, cap); \
if (ACPI_SUCCESS(status)) \
return sprintf(buf, "%u\n", result); \
return sprintf(buf, "Read error\n"); \
} \
\
static ssize_t \
set_bool_##value(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
u32 tmp = simple_strtoul(buf, NULL, 10); \
acpi_status status = set_u32(tmp, cap); \
if (ACPI_FAILURE(status)) \
return -EINVAL; \
return count; \
} \
static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
show_bool_##value, set_bool_##value);
static void acer_rfkill_update(struct work_struct *ignored);
static DECLARE_DELAYED_WORK(acer_rfkill_work, acer_rfkill_update);
static void acer_rfkill_update(struct work_struct *ignored)
{
u32 state;
acpi_status status;
show_set_bool(wireless, ACER_CAP_WIRELESS);
show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
show_set_bool(threeg, ACER_CAP_THREEG);
status = get_u32(&state, ACER_CAP_WIRELESS);
if (ACPI_SUCCESS(status))
rfkill_force_state(wireless_rfkill, state ?
RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED);
if (has_cap(ACER_CAP_BLUETOOTH)) {
status = get_u32(&state, ACER_CAP_BLUETOOTH);
if (ACPI_SUCCESS(status))
rfkill_force_state(bluetooth_rfkill, state ?
RFKILL_STATE_UNBLOCKED :
RFKILL_STATE_SOFT_BLOCKED);
}
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
}
static int acer_rfkill_set(void *data, enum rfkill_state state)
{
acpi_status status;
u32 *cap = data;
status = set_u32((u32) (state == RFKILL_STATE_UNBLOCKED), *cap);
if (ACPI_FAILURE(status))
return -ENODEV;
return 0;
}
static struct rfkill * acer_rfkill_register(struct device *dev,
enum rfkill_type type, char *name, u32 cap)
{
int err;
u32 state;
u32 *data;
struct rfkill *rfkill_dev;
rfkill_dev = rfkill_allocate(dev, type);
if (!rfkill_dev)
return ERR_PTR(-ENOMEM);
rfkill_dev->name = name;
get_u32(&state, cap);
rfkill_dev->state = state ? RFKILL_STATE_UNBLOCKED :
RFKILL_STATE_SOFT_BLOCKED;
data = kzalloc(sizeof(u32), GFP_KERNEL);
if (!data) {
rfkill_free(rfkill_dev);
return ERR_PTR(-ENOMEM);
}
*data = cap;
rfkill_dev->data = data;
rfkill_dev->toggle_radio = acer_rfkill_set;
rfkill_dev->user_claim_unsupported = 1;
err = rfkill_register(rfkill_dev);
if (err) {
kfree(rfkill_dev->data);
rfkill_free(rfkill_dev);
return ERR_PTR(err);
}
return rfkill_dev;
}
static int acer_rfkill_init(struct device *dev)
{
wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
"acer-wireless", ACER_CAP_WIRELESS);
if (IS_ERR(wireless_rfkill))
return PTR_ERR(wireless_rfkill);
if (has_cap(ACER_CAP_BLUETOOTH)) {
bluetooth_rfkill = acer_rfkill_register(dev,
RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
ACER_CAP_BLUETOOTH);
if (IS_ERR(bluetooth_rfkill)) {
kfree(wireless_rfkill->data);
rfkill_unregister(wireless_rfkill);
return PTR_ERR(bluetooth_rfkill);
}
}
schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ));
return 0;
}
static void acer_rfkill_exit(void)
{
cancel_delayed_work_sync(&acer_rfkill_work);
kfree(wireless_rfkill->data);
rfkill_unregister(wireless_rfkill);
if (has_cap(ACER_CAP_BLUETOOTH)) {
kfree(wireless_rfkill->data);
rfkill_unregister(bluetooth_rfkill);
}
return;
}
/*
* Read interface sysfs macro
* sysfs interface
*/
static ssize_t show_bool_threeg(struct device *dev,
struct device_attribute *attr, char *buf)
{
u32 result; \
acpi_status status = get_u32(&result, ACER_CAP_THREEG);
if (ACPI_SUCCESS(status))
return sprintf(buf, "%u\n", result);
return sprintf(buf, "Read error\n");
}
static ssize_t set_bool_threeg(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
u32 tmp = simple_strtoul(buf, NULL, 10);
acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
if (ACPI_FAILURE(status))
return -EINVAL;
return count;
}
static DEVICE_ATTR(threeg, S_IWUGO | S_IRUGO | S_IWUSR, show_bool_threeg,
set_bool_threeg);
static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
char *buf)
{
@ -1026,7 +1116,9 @@ static int __devinit acer_platform_probe(struct platform_device *device)
goto error_brightness;
}
return 0;
err = acer_rfkill_init(&device->dev);
return err;
error_brightness:
acer_led_exit();
@ -1040,6 +1132,8 @@ static int acer_platform_remove(struct platform_device *device)
acer_led_exit();
if (has_cap(ACER_CAP_BRIGHTNESS))
acer_backlight_exit();
acer_rfkill_exit();
return 0;
}
@ -1052,16 +1146,6 @@ pm_message_t state)
if (!data)
return -ENOMEM;
if (has_cap(ACER_CAP_WIRELESS)) {
get_u32(&value, ACER_CAP_WIRELESS);
data->wireless = value;
}
if (has_cap(ACER_CAP_BLUETOOTH)) {
get_u32(&value, ACER_CAP_BLUETOOTH);
data->bluetooth = value;
}
if (has_cap(ACER_CAP_MAILLED)) {
get_u32(&value, ACER_CAP_MAILLED);
data->mailled = value;
@ -1082,15 +1166,6 @@ static int acer_platform_resume(struct platform_device *device)
if (!data)
return -ENOMEM;
if (has_cap(ACER_CAP_WIRELESS))
set_u32(data->wireless, ACER_CAP_WIRELESS);
if (has_cap(ACER_CAP_BLUETOOTH))
set_u32(data->bluetooth, ACER_CAP_BLUETOOTH);
if (has_cap(ACER_CAP_THREEG))
set_u32(data->threeg, ACER_CAP_THREEG);
if (has_cap(ACER_CAP_MAILLED))
set_u32(data->mailled, ACER_CAP_MAILLED);
@ -1115,12 +1190,6 @@ static struct platform_device *acer_platform_device;
static int remove_sysfs(struct platform_device *device)
{
if (has_cap(ACER_CAP_WIRELESS))
device_remove_file(&device->dev, &dev_attr_wireless);
if (has_cap(ACER_CAP_BLUETOOTH))
device_remove_file(&device->dev, &dev_attr_bluetooth);
if (has_cap(ACER_CAP_THREEG))
device_remove_file(&device->dev, &dev_attr_threeg);
@ -1133,20 +1202,6 @@ static int create_sysfs(void)
{
int retval = -ENOMEM;
if (has_cap(ACER_CAP_WIRELESS)) {
retval = device_create_file(&acer_platform_device->dev,
&dev_attr_wireless);
if (retval)
goto error_sysfs;
}
if (has_cap(ACER_CAP_BLUETOOTH)) {
retval = device_create_file(&acer_platform_device->dev,
&dev_attr_bluetooth);
if (retval)
goto error_sysfs;
}
if (has_cap(ACER_CAP_THREEG)) {
retval = device_create_file(&acer_platform_device->dev,
&dev_attr_threeg);