Commit 2560540b authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of...

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86: (38 commits)
  acer-wmi: support Lenovo ideapad S205 wifi switch
  acerhdf.c: spaces in aliased changed to *
  platform-drivers-x86: ideapad-laptop: add missing ideapad_input_exit in ideapad_acpi_add error path
  x86 driver: fix typo in TDP override enabling
  Platform: fix samsung-laptop DMI identification for N150/N210/220/N230
  dell-wmi: Add keys for Dell XPS L502X
  platform-drivers-x86: samsung-q10: make dmi_check_callback return 1
  Platform: Samsung Q10 backlight driver
  platform-drivers-x86: intel_scu_ipc: convert to DEFINE_PCI_DEVICE_TABLE
  platform-drivers-x86: intel_rar_register: convert to DEFINE_PCI_DEVICE_TABLE
  platform-drivers-x86: intel_menlow: add missing return AE_OK for intel_menlow_register_sensor()
  platform-drivers-x86: intel_mid_thermal: fix memory leak
  platform-drivers-x86: msi-wmi: add missing sparse_keymap_free in msi_wmi_init error path
  Samsung Laptop platform driver: support N510
  asus-wmi: add uwb rfkill support
  asus-wmi: add gps rfkill support
  asus-wmi: add CWAP support and clarify the meaning of WAPF bits
  asus-wmi: return proper value in store_cpufv()
  asus-wmi: check for temp1 presence
  asus-wmi: add thermal sensor
  ...
parents 45a05f94 15b956a0
......@@ -4,3 +4,20 @@ KernelVersion: 2.6.37
Contact: "Ike Panhc <ike.pan@canonical.com>"
Description:
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)
......@@ -581,3 +581,14 @@ Why: This driver has been superseded by g_mass_storage.
Who: Alan Stern <stern@rowland.harvard.edu>
----------------------------
What: threeg and interface sysfs files in /sys/devices/platform/acer-wmi
When: 2012
Why: In 3.0, we can now autodetect internal 3G device and already have
the threeg rfkill device. So, we plan to remove threeg sysfs support
for it's no longer necessary.
We also plan to remove interface sysfs file that exposed which ACPI-WMI
interface that was used by acer-wmi driver. It will replaced by
information log when acer-wmi initial.
Who: Lee, Chun-Yi <jlee@novell.com>
......@@ -769,4 +769,12 @@ config INTEL_OAKTRAIL
enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y
here; it will only load on supported platforms.
config SAMSUNG_Q10
tristate "Samsung Q10 Extras"
depends on SERIO_I8042
select BACKLIGHT_CLASS_DEVICE
---help---
This driver provides support for backlight control on Samsung Q10
and related laptops, including Dell Latitude X200.
endif # X86_PLATFORM_DEVICES
......@@ -44,3 +44,4 @@ obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o
obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
......@@ -99,6 +99,7 @@ enum acer_wmi_event_ids {
static const struct key_entry acer_wmi_keymap[] = {
{KE_KEY, 0x01, {KEY_WLAN} }, /* WiFi */
{KE_KEY, 0x03, {KEY_WLAN} }, /* WiFi */
{KE_KEY, 0x04, {KEY_WLAN} }, /* WiFi */
{KE_KEY, 0x12, {KEY_BLUETOOTH} }, /* BT */
{KE_KEY, 0x21, {KEY_PROG1} }, /* Backup */
{KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */
......@@ -304,6 +305,10 @@ static struct quirk_entry quirk_fujitsu_amilo_li_1718 = {
.wireless = 2,
};
static struct quirk_entry quirk_lenovo_ideapad_s205 = {
.wireless = 3,
};
/* The Aspire One has a dummy ACPI-WMI interface - disable it */
static struct dmi_system_id __devinitdata acer_blacklist[] = {
{
......@@ -450,6 +455,15 @@ static struct dmi_system_id acer_quirks[] = {
},
.driver_data = &quirk_medion_md_98300,
},
{
.callback = dmi_matched,
.ident = "Lenovo Ideapad S205",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "10382LG"),
},
.driver_data = &quirk_lenovo_ideapad_s205,
},
{}
};
......@@ -542,6 +556,12 @@ struct wmi_interface *iface)
return AE_ERROR;
*value = result & 0x1;
return AE_OK;
case 3:
err = ec_read(0x78, &result);
if (err)
return AE_ERROR;
*value = result & 0x1;
return AE_OK;
default:
err = ec_read(0xA, &result);
if (err)
......@@ -1266,8 +1286,13 @@ static void acer_rfkill_update(struct work_struct *ignored)
acpi_status status;
status = get_u32(&state, ACER_CAP_WIRELESS);
if (ACPI_SUCCESS(status))
rfkill_set_sw_state(wireless_rfkill, !state);
if (ACPI_SUCCESS(status)) {
if (quirks->wireless == 3) {
rfkill_set_hw_state(wireless_rfkill, !state);
} else {
rfkill_set_sw_state(wireless_rfkill, !state);
}
}
if (has_cap(ACER_CAP_BLUETOOTH)) {
status = get_u32(&state, ACER_CAP_BLUETOOTH);
......@@ -1400,6 +1425,9 @@ static ssize_t show_bool_threeg(struct device *dev,
{
u32 result; \
acpi_status status;
pr_info("This threeg sysfs will be removed in 2012"
" - used by: %s\n", current->comm);
if (wmi_has_guid(WMID_GUID3))
status = wmid3_get_device_status(&result,
ACER_WMID3_GDS_THREEG);
......@@ -1415,8 +1443,10 @@ static ssize_t set_bool_threeg(struct device *dev,
{
u32 tmp = simple_strtoul(buf, NULL, 10);
acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
if (ACPI_FAILURE(status))
return -EINVAL;
pr_info("This threeg sysfs will be removed in 2012"
" - used by: %s\n", current->comm);
if (ACPI_FAILURE(status))
return -EINVAL;
return count;
}
static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
......@@ -1425,6 +1455,8 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
char *buf)
{
pr_info("This interface sysfs will be removed in 2012"
" - used by: %s\n", current->comm);
switch (interface->type) {
case ACER_AMW0:
return sprintf(buf, "AMW0\n");
......
......@@ -182,6 +182,7 @@ static const struct bios_settings_t bios_tbl[] = {
{"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00} },
{"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
{"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00} },
{"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00} },
/* Acer 531 */
{"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00} },
/* Gateway */
......@@ -703,15 +704,15 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Peter Feuerer");
MODULE_DESCRIPTION("Aspire One temperature and fan driver");
MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1410*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1810*:");
MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:");
MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:");
MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:");
MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:");
MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:");
MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:");
MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMA*:");
MODULE_ALIAS("dmi:*:*Packard*Bell*:pnAOA*:");
MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOA*:");
MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMU*:");
MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMA*:");
module_init(acerhdf_init);
module_exit(acerhdf_exit);
......@@ -70,11 +70,10 @@ MODULE_LICENSE("GPL");
* WAPF defines the behavior of the Fn+Fx wlan key
* The significance of values is yet to be found, but
* most of the time:
* 0x0 will do nothing
* 0x1 will allow to control the device with Fn+Fx key.
* 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key
* 0x5 like 0x1 or 0x4
* So, if something doesn't work as you want, just try other values =)
* Bit | Bluetooth | WLAN
* 0 | Hardware | Hardware
* 1 | Hardware | Software
* 4 | Software | Software
*/
static uint wapf = 1;
module_param(wapf, uint, 0444);
......
......@@ -38,6 +38,24 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID);
/*
* WAPF defines the behavior of the Fn+Fx wlan key
* The significance of values is yet to be found, but
* most of the time:
* Bit | Bluetooth | WLAN
* 0 | Hardware | Hardware
* 1 | Hardware | Software
* 4 | Software | Software
*/
static uint wapf;
module_param(wapf, uint, 0444);
MODULE_PARM_DESC(wapf, "WAPF value");
static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
{
driver->wapf = wapf;
}
static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0x30, { KEY_VOLUMEUP } },
{ KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
......@@ -53,16 +71,16 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0x51, { KEY_WWW } },
{ KE_KEY, 0x55, { KEY_CALC } },
{ KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */
{ KE_KEY, 0x5D, { KEY_WLAN } },
{ KE_KEY, 0x5E, { KEY_WLAN } },
{ KE_KEY, 0x5F, { KEY_WLAN } },
{ KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
{ KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
{ KE_KEY, 0x5F, { KEY_WLAN } }, /* Wireless console Disable */
{ KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } },
{ KE_KEY, 0x7E, { KEY_BLUETOOTH } },
{ KE_KEY, 0x7D, { KEY_BLUETOOTH } },
{ KE_KEY, 0x7E, { KEY_BLUETOOTH } },
{ KE_KEY, 0x82, { KEY_CAMERA } },
{ KE_KEY, 0x88, { KEY_RFKILL } },
{ KE_KEY, 0x8A, { KEY_PROG1 } },
......@@ -81,6 +99,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = {
.keymap = asus_nb_wmi_keymap,
.input_name = "Asus WMI hotkeys",
.input_phys = ASUS_NB_WMI_FILE "/input0",
.quirks = asus_nb_wmi_quirks,
};
......
......@@ -44,6 +44,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
......@@ -66,6 +67,8 @@ MODULE_LICENSE("GPL");
#define NOTIFY_BRNUP_MAX 0x1f
#define NOTIFY_BRNDOWN_MIN 0x20
#define NOTIFY_BRNDOWN_MAX 0x2e
#define NOTIFY_KBD_BRTUP 0xc4
#define NOTIFY_KBD_BRTDWN 0xc5
/* WMI Methods */
#define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */
......@@ -93,6 +96,7 @@ MODULE_LICENSE("GPL");
/* Wireless */
#define ASUS_WMI_DEVID_HW_SWITCH 0x00010001
#define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002
#define ASUS_WMI_DEVID_CWAP 0x00010003
#define ASUS_WMI_DEVID_WLAN 0x00010011
#define ASUS_WMI_DEVID_BLUETOOTH 0x00010013
#define ASUS_WMI_DEVID_GPS 0x00010015
......@@ -102,6 +106,12 @@ MODULE_LICENSE("GPL");
/* Leds */
/* 0x000200XX and 0x000400XX */
#define ASUS_WMI_DEVID_LED1 0x00020011
#define ASUS_WMI_DEVID_LED2 0x00020012
#define ASUS_WMI_DEVID_LED3 0x00020013
#define ASUS_WMI_DEVID_LED4 0x00020014
#define ASUS_WMI_DEVID_LED5 0x00020015
#define ASUS_WMI_DEVID_LED6 0x00020016
/* Backlight and Brightness */
#define ASUS_WMI_DEVID_BACKLIGHT 0x00050011
......@@ -174,13 +184,18 @@ struct asus_wmi {
struct led_classdev tpd_led;
int tpd_led_wk;
struct led_classdev kbd_led;
int kbd_led_wk;
struct workqueue_struct *led_workqueue;
struct work_struct tpd_led_work;
struct work_struct kbd_led_work;
struct asus_rfkill wlan;
struct asus_rfkill bluetooth;
struct asus_rfkill wimax;
struct asus_rfkill wwan3g;
struct asus_rfkill gps;
struct asus_rfkill uwb;
struct hotplug_slot *hotplug_slot;
struct mutex hotplug_lock;
......@@ -205,6 +220,7 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
asus->inputdev->phys = asus->driver->input_phys;
asus->inputdev->id.bustype = BUS_HOST;
asus->inputdev->dev.parent = &asus->platform_device->dev;
set_bit(EV_REP, asus->inputdev->evbit);
err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL);
if (err)
......@@ -359,30 +375,80 @@ static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
return read_tpd_led_state(asus);
}
static int asus_wmi_led_init(struct asus_wmi *asus)
static void kbd_led_update(struct work_struct *work)
{
int rv;
int ctrl_param = 0;
struct asus_wmi *asus;
if (read_tpd_led_state(asus) < 0)
return 0;
asus = container_of(work, struct asus_wmi, kbd_led_work);
asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
if (!asus->led_workqueue)
return -ENOMEM;
INIT_WORK(&asus->tpd_led_work, tpd_led_update);
/*
* bits 0-2: level
* bit 7: light on/off
*/
if (asus->kbd_led_wk > 0)
ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F);
asus->tpd_led.name = "asus::touchpad";
asus->tpd_led.brightness_set = tpd_led_set;
asus->tpd_led.brightness_get = tpd_led_get;
asus->tpd_led.max_brightness = 1;
asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL);
}
rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led);
if (rv) {
destroy_workqueue(asus->led_workqueue);
return rv;
static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
{
int retval;
/*
* bits 0-2: level
* bit 7: light on/off
* bit 8-10: environment (0: dark, 1: normal, 2: light)
* bit 17: status unknown
*/
retval = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_KBD_BACKLIGHT,
0xFFFF);
/* Unknown status is considered as off */
if (retval == 0x8000)
retval = 0;
if (retval >= 0) {
if (level)
*level = retval & 0x80 ? retval & 0x7F : 0;
if (env)
*env = (retval >> 8) & 0x7F;
retval = 0;
}
return 0;
return retval;
}
static void kbd_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct asus_wmi *asus;
asus = container_of(led_cdev, struct asus_wmi, kbd_led);
if (value > asus->kbd_led.max_brightness)
value = asus->kbd_led.max_brightness;
else if (value < 0)
value = 0;
asus->kbd_led_wk = value;
queue_work(asus->led_workqueue, &asus->kbd_led_work);
}
static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
{
struct asus_wmi *asus;
int retval, value;
asus = container_of(led_cdev, struct asus_wmi, kbd_led);
retval = kbd_led_read(asus, &value, NULL);
if (retval < 0)
return retval;
return value;
}
static void asus_wmi_led_exit(struct asus_wmi *asus)
......@@ -393,6 +459,48 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
destroy_workqueue(asus->led_workqueue);
}
static int asus_wmi_led_init(struct asus_wmi *asus)
{
int rv = 0;
asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
if (!asus->led_workqueue)
return -ENOMEM;
if (read_tpd_led_state(asus) >= 0) {
INIT_WORK(&asus->tpd_led_work, tpd_led_update);
asus->tpd_led.name = "asus::touchpad";
asus->tpd_led.brightness_set = tpd_led_set;
asus->tpd_led.brightness_get = tpd_led_get;
asus->tpd_led.max_brightness = 1;
rv = led_classdev_register(&asus->platform_device->dev,
&asus->tpd_led);
if (rv)
goto error;
}
if (kbd_led_read(asus, NULL, NULL) >= 0) {
INIT_WORK(&asus->kbd_led_work, kbd_led_update);
asus->kbd_led.name = "asus::kbd_backlight";
asus->kbd_led.brightness_set = kbd_led_set;
asus->kbd_led.brightness_get = kbd_led_get;
asus->kbd_led.max_brightness = 3;
rv = led_classdev_register(&asus->platform_device->dev,
&asus->kbd_led);
}
error:
if (rv)
asus_wmi_led_exit(asus);
return rv;
}
/*
* PCI hotplug (for wlan rfkill)
*/
......@@ -729,6 +837,16 @@ static void asus_wmi_rfkill_exit(struct asus_wmi *asus)
rfkill_destroy(asus->wwan3g.rfkill);
asus->wwan3g.rfkill = NULL;
}
if (asus->gps.rfkill) {
rfkill_unregister(asus->gps.rfkill);
rfkill_destroy(asus->gps.rfkill);
asus->gps.rfkill = NULL;
}
if (asus->uwb.rfkill) {
rfkill_unregister(asus->uwb.rfkill);
rfkill_destroy(asus->uwb.rfkill);
asus->uwb.rfkill = NULL;
}
}
static int asus_wmi_rfkill_init(struct asus_wmi *asus)
......@@ -763,6 +881,18 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
if (result && result != -ENODEV)
goto exit;
result = asus_new_rfkill(asus, &asus->gps, "asus-gps",
RFKILL_TYPE_GPS, ASUS_WMI_DEVID_GPS);
if (result && result != -ENODEV)
goto exit;
result = asus_new_rfkill(asus, &asus->uwb, "asus-uwb",
RFKILL_TYPE_UWB, ASUS_WMI_DEVID_UWB);
if (result && result != -ENODEV)
goto exit;
if (!asus->driver->hotplug_wireless)
goto exit;
......@@ -797,8 +927,8 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
* Hwmon device
*/
static ssize_t asus_hwmon_pwm1(struct device *dev,
struct device_attribute *attr,
char *buf)
struct device_attribute *attr,
char *buf)
{
struct asus_wmi *asus = dev_get_drvdata(dev);
u32 value;
......@@ -809,7 +939,7 @@ static ssize_t asus_hwmon_pwm1(struct device *dev,
if (err < 0)
return err;
value |= 0xFF;
value &= 0xFF;
if (value == 1) /* Low Speed */
value = 85;
......@@ -825,7 +955,26 @@ static ssize_t asus_hwmon_pwm1(struct device *dev,
return sprintf(buf, "%d\n", value);
}
static ssize_t asus_hwmon_temp1(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct asus_wmi *asus = dev_get_drvdata(dev);
u32 value;
int err;
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_THERMAL_CTRL, &value);
if (err < 0)
return err;
value = KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000;
return sprintf(buf, "%d\n", value);
}
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL, 0);
static ssize_t
show_name(struct device *dev, struct device_attribute *attr, char *buf)
......@@ -836,12 +985,13 @@ static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
static struct attribute *hwmon_attributes[] = {
&sensor_dev_attr_pwm1.dev_attr.attr,
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_name.dev_attr.attr,
NULL
};
static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
struct attribute *attr, int idx)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct platform_device *pdev = to_platform_device(dev->parent);
......@@ -852,6 +1002,8 @@ static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
if (attr == &sensor_dev_attr_pwm1.dev_attr.attr)
dev_id = ASUS_WMI_DEVID_FAN_CTRL;
else if (attr == &sensor_dev_attr_temp1_input.dev_attr.attr)
dev_id = ASUS_WMI_DEVID_THERMAL_CTRL;
if (dev_id != -1) {
int err = asus_wmi_get_devstate(asus, dev_id, &value);
......@@ -869,9 +1021,13 @@ static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
* - reverved bits are non-zero
* - sfun and presence bit are not set
*/
if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
if (value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
|| (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT)))
ok = false;
} else if (dev_id == ASUS_WMI_DEVID_THERMAL_CTRL) {
/* If value is zero, something is clearly wrong */
if (value == 0)
ok = false;
}
return ok ? attr->mode : 0;
......@@ -904,6 +1060,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
pr_err("Could not register asus hwmon device\n");
return PTR_ERR(hwmon);
}
dev_set_drvdata(hwmon, asus);
asus->hwmon_device = hwmon;
result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group);
if (result)
......@@ -1060,6 +1217,8 @@ static void asus_wmi_notify(u32 value, void *context)
acpi_status status;
int code;
int orig_code;
unsigned int key_value = 1;
bool autorelease = 1;
status = wmi_get_event_data(value, &response);
if (status != AE_OK) {
......@@ -1075,6 +1234,13 @@ static void asus_wmi_notify(u32 value, void *context)
code = obj->integer.value;
orig_code = code;
if (asus->driver->key_filter) {
asus->driver->key_filter(asus->driver, &code, &key_value,
&autorelease);
if (code == ASUS_WMI_KEY_IGNORE)
goto exit;
}
if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
code = NOTIFY_BRNUP_MIN;
else if (code >= NOTIFY_BRNDOWN_MIN &&
......@@ -1084,7 +1250,8 @@ static void asus_wmi_notify(u32 value, void *context)
if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) {
if (!acpi_video_backlight_support())
asus_wmi_backlight_notify(asus, orig_code);
} else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true))
} else if (!sparse_keymap_report_event(asus->inputdev, code,
key_value, autorelease))
pr_info("Unknown key %x pressed\n", code);
exit:
......@@ -1164,14 +1331,18 @@ ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER);
static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
int value;
int value, rv;
if (!count || sscanf(buf, "%i", &value) != 1)
return -EINVAL;
if (value < 0 || value > 2)
return -EINVAL;
return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL);
rv = asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL);
if (rv < 0)
return rv;
return count;
}
static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv);
......@@ -1234,7 +1405,7 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
/* We don't know yet what to do with this version... */
if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) {
pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF);
pr_info("BIOS WMI version: %d.%d", rv >> 16, rv & 0xFF);
asus->spec = rv;
}
......@@ -1266,6 +1437,12 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
return -ENODEV;
}
/* CWAP allow to define the behavior of the Fn+F2 key,
* this method doesn't seems to be present on Eee PCs */
if (asus->driver->wapf >= 0)
asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
asus->driver->wapf, NULL);
return asus_wmi_sysfs_init(asus->platform_device);
}
......@@ -1568,6 +1745,14 @@ static int asus_hotk_restore(struct device *device)
bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G);
rfkill_set_sw_state(asus->wwan3g.rfkill, bl);
}
if (asus->gps.rfkill) {
bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPS);
rfkill_set_sw_state(asus->gps.rfkill, bl);
}
if (asus->uwb.rfkill) {
bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB);
rfkill_set_sw_state(asus->uwb.rfkill, bl);
}
return 0;
}
......@@ -1604,7 +1789,7 @@ static int asus_wmi_probe(struct platform_device *pdev)
static bool used;
int asus_wmi_register_driver(struct asus_wmi_driver *driver)
int __init_or_module asus_wmi_register_driver(struct asus_wmi_driver *driver)
{
struct platform_driver *platform_driver;
struct platform_device *platform_device;
......
......@@ -29,12 +29,15 @@
#include <linux/platform_device.h>
#define ASUS_WMI_KEY_IGNORE (-1)
struct module;
struct key_entry;
struct asus_wmi;
struct asus_wmi_driver {
bool hotplug_wireless;
int wapf;
const char *name;
struct module *owner;
......@@ -44,6 +47,10 @@ struct asus_wmi_driver {
const struct key_entry *keymap;
const char *input_name;
const char *input_phys;
/* Returns new code, value, and autorelease values in arguments.
* Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */
void (*key_filter) (struct asus_wmi_driver *driver, int *code,
unsigned int *value, bool *autorelease);
int (*probe) (struct platform_device *device);
void (*quirks) (struct asus_wmi_driver *driver);
......
......@@ -612,7 +612,6 @@ static int __init dell_init(void)
if (!bufferpage)
goto fail_buffer;
buffer = page_address(bufferpage);
mutex_init(&buffer_mutex);
ret = dell_setup_rfkill();
......
......@@ -54,6 +54,8 @@ MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
*/
static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
{ KE_IGNORE, 0x003a, { KEY_CAPSLOCK } },
{ KE_KEY, 0xe045, { KEY_PROG1 } },
{ KE_KEY, 0xe009, { KEY_EJECTCD } },
......@@ -85,6 +87,11 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
{ KE_IGNORE, 0xe013, { KEY_RESERVED } },
{ KE_IGNORE, 0xe020, { KEY_MUTE } },
/* Shortcut and audio panel keys */
{ KE_IGNORE, 0xe025, { KEY_RESERVED } },
{ KE_IGNORE, 0xe026, { KEY_RESERVED } },
{ KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } },
{ KE_IGNORE, 0xe030, { KEY_VOLUMEUP } },
{ KE_IGNORE, 0xe033, { KEY_KBDILLUMUP } },
......@@ -92,6 +99,9 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = {
{ KE_IGNORE, 0xe03a, { KEY_CAPSLOCK } },
{ KE_IGNORE, 0xe045, { KEY_NUMLOCK } },
{ KE_IGNORE, 0xe046, { KEY_SCROLLLOCK } },
{ KE_IGNORE, 0xe0f7, { KEY_MUTE } },
{ KE_IGNORE, 0xe0f8, { KEY_VOLUMEDOWN } },
{ KE_IGNORE, 0xe0f9, { KEY_VOLUMEUP } },
{ KE_END, 0 }
};
......
......@@ -56,6 +56,11 @@ MODULE_PARM_DESC(hotplug_wireless,
"If your laptop needs that, please report to "
"acpi4asus-user@lists.sourceforge.net.");
/* Values for T101MT "Home" key */
#define HOME_PRESS 0xe4
#define HOME_HOLD 0xea
#define HOME_RELEASE 0xe5
static const struct key_entry eeepc_wmi_keymap[] = {
/* Sleep already handled via generic ACPI code */
{ KE_KEY, 0x30, { KEY_VOLUMEUP } },
......@@ -71,6 +76,7 @@ static const struct key_entry eeepc_wmi_keymap[] = {
{ KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } },
{ KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */
{ KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */
{ KE_KEY, HOME_PRESS, { KEY_CONFIG } }, /* Home/Express gate key */
{ KE_KEY, 0xe8, { KEY_SCREENLOCK } },
{ KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } },
{ KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } },
......@@ -81,6 +87,25 @@ static const struct key_entry eeepc_wmi_keymap[] = {
{ KE_END, 0},
};
static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
unsigned int *value, bool *autorelease)
{
switch (*code) {
case HOME_PRESS:
*value = 1;
*autorelease = 0;
break;
case HOME_HOLD:
*code = ASUS_WMI_KEY_IGNORE;
break;
case HOME_RELEASE:
*code = HOME_PRESS;
*value = 0;
*autorelease = 0;
break;
}
}
static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level,
void *context, void **retval)
{
......@@ -141,6 +166,7 @@ static void eeepc_dmi_check(struct asus_wmi_driver *driver)
static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
{
driver->hotplug_wireless = hotplug_wireless;
driver->wapf = -1;
eeepc_dmi_check(driver);
}
......@@ -151,6 +177,7 @@ static struct asus_wmi_driver asus_wmi_driver = {
.keymap = eeepc_wmi_keymap,
.input_name = "Eee PC WMI hotkeys",
.input_phys = EEEPC_WMI_FILE "/input0",
.key_filter = eeepc_wmi_key_filter,
.probe = eeepc_wmi_probe,
.quirks = eeepc_wmi_quirks,
};
......
......@@ -32,13 +32,22 @@
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/backlight.h>
#include <linux/fb.h>
#define IDEAPAD_RFKILL_DEV_NUM (3)
#define CFG_BT_BIT (16)
#define CFG_3G_BIT (17)
#define CFG_WIFI_BIT (18)
#define CFG_CAMERA_BIT (19)
struct ideapad_private {
struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
struct platform_device *platform_device;
struct input_dev *inputdev;
struct backlight_device *blightdev;
unsigned long cfg;
};
static acpi_handle ideapad_handle;
......@@ -155,7 +164,7 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
}
/*
* camera power
* sysfs
*/
static ssize_t show_ideapad_cam(struct device *dev,
struct device_attribute *attr,
......@@ -186,6 +195,44 @@ static ssize_t store_ideapad_cam(struct device *dev,
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[] = {
&dev_attr_camera_power.attr,
&dev_attr_cfg.attr,
NULL
};
static mode_t ideapad_is_visible(struct kobject *kobj,
struct attribute *attr,
int idx)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct ideapad_private *priv = dev_get_drvdata(dev);
bool supported;
if (attr == &dev_attr_camera_power.attr)
supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg));
else
supported = true;
return supported ? attr->mode : 0;
}
static struct attribute_group ideapad_attribute_group = {
.is_visible = ideapad_is_visible,
.attrs = ideapad_attributes
};
/*
* Rfkill
*/
......@@ -197,9 +244,9 @@ struct ideapad_rfk_data {
};
const struct ideapad_rfk_data ideapad_rfk_data[] = {
{ "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN },
{ "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH },
{ "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN },
{ "ideapad_wlan", CFG_WIFI_BIT, 0x15, RFKILL_TYPE_WLAN },
{ "ideapad_bluetooth", CFG_BT_BIT, 0x17, RFKILL_TYPE_BLUETOOTH },
{ "ideapad_3g", CFG_3G_BIT, 0x20, RFKILL_TYPE_WWAN },
};
static int ideapad_rfk_set(void *data, bool blocked)
......@@ -265,8 +312,7 @@ static int __devinit ideapad_register_rfkill(struct acpi_device *adevice,
return 0;
}
static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice,
int dev)
static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
......@@ -280,15 +326,6 @@ static void __devexit ideapad_unregister_rfkill(struct acpi_device *adevice,
/*
* Platform device
*/
static struct attribute *ideapad_attributes[] = {
&dev_attr_camera_power.attr,
NULL
};
static struct attribute_group ideapad_attribute_group = {
.attrs = ideapad_attributes
};
static int __devinit ideapad_platform_init(struct ideapad_private *priv)
{
int result;
......@@ -369,7 +406,7 @@ static int __devinit ideapad_input_init(struct ideapad_private *priv)
return error;
}
static void __devexit ideapad_input_exit(struct ideapad_private *priv)
static void ideapad_input_exit(struct ideapad_private *priv)
{
sparse_keymap_free(priv->inputdev);
input_unregister_device(priv->inputdev);
......@@ -382,6 +419,98 @@ static void ideapad_input_report(struct ideapad_private *priv,
sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
}
/*
* backlight
*/
static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
{
unsigned long now;
if (read_ec_data(ideapad_handle, 0x12, &now))
return -EIO;
return now;
}
static int ideapad_backlight_update_status(struct backlight_device *blightdev)
{
if (write_ec_cmd(ideapad_handle, 0x13, blightdev->props.brightness))
return -EIO;
if (write_ec_cmd(ideapad_handle, 0x33,
blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1))
return -EIO;
return 0;
}
static const struct backlight_ops ideapad_backlight_ops = {
.get_brightness = ideapad_backlight_get_brightness,
.update_status = ideapad_backlight_update_status,
};
static int ideapad_backlight_init(struct ideapad_private *priv)
{
struct backlight_device *blightdev;
struct backlight_properties props;
unsigned long max, now, power;
if (read_ec_data(ideapad_handle, 0x11, &max))
return -EIO;
if (read_ec_data(ideapad_handle, 0x12, &now))
return -EIO;
if (read_ec_data(ideapad_handle, 0x18, &power))
return -EIO;
memset(&props, 0, sizeof(struct backlight_properties));
props.max_brightness = max;
props.type = BACKLIGHT_PLATFORM;
blightdev = backlight_device_register("ideapad",
&priv->platform_device->dev,
priv,
&ideapad_backlight_ops,
&props);
if (IS_ERR(blightdev)) {
pr_err("Could not register backlight device\n");
return PTR_ERR(blightdev);
}
priv->blightdev = blightdev;
blightdev->props.brightness = now;
blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
backlight_update_status(blightdev);
return 0;
}
static void ideapad_backlight_exit(struct ideapad_private *priv)
{
if (priv->blightdev)
backlight_device_unregister(priv->blightdev);
priv->blightdev = NULL;
}
static void ideapad_backlight_notify_power(struct ideapad_private *priv)
{
unsigned long power;
struct backlight_device *blightdev = priv->blightdev;
if (read_ec_data(ideapad_handle, 0x18, &power))
return;
blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
}
static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
{
unsigned long now;
/* if we control brightness via acpi video driver */
if (priv->blightdev == NULL) {
read_ec_data(ideapad_handle, 0x12, &now);
return;
}
backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
}
/*
* module init/exit
*/
......@@ -393,10 +522,11 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
{
int ret, i, cfg;
int ret, i;
unsigned long cfg;
struct ideapad_private *priv;
if (read_method_int(adevice->handle, "_CFG", &cfg))
if (read_method_int(adevice->handle, "_CFG", (int *)&cfg))
return -ENODEV;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
......@@ -404,6 +534,7 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
return -ENOMEM;
dev_set_drvdata(&adevice->dev, priv);
ideapad_handle = adevice->handle;
priv->cfg = cfg;
ret = ideapad_platform_init(priv);
if (ret)
......@@ -414,15 +545,25 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice)
goto input_failed;
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) {
if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
if (test_bit(ideapad_rfk_data[i].cfgbit, &cfg))
ideapad_register_rfkill(adevice, i);
else
priv->rfk[i] = NULL;
}
ideapad_sync_rfk_state(adevice);
if (!acpi_video_backlight_support()) {
ret = ideapad_backlight_init(priv);
if (ret && ret != -ENODEV)
goto backlight_failed;
}
return 0;
backlight_failed:
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
ideapad_unregister_rfkill(adevice, i);
ideapad_input_exit(priv);
input_failed:
ideapad_platform_exit(priv);
platform_failed:
......@@ -435,6 +576,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type)
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
int i;
ideapad_backlight_exit(priv);
for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
ideapad_unregister_rfkill(adevice, i);
ideapad_input_exit(priv);
......@@ -459,12 +601,19 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
vpc1 = (vpc2 << 8) | vpc1;
for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
if (test_bit(vpc_bit, &vpc1)) {
if (vpc_bit == 9)
switch (vpc_bit) {
case 9:
ideapad_sync_rfk_state(adevice);
else if (vpc_bit == 4)
read_ec_data(handle, 0x12, &vpc2);
else
break;
case 4:
ideapad_backlight_notify_brightness(priv);
break;
case 2:
ideapad_backlight_notify_power(priv);
break;
default:
ideapad_input_report(priv, vpc_bit);
}
}
}
}
......
......@@ -403,7 +403,7 @@ static void ips_cpu_raise(struct ips_driver *ips)
thm_writew(THM_MPCPC, (new_tdp_limit * 10) / 8);
turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN;
turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN;
wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
turbo_override &= ~TURBO_TDP_MASK;
......@@ -438,7 +438,7 @@ static void ips_cpu_lower(struct ips_driver *ips)
thm_writew(THM_MPCPC, (new_limit * 10) / 8);
turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN;
turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN;
wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override);
turbo_override &= ~TURBO_TDP_MASK;
......
......@@ -477,6 +477,8 @@ static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
return AE_ERROR;
}
return AE_OK;
aux1_not_found:
if (status == AE_NOT_FOUND)
return AE_OK;
......
......@@ -493,20 +493,30 @@ static int mid_thermal_probe(struct platform_device *pdev)
/* Register each sensor with the generic thermal framework*/
for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
struct thermal_device_info *td_info = initialize_sensor(i);
if (!td_info) {
ret = -ENOMEM;
goto err;
}
pinfo->tzd[i] = thermal_zone_device_register(name[i],
0, initialize_sensor(i), &tzd_ops, 0, 0, 0, 0);
if (IS_ERR(pinfo->tzd[i]))
goto reg_fail;
0, td_info, &tzd_ops, 0, 0, 0, 0);
if (IS_ERR(pinfo->tzd[i])) {
kfree(td_info);
ret = PTR_ERR(pinfo->tzd[i]);
goto err;
}
}
pinfo->pdev = pdev;
platform_set_drvdata(pdev, pinfo);
return 0;
reg_fail:
ret = PTR_ERR(pinfo->tzd[i]);
while (--i >= 0)
err:
while (--i >= 0) {
kfree(pinfo->tzd[i]->devdata);
thermal_zone_device_unregister(pinfo->tzd[i]);
}
configure_adc(0);
kfree(pinfo);
return ret;
......@@ -524,8 +534,10 @@ static int mid_thermal_remove(struct platform_device *pdev)
int i;
struct platform_info *pinfo = platform_get_drvdata(pdev);
for (i = 0; i < MSIC_THERMAL_SENSORS; i++)
for (i = 0; i < MSIC_THERMAL_SENSORS; i++) {
kfree(pinfo->tzd[i]->devdata);
thermal_zone_device_unregister(pinfo->tzd[i]);
}
kfree(pinfo);
platform_set_drvdata(pdev, NULL);
......
......@@ -637,15 +637,13 @@ static int rar_probe(struct pci_dev *dev, const struct pci_device_id *id)
return error;
}
const struct pci_device_id rar_pci_id_tbl[] = {
static DEFINE_PCI_DEVICE_TABLE(rar_pci_id_tbl) = {
{ PCI_VDEVICE(INTEL, 0x4110) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
const struct pci_device_id *my_id_table = rar_pci_id_tbl;
/* field for registering driver to PCI device */
static struct pci_driver rar_pci_driver = {
.name = "rar_register_driver",
......
......@@ -725,7 +725,7 @@ static void ipc_remove(struct pci_dev *pdev)
intel_scu_devices_destroy();
}
static const struct pci_device_id pci_ids[] = {
static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},
{ 0,}
......
......@@ -538,6 +538,15 @@ static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
},
.callback = dmi_check_cb
},
{
.ident = "MSI U270",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR,
"Micro-Star International Co., Ltd."),
DMI_MATCH(DMI_PRODUCT_NAME, "U270 series"),
},
.callback = dmi_check_cb
},
{ }
};
......@@ -996,3 +1005,4 @@ MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N034:*");
MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N051:*");
MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-N014:*");
MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnCR620:*");
MODULE_ALIAS("dmi:*:svnMicro-StarInternational*:pnU270series:*");
......@@ -272,6 +272,7 @@ static int __init msi_wmi_init(void)
err_free_backlight:
backlight_device_unregister(backlight);
err_free_input:
sparse_keymap_free(msi_wmi_input_dev);
input_unregister_device(msi_wmi_input_dev);
err_uninstall_notifier:
wmi_remove_notify_handler(MSIWMI_EVENT_GUID);
......
......@@ -520,6 +520,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
},
.callback = dmi_check_cb,
},
{
.ident = "N510",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR,
"SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N510"),
DMI_MATCH(DMI_BOARD_NAME, "N510"),
},
.callback = dmi_check_cb,
},
{
.ident = "X125",
.matches = {
......@@ -600,6 +610,16 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
},
.callback = dmi_check_cb,
},
{
.ident = "N150/N210/N220",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR,
"SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
},
.callback = dmi_check_cb,
},
{
.ident = "N150/N210/N220/N230",
.matches = {
......
/*
* Driver for Samsung Q10 and related laptops: controls the backlight
*
* Copyright (c) 2011 Frederick van der Wyck <fvanderwyck@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/backlight.h>
#include <linux/i8042.h>
#include <linux/dmi.h>
#define SAMSUNGQ10_BL_MAX_INTENSITY 255
#define SAMSUNGQ10_BL_DEFAULT_INTENSITY 185
#define SAMSUNGQ10_BL_8042_CMD 0xbe
#define SAMSUNGQ10_BL_8042_DATA { 0x89, 0x91 }
static int samsungq10_bl_brightness;
static bool force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force,
"Disable the DMI check and force the driver to be loaded");
static int samsungq10_bl_set_intensity(struct backlight_device *bd)
{
int brightness = bd->props.brightness;
unsigned char c[3] = SAMSUNGQ10_BL_8042_DATA;
c[2] = (unsigned char)brightness;
i8042_lock_chip();
i8042_command(c, (0x30 << 8) | SAMSUNGQ10_BL_8042_CMD);
i8042_unlock_chip();
samsungq10_bl_brightness = brightness;
return 0;
}
static int samsungq10_bl_get_intensity(struct backlight_device *bd)
{
return samsungq10_bl_brightness;
}
static const struct backlight_ops samsungq10_bl_ops = {
.get_brightness = samsungq10_bl_get_intensity,
.update_status = samsungq10_bl_set_intensity,
};
#ifdef CONFIG_PM_SLEEP
static int samsungq10_suspend(struct device *dev)
{
return 0;
}
static int samsungq10_resume(struct device *dev)
{
struct backlight_device *bd = dev_get_drvdata(dev);
samsungq10_bl_set_intensity(bd);
return 0;
}
#else
#define samsungq10_suspend NULL
#define samsungq10_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(samsungq10_pm_ops,
samsungq10_suspend, samsungq10_resume);
static int __devinit samsungq10_probe(struct platform_device *pdev)
{
struct backlight_properties props;
struct backlight_device *bd;
memset(&props, 0, sizeof(struct backlight_properties));
props.type = BACKLIGHT_PLATFORM;
props.max_brightness = SAMSUNGQ10_BL_MAX_INTENSITY;
bd = backlight_device_register("samsung", &pdev->dev, NULL,
&samsungq10_bl_ops, &props);
if (IS_ERR(bd))
return PTR_ERR(bd);
platform_set_drvdata(pdev, bd);
bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY;
samsungq10_bl_set_intensity(bd);
return 0;
}
static int __devexit samsungq10_remove(struct platform_device *pdev)
{
struct backlight_device *bd = platform_get_drvdata(pdev);
bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY;
samsungq10_bl_set_intensity(bd);
backlight_device_unregister(bd);
return 0;
}
static struct platform_driver samsungq10_driver = {
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
.pm = &samsungq10_pm_ops,
},
.probe = samsungq10_probe,
.remove = __devexit_p(samsungq10_remove),
};
static struct platform_device *samsungq10_device;
static int __init dmi_check_callback(const struct dmi_system_id *id)
{
printk(KERN_INFO KBUILD_MODNAME ": found model '%s'\n", id->ident);
return 1;
}
static struct dmi_system_id __initdata samsungq10_dmi_table[] = {
{
.ident = "Samsung Q10",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Samsung"),
DMI_MATCH(DMI_PRODUCT_NAME, "SQ10"),
},
.callback = dmi_check_callback,
},
{
.ident = "Samsung Q20",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"),
DMI_MATCH(DMI_PRODUCT_NAME, "SENS Q20"),
},
.callback = dmi_check_callback,
},
{
.ident = "Samsung Q25",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG Electronics"),
DMI_MATCH(DMI_PRODUCT_NAME, "NQ25"),
},
.callback = dmi_check_callback,
},
{
.ident = "Dell Latitude X200",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
DMI_MATCH(DMI_PRODUCT_NAME, "X200"),
},
.callback = dmi_check_callback,
},
{ },
};
MODULE_DEVICE_TABLE(dmi, samsungq10_dmi_table);
static int __init samsungq10_init(void)
{
if (!force && !dmi_check_system(samsungq10_dmi_table))
return -ENODEV;
samsungq10_device = platform_create_bundle(&samsungq10_driver,
samsungq10_probe,
NULL, 0, NULL, 0);
if (IS_ERR(samsungq10_device))
return PTR_ERR(samsungq10_device);
return 0;
}
static void __exit samsungq10_exit(void)
{
platform_device_unregister(samsungq10_device);
platform_driver_unregister(&samsungq10_driver);
}
module_init(samsungq10_init);
module_exit(samsungq10_exit);
MODULE_AUTHOR("Frederick van der Wyck <fvanderwyck@gmail.com>");
MODULE_DESCRIPTION("Samsung Q10 Driver");
MODULE_LICENSE("GPL");
......@@ -3185,9 +3185,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
/* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN,
/*
* The mic mute button only sends 0x1a. It does not
* automatically mute the mic or change the mute light.
*/
KEY_MICMUTE, /* 0x1a: Mic mute (since ?400 or so) */
/* (assignments unknown, please report if found) */
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
KEY_UNKNOWN,
},
};
......
......@@ -438,6 +438,8 @@ struct input_keymap_entry {
#define KEY_WIMAX 246
#define KEY_RFKILL 247 /* Key that controls all radios */
#define KEY_MICMUTE 248 /* Mute / unmute the microphone */
/* Code 255 is reserved for special needs of AT keyboard driver */
#define BTN_MISC 0x100
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment