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
  ...
This commit is contained in:
Linus Torvalds 2011-08-06 13:26:15 -07:00
commit 2560540b78
25 changed files with 799 additions and 84 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 @@ exit:
* 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;

View file

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

View file

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

View file

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

View file

@ -56,6 +56,11 @@ MODULE_PARM_DESC(hotplug_wireless,
"If your laptop needs that, please report to "
"[email protected].");
/* 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,
};

View file

@ -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 @@ err_free_dev:
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);
}
}
}
}

View file

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

View file

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

View file

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

View file

@ -637,15 +637,13 @@ end_function:
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",

View file

@ -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,}

View file

@ -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:*");

View file

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

View file

@ -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 = {

View file

@ -0,0 +1,196 @@
/*
* 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 <[email protected]>");
MODULE_DESCRIPTION("Samsung Q10 Driver");
MODULE_LICENSE("GPL");

View file

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