Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
* 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: (45 commits) acer-wmi: replaced the hard coded bitmap by the communication devices bitmap from SMBIOS acer-wmi: check the existence of internal wireless device when set capability acer-wmi: add ACER_WMID_v2 interface flag to represent new notebooks sony-laptop:irq: Remove IRQF_DISABLED asus-laptop: Add rfkill support for Pegatron Lucid tablet asus-laptop: pega_accel - Report accelerometer orientation change through udev asus-laptop: fix module description asus-laptop: hide leds on Pegatron Lucid asus-laptop: Pegatron Lucid accelerometer asus-laptop: allow boot time control of Pegatron ALS sensor Platform: samsung_laptop: add support for X520 machines. platform: samsung_laptop: add dmi information for Samsung R700 laptops hp_accel: Add axis-mapping for HP ProBook / EliteBook hp_accel: Add a new PNP id WMI: properly cleanup devices to avoid crashes ideapad: remove sysfs node for cfg ideapad: add debugfs support ideapad: add event for Novo key ideapad: change parameter of ideapad_sync_rfk_state ideapad: define vpc commands ...
This commit is contained in:
commit
91e67a996c
19
Documentation/ABI/testing/debugfs-ideapad
Normal file
19
Documentation/ABI/testing/debugfs-ideapad
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
What: /sys/kernel/debug/ideapad/cfg
|
||||||
|
Date: Sep 2011
|
||||||
|
KernelVersion: 3.2
|
||||||
|
Contact: Ike Panhc <ike.pan@canonical.com>
|
||||||
|
Description:
|
||||||
|
|
||||||
|
cfg shows the return value of _CFG method in VPC2004 device. It tells machine
|
||||||
|
capability and what graphic component within the machine.
|
||||||
|
|
||||||
|
|
||||||
|
What: /sys/kernel/debug/ideapad/status
|
||||||
|
Date: Sep 2011
|
||||||
|
KernelVersion: 3.2
|
||||||
|
Contact: Ike Panhc <ike.pan@canonical.com>
|
||||||
|
Description:
|
||||||
|
|
||||||
|
status shows infos we can read and tells its meaning and value.
|
||||||
|
|
||||||
|
|
|
@ -5,19 +5,4 @@ Contact: "Ike Panhc <ike.pan@canonical.com>"
|
||||||
Description:
|
Description:
|
||||||
Control the power of camera module. 1 means on, 0 means off.
|
Control the power of camera module. 1 means on, 0 means off.
|
||||||
|
|
||||||
What: /sys/devices/platform/ideapad/cfg
|
|
||||||
Date: Jun 2011
|
|
||||||
KernelVersion: 3.1
|
|
||||||
Contact: "Ike Panhc <ike.pan@canonical.com>"
|
|
||||||
Description:
|
|
||||||
Ideapad capability bits.
|
|
||||||
Bit 8-10: 1 - Intel graphic only
|
|
||||||
2 - ATI graphic only
|
|
||||||
3 - Nvidia graphic only
|
|
||||||
4 - Intel and ATI graphic
|
|
||||||
5 - Intel and Nvidia graphic
|
|
||||||
Bit 16: Bluetooth exist (1 for exist)
|
|
||||||
Bit 17: 3G exist (1 for exist)
|
|
||||||
Bit 18: Wifi exist (1 for exist)
|
|
||||||
Bit 19: Camera exist (1 for exist)
|
|
||||||
|
|
||||||
|
|
|
@ -3227,6 +3227,13 @@ F: Documentation/ide/
|
||||||
F: drivers/ide/
|
F: drivers/ide/
|
||||||
F: include/linux/ide.h
|
F: include/linux/ide.h
|
||||||
|
|
||||||
|
IDEAPAD LAPTOP EXTRAS DRIVER
|
||||||
|
M: Ike Panhc <ike.pan@canonical.com>
|
||||||
|
L: platform-driver-x86@vger.kernel.org
|
||||||
|
W: http://launchpad.net/ideapad-laptop
|
||||||
|
S: Maintained
|
||||||
|
F: drivers/platform/x86/ideapad-laptop.c
|
||||||
|
|
||||||
IDE/ATAPI DRIVERS
|
IDE/ATAPI DRIVERS
|
||||||
M: Borislav Petkov <petkovbb@gmail.com>
|
M: Borislav Petkov <petkovbb@gmail.com>
|
||||||
L: linux-ide@vger.kernel.org
|
L: linux-ide@vger.kernel.org
|
||||||
|
|
|
@ -61,15 +61,18 @@ config ASUS_LAPTOP
|
||||||
depends on INPUT
|
depends on INPUT
|
||||||
depends on RFKILL || RFKILL = n
|
depends on RFKILL || RFKILL = n
|
||||||
select INPUT_SPARSEKMAP
|
select INPUT_SPARSEKMAP
|
||||||
|
select INPUT_POLLDEV
|
||||||
---help---
|
---help---
|
||||||
This is the new Linux driver for Asus laptops. It may also support some
|
This is a driver for Asus laptops, Lenovo SL and the Pegatron
|
||||||
MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
|
Lucid tablet. It may also support some MEDION, JVC or VICTOR
|
||||||
standard ACPI events and input events. It also adds
|
laptops. It makes all the extra buttons generate standard
|
||||||
support for video output switching, LCD backlight control, Bluetooth and
|
ACPI events and input events, and on the Lucid the built-in
|
||||||
Wlan control, and most importantly, allows you to blink those fancy LEDs.
|
accelerometer appears as an input device. It also adds
|
||||||
|
support for video output switching, LCD backlight control,
|
||||||
|
Bluetooth and Wlan control, and most importantly, allows you
|
||||||
|
to blink those fancy LEDs.
|
||||||
|
|
||||||
For more information and a userspace daemon for handling the extra
|
For more information see <http://acpi4asus.sf.net>.
|
||||||
buttons see <http://acpi4asus.sf.net>.
|
|
||||||
|
|
||||||
If you have an ACPI-compatible ASUS laptop, say Y or M here.
|
If you have an ACPI-compatible ASUS laptop, say Y or M here.
|
||||||
|
|
||||||
|
|
|
@ -190,6 +190,7 @@ enum interface_flags {
|
||||||
ACER_AMW0,
|
ACER_AMW0,
|
||||||
ACER_AMW0_V2,
|
ACER_AMW0_V2,
|
||||||
ACER_WMID,
|
ACER_WMID,
|
||||||
|
ACER_WMID_v2,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ACER_DEFAULT_WIRELESS 0
|
#define ACER_DEFAULT_WIRELESS 0
|
||||||
|
@ -205,6 +206,7 @@ static int threeg = -1;
|
||||||
static int force_series;
|
static int force_series;
|
||||||
static bool ec_raw_mode;
|
static bool ec_raw_mode;
|
||||||
static bool has_type_aa;
|
static bool has_type_aa;
|
||||||
|
static u16 commun_func_bitmap;
|
||||||
|
|
||||||
module_param(mailled, int, 0444);
|
module_param(mailled, int, 0444);
|
||||||
module_param(brightness, int, 0444);
|
module_param(brightness, int, 0444);
|
||||||
|
@ -464,6 +466,15 @@ static struct dmi_system_id acer_quirks[] = {
|
||||||
},
|
},
|
||||||
.driver_data = &quirk_lenovo_ideapad_s205,
|
.driver_data = &quirk_lenovo_ideapad_s205,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Lenovo 3000 N200",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "0687A31"),
|
||||||
|
},
|
||||||
|
.driver_data = &quirk_fujitsu_amilo_li_1718,
|
||||||
|
},
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -868,6 +879,174 @@ static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface)
|
||||||
return WMI_execute_u32(method_id, (u32)value, NULL);
|
return WMI_execute_u32(method_id, (u32)value, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static acpi_status wmid3_get_device_status(u32 *value, u16 device)
|
||||||
|
{
|
||||||
|
struct wmid3_gds_return_value return_value;
|
||||||
|
acpi_status status;
|
||||||
|
union acpi_object *obj;
|
||||||
|
struct wmid3_gds_input_param params = {
|
||||||
|
.function_num = 0x1,
|
||||||
|
.hotkey_number = 0x01,
|
||||||
|
.devices = device,
|
||||||
|
};
|
||||||
|
struct acpi_buffer input = {
|
||||||
|
sizeof(struct wmid3_gds_input_param),
|
||||||
|
¶ms
|
||||||
|
};
|
||||||
|
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
|
|
||||||
|
status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
obj = output.pointer;
|
||||||
|
|
||||||
|
if (!obj)
|
||||||
|
return AE_ERROR;
|
||||||
|
else if (obj->type != ACPI_TYPE_BUFFER) {
|
||||||
|
kfree(obj);
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
if (obj->buffer.length != 8) {
|
||||||
|
pr_warn("Unknown buffer length %d\n", obj->buffer.length);
|
||||||
|
kfree(obj);
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
|
||||||
|
kfree(obj);
|
||||||
|
|
||||||
|
if (return_value.error_code || return_value.ec_return_value)
|
||||||
|
pr_warn("Get 0x%x Device Status failed: 0x%x - 0x%x\n",
|
||||||
|
device,
|
||||||
|
return_value.error_code,
|
||||||
|
return_value.ec_return_value);
|
||||||
|
else
|
||||||
|
*value = !!(return_value.devices & device);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static acpi_status wmid_v2_get_u32(u32 *value, u32 cap)
|
||||||
|
{
|
||||||
|
u16 device;
|
||||||
|
|
||||||
|
switch (cap) {
|
||||||
|
case ACER_CAP_WIRELESS:
|
||||||
|
device = ACER_WMID3_GDS_WIRELESS;
|
||||||
|
break;
|
||||||
|
case ACER_CAP_BLUETOOTH:
|
||||||
|
device = ACER_WMID3_GDS_BLUETOOTH;
|
||||||
|
break;
|
||||||
|
case ACER_CAP_THREEG:
|
||||||
|
device = ACER_WMID3_GDS_THREEG;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
return wmid3_get_device_status(value, device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static acpi_status wmid3_set_device_status(u32 value, u16 device)
|
||||||
|
{
|
||||||
|
struct wmid3_gds_return_value return_value;
|
||||||
|
acpi_status status;
|
||||||
|
union acpi_object *obj;
|
||||||
|
u16 devices;
|
||||||
|
struct wmid3_gds_input_param params = {
|
||||||
|
.function_num = 0x1,
|
||||||
|
.hotkey_number = 0x01,
|
||||||
|
.devices = commun_func_bitmap,
|
||||||
|
};
|
||||||
|
struct acpi_buffer input = {
|
||||||
|
sizeof(struct wmid3_gds_input_param),
|
||||||
|
¶ms
|
||||||
|
};
|
||||||
|
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
|
struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
|
|
||||||
|
status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
obj = output.pointer;
|
||||||
|
|
||||||
|
if (!obj)
|
||||||
|
return AE_ERROR;
|
||||||
|
else if (obj->type != ACPI_TYPE_BUFFER) {
|
||||||
|
kfree(obj);
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
if (obj->buffer.length != 8) {
|
||||||
|
pr_warning("Unknown buffer length %d\n", obj->buffer.length);
|
||||||
|
kfree(obj);
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
|
||||||
|
kfree(obj);
|
||||||
|
|
||||||
|
if (return_value.error_code || return_value.ec_return_value) {
|
||||||
|
pr_warning("Get Current Device Status failed: "
|
||||||
|
"0x%x - 0x%x\n", return_value.error_code,
|
||||||
|
return_value.ec_return_value);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
devices = return_value.devices;
|
||||||
|
params.function_num = 0x2;
|
||||||
|
params.hotkey_number = 0x01;
|
||||||
|
params.devices = (value) ? (devices | device) : (devices & ~device);
|
||||||
|
|
||||||
|
status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
obj = output2.pointer;
|
||||||
|
|
||||||
|
if (!obj)
|
||||||
|
return AE_ERROR;
|
||||||
|
else if (obj->type != ACPI_TYPE_BUFFER) {
|
||||||
|
kfree(obj);
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
if (obj->buffer.length != 4) {
|
||||||
|
pr_warning("Unknown buffer length %d\n", obj->buffer.length);
|
||||||
|
kfree(obj);
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
|
||||||
|
kfree(obj);
|
||||||
|
|
||||||
|
if (return_value.error_code || return_value.ec_return_value)
|
||||||
|
pr_warning("Set Device Status failed: "
|
||||||
|
"0x%x - 0x%x\n", return_value.error_code,
|
||||||
|
return_value.ec_return_value);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static acpi_status wmid_v2_set_u32(u32 value, u32 cap)
|
||||||
|
{
|
||||||
|
u16 device;
|
||||||
|
|
||||||
|
switch (cap) {
|
||||||
|
case ACER_CAP_WIRELESS:
|
||||||
|
device = ACER_WMID3_GDS_WIRELESS;
|
||||||
|
break;
|
||||||
|
case ACER_CAP_BLUETOOTH:
|
||||||
|
device = ACER_WMID3_GDS_BLUETOOTH;
|
||||||
|
break;
|
||||||
|
case ACER_CAP_THREEG:
|
||||||
|
device = ACER_WMID3_GDS_THREEG;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return AE_ERROR;
|
||||||
|
}
|
||||||
|
return wmid3_set_device_status(value, device);
|
||||||
|
}
|
||||||
|
|
||||||
static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
|
static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
|
||||||
{
|
{
|
||||||
struct hotkey_function_type_aa *type_aa;
|
struct hotkey_function_type_aa *type_aa;
|
||||||
|
@ -881,6 +1060,7 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
|
||||||
|
|
||||||
pr_info("Function bitmap for Communication Button: 0x%x\n",
|
pr_info("Function bitmap for Communication Button: 0x%x\n",
|
||||||
type_aa->commun_func_bitmap);
|
type_aa->commun_func_bitmap);
|
||||||
|
commun_func_bitmap = type_aa->commun_func_bitmap;
|
||||||
|
|
||||||
if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
|
if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS)
|
||||||
interface->capability |= ACER_CAP_WIRELESS;
|
interface->capability |= ACER_CAP_WIRELESS;
|
||||||
|
@ -913,17 +1093,13 @@ static acpi_status WMID_set_capabilities(void)
|
||||||
return AE_ERROR;
|
return AE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
dmi_walk(type_aa_dmi_decode, NULL);
|
pr_info("Function bitmap for Communication Device: 0x%x\n", devices);
|
||||||
if (!has_type_aa) {
|
if (devices & 0x07)
|
||||||
interface->capability |= ACER_CAP_WIRELESS;
|
interface->capability |= ACER_CAP_WIRELESS;
|
||||||
if (devices & 0x40)
|
if (devices & 0x40)
|
||||||
interface->capability |= ACER_CAP_THREEG;
|
interface->capability |= ACER_CAP_THREEG;
|
||||||
if (devices & 0x10)
|
if (devices & 0x10)
|
||||||
interface->capability |= ACER_CAP_BLUETOOTH;
|
interface->capability |= ACER_CAP_BLUETOOTH;
|
||||||
}
|
|
||||||
|
|
||||||
/* WMID always provides brightness methods */
|
|
||||||
interface->capability |= ACER_CAP_BRIGHTNESS;
|
|
||||||
|
|
||||||
if (!(devices & 0x20))
|
if (!(devices & 0x20))
|
||||||
max_brightness = 0x9;
|
max_brightness = 0x9;
|
||||||
|
@ -936,6 +1112,10 @@ static struct wmi_interface wmid_interface = {
|
||||||
.type = ACER_WMID,
|
.type = ACER_WMID,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct wmi_interface wmid_v2_interface = {
|
||||||
|
.type = ACER_WMID_v2,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic Device (interface-independent)
|
* Generic Device (interface-independent)
|
||||||
*/
|
*/
|
||||||
|
@ -956,6 +1136,14 @@ static acpi_status get_u32(u32 *value, u32 cap)
|
||||||
case ACER_WMID:
|
case ACER_WMID:
|
||||||
status = WMID_get_u32(value, cap, interface);
|
status = WMID_get_u32(value, cap, interface);
|
||||||
break;
|
break;
|
||||||
|
case ACER_WMID_v2:
|
||||||
|
if (cap & (ACER_CAP_WIRELESS |
|
||||||
|
ACER_CAP_BLUETOOTH |
|
||||||
|
ACER_CAP_THREEG))
|
||||||
|
status = wmid_v2_get_u32(value, cap);
|
||||||
|
else if (wmi_has_guid(WMID_GUID2))
|
||||||
|
status = WMID_get_u32(value, cap, interface);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
@ -989,6 +1177,13 @@ static acpi_status set_u32(u32 value, u32 cap)
|
||||||
}
|
}
|
||||||
case ACER_WMID:
|
case ACER_WMID:
|
||||||
return WMID_set_u32(value, cap, interface);
|
return WMID_set_u32(value, cap, interface);
|
||||||
|
case ACER_WMID_v2:
|
||||||
|
if (cap & (ACER_CAP_WIRELESS |
|
||||||
|
ACER_CAP_BLUETOOTH |
|
||||||
|
ACER_CAP_THREEG))
|
||||||
|
return wmid_v2_set_u32(value, cap);
|
||||||
|
else if (wmi_has_guid(WMID_GUID2))
|
||||||
|
return WMID_set_u32(value, cap, interface);
|
||||||
default:
|
default:
|
||||||
return AE_BAD_PARAMETER;
|
return AE_BAD_PARAMETER;
|
||||||
}
|
}
|
||||||
|
@ -1095,186 +1290,6 @@ static void acer_backlight_exit(void)
|
||||||
backlight_device_unregister(acer_backlight_device);
|
backlight_device_unregister(acer_backlight_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
static acpi_status wmid3_get_device_status(u32 *value, u16 device)
|
|
||||||
{
|
|
||||||
struct wmid3_gds_return_value return_value;
|
|
||||||
acpi_status status;
|
|
||||||
union acpi_object *obj;
|
|
||||||
struct wmid3_gds_input_param params = {
|
|
||||||
.function_num = 0x1,
|
|
||||||
.hotkey_number = 0x01,
|
|
||||||
.devices = device,
|
|
||||||
};
|
|
||||||
struct acpi_buffer input = {
|
|
||||||
sizeof(struct wmid3_gds_input_param),
|
|
||||||
¶ms
|
|
||||||
};
|
|
||||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
||||||
|
|
||||||
status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
|
|
||||||
if (ACPI_FAILURE(status))
|
|
||||||
return status;
|
|
||||||
|
|
||||||
obj = output.pointer;
|
|
||||||
|
|
||||||
if (!obj)
|
|
||||||
return AE_ERROR;
|
|
||||||
else if (obj->type != ACPI_TYPE_BUFFER) {
|
|
||||||
kfree(obj);
|
|
||||||
return AE_ERROR;
|
|
||||||
}
|
|
||||||
if (obj->buffer.length != 8) {
|
|
||||||
pr_warn("Unknown buffer length %d\n", obj->buffer.length);
|
|
||||||
kfree(obj);
|
|
||||||
return AE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
|
|
||||||
kfree(obj);
|
|
||||||
|
|
||||||
if (return_value.error_code || return_value.ec_return_value)
|
|
||||||
pr_warn("Get Device Status failed: 0x%x - 0x%x\n",
|
|
||||||
return_value.error_code,
|
|
||||||
return_value.ec_return_value);
|
|
||||||
else
|
|
||||||
*value = !!(return_value.devices & device);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static acpi_status get_device_status(u32 *value, u32 cap)
|
|
||||||
{
|
|
||||||
if (wmi_has_guid(WMID_GUID3)) {
|
|
||||||
u16 device;
|
|
||||||
|
|
||||||
switch (cap) {
|
|
||||||
case ACER_CAP_WIRELESS:
|
|
||||||
device = ACER_WMID3_GDS_WIRELESS;
|
|
||||||
break;
|
|
||||||
case ACER_CAP_BLUETOOTH:
|
|
||||||
device = ACER_WMID3_GDS_BLUETOOTH;
|
|
||||||
break;
|
|
||||||
case ACER_CAP_THREEG:
|
|
||||||
device = ACER_WMID3_GDS_THREEG;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return AE_ERROR;
|
|
||||||
}
|
|
||||||
return wmid3_get_device_status(value, device);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return get_u32(value, cap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static acpi_status wmid3_set_device_status(u32 value, u16 device)
|
|
||||||
{
|
|
||||||
struct wmid3_gds_return_value return_value;
|
|
||||||
acpi_status status;
|
|
||||||
union acpi_object *obj;
|
|
||||||
u16 devices;
|
|
||||||
struct wmid3_gds_input_param params = {
|
|
||||||
.function_num = 0x1,
|
|
||||||
.hotkey_number = 0x01,
|
|
||||||
.devices = ACER_WMID3_GDS_WIRELESS |
|
|
||||||
ACER_WMID3_GDS_THREEG |
|
|
||||||
ACER_WMID3_GDS_WIMAX |
|
|
||||||
ACER_WMID3_GDS_BLUETOOTH,
|
|
||||||
};
|
|
||||||
struct acpi_buffer input = {
|
|
||||||
sizeof(struct wmid3_gds_input_param),
|
|
||||||
¶ms
|
|
||||||
};
|
|
||||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
||||||
struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
||||||
|
|
||||||
status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output);
|
|
||||||
if (ACPI_FAILURE(status))
|
|
||||||
return status;
|
|
||||||
|
|
||||||
obj = output.pointer;
|
|
||||||
|
|
||||||
if (!obj)
|
|
||||||
return AE_ERROR;
|
|
||||||
else if (obj->type != ACPI_TYPE_BUFFER) {
|
|
||||||
kfree(obj);
|
|
||||||
return AE_ERROR;
|
|
||||||
}
|
|
||||||
if (obj->buffer.length != 8) {
|
|
||||||
pr_warning("Unknown buffer length %d\n", obj->buffer.length);
|
|
||||||
kfree(obj);
|
|
||||||
return AE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
|
|
||||||
kfree(obj);
|
|
||||||
|
|
||||||
if (return_value.error_code || return_value.ec_return_value) {
|
|
||||||
pr_warning("Get Current Device Status failed: "
|
|
||||||
"0x%x - 0x%x\n", return_value.error_code,
|
|
||||||
return_value.ec_return_value);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
devices = return_value.devices;
|
|
||||||
params.function_num = 0x2;
|
|
||||||
params.hotkey_number = 0x01;
|
|
||||||
params.devices = (value) ? (devices | device) : (devices & ~device);
|
|
||||||
|
|
||||||
status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2);
|
|
||||||
if (ACPI_FAILURE(status))
|
|
||||||
return status;
|
|
||||||
|
|
||||||
obj = output2.pointer;
|
|
||||||
|
|
||||||
if (!obj)
|
|
||||||
return AE_ERROR;
|
|
||||||
else if (obj->type != ACPI_TYPE_BUFFER) {
|
|
||||||
kfree(obj);
|
|
||||||
return AE_ERROR;
|
|
||||||
}
|
|
||||||
if (obj->buffer.length != 4) {
|
|
||||||
pr_warning("Unknown buffer length %d\n", obj->buffer.length);
|
|
||||||
kfree(obj);
|
|
||||||
return AE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return_value = *((struct wmid3_gds_return_value *)obj->buffer.pointer);
|
|
||||||
kfree(obj);
|
|
||||||
|
|
||||||
if (return_value.error_code || return_value.ec_return_value)
|
|
||||||
pr_warning("Set Device Status failed: "
|
|
||||||
"0x%x - 0x%x\n", return_value.error_code,
|
|
||||||
return_value.ec_return_value);
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static acpi_status set_device_status(u32 value, u32 cap)
|
|
||||||
{
|
|
||||||
if (wmi_has_guid(WMID_GUID3)) {
|
|
||||||
u16 device;
|
|
||||||
|
|
||||||
switch (cap) {
|
|
||||||
case ACER_CAP_WIRELESS:
|
|
||||||
device = ACER_WMID3_GDS_WIRELESS;
|
|
||||||
break;
|
|
||||||
case ACER_CAP_BLUETOOTH:
|
|
||||||
device = ACER_WMID3_GDS_BLUETOOTH;
|
|
||||||
break;
|
|
||||||
case ACER_CAP_THREEG:
|
|
||||||
device = ACER_WMID3_GDS_THREEG;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return AE_ERROR;
|
|
||||||
}
|
|
||||||
return wmid3_set_device_status(value, device);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return set_u32(value, cap);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Rfkill devices
|
* Rfkill devices
|
||||||
*/
|
*/
|
||||||
|
@ -1285,11 +1300,12 @@ static void acer_rfkill_update(struct work_struct *ignored)
|
||||||
u32 state;
|
u32 state;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
|
|
||||||
|
if (has_cap(ACER_CAP_WIRELESS)) {
|
||||||
status = get_u32(&state, ACER_CAP_WIRELESS);
|
status = get_u32(&state, ACER_CAP_WIRELESS);
|
||||||
if (ACPI_SUCCESS(status)) {
|
if (ACPI_SUCCESS(status)) {
|
||||||
if (quirks->wireless == 3) {
|
if (quirks->wireless == 3)
|
||||||
rfkill_set_hw_state(wireless_rfkill, !state);
|
rfkill_set_hw_state(wireless_rfkill, !state);
|
||||||
} else {
|
else
|
||||||
rfkill_set_sw_state(wireless_rfkill, !state);
|
rfkill_set_sw_state(wireless_rfkill, !state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1301,8 +1317,7 @@ static void acer_rfkill_update(struct work_struct *ignored)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
|
if (has_cap(ACER_CAP_THREEG) && wmi_has_guid(WMID_GUID3)) {
|
||||||
status = wmid3_get_device_status(&state,
|
status = get_u32(&state, ACER_WMID3_GDS_THREEG);
|
||||||
ACER_WMID3_GDS_THREEG);
|
|
||||||
if (ACPI_SUCCESS(status))
|
if (ACPI_SUCCESS(status))
|
||||||
rfkill_set_sw_state(threeg_rfkill, !state);
|
rfkill_set_sw_state(threeg_rfkill, !state);
|
||||||
}
|
}
|
||||||
|
@ -1316,7 +1331,7 @@ static int acer_rfkill_set(void *data, bool blocked)
|
||||||
u32 cap = (unsigned long)data;
|
u32 cap = (unsigned long)data;
|
||||||
|
|
||||||
if (rfkill_inited) {
|
if (rfkill_inited) {
|
||||||
status = set_device_status(!blocked, cap);
|
status = set_u32(!blocked, cap);
|
||||||
if (ACPI_FAILURE(status))
|
if (ACPI_FAILURE(status))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -1343,7 +1358,7 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
|
||||||
if (!rfkill_dev)
|
if (!rfkill_dev)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
status = get_device_status(&state, cap);
|
status = get_u32(&state, cap);
|
||||||
|
|
||||||
err = rfkill_register(rfkill_dev);
|
err = rfkill_register(rfkill_dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -1359,19 +1374,24 @@ static struct rfkill *acer_rfkill_register(struct device *dev,
|
||||||
|
|
||||||
static int acer_rfkill_init(struct device *dev)
|
static int acer_rfkill_init(struct device *dev)
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (has_cap(ACER_CAP_WIRELESS)) {
|
||||||
wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
|
wireless_rfkill = acer_rfkill_register(dev, RFKILL_TYPE_WLAN,
|
||||||
"acer-wireless", ACER_CAP_WIRELESS);
|
"acer-wireless", ACER_CAP_WIRELESS);
|
||||||
if (IS_ERR(wireless_rfkill))
|
if (IS_ERR(wireless_rfkill)) {
|
||||||
return PTR_ERR(wireless_rfkill);
|
err = PTR_ERR(wireless_rfkill);
|
||||||
|
goto error_wireless;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||||
bluetooth_rfkill = acer_rfkill_register(dev,
|
bluetooth_rfkill = acer_rfkill_register(dev,
|
||||||
RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
|
RFKILL_TYPE_BLUETOOTH, "acer-bluetooth",
|
||||||
ACER_CAP_BLUETOOTH);
|
ACER_CAP_BLUETOOTH);
|
||||||
if (IS_ERR(bluetooth_rfkill)) {
|
if (IS_ERR(bluetooth_rfkill)) {
|
||||||
rfkill_unregister(wireless_rfkill);
|
err = PTR_ERR(bluetooth_rfkill);
|
||||||
rfkill_destroy(wireless_rfkill);
|
goto error_bluetooth;
|
||||||
return PTR_ERR(bluetooth_rfkill);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1380,30 +1400,44 @@ static int acer_rfkill_init(struct device *dev)
|
||||||
RFKILL_TYPE_WWAN, "acer-threeg",
|
RFKILL_TYPE_WWAN, "acer-threeg",
|
||||||
ACER_CAP_THREEG);
|
ACER_CAP_THREEG);
|
||||||
if (IS_ERR(threeg_rfkill)) {
|
if (IS_ERR(threeg_rfkill)) {
|
||||||
rfkill_unregister(wireless_rfkill);
|
err = PTR_ERR(threeg_rfkill);
|
||||||
rfkill_destroy(wireless_rfkill);
|
goto error_threeg;
|
||||||
rfkill_unregister(bluetooth_rfkill);
|
|
||||||
rfkill_destroy(bluetooth_rfkill);
|
|
||||||
return PTR_ERR(threeg_rfkill);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rfkill_inited = true;
|
rfkill_inited = true;
|
||||||
|
|
||||||
if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID))
|
if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
|
||||||
|
has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
|
||||||
schedule_delayed_work(&acer_rfkill_work,
|
schedule_delayed_work(&acer_rfkill_work,
|
||||||
round_jiffies_relative(HZ));
|
round_jiffies_relative(HZ));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
error_threeg:
|
||||||
|
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||||
|
rfkill_unregister(bluetooth_rfkill);
|
||||||
|
rfkill_destroy(bluetooth_rfkill);
|
||||||
|
}
|
||||||
|
error_bluetooth:
|
||||||
|
if (has_cap(ACER_CAP_WIRELESS)) {
|
||||||
|
rfkill_unregister(wireless_rfkill);
|
||||||
|
rfkill_destroy(wireless_rfkill);
|
||||||
|
}
|
||||||
|
error_wireless:
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void acer_rfkill_exit(void)
|
static void acer_rfkill_exit(void)
|
||||||
{
|
{
|
||||||
if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID))
|
if ((ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) &&
|
||||||
|
has_cap(ACER_CAP_WIRELESS | ACER_CAP_BLUETOOTH | ACER_CAP_THREEG))
|
||||||
cancel_delayed_work_sync(&acer_rfkill_work);
|
cancel_delayed_work_sync(&acer_rfkill_work);
|
||||||
|
|
||||||
|
if (has_cap(ACER_CAP_WIRELESS)) {
|
||||||
rfkill_unregister(wireless_rfkill);
|
rfkill_unregister(wireless_rfkill);
|
||||||
rfkill_destroy(wireless_rfkill);
|
rfkill_destroy(wireless_rfkill);
|
||||||
|
}
|
||||||
|
|
||||||
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
if (has_cap(ACER_CAP_BLUETOOTH)) {
|
||||||
rfkill_unregister(bluetooth_rfkill);
|
rfkill_unregister(bluetooth_rfkill);
|
||||||
|
@ -1428,10 +1462,6 @@ static ssize_t show_bool_threeg(struct device *dev,
|
||||||
|
|
||||||
pr_info("This threeg sysfs will be removed in 2012"
|
pr_info("This threeg sysfs will be removed in 2012"
|
||||||
" - used by: %s\n", current->comm);
|
" - used by: %s\n", current->comm);
|
||||||
if (wmi_has_guid(WMID_GUID3))
|
|
||||||
status = wmid3_get_device_status(&result,
|
|
||||||
ACER_WMID3_GDS_THREEG);
|
|
||||||
else
|
|
||||||
status = get_u32(&result, ACER_CAP_THREEG);
|
status = get_u32(&result, ACER_CAP_THREEG);
|
||||||
if (ACPI_SUCCESS(status))
|
if (ACPI_SUCCESS(status))
|
||||||
return sprintf(buf, "%u\n", result);
|
return sprintf(buf, "%u\n", result);
|
||||||
|
@ -1464,6 +1494,8 @@ static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
|
||||||
return sprintf(buf, "AMW0 v2\n");
|
return sprintf(buf, "AMW0 v2\n");
|
||||||
case ACER_WMID:
|
case ACER_WMID:
|
||||||
return sprintf(buf, "WMID\n");
|
return sprintf(buf, "WMID\n");
|
||||||
|
case ACER_WMID_v2:
|
||||||
|
return sprintf(buf, "WMID v2\n");
|
||||||
default:
|
default:
|
||||||
return sprintf(buf, "Error!\n");
|
return sprintf(buf, "Error!\n");
|
||||||
}
|
}
|
||||||
|
@ -1883,12 +1915,20 @@ static int __init acer_wmi_init(void)
|
||||||
if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
|
if (!wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
|
||||||
interface = &wmid_interface;
|
interface = &wmid_interface;
|
||||||
|
|
||||||
|
if (wmi_has_guid(WMID_GUID3))
|
||||||
|
interface = &wmid_v2_interface;
|
||||||
|
|
||||||
|
if (interface)
|
||||||
|
dmi_walk(type_aa_dmi_decode, NULL);
|
||||||
|
|
||||||
if (wmi_has_guid(WMID_GUID2) && interface) {
|
if (wmi_has_guid(WMID_GUID2) && interface) {
|
||||||
if (ACPI_FAILURE(WMID_set_capabilities())) {
|
if (!has_type_aa && ACPI_FAILURE(WMID_set_capabilities())) {
|
||||||
pr_err("Unable to detect available WMID devices\n");
|
pr_err("Unable to detect available WMID devices\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
} else if (!wmi_has_guid(WMID_GUID2) && interface) {
|
/* WMID always provides brightness methods */
|
||||||
|
interface->capability |= ACER_CAP_BRIGHTNESS;
|
||||||
|
} else if (!wmi_has_guid(WMID_GUID2) && interface && !has_type_aa) {
|
||||||
pr_err("No WMID device detection method found\n");
|
pr_err("No WMID device detection method found\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -1912,7 +1952,7 @@ static int __init acer_wmi_init(void)
|
||||||
|
|
||||||
set_quirks();
|
set_quirks();
|
||||||
|
|
||||||
if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) {
|
if (acpi_video_backlight_support()) {
|
||||||
interface->capability &= ~ACER_CAP_BRIGHTNESS;
|
interface->capability &= ~ACER_CAP_BRIGHTNESS;
|
||||||
pr_info("Brightness must be controlled by "
|
pr_info("Brightness must be controlled by "
|
||||||
"generic video driver\n");
|
"generic video driver\n");
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
|
* Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
|
||||||
* Copyright (C) 2006-2007 Corentin Chary
|
* Copyright (C) 2006-2007 Corentin Chary
|
||||||
|
* Copyright (C) 2011 Wind River Systems
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/input/sparse-keymap.h>
|
#include <linux/input/sparse-keymap.h>
|
||||||
|
#include <linux/input-polldev.h>
|
||||||
#include <linux/rfkill.h>
|
#include <linux/rfkill.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
|
@ -83,26 +85,32 @@ static int wlan_status = 1;
|
||||||
static int bluetooth_status = 1;
|
static int bluetooth_status = 1;
|
||||||
static int wimax_status = -1;
|
static int wimax_status = -1;
|
||||||
static int wwan_status = -1;
|
static int wwan_status = -1;
|
||||||
|
static int als_status;
|
||||||
|
|
||||||
module_param(wlan_status, int, 0444);
|
module_param(wlan_status, int, 0444);
|
||||||
MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
|
MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
|
||||||
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
|
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
|
||||||
"default is 1");
|
"default is -1");
|
||||||
|
|
||||||
module_param(bluetooth_status, int, 0444);
|
module_param(bluetooth_status, int, 0444);
|
||||||
MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
|
MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
|
||||||
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
|
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
|
||||||
"default is 1");
|
"default is -1");
|
||||||
|
|
||||||
module_param(wimax_status, int, 0444);
|
module_param(wimax_status, int, 0444);
|
||||||
MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot "
|
MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot "
|
||||||
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
|
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
|
||||||
"default is 1");
|
"default is -1");
|
||||||
|
|
||||||
module_param(wwan_status, int, 0444);
|
module_param(wwan_status, int, 0444);
|
||||||
MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
|
MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
|
||||||
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
|
"(0 = disabled, 1 = enabled, -1 = don't do anything). "
|
||||||
"default is 1");
|
"default is -1");
|
||||||
|
|
||||||
|
module_param(als_status, int, 0444);
|
||||||
|
MODULE_PARM_DESC(als_status, "Set the ALS status on boot "
|
||||||
|
"(0 = disabled, 1 = enabled). "
|
||||||
|
"default is 0");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some events we use, same for all Asus
|
* Some events we use, same for all Asus
|
||||||
|
@ -173,6 +181,29 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
|
||||||
#define METHOD_KBD_LIGHT_SET "SLKB"
|
#define METHOD_KBD_LIGHT_SET "SLKB"
|
||||||
#define METHOD_KBD_LIGHT_GET "GLKB"
|
#define METHOD_KBD_LIGHT_GET "GLKB"
|
||||||
|
|
||||||
|
/* For Pegatron Lucid tablet */
|
||||||
|
#define DEVICE_NAME_PEGA "Lucid"
|
||||||
|
|
||||||
|
#define METHOD_PEGA_ENABLE "ENPR"
|
||||||
|
#define METHOD_PEGA_DISABLE "DAPR"
|
||||||
|
#define PEGA_WLAN 0x00
|
||||||
|
#define PEGA_BLUETOOTH 0x01
|
||||||
|
#define PEGA_WWAN 0x02
|
||||||
|
#define PEGA_ALS 0x04
|
||||||
|
#define PEGA_ALS_POWER 0x05
|
||||||
|
|
||||||
|
#define METHOD_PEGA_READ "RDLN"
|
||||||
|
#define PEGA_READ_ALS_H 0x02
|
||||||
|
#define PEGA_READ_ALS_L 0x03
|
||||||
|
|
||||||
|
#define PEGA_ACCEL_NAME "pega_accel"
|
||||||
|
#define PEGA_ACCEL_DESC "Pegatron Lucid Tablet Accelerometer"
|
||||||
|
#define METHOD_XLRX "XLRX"
|
||||||
|
#define METHOD_XLRY "XLRY"
|
||||||
|
#define METHOD_XLRZ "XLRZ"
|
||||||
|
#define PEGA_ACC_CLAMP 512 /* 1G accel is reported as ~256, so clamp to 2G */
|
||||||
|
#define PEGA_ACC_RETRIES 3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Define a specific led structure to keep the main structure clean
|
* Define a specific led structure to keep the main structure clean
|
||||||
*/
|
*/
|
||||||
|
@ -184,6 +215,15 @@ struct asus_led {
|
||||||
const char *method;
|
const char *method;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Same thing for rfkill
|
||||||
|
*/
|
||||||
|
struct asus_pega_rfkill {
|
||||||
|
int control_id; /* type of control. Maps to PEGA_* values */
|
||||||
|
struct rfkill *rfkill;
|
||||||
|
struct asus_laptop *asus;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the main structure, we can use it to store anything interesting
|
* This is the main structure, we can use it to store anything interesting
|
||||||
* about the hotk device
|
* about the hotk device
|
||||||
|
@ -198,6 +238,7 @@ struct asus_laptop {
|
||||||
|
|
||||||
struct input_dev *inputdev;
|
struct input_dev *inputdev;
|
||||||
struct key_entry *keymap;
|
struct key_entry *keymap;
|
||||||
|
struct input_polled_dev *pega_accel_poll;
|
||||||
|
|
||||||
struct asus_led mled;
|
struct asus_led mled;
|
||||||
struct asus_led tled;
|
struct asus_led tled;
|
||||||
|
@ -209,9 +250,18 @@ struct asus_laptop {
|
||||||
|
|
||||||
int wireless_status;
|
int wireless_status;
|
||||||
bool have_rsts;
|
bool have_rsts;
|
||||||
|
bool is_pega_lucid;
|
||||||
|
bool pega_acc_live;
|
||||||
|
int pega_acc_x;
|
||||||
|
int pega_acc_y;
|
||||||
|
int pega_acc_z;
|
||||||
|
|
||||||
struct rfkill *gps_rfkill;
|
struct rfkill *gps_rfkill;
|
||||||
|
|
||||||
|
struct asus_pega_rfkill wlanrfk;
|
||||||
|
struct asus_pega_rfkill btrfk;
|
||||||
|
struct asus_pega_rfkill wwanrfk;
|
||||||
|
|
||||||
acpi_handle handle; /* the handle of the hotk device */
|
acpi_handle handle; /* the handle of the hotk device */
|
||||||
u32 ledd_status; /* status of the LED display */
|
u32 ledd_status; /* status of the LED display */
|
||||||
u8 light_level; /* light sensor level */
|
u8 light_level; /* light sensor level */
|
||||||
|
@ -323,6 +373,127 @@ static int acpi_check_handle(acpi_handle handle, const char *method,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool asus_check_pega_lucid(struct asus_laptop *asus)
|
||||||
|
{
|
||||||
|
return !strcmp(asus->name, DEVICE_NAME_PEGA) &&
|
||||||
|
!acpi_check_handle(asus->handle, METHOD_PEGA_ENABLE, NULL) &&
|
||||||
|
!acpi_check_handle(asus->handle, METHOD_PEGA_DISABLE, NULL) &&
|
||||||
|
!acpi_check_handle(asus->handle, METHOD_PEGA_READ, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int asus_pega_lucid_set(struct asus_laptop *asus, int unit, bool enable)
|
||||||
|
{
|
||||||
|
char *method = enable ? METHOD_PEGA_ENABLE : METHOD_PEGA_DISABLE;
|
||||||
|
return write_acpi_int(asus->handle, method, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method)
|
||||||
|
{
|
||||||
|
int i, delta;
|
||||||
|
unsigned long long val;
|
||||||
|
for (i = 0; i < PEGA_ACC_RETRIES; i++) {
|
||||||
|
acpi_evaluate_integer(asus->handle, method, NULL, &val);
|
||||||
|
|
||||||
|
/* The output is noisy. From reading the ASL
|
||||||
|
* dissassembly, timeout errors are returned with 1's
|
||||||
|
* in the high word, and the lack of locking around
|
||||||
|
* thei hi/lo byte reads means that a transition
|
||||||
|
* between (for example) -1 and 0 could be read as
|
||||||
|
* 0xff00 or 0x00ff. */
|
||||||
|
delta = abs(curr - (short)val);
|
||||||
|
if (delta < 128 && !(val & ~0xffff))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return clamp_val((short)val, -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pega_accel_poll(struct input_polled_dev *ipd)
|
||||||
|
{
|
||||||
|
struct device *parent = ipd->input->dev.parent;
|
||||||
|
struct asus_laptop *asus = dev_get_drvdata(parent);
|
||||||
|
|
||||||
|
/* In some cases, the very first call to poll causes a
|
||||||
|
* recursive fault under the polldev worker. This is
|
||||||
|
* apparently related to very early userspace access to the
|
||||||
|
* device, and perhaps a firmware bug. Fake the first report. */
|
||||||
|
if (!asus->pega_acc_live) {
|
||||||
|
asus->pega_acc_live = true;
|
||||||
|
input_report_abs(ipd->input, ABS_X, 0);
|
||||||
|
input_report_abs(ipd->input, ABS_Y, 0);
|
||||||
|
input_report_abs(ipd->input, ABS_Z, 0);
|
||||||
|
input_sync(ipd->input);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
asus->pega_acc_x = pega_acc_axis(asus, asus->pega_acc_x, METHOD_XLRX);
|
||||||
|
asus->pega_acc_y = pega_acc_axis(asus, asus->pega_acc_y, METHOD_XLRY);
|
||||||
|
asus->pega_acc_z = pega_acc_axis(asus, asus->pega_acc_z, METHOD_XLRZ);
|
||||||
|
|
||||||
|
/* Note transform, convert to "right/up/out" in the native
|
||||||
|
* landscape orientation (i.e. the vector is the direction of
|
||||||
|
* "real up" in the device's cartiesian coordinates). */
|
||||||
|
input_report_abs(ipd->input, ABS_X, -asus->pega_acc_x);
|
||||||
|
input_report_abs(ipd->input, ABS_Y, -asus->pega_acc_y);
|
||||||
|
input_report_abs(ipd->input, ABS_Z, asus->pega_acc_z);
|
||||||
|
input_sync(ipd->input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pega_accel_exit(struct asus_laptop *asus)
|
||||||
|
{
|
||||||
|
if (asus->pega_accel_poll) {
|
||||||
|
input_unregister_polled_device(asus->pega_accel_poll);
|
||||||
|
input_free_polled_device(asus->pega_accel_poll);
|
||||||
|
}
|
||||||
|
asus->pega_accel_poll = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pega_accel_init(struct asus_laptop *asus)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct input_polled_dev *ipd;
|
||||||
|
|
||||||
|
if (!asus->is_pega_lucid)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (acpi_check_handle(asus->handle, METHOD_XLRX, NULL) ||
|
||||||
|
acpi_check_handle(asus->handle, METHOD_XLRY, NULL) ||
|
||||||
|
acpi_check_handle(asus->handle, METHOD_XLRZ, NULL))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ipd = input_allocate_polled_device();
|
||||||
|
if (!ipd)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ipd->poll = pega_accel_poll;
|
||||||
|
ipd->poll_interval = 125;
|
||||||
|
ipd->poll_interval_min = 50;
|
||||||
|
ipd->poll_interval_max = 2000;
|
||||||
|
|
||||||
|
ipd->input->name = PEGA_ACCEL_DESC;
|
||||||
|
ipd->input->phys = PEGA_ACCEL_NAME "/input0";
|
||||||
|
ipd->input->dev.parent = &asus->platform_device->dev;
|
||||||
|
ipd->input->id.bustype = BUS_HOST;
|
||||||
|
|
||||||
|
set_bit(EV_ABS, ipd->input->evbit);
|
||||||
|
input_set_abs_params(ipd->input, ABS_X,
|
||||||
|
-PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
|
||||||
|
input_set_abs_params(ipd->input, ABS_Y,
|
||||||
|
-PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
|
||||||
|
input_set_abs_params(ipd->input, ABS_Z,
|
||||||
|
-PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
|
||||||
|
|
||||||
|
err = input_register_polled_device(ipd);
|
||||||
|
if (err)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
asus->pega_accel_poll = ipd;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
input_free_polled_device(ipd);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Generic LED function */
|
/* Generic LED function */
|
||||||
static int asus_led_set(struct asus_laptop *asus, const char *method,
|
static int asus_led_set(struct asus_laptop *asus, const char *method,
|
||||||
int value)
|
int value)
|
||||||
|
@ -430,17 +601,17 @@ static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
|
||||||
|
|
||||||
static void asus_led_exit(struct asus_laptop *asus)
|
static void asus_led_exit(struct asus_laptop *asus)
|
||||||
{
|
{
|
||||||
if (asus->mled.led.dev)
|
if (!IS_ERR_OR_NULL(asus->mled.led.dev))
|
||||||
led_classdev_unregister(&asus->mled.led);
|
led_classdev_unregister(&asus->mled.led);
|
||||||
if (asus->tled.led.dev)
|
if (!IS_ERR_OR_NULL(asus->tled.led.dev))
|
||||||
led_classdev_unregister(&asus->tled.led);
|
led_classdev_unregister(&asus->tled.led);
|
||||||
if (asus->pled.led.dev)
|
if (!IS_ERR_OR_NULL(asus->pled.led.dev))
|
||||||
led_classdev_unregister(&asus->pled.led);
|
led_classdev_unregister(&asus->pled.led);
|
||||||
if (asus->rled.led.dev)
|
if (!IS_ERR_OR_NULL(asus->rled.led.dev))
|
||||||
led_classdev_unregister(&asus->rled.led);
|
led_classdev_unregister(&asus->rled.led);
|
||||||
if (asus->gled.led.dev)
|
if (!IS_ERR_OR_NULL(asus->gled.led.dev))
|
||||||
led_classdev_unregister(&asus->gled.led);
|
led_classdev_unregister(&asus->gled.led);
|
||||||
if (asus->kled.led.dev)
|
if (!IS_ERR_OR_NULL(asus->kled.led.dev))
|
||||||
led_classdev_unregister(&asus->kled.led);
|
led_classdev_unregister(&asus->kled.led);
|
||||||
if (asus->led_workqueue) {
|
if (asus->led_workqueue) {
|
||||||
destroy_workqueue(asus->led_workqueue);
|
destroy_workqueue(asus->led_workqueue);
|
||||||
|
@ -473,6 +644,13 @@ static int asus_led_init(struct asus_laptop *asus)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Pegatron Lucid has no physical leds, but all methods are
|
||||||
|
* available in the DSDT...
|
||||||
|
*/
|
||||||
|
if (asus->is_pega_lucid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Functions that actually update the LED's are called from a
|
* Functions that actually update the LED's are called from a
|
||||||
* workqueue. By doing this as separate work rather than when the LED
|
* workqueue. By doing this as separate work rather than when the LED
|
||||||
|
@ -907,8 +1085,18 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
|
||||||
*/
|
*/
|
||||||
static void asus_als_switch(struct asus_laptop *asus, int value)
|
static void asus_als_switch(struct asus_laptop *asus, int value)
|
||||||
{
|
{
|
||||||
if (write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value))
|
int ret;
|
||||||
pr_warn("Error setting light sensor switch\n");
|
|
||||||
|
if (asus->is_pega_lucid) {
|
||||||
|
ret = asus_pega_lucid_set(asus, PEGA_ALS, value);
|
||||||
|
if (!ret)
|
||||||
|
ret = asus_pega_lucid_set(asus, PEGA_ALS_POWER, value);
|
||||||
|
} else {
|
||||||
|
ret = write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value);
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
pr_warning("Error setting light sensor switch\n");
|
||||||
|
|
||||||
asus->light_switch = value;
|
asus->light_switch = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -964,6 +1152,35 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pega_int_read(struct asus_laptop *asus, int arg, int *result)
|
||||||
|
{
|
||||||
|
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
|
int err = write_acpi_int_ret(asus->handle, METHOD_PEGA_READ, arg,
|
||||||
|
&buffer);
|
||||||
|
if (!err) {
|
||||||
|
union acpi_object *obj = buffer.pointer;
|
||||||
|
if (obj && obj->type == ACPI_TYPE_INTEGER)
|
||||||
|
*result = obj->integer.value;
|
||||||
|
else
|
||||||
|
err = -EIO;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t show_lsvalue(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct asus_laptop *asus = dev_get_drvdata(dev);
|
||||||
|
int err, hi, lo;
|
||||||
|
|
||||||
|
err = pega_int_read(asus, PEGA_READ_ALS_H, &hi);
|
||||||
|
if (!err)
|
||||||
|
err = pega_int_read(asus, PEGA_READ_ALS_L, &lo);
|
||||||
|
if (!err)
|
||||||
|
return sprintf(buf, "%d\n", 10 * hi + lo);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPS
|
* GPS
|
||||||
*/
|
*/
|
||||||
|
@ -1062,6 +1279,86 @@ static int asus_rfkill_init(struct asus_laptop *asus)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pega_rfkill_set(void *data, bool blocked)
|
||||||
|
{
|
||||||
|
struct asus_pega_rfkill *pega_rfk = data;
|
||||||
|
|
||||||
|
int ret = asus_pega_lucid_set(pega_rfk->asus, pega_rfk->control_id, !blocked);
|
||||||
|
pr_warn("Setting rfkill %d, to %d; returned %d\n", pega_rfk->control_id, !blocked, ret);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct rfkill_ops pega_rfkill_ops = {
|
||||||
|
.set_block = pega_rfkill_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void pega_rfkill_terminate(struct asus_pega_rfkill *pega_rfk)
|
||||||
|
{
|
||||||
|
pr_warn("Terminating %d\n", pega_rfk->control_id);
|
||||||
|
if (pega_rfk->rfkill) {
|
||||||
|
rfkill_unregister(pega_rfk->rfkill);
|
||||||
|
rfkill_destroy(pega_rfk->rfkill);
|
||||||
|
pega_rfk->rfkill = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pega_rfkill_exit(struct asus_laptop *asus)
|
||||||
|
{
|
||||||
|
pega_rfkill_terminate(&asus->wwanrfk);
|
||||||
|
pega_rfkill_terminate(&asus->btrfk);
|
||||||
|
pega_rfkill_terminate(&asus->wlanrfk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_pega_rfkill *pega_rfk,
|
||||||
|
const char *name, int controlid, int rfkill_type)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
|
||||||
|
pr_warn("Setting up rfk %s, control %d, type %d\n", name, controlid, rfkill_type);
|
||||||
|
pega_rfk->control_id = controlid;
|
||||||
|
pega_rfk->asus = asus;
|
||||||
|
pega_rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
|
||||||
|
rfkill_type, &pega_rfkill_ops, pega_rfk);
|
||||||
|
if (!pega_rfk->rfkill)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
result = rfkill_register(pega_rfk->rfkill);
|
||||||
|
if (result) {
|
||||||
|
rfkill_destroy(pega_rfk->rfkill);
|
||||||
|
pega_rfk->rfkill = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pega_rfkill_init(struct asus_laptop *asus)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if(!asus->is_pega_lucid)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = pega_rfkill_setup(asus, &asus->wlanrfk, "pega-wlan", PEGA_WLAN, RFKILL_TYPE_WLAN);
|
||||||
|
if(ret)
|
||||||
|
return ret;
|
||||||
|
ret = pega_rfkill_setup(asus, &asus->btrfk, "pega-bt", PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
|
||||||
|
if(ret)
|
||||||
|
goto err_btrfk;
|
||||||
|
ret = pega_rfkill_setup(asus, &asus->wwanrfk, "pega-wwan", PEGA_WWAN, RFKILL_TYPE_WWAN);
|
||||||
|
if(ret)
|
||||||
|
goto err_wwanrfk;
|
||||||
|
|
||||||
|
pr_warn("Pega rfkill init succeeded\n");
|
||||||
|
return 0;
|
||||||
|
err_wwanrfk:
|
||||||
|
pega_rfkill_terminate(&asus->btrfk);
|
||||||
|
err_btrfk:
|
||||||
|
pega_rfkill_terminate(&asus->wlanrfk);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Input device (i.e. hotkeys)
|
* Input device (i.e. hotkeys)
|
||||||
*/
|
*/
|
||||||
|
@ -1141,6 +1438,14 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
|
||||||
}
|
}
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Accelerometer "coarse orientation change" event */
|
||||||
|
if (asus->pega_accel_poll && event == 0xEA) {
|
||||||
|
kobject_uevent(&asus->pega_accel_poll->input->dev.kobj,
|
||||||
|
KOBJ_CHANGE);
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
asus_input_notify(asus, event);
|
asus_input_notify(asus, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1152,6 +1457,7 @@ static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
|
||||||
static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
|
static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
|
||||||
static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp);
|
static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp);
|
||||||
static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
|
static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
|
||||||
|
static DEVICE_ATTR(ls_value, S_IRUGO, show_lsvalue, NULL);
|
||||||
static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
|
static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
|
||||||
static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
|
static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
|
||||||
static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
|
static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
|
||||||
|
@ -1164,6 +1470,7 @@ static struct attribute *asus_attributes[] = {
|
||||||
&dev_attr_wwan.attr,
|
&dev_attr_wwan.attr,
|
||||||
&dev_attr_display.attr,
|
&dev_attr_display.attr,
|
||||||
&dev_attr_ledd.attr,
|
&dev_attr_ledd.attr,
|
||||||
|
&dev_attr_ls_value.attr,
|
||||||
&dev_attr_ls_level.attr,
|
&dev_attr_ls_level.attr,
|
||||||
&dev_attr_ls_switch.attr,
|
&dev_attr_ls_switch.attr,
|
||||||
&dev_attr_gps.attr,
|
&dev_attr_gps.attr,
|
||||||
|
@ -1180,6 +1487,19 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj,
|
||||||
acpi_handle handle = asus->handle;
|
acpi_handle handle = asus->handle;
|
||||||
bool supported;
|
bool supported;
|
||||||
|
|
||||||
|
if (asus->is_pega_lucid) {
|
||||||
|
/* no ls_level interface on the Lucid */
|
||||||
|
if (attr == &dev_attr_ls_switch.attr)
|
||||||
|
supported = true;
|
||||||
|
else if (attr == &dev_attr_ls_level.attr)
|
||||||
|
supported = false;
|
||||||
|
else
|
||||||
|
goto normal;
|
||||||
|
|
||||||
|
return supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
normal:
|
||||||
if (attr == &dev_attr_wlan.attr) {
|
if (attr == &dev_attr_wlan.attr) {
|
||||||
supported = !acpi_check_handle(handle, METHOD_WLAN, NULL);
|
supported = !acpi_check_handle(handle, METHOD_WLAN, NULL);
|
||||||
|
|
||||||
|
@ -1203,7 +1523,8 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj,
|
||||||
attr == &dev_attr_ls_level.attr) {
|
attr == &dev_attr_ls_level.attr) {
|
||||||
supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) &&
|
supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) &&
|
||||||
!acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL);
|
!acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL);
|
||||||
|
} else if (attr == &dev_attr_ls_value.attr) {
|
||||||
|
supported = asus->is_pega_lucid;
|
||||||
} else if (attr == &dev_attr_gps.attr) {
|
} else if (attr == &dev_attr_gps.attr) {
|
||||||
supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) &&
|
supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) &&
|
||||||
!acpi_check_handle(handle, METHOD_GPS_OFF, NULL) &&
|
!acpi_check_handle(handle, METHOD_GPS_OFF, NULL) &&
|
||||||
|
@ -1258,7 +1579,7 @@ static struct platform_driver platform_driver = {
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = ASUS_LAPTOP_FILE,
|
.name = ASUS_LAPTOP_FILE,
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1388,10 +1709,12 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
|
||||||
asus->ledd_status = 0xFFF;
|
asus->ledd_status = 0xFFF;
|
||||||
|
|
||||||
/* Set initial values of light sensor and level */
|
/* Set initial values of light sensor and level */
|
||||||
asus->light_switch = 0; /* Default to light sensor disabled */
|
asus->light_switch = !!als_status;
|
||||||
asus->light_level = 5; /* level 5 for sensor sensitivity */
|
asus->light_level = 5; /* level 5 for sensor sensitivity */
|
||||||
|
|
||||||
if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
|
if (asus->is_pega_lucid) {
|
||||||
|
asus_als_switch(asus, asus->light_switch);
|
||||||
|
} else if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
|
||||||
!acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
|
!acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
|
||||||
asus_als_switch(asus, asus->light_switch);
|
asus_als_switch(asus, asus->light_switch);
|
||||||
asus_als_level(asus, asus->light_level);
|
asus_als_level(asus, asus->light_level);
|
||||||
|
@ -1439,9 +1762,10 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
|
||||||
goto fail_platform;
|
goto fail_platform;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Register the platform device first. It is used as a parent for the
|
* Need platform type detection first, then the platform
|
||||||
* sub-devices below.
|
* device. It is used as a parent for the sub-devices below.
|
||||||
*/
|
*/
|
||||||
|
asus->is_pega_lucid = asus_check_pega_lucid(asus);
|
||||||
result = asus_platform_init(asus);
|
result = asus_platform_init(asus);
|
||||||
if (result)
|
if (result)
|
||||||
goto fail_platform;
|
goto fail_platform;
|
||||||
|
@ -1465,9 +1789,21 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
|
||||||
if (result)
|
if (result)
|
||||||
goto fail_rfkill;
|
goto fail_rfkill;
|
||||||
|
|
||||||
|
result = pega_accel_init(asus);
|
||||||
|
if (result && result != -ENODEV)
|
||||||
|
goto fail_pega_accel;
|
||||||
|
|
||||||
|
result = pega_rfkill_init(asus);
|
||||||
|
if (result && result != -ENODEV)
|
||||||
|
goto fail_pega_rfkill;
|
||||||
|
|
||||||
asus_device_present = true;
|
asus_device_present = true;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail_pega_rfkill:
|
||||||
|
pega_accel_exit(asus);
|
||||||
|
fail_pega_accel:
|
||||||
|
asus_rfkill_exit(asus);
|
||||||
fail_rfkill:
|
fail_rfkill:
|
||||||
asus_led_exit(asus);
|
asus_led_exit(asus);
|
||||||
fail_led:
|
fail_led:
|
||||||
|
@ -1491,6 +1827,8 @@ static int asus_acpi_remove(struct acpi_device *device, int type)
|
||||||
asus_rfkill_exit(asus);
|
asus_rfkill_exit(asus);
|
||||||
asus_led_exit(asus);
|
asus_led_exit(asus);
|
||||||
asus_input_exit(asus);
|
asus_input_exit(asus);
|
||||||
|
pega_accel_exit(asus);
|
||||||
|
pega_rfkill_exit(asus);
|
||||||
asus_platform_exit(asus);
|
asus_platform_exit(asus);
|
||||||
|
|
||||||
kfree(asus->name);
|
kfree(asus->name);
|
||||||
|
|
|
@ -453,7 +453,9 @@ static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
|
||||||
|
|
||||||
static void asus_wmi_led_exit(struct asus_wmi *asus)
|
static void asus_wmi_led_exit(struct asus_wmi *asus)
|
||||||
{
|
{
|
||||||
if (asus->tpd_led.dev)
|
if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
|
||||||
|
led_classdev_unregister(&asus->kbd_led);
|
||||||
|
if (!IS_ERR_OR_NULL(asus->tpd_led.dev))
|
||||||
led_classdev_unregister(&asus->tpd_led);
|
led_classdev_unregister(&asus->tpd_led);
|
||||||
if (asus->led_workqueue)
|
if (asus->led_workqueue)
|
||||||
destroy_workqueue(asus->led_workqueue);
|
destroy_workqueue(asus->led_workqueue);
|
||||||
|
|
|
@ -60,6 +60,22 @@ struct calling_interface_structure {
|
||||||
struct calling_interface_token tokens[];
|
struct calling_interface_token tokens[];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct quirk_entry {
|
||||||
|
u8 touchpad_led;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct quirk_entry *quirks;
|
||||||
|
|
||||||
|
static struct quirk_entry quirk_dell_vostro_v130 = {
|
||||||
|
.touchpad_led = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dmi_matched(const struct dmi_system_id *dmi)
|
||||||
|
{
|
||||||
|
quirks = dmi->driver_data;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int da_command_address;
|
static int da_command_address;
|
||||||
static int da_command_code;
|
static int da_command_code;
|
||||||
static int da_num_tokens;
|
static int da_num_tokens;
|
||||||
|
@ -149,6 +165,27 @@ static struct dmi_system_id __devinitdata dell_blacklist[] = {
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct dmi_system_id __devinitdata dell_quirks[] = {
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Dell Vostro V130",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V130"),
|
||||||
|
},
|
||||||
|
.driver_data = &quirk_dell_vostro_v130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.callback = dmi_matched,
|
||||||
|
.ident = "Dell Vostro V131",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
|
||||||
|
},
|
||||||
|
.driver_data = &quirk_dell_vostro_v130,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static struct calling_interface_buffer *buffer;
|
static struct calling_interface_buffer *buffer;
|
||||||
static struct page *bufferpage;
|
static struct page *bufferpage;
|
||||||
static DEFINE_MUTEX(buffer_mutex);
|
static DEFINE_MUTEX(buffer_mutex);
|
||||||
|
@ -552,6 +589,44 @@ static const struct backlight_ops dell_ops = {
|
||||||
.update_status = dell_send_intensity,
|
.update_status = dell_send_intensity,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void touchpad_led_on()
|
||||||
|
{
|
||||||
|
int command = 0x97;
|
||||||
|
char data = 1;
|
||||||
|
i8042_command(&data, command | 1 << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touchpad_led_off()
|
||||||
|
{
|
||||||
|
int command = 0x97;
|
||||||
|
char data = 2;
|
||||||
|
i8042_command(&data, command | 1 << 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touchpad_led_set(struct led_classdev *led_cdev,
|
||||||
|
enum led_brightness value)
|
||||||
|
{
|
||||||
|
if (value > 0)
|
||||||
|
touchpad_led_on();
|
||||||
|
else
|
||||||
|
touchpad_led_off();
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct led_classdev touchpad_led = {
|
||||||
|
.name = "dell-laptop::touchpad",
|
||||||
|
.brightness_set = touchpad_led_set,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __devinit touchpad_led_init(struct device *dev)
|
||||||
|
{
|
||||||
|
return led_classdev_register(dev, &touchpad_led);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touchpad_led_exit(void)
|
||||||
|
{
|
||||||
|
led_classdev_unregister(&touchpad_led);
|
||||||
|
}
|
||||||
|
|
||||||
static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
|
static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
|
||||||
struct serio *port)
|
struct serio *port)
|
||||||
{
|
{
|
||||||
|
@ -584,6 +659,10 @@ static int __init dell_init(void)
|
||||||
if (!dmi_check_system(dell_device_table))
|
if (!dmi_check_system(dell_device_table))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
quirks = NULL;
|
||||||
|
/* find if this machine support other functions */
|
||||||
|
dmi_check_system(dell_quirks);
|
||||||
|
|
||||||
dmi_walk(find_tokens, NULL);
|
dmi_walk(find_tokens, NULL);
|
||||||
|
|
||||||
if (!da_tokens) {
|
if (!da_tokens) {
|
||||||
|
@ -626,6 +705,9 @@ static int __init dell_init(void)
|
||||||
goto fail_filter;
|
goto fail_filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (quirks && quirks->touchpad_led)
|
||||||
|
touchpad_led_init(&platform_device->dev);
|
||||||
|
|
||||||
dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
|
dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
|
||||||
if (dell_laptop_dir != NULL)
|
if (dell_laptop_dir != NULL)
|
||||||
debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
|
debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
|
||||||
|
@ -692,6 +774,8 @@ fail_platform_driver:
|
||||||
static void __exit dell_exit(void)
|
static void __exit dell_exit(void)
|
||||||
{
|
{
|
||||||
debugfs_remove_recursive(dell_laptop_dir);
|
debugfs_remove_recursive(dell_laptop_dir);
|
||||||
|
if (quirks && quirks->touchpad_led)
|
||||||
|
touchpad_led_exit();
|
||||||
i8042_remove_filter(dell_laptop_i8042_filter);
|
i8042_remove_filter(dell_laptop_i8042_filter);
|
||||||
cancel_delayed_work_sync(&dell_rfkill_work);
|
cancel_delayed_work_sync(&dell_rfkill_work);
|
||||||
backlight_device_unregister(dell_backlight_device);
|
backlight_device_unregister(dell_backlight_device);
|
||||||
|
|
|
@ -568,7 +568,7 @@ static int eeepc_led_init(struct eeepc_laptop *eeepc)
|
||||||
|
|
||||||
static void eeepc_led_exit(struct eeepc_laptop *eeepc)
|
static void eeepc_led_exit(struct eeepc_laptop *eeepc)
|
||||||
{
|
{
|
||||||
if (eeepc->tpd_led.dev)
|
if (!IS_ERR_OR_NULL(eeepc->tpd_led.dev))
|
||||||
led_classdev_unregister(&eeepc->tpd_led);
|
led_classdev_unregister(&eeepc->tpd_led);
|
||||||
if (eeepc->led_workqueue)
|
if (eeepc->led_workqueue)
|
||||||
destroy_workqueue(eeepc->led_workqueue);
|
destroy_workqueue(eeepc->led_workqueue);
|
||||||
|
|
|
@ -76,6 +76,7 @@ static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
|
||||||
/* For automatic insertion of the module */
|
/* For automatic insertion of the module */
|
||||||
static struct acpi_device_id lis3lv02d_device_ids[] = {
|
static struct acpi_device_id lis3lv02d_device_ids[] = {
|
||||||
{"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
|
{"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
|
||||||
|
{"HPQ6000", 0}, /* HP Mobile Data Protection System PNP */
|
||||||
{"", 0},
|
{"", 0},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
|
MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
|
||||||
|
@ -228,6 +229,10 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
|
||||||
AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
|
AXIS_DMI_MATCH("HPB522x", "HP ProBook 522", xy_swap),
|
||||||
AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
|
AXIS_DMI_MATCH("HPB532x", "HP ProBook 532", y_inverted),
|
||||||
AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd),
|
AXIS_DMI_MATCH("Mini510x", "HP Mini 510", xy_rotated_left_usd),
|
||||||
|
AXIS_DMI_MATCH("HPB63xx", "HP ProBook 63", xy_swap),
|
||||||
|
AXIS_DMI_MATCH("HPB64xx", "HP ProBook 64", xy_swap),
|
||||||
|
AXIS_DMI_MATCH("HPB64xx", "HP EliteBook 84", xy_swap),
|
||||||
|
AXIS_DMI_MATCH("HPB65xx", "HP ProBook 65", x_inverted),
|
||||||
{ NULL, }
|
{ NULL, }
|
||||||
/* Laptop models without axis info (yet):
|
/* Laptop models without axis info (yet):
|
||||||
* "NC6910" "HP Compaq 6910"
|
* "NC6910" "HP Compaq 6910"
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
#include <linux/input/sparse-keymap.h>
|
#include <linux/input/sparse-keymap.h>
|
||||||
#include <linux/backlight.h>
|
#include <linux/backlight.h>
|
||||||
#include <linux/fb.h>
|
#include <linux/fb.h>
|
||||||
|
#include <linux/debugfs.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
|
|
||||||
#define IDEAPAD_RFKILL_DEV_NUM (3)
|
#define IDEAPAD_RFKILL_DEV_NUM (3)
|
||||||
|
|
||||||
|
@ -42,15 +44,41 @@
|
||||||
#define CFG_WIFI_BIT (18)
|
#define CFG_WIFI_BIT (18)
|
||||||
#define CFG_CAMERA_BIT (19)
|
#define CFG_CAMERA_BIT (19)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VPCCMD_R_VPC1 = 0x10,
|
||||||
|
VPCCMD_R_BL_MAX,
|
||||||
|
VPCCMD_R_BL,
|
||||||
|
VPCCMD_W_BL,
|
||||||
|
VPCCMD_R_WIFI,
|
||||||
|
VPCCMD_W_WIFI,
|
||||||
|
VPCCMD_R_BT,
|
||||||
|
VPCCMD_W_BT,
|
||||||
|
VPCCMD_R_BL_POWER,
|
||||||
|
VPCCMD_R_NOVO,
|
||||||
|
VPCCMD_R_VPC2,
|
||||||
|
VPCCMD_R_TOUCHPAD,
|
||||||
|
VPCCMD_W_TOUCHPAD,
|
||||||
|
VPCCMD_R_CAMERA,
|
||||||
|
VPCCMD_W_CAMERA,
|
||||||
|
VPCCMD_R_3G,
|
||||||
|
VPCCMD_W_3G,
|
||||||
|
VPCCMD_R_ODD, /* 0x21 */
|
||||||
|
VPCCMD_R_RF = 0x23,
|
||||||
|
VPCCMD_W_RF,
|
||||||
|
VPCCMD_W_BL_POWER = 0x33,
|
||||||
|
};
|
||||||
|
|
||||||
struct ideapad_private {
|
struct ideapad_private {
|
||||||
struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
|
struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
|
||||||
struct platform_device *platform_device;
|
struct platform_device *platform_device;
|
||||||
struct input_dev *inputdev;
|
struct input_dev *inputdev;
|
||||||
struct backlight_device *blightdev;
|
struct backlight_device *blightdev;
|
||||||
|
struct dentry *debug;
|
||||||
unsigned long cfg;
|
unsigned long cfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
static acpi_handle ideapad_handle;
|
static acpi_handle ideapad_handle;
|
||||||
|
static struct ideapad_private *ideapad_priv;
|
||||||
static bool no_bt_rfkill;
|
static bool no_bt_rfkill;
|
||||||
module_param(no_bt_rfkill, bool, 0444);
|
module_param(no_bt_rfkill, bool, 0444);
|
||||||
MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
|
MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
|
||||||
|
@ -163,6 +191,146 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* debugfs
|
||||||
|
*/
|
||||||
|
#define DEBUGFS_EVENT_LEN (4096)
|
||||||
|
static int debugfs_status_show(struct seq_file *s, void *data)
|
||||||
|
{
|
||||||
|
unsigned long value;
|
||||||
|
|
||||||
|
if (!read_ec_data(ideapad_handle, VPCCMD_R_BL_MAX, &value))
|
||||||
|
seq_printf(s, "Backlight max:\t%lu\n", value);
|
||||||
|
if (!read_ec_data(ideapad_handle, VPCCMD_R_BL, &value))
|
||||||
|
seq_printf(s, "Backlight now:\t%lu\n", value);
|
||||||
|
if (!read_ec_data(ideapad_handle, VPCCMD_R_BL_POWER, &value))
|
||||||
|
seq_printf(s, "BL power value:\t%s\n", value ? "On" : "Off");
|
||||||
|
seq_printf(s, "=====================\n");
|
||||||
|
|
||||||
|
if (!read_ec_data(ideapad_handle, VPCCMD_R_RF, &value))
|
||||||
|
seq_printf(s, "Radio status:\t%s(%lu)\n",
|
||||||
|
value ? "On" : "Off", value);
|
||||||
|
if (!read_ec_data(ideapad_handle, VPCCMD_R_WIFI, &value))
|
||||||
|
seq_printf(s, "Wifi status:\t%s(%lu)\n",
|
||||||
|
value ? "On" : "Off", value);
|
||||||
|
if (!read_ec_data(ideapad_handle, VPCCMD_R_BT, &value))
|
||||||
|
seq_printf(s, "BT status:\t%s(%lu)\n",
|
||||||
|
value ? "On" : "Off", value);
|
||||||
|
if (!read_ec_data(ideapad_handle, VPCCMD_R_3G, &value))
|
||||||
|
seq_printf(s, "3G status:\t%s(%lu)\n",
|
||||||
|
value ? "On" : "Off", value);
|
||||||
|
seq_printf(s, "=====================\n");
|
||||||
|
|
||||||
|
if (!read_ec_data(ideapad_handle, VPCCMD_R_TOUCHPAD, &value))
|
||||||
|
seq_printf(s, "Touchpad status:%s(%lu)\n",
|
||||||
|
value ? "On" : "Off", value);
|
||||||
|
if (!read_ec_data(ideapad_handle, VPCCMD_R_CAMERA, &value))
|
||||||
|
seq_printf(s, "Camera status:\t%s(%lu)\n",
|
||||||
|
value ? "On" : "Off", value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int debugfs_status_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, debugfs_status_show, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations debugfs_status_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = debugfs_status_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int debugfs_cfg_show(struct seq_file *s, void *data)
|
||||||
|
{
|
||||||
|
if (!ideapad_priv) {
|
||||||
|
seq_printf(s, "cfg: N/A\n");
|
||||||
|
} else {
|
||||||
|
seq_printf(s, "cfg: 0x%.8lX\n\nCapability: ",
|
||||||
|
ideapad_priv->cfg);
|
||||||
|
if (test_bit(CFG_BT_BIT, &ideapad_priv->cfg))
|
||||||
|
seq_printf(s, "Bluetooth ");
|
||||||
|
if (test_bit(CFG_3G_BIT, &ideapad_priv->cfg))
|
||||||
|
seq_printf(s, "3G ");
|
||||||
|
if (test_bit(CFG_WIFI_BIT, &ideapad_priv->cfg))
|
||||||
|
seq_printf(s, "Wireless ");
|
||||||
|
if (test_bit(CFG_CAMERA_BIT, &ideapad_priv->cfg))
|
||||||
|
seq_printf(s, "Camera ");
|
||||||
|
seq_printf(s, "\nGraphic: ");
|
||||||
|
switch ((ideapad_priv->cfg)&0x700) {
|
||||||
|
case 0x100:
|
||||||
|
seq_printf(s, "Intel");
|
||||||
|
break;
|
||||||
|
case 0x200:
|
||||||
|
seq_printf(s, "ATI");
|
||||||
|
break;
|
||||||
|
case 0x300:
|
||||||
|
seq_printf(s, "Nvidia");
|
||||||
|
break;
|
||||||
|
case 0x400:
|
||||||
|
seq_printf(s, "Intel and ATI");
|
||||||
|
break;
|
||||||
|
case 0x500:
|
||||||
|
seq_printf(s, "Intel and Nvidia");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
seq_printf(s, "\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int debugfs_cfg_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, debugfs_cfg_show, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations debugfs_cfg_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = debugfs_cfg_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __devinit ideapad_debugfs_init(struct ideapad_private *priv)
|
||||||
|
{
|
||||||
|
struct dentry *node;
|
||||||
|
|
||||||
|
priv->debug = debugfs_create_dir("ideapad", NULL);
|
||||||
|
if (priv->debug == NULL) {
|
||||||
|
pr_err("failed to create debugfs directory");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = debugfs_create_file("cfg", S_IRUGO, priv->debug, NULL,
|
||||||
|
&debugfs_cfg_fops);
|
||||||
|
if (!node) {
|
||||||
|
pr_err("failed to create cfg in debugfs");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = debugfs_create_file("status", S_IRUGO, priv->debug, NULL,
|
||||||
|
&debugfs_status_fops);
|
||||||
|
if (!node) {
|
||||||
|
pr_err("failed to create event in debugfs");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
errout:
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ideapad_debugfs_exit(struct ideapad_private *priv)
|
||||||
|
{
|
||||||
|
debugfs_remove_recursive(priv->debug);
|
||||||
|
priv->debug = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sysfs
|
* sysfs
|
||||||
*/
|
*/
|
||||||
|
@ -172,7 +340,7 @@ static ssize_t show_ideapad_cam(struct device *dev,
|
||||||
{
|
{
|
||||||
unsigned long result;
|
unsigned long result;
|
||||||
|
|
||||||
if (read_ec_data(ideapad_handle, 0x1D, &result))
|
if (read_ec_data(ideapad_handle, VPCCMD_R_CAMERA, &result))
|
||||||
return sprintf(buf, "-1\n");
|
return sprintf(buf, "-1\n");
|
||||||
return sprintf(buf, "%lu\n", result);
|
return sprintf(buf, "%lu\n", result);
|
||||||
}
|
}
|
||||||
|
@ -187,7 +355,7 @@ static ssize_t store_ideapad_cam(struct device *dev,
|
||||||
return 0;
|
return 0;
|
||||||
if (sscanf(buf, "%i", &state) != 1)
|
if (sscanf(buf, "%i", &state) != 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
ret = write_ec_cmd(ideapad_handle, 0x1E, state);
|
ret = write_ec_cmd(ideapad_handle, VPCCMD_W_CAMERA, state);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
return count;
|
return count;
|
||||||
|
@ -195,20 +363,8 @@ static ssize_t store_ideapad_cam(struct device *dev,
|
||||||
|
|
||||||
static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
|
static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
|
||||||
|
|
||||||
static ssize_t show_ideapad_cfg(struct device *dev,
|
|
||||||
struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
struct ideapad_private *priv = dev_get_drvdata(dev);
|
|
||||||
|
|
||||||
return sprintf(buf, "0x%.8lX\n", priv->cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DEVICE_ATTR(cfg, 0444, show_ideapad_cfg, NULL);
|
|
||||||
|
|
||||||
static struct attribute *ideapad_attributes[] = {
|
static struct attribute *ideapad_attributes[] = {
|
||||||
&dev_attr_camera_power.attr,
|
&dev_attr_camera_power.attr,
|
||||||
&dev_attr_cfg.attr,
|
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -244,9 +400,9 @@ struct ideapad_rfk_data {
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct ideapad_rfk_data ideapad_rfk_data[] = {
|
const struct ideapad_rfk_data ideapad_rfk_data[] = {
|
||||||
{ "ideapad_wlan", CFG_WIFI_BIT, 0x15, RFKILL_TYPE_WLAN },
|
{ "ideapad_wlan", CFG_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
|
||||||
{ "ideapad_bluetooth", CFG_BT_BIT, 0x17, RFKILL_TYPE_BLUETOOTH },
|
{ "ideapad_bluetooth", CFG_BT_BIT, VPCCMD_W_BT, RFKILL_TYPE_BLUETOOTH },
|
||||||
{ "ideapad_3g", CFG_3G_BIT, 0x20, RFKILL_TYPE_WWAN },
|
{ "ideapad_3g", CFG_3G_BIT, VPCCMD_W_3G, RFKILL_TYPE_WWAN },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ideapad_rfk_set(void *data, bool blocked)
|
static int ideapad_rfk_set(void *data, bool blocked)
|
||||||
|
@ -260,13 +416,12 @@ static struct rfkill_ops ideapad_rfk_ops = {
|
||||||
.set_block = ideapad_rfk_set,
|
.set_block = ideapad_rfk_set,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ideapad_sync_rfk_state(struct acpi_device *adevice)
|
static void ideapad_sync_rfk_state(struct ideapad_private *priv)
|
||||||
{
|
{
|
||||||
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
|
|
||||||
unsigned long hw_blocked;
|
unsigned long hw_blocked;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (read_ec_data(ideapad_handle, 0x23, &hw_blocked))
|
if (read_ec_data(ideapad_handle, VPCCMD_R_RF, &hw_blocked))
|
||||||
return;
|
return;
|
||||||
hw_blocked = !hw_blocked;
|
hw_blocked = !hw_blocked;
|
||||||
|
|
||||||
|
@ -363,8 +518,10 @@ static void ideapad_platform_exit(struct ideapad_private *priv)
|
||||||
* input device
|
* input device
|
||||||
*/
|
*/
|
||||||
static const struct key_entry ideapad_keymap[] = {
|
static const struct key_entry ideapad_keymap[] = {
|
||||||
{ KE_KEY, 0x06, { KEY_SWITCHVIDEOMODE } },
|
{ KE_KEY, 6, { KEY_SWITCHVIDEOMODE } },
|
||||||
{ KE_KEY, 0x0D, { KEY_WLAN } },
|
{ KE_KEY, 13, { KEY_WLAN } },
|
||||||
|
{ KE_KEY, 16, { KEY_PROG1 } },
|
||||||
|
{ KE_KEY, 17, { KEY_PROG2 } },
|
||||||
{ KE_END, 0 },
|
{ KE_END, 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -419,6 +576,18 @@ static void ideapad_input_report(struct ideapad_private *priv,
|
||||||
sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
|
sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ideapad_input_novokey(struct ideapad_private *priv)
|
||||||
|
{
|
||||||
|
unsigned long long_pressed;
|
||||||
|
|
||||||
|
if (read_ec_data(ideapad_handle, VPCCMD_R_NOVO, &long_pressed))
|
||||||
|
return;
|
||||||
|
if (long_pressed)
|
||||||
|
ideapad_input_report(priv, 17);
|
||||||
|
else
|
||||||
|
ideapad_input_report(priv, 16);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* backlight
|
* backlight
|
||||||
*/
|
*/
|
||||||
|
@ -426,16 +595,17 @@ static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
|
||||||
{
|
{
|
||||||
unsigned long now;
|
unsigned long now;
|
||||||
|
|
||||||
if (read_ec_data(ideapad_handle, 0x12, &now))
|
if (read_ec_data(ideapad_handle, VPCCMD_R_BL, &now))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
return now;
|
return now;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ideapad_backlight_update_status(struct backlight_device *blightdev)
|
static int ideapad_backlight_update_status(struct backlight_device *blightdev)
|
||||||
{
|
{
|
||||||
if (write_ec_cmd(ideapad_handle, 0x13, blightdev->props.brightness))
|
if (write_ec_cmd(ideapad_handle, VPCCMD_W_BL,
|
||||||
|
blightdev->props.brightness))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
if (write_ec_cmd(ideapad_handle, 0x33,
|
if (write_ec_cmd(ideapad_handle, VPCCMD_W_BL_POWER,
|
||||||
blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1))
|
blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
@ -453,11 +623,11 @@ static int ideapad_backlight_init(struct ideapad_private *priv)
|
||||||
struct backlight_properties props;
|
struct backlight_properties props;
|
||||||
unsigned long max, now, power;
|
unsigned long max, now, power;
|
||||||
|
|
||||||
if (read_ec_data(ideapad_handle, 0x11, &max))
|
if (read_ec_data(ideapad_handle, VPCCMD_R_BL_MAX, &max))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
if (read_ec_data(ideapad_handle, 0x12, &now))
|
if (read_ec_data(ideapad_handle, VPCCMD_R_BL, &now))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
if (read_ec_data(ideapad_handle, 0x18, &power))
|
if (read_ec_data(ideapad_handle, VPCCMD_R_BL_POWER, &power))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
memset(&props, 0, sizeof(struct backlight_properties));
|
memset(&props, 0, sizeof(struct backlight_properties));
|
||||||
|
@ -493,7 +663,9 @@ static void ideapad_backlight_notify_power(struct ideapad_private *priv)
|
||||||
unsigned long power;
|
unsigned long power;
|
||||||
struct backlight_device *blightdev = priv->blightdev;
|
struct backlight_device *blightdev = priv->blightdev;
|
||||||
|
|
||||||
if (read_ec_data(ideapad_handle, 0x18, &power))
|
if (!blightdev)
|
||||||
|
return;
|
||||||
|
if (read_ec_data(ideapad_handle, VPCCMD_R_BL_POWER, &power))
|
||||||
return;
|
return;
|
||||||
blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
|
blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
|
||||||
}
|
}
|
||||||
|
@ -504,7 +676,7 @@ static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
|
||||||
|
|
||||||
/* if we control brightness via acpi video driver */
|
/* if we control brightness via acpi video driver */
|
||||||
if (priv->blightdev == NULL) {
|
if (priv->blightdev == NULL) {
|
||||||
read_ec_data(ideapad_handle, 0x12, &now);
|
read_ec_data(ideapad_handle, VPCCMD_R_BL, &now);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,6 +705,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
dev_set_drvdata(&adevice->dev, priv);
|
dev_set_drvdata(&adevice->dev, priv);
|
||||||
|
ideapad_priv = priv;
|
||||||
ideapad_handle = adevice->handle;
|
ideapad_handle = adevice->handle;
|
||||||
priv->cfg = cfg;
|
priv->cfg = cfg;
|
||||||
|
|
||||||
|
@ -540,6 +713,10 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto platform_failed;
|
goto platform_failed;
|
||||||
|
|
||||||
|
ret = ideapad_debugfs_init(priv);
|
||||||
|
if (ret)
|
||||||
|
goto debugfs_failed;
|
||||||
|
|
||||||
ret = ideapad_input_init(priv);
|
ret = ideapad_input_init(priv);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto input_failed;
|
goto input_failed;
|
||||||
|
@ -550,7 +727,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
|
||||||
else
|
else
|
||||||
priv->rfk[i] = NULL;
|
priv->rfk[i] = NULL;
|
||||||
}
|
}
|
||||||
ideapad_sync_rfk_state(adevice);
|
ideapad_sync_rfk_state(priv);
|
||||||
|
|
||||||
if (!acpi_video_backlight_support()) {
|
if (!acpi_video_backlight_support()) {
|
||||||
ret = ideapad_backlight_init(priv);
|
ret = ideapad_backlight_init(priv);
|
||||||
|
@ -565,6 +742,8 @@ backlight_failed:
|
||||||
ideapad_unregister_rfkill(adevice, i);
|
ideapad_unregister_rfkill(adevice, i);
|
||||||
ideapad_input_exit(priv);
|
ideapad_input_exit(priv);
|
||||||
input_failed:
|
input_failed:
|
||||||
|
ideapad_debugfs_exit(priv);
|
||||||
|
debugfs_failed:
|
||||||
ideapad_platform_exit(priv);
|
ideapad_platform_exit(priv);
|
||||||
platform_failed:
|
platform_failed:
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
|
@ -580,6 +759,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type)
|
||||||
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
|
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
|
||||||
ideapad_unregister_rfkill(adevice, i);
|
ideapad_unregister_rfkill(adevice, i);
|
||||||
ideapad_input_exit(priv);
|
ideapad_input_exit(priv);
|
||||||
|
ideapad_debugfs_exit(priv);
|
||||||
ideapad_platform_exit(priv);
|
ideapad_platform_exit(priv);
|
||||||
dev_set_drvdata(&adevice->dev, NULL);
|
dev_set_drvdata(&adevice->dev, NULL);
|
||||||
kfree(priv);
|
kfree(priv);
|
||||||
|
@ -593,9 +773,9 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
|
||||||
acpi_handle handle = adevice->handle;
|
acpi_handle handle = adevice->handle;
|
||||||
unsigned long vpc1, vpc2, vpc_bit;
|
unsigned long vpc1, vpc2, vpc_bit;
|
||||||
|
|
||||||
if (read_ec_data(handle, 0x10, &vpc1))
|
if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
|
||||||
return;
|
return;
|
||||||
if (read_ec_data(handle, 0x1A, &vpc2))
|
if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
vpc1 = (vpc2 << 8) | vpc1;
|
vpc1 = (vpc2 << 8) | vpc1;
|
||||||
|
@ -603,11 +783,14 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
|
||||||
if (test_bit(vpc_bit, &vpc1)) {
|
if (test_bit(vpc_bit, &vpc1)) {
|
||||||
switch (vpc_bit) {
|
switch (vpc_bit) {
|
||||||
case 9:
|
case 9:
|
||||||
ideapad_sync_rfk_state(adevice);
|
ideapad_sync_rfk_state(priv);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
ideapad_backlight_notify_brightness(priv);
|
ideapad_backlight_notify_brightness(priv);
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
|
ideapad_input_novokey(priv);
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
ideapad_backlight_notify_power(priv);
|
ideapad_backlight_notify_power(priv);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <asm/intel_scu_ipc.h>
|
#include <asm/intel_scu_ipc.h>
|
||||||
|
|
||||||
static u32 major;
|
static int major;
|
||||||
|
|
||||||
#define MAX_FW_SIZE 264192
|
#define MAX_FW_SIZE 264192
|
||||||
|
|
||||||
|
@ -117,7 +117,11 @@ static const struct file_operations scu_ipc_fops = {
|
||||||
|
|
||||||
static int __init ipc_module_init(void)
|
static int __init ipc_module_init(void)
|
||||||
{
|
{
|
||||||
return register_chrdev(0, "intel_mid_scu", &scu_ipc_fops);
|
major = register_chrdev(0, "intel_mid_scu", &scu_ipc_fops);
|
||||||
|
if (major < 0)
|
||||||
|
return major;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit ipc_module_exit(void)
|
static void __exit ipc_module_exit(void)
|
||||||
|
|
|
@ -226,6 +226,7 @@ static struct backlight_device *backlight_device;
|
||||||
static struct mutex sabi_mutex;
|
static struct mutex sabi_mutex;
|
||||||
static struct platform_device *sdev;
|
static struct platform_device *sdev;
|
||||||
static struct rfkill *rfk;
|
static struct rfkill *rfk;
|
||||||
|
static bool has_stepping_quirk;
|
||||||
|
|
||||||
static int force;
|
static int force;
|
||||||
module_param(force, bool, 0);
|
module_param(force, bool, 0);
|
||||||
|
@ -370,15 +371,28 @@ static u8 read_brightness(void)
|
||||||
&sretval);
|
&sretval);
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
user_brightness = sretval.retval[0];
|
user_brightness = sretval.retval[0];
|
||||||
if (user_brightness != 0)
|
if (user_brightness > sabi_config->min_brightness)
|
||||||
user_brightness -= sabi_config->min_brightness;
|
user_brightness -= sabi_config->min_brightness;
|
||||||
|
else
|
||||||
|
user_brightness = 0;
|
||||||
}
|
}
|
||||||
return user_brightness;
|
return user_brightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_brightness(u8 user_brightness)
|
static void set_brightness(u8 user_brightness)
|
||||||
{
|
{
|
||||||
u8 user_level = user_brightness - sabi_config->min_brightness;
|
u8 user_level = user_brightness + sabi_config->min_brightness;
|
||||||
|
|
||||||
|
if (has_stepping_quirk && user_level != 0) {
|
||||||
|
/*
|
||||||
|
* short circuit if the specified level is what's already set
|
||||||
|
* to prevent the screen from flickering needlessly
|
||||||
|
*/
|
||||||
|
if (user_brightness == read_brightness())
|
||||||
|
return;
|
||||||
|
|
||||||
|
sabi_set_command(sabi_config->commands.set_brightness, 0);
|
||||||
|
}
|
||||||
|
|
||||||
sabi_set_command(sabi_config->commands.set_brightness, user_level);
|
sabi_set_command(sabi_config->commands.set_brightness, user_level);
|
||||||
}
|
}
|
||||||
|
@ -388,6 +402,40 @@ static int get_brightness(struct backlight_device *bd)
|
||||||
return (int)read_brightness();
|
return (int)read_brightness();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void check_for_stepping_quirk(void)
|
||||||
|
{
|
||||||
|
u8 initial_level;
|
||||||
|
u8 check_level;
|
||||||
|
u8 orig_level = read_brightness();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some laptops exhibit the strange behaviour of stepping toward
|
||||||
|
* (rather than setting) the brightness except when changing to/from
|
||||||
|
* brightness level 0. This behaviour is checked for here and worked
|
||||||
|
* around in set_brightness.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (orig_level == 0)
|
||||||
|
set_brightness(1);
|
||||||
|
|
||||||
|
initial_level = read_brightness();
|
||||||
|
|
||||||
|
if (initial_level <= 2)
|
||||||
|
check_level = initial_level + 2;
|
||||||
|
else
|
||||||
|
check_level = initial_level - 2;
|
||||||
|
|
||||||
|
has_stepping_quirk = false;
|
||||||
|
set_brightness(check_level);
|
||||||
|
|
||||||
|
if (read_brightness() != check_level) {
|
||||||
|
has_stepping_quirk = true;
|
||||||
|
pr_info("enabled workaround for brightness stepping quirk\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
set_brightness(orig_level);
|
||||||
|
}
|
||||||
|
|
||||||
static int update_status(struct backlight_device *bd)
|
static int update_status(struct backlight_device *bd)
|
||||||
{
|
{
|
||||||
set_brightness(bd->props.brightness);
|
set_brightness(bd->props.brightness);
|
||||||
|
@ -620,6 +668,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
|
||||||
},
|
},
|
||||||
.callback = dmi_check_cb,
|
.callback = dmi_check_cb,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.ident = "N220",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR,
|
||||||
|
"SAMSUNG ELECTRONICS CO., LTD."),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "N220"),
|
||||||
|
DMI_MATCH(DMI_BOARD_NAME, "N220"),
|
||||||
|
},
|
||||||
|
.callback = dmi_check_cb,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.ident = "N150/N210/N220/N230",
|
.ident = "N150/N210/N220/N230",
|
||||||
.matches = {
|
.matches = {
|
||||||
|
@ -640,6 +698,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
|
||||||
},
|
},
|
||||||
.callback = dmi_check_cb,
|
.callback = dmi_check_cb,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.ident = "R700",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "SR700"),
|
||||||
|
DMI_MATCH(DMI_BOARD_NAME, "SR700"),
|
||||||
|
},
|
||||||
|
.callback = dmi_check_cb,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.ident = "R530/R730",
|
.ident = "R530/R730",
|
||||||
.matches = {
|
.matches = {
|
||||||
|
@ -686,6 +753,33 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
|
||||||
},
|
},
|
||||||
.callback = dmi_check_cb,
|
.callback = dmi_check_cb,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.ident = "R528/R728",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "R528/R728"),
|
||||||
|
DMI_MATCH(DMI_BOARD_NAME, "R528/R728"),
|
||||||
|
},
|
||||||
|
.callback = dmi_check_cb,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ident = "NC210/NC110",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
|
||||||
|
DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
|
||||||
|
},
|
||||||
|
.callback = dmi_check_cb,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ident = "X520",
|
||||||
|
.matches = {
|
||||||
|
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
|
||||||
|
DMI_MATCH(DMI_PRODUCT_NAME, "X520"),
|
||||||
|
DMI_MATCH(DMI_BOARD_NAME, "X520"),
|
||||||
|
},
|
||||||
|
.callback = dmi_check_cb,
|
||||||
|
},
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
|
MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
|
||||||
|
@ -770,7 +864,7 @@ static int __init samsung_init(void)
|
||||||
sabi_iface = ioremap_nocache(ifaceP, 16);
|
sabi_iface = ioremap_nocache(ifaceP, 16);
|
||||||
if (!sabi_iface) {
|
if (!sabi_iface) {
|
||||||
pr_err("Can't remap %x\n", ifaceP);
|
pr_err("Can't remap %x\n", ifaceP);
|
||||||
goto exit;
|
goto error_no_signature;
|
||||||
}
|
}
|
||||||
if (debug) {
|
if (debug) {
|
||||||
printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
|
printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
|
||||||
|
@ -794,6 +888,9 @@ static int __init samsung_init(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for stepping quirk */
|
||||||
|
check_for_stepping_quirk();
|
||||||
|
|
||||||
/* knock up a platform device to hang stuff off of */
|
/* knock up a platform device to hang stuff off of */
|
||||||
sdev = platform_device_register_simple("samsung", -1, NULL, 0);
|
sdev = platform_device_register_simple("samsung", -1, NULL, 0);
|
||||||
if (IS_ERR(sdev))
|
if (IS_ERR(sdev))
|
||||||
|
@ -802,7 +899,8 @@ static int __init samsung_init(void)
|
||||||
/* create a backlight device to talk to this one */
|
/* create a backlight device to talk to this one */
|
||||||
memset(&props, 0, sizeof(struct backlight_properties));
|
memset(&props, 0, sizeof(struct backlight_properties));
|
||||||
props.type = BACKLIGHT_PLATFORM;
|
props.type = BACKLIGHT_PLATFORM;
|
||||||
props.max_brightness = sabi_config->max_brightness;
|
props.max_brightness = sabi_config->max_brightness -
|
||||||
|
sabi_config->min_brightness;
|
||||||
backlight_device = backlight_device_register("samsung", &sdev->dev,
|
backlight_device = backlight_device_register("samsung", &sdev->dev,
|
||||||
NULL, &backlight_ops,
|
NULL, &backlight_ops,
|
||||||
&props);
|
&props);
|
||||||
|
@ -821,7 +919,6 @@ static int __init samsung_init(void)
|
||||||
if (retval)
|
if (retval)
|
||||||
goto error_file_create;
|
goto error_file_create;
|
||||||
|
|
||||||
exit:
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error_file_create:
|
error_file_create:
|
||||||
|
|
|
@ -3281,7 +3281,7 @@ static int sony_pic_add(struct acpi_device *device)
|
||||||
/* request IRQ */
|
/* request IRQ */
|
||||||
list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
|
list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
|
||||||
if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
|
if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
|
||||||
IRQF_DISABLED, "sony-laptop", &spic_dev)) {
|
0, "sony-laptop", &spic_dev)) {
|
||||||
dprintk("IRQ: %d - triggering: %d - "
|
dprintk("IRQ: %d - triggering: %d - "
|
||||||
"polarity: %d - shr: %d\n",
|
"polarity: %d - shr: %d\n",
|
||||||
irq->irq.interrupts[0],
|
irq->irq.interrupts[0],
|
||||||
|
|
|
@ -41,6 +41,7 @@ static const struct key_entry topstar_keymap[] = {
|
||||||
{ KE_KEY, 0x8c, { KEY_MEDIA } },
|
{ KE_KEY, 0x8c, { KEY_MEDIA } },
|
||||||
|
|
||||||
/* Known non hotkey events don't handled or that we don't care yet */
|
/* Known non hotkey events don't handled or that we don't care yet */
|
||||||
|
{ KE_IGNORE, 0x82, }, /* backlight event */
|
||||||
{ KE_IGNORE, 0x8e, },
|
{ KE_IGNORE, 0x8e, },
|
||||||
{ KE_IGNORE, 0x8f, },
|
{ KE_IGNORE, 0x8f, },
|
||||||
{ KE_IGNORE, 0x90, },
|
{ KE_IGNORE, 0x90, },
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -754,9 +754,13 @@ static void wmi_free_devices(void)
|
||||||
struct wmi_block *wblock, *next;
|
struct wmi_block *wblock, *next;
|
||||||
|
|
||||||
/* Delete devices for all the GUIDs */
|
/* Delete devices for all the GUIDs */
|
||||||
list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
|
list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
|
||||||
|
list_del(&wblock->list);
|
||||||
if (wblock->dev.class)
|
if (wblock->dev.class)
|
||||||
device_unregister(&wblock->dev);
|
device_unregister(&wblock->dev);
|
||||||
|
else
|
||||||
|
kfree(wblock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool guid_already_parsed(const char *guid_string)
|
static bool guid_already_parsed(const char *guid_string)
|
||||||
|
|
Loading…
Reference in a new issue