Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98723153 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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:
  toshiba_acpi: Add full hotkey support
  hp-wmi: Add support for tablet rotation key
  dell-laptop: Add another Dell laptop to the DMI whitelist
  classmate-laptop: use a single MODULE_DEVICE_TABLE to get correct aliases
  dell-laptop: Pay attention to which devices the hardware switch controls
  dell-laptop: Use buffer with 32-bit physical address
  dell-laptop: Blacklist machines not supporting dell-laptop
  dell-laptop: Block software state changes when rfkill hard blocked
  dell-laptop: Fix small memory leak
  dell-laptop: Fix platform device unregistration
  dell-laptop: Update rfkill state on kill switch
  compal-laptop: Replace sysfs support with rfkill support
  compal-laptop: Add support for known Compal made Dell laptops
  MAINTAINERS: update drivers/platform/x86 information
parents 4cbd5518 6335e4d5
Loading
Loading
Loading
Loading
+25 −4
Original line number Diff line number Diff line
@@ -221,6 +221,7 @@ F: drivers/net/acenic*

ACER ASPIRE ONE TEMPERATURE AND FAN DRIVER
M:	Peter Feuerer <peter@piie.net>
L:	platform-driver-x86@vger.kernel.org
W:	http://piie.net/?section=acerhdf
S:	Maintained
F:	drivers/platform/x86/acerhdf.c
@@ -228,6 +229,7 @@ F: drivers/platform/x86/acerhdf.c
ACER WMI LAPTOP EXTRAS
M:	Carlos Corbacho <carlos@strangeworlds.co.uk>
L:	aceracpi@googlegroups.com (subscribers-only)
L:	platform-driver-x86@vger.kernel.org
W:	http://code.google.com/p/aceracpi
S:	Maintained
F:	drivers/platform/x86/acer-wmi.c
@@ -288,7 +290,7 @@ F: drivers/acpi/video.c

ACPI WMI DRIVER
M:	Carlos Corbacho <carlos@strangeworlds.co.uk>
L:	linux-acpi@vger.kernel.org
L:	platform-driver-x86@vger.kernel.org
W:	http://www.lesswatts.org/projects/acpi/
S:	Maintained
F:	drivers/platform/x86/wmi.c
@@ -968,6 +970,7 @@ ASUS ACPI EXTRAS DRIVER
M:	Corentin Chary <corentincj@iksaif.net>
M:	Karol Kozimor <sziwan@users.sourceforge.net>
L:	acpi4asus-user@lists.sourceforge.net
L:	platform-driver-x86@vger.kernel.org
W:	http://acpi4asus.sf.net
S:	Maintained
F:	drivers/platform/x86/asus_acpi.c
@@ -981,6 +984,7 @@ F: drivers/hwmon/asb100.c
ASUS LAPTOP EXTRAS DRIVER
M:	Corentin Chary <corentincj@iksaif.net>
L:	acpi4asus-user@lists.sourceforge.net
L:	platform-driver-x86@vger.kernel.org
W:	http://acpi4asus.sf.net
S:	Maintained
F:	drivers/platform/x86/asus-laptop.c
@@ -1473,6 +1477,7 @@ F: drivers/scsi/fnic/
CMPC ACPI DRIVER
M:	Thadeu Lima de Souza Cascardo <cascardo@holoscopio.com>
M:	Daniel Oliveira Nascimento <don@syst.com.br>
L:	platform-driver-x86@vger.kernel.org
S:	Supported
F:	drivers/platform/x86/classmate-laptop.c

@@ -1516,6 +1521,7 @@ F: drivers/pci/hotplug/cpcihp_generic.c

COMPAL LAPTOP SUPPORT
M:	Cezary Jackiewicz <cezary.jackiewicz@gmail.com>
L:	platform-driver-x86@vger.kernel.org
S:	Maintained
F:	drivers/platform/x86/compal-laptop.c

@@ -1746,6 +1752,7 @@ F: drivers/net/defxx.*

DELL LAPTOP DRIVER
M:	Matthew Garrett <mjg59@srcf.ucam.org>
L:	platform-driver-x86@vger.kernel.org
S:	Maintained
F:	drivers/platform/x86/dell-laptop.c

@@ -2028,6 +2035,7 @@ F: drivers/edac/r82600_edac.c
EEEPC LAPTOP EXTRAS DRIVER
M:	Corentin Chary <corentincj@iksaif.net>
L:	acpi4asus-user@lists.sourceforge.net
L:	platform-driver-x86@vger.kernel.org
W:	http://acpi4asus.sf.net
S:	Maintained
F:	drivers/platform/x86/eeepc-laptop.c
@@ -2306,7 +2314,7 @@ F: arch/frv/

FUJITSU LAPTOP EXTRAS
M:	Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
L:	linux-acpi@vger.kernel.org
L:	platform-driver-x86@vger.kernel.org
S:	Maintained
F:	drivers/platform/x86/fujitsu-laptop.c

@@ -2584,6 +2592,7 @@ F: drivers/net/wireless/hostap/

HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
M:	Carlos Corbacho <carlos@strangeworlds.co.uk>
L:	platform-driver-x86@vger.kernel.org
S:	Odd Fixes
F:	drivers/platform/x86/tc1100-wmi.c

@@ -2794,7 +2803,7 @@ F: drivers/video/i810/

INTEL MENLOW THERMAL DRIVER
M:	Sujith Thomas <sujith.thomas@intel.com>
L:	linux-acpi@vger.kernel.org
L:	platform-driver-x86@vger.kernel.org
W:	http://www.lesswatts.org/projects/acpi/
S:	Supported
F:	drivers/platform/x86/intel_menlow.c
@@ -3660,6 +3669,7 @@ F: drivers/char/mxser.*

MSI LAPTOP SUPPORT
M:	Lennart Poettering <mzxreary@0pointer.de>
L:	platform-driver-x86@vger.kernel.org
W:	https://tango.0pointer.de/mailman/listinfo/s270-linux
W:	http://0pointer.de/lennart/tchibo.html
S:	Maintained
@@ -3667,6 +3677,7 @@ F: drivers/platform/x86/msi-laptop.c

MSI WMI SUPPORT
M:	Anisse Astier <anisse@astier.eu>
L:	platform-driver-x86@vger.kernel.org
S:	Supported
F:	drivers/platform/x86/msi-wmi.c

@@ -4119,6 +4130,7 @@ F: drivers/i2c/busses/i2c-pasemi.c

PANASONIC LAPTOP ACPI EXTRAS DRIVER
M:	Harald Welte <laforge@gnumonks.org>
L:	platform-driver-x86@vger.kernel.org
S:	Maintained
F:	drivers/platform/x86/panasonic-laptop.c

@@ -5064,7 +5076,7 @@ F: include/linux/ssb/

SONY VAIO CONTROL DEVICE DRIVER
M:	Mattia Dongili <malattia@linux.it>
L:	linux-acpi@vger.kernel.org
L:	platform-driver-x86@vger.kernel.org
W:	http://www.linux.it/~malattia/wiki/index.php/Sony_drivers
S:	Maintained
F:	Documentation/laptops/sony-laptop.txt
@@ -5270,6 +5282,7 @@ F: arch/xtensa/
THINKPAD ACPI EXTRAS DRIVER
M:	Henrique de Moraes Holschuh <ibm-acpi@hmh.eng.br>
L:	ibm-acpi-devel@lists.sourceforge.net
L:	platform-driver-x86@vger.kernel.org
W:	http://ibm-acpi.sourceforge.net
W:	http://thinkwiki.org/wiki/Ibm-acpi
T:	git git://repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
@@ -5323,10 +5336,12 @@ F: security/tomoyo/

TOPSTAR LAPTOP EXTRAS DRIVER
M:	Herton Ronaldo Krzesinski <herton@mandriva.com.br>
L:	platform-driver-x86@vger.kernel.org
S:	Maintained
F:	drivers/platform/x86/topstar-laptop.c

TOSHIBA ACPI EXTRAS DRIVER
L:	platform-driver-x86@vger.kernel.org
S:	Orphan
F:	drivers/platform/x86/toshiba_acpi.c

@@ -6054,6 +6069,12 @@ S: Maintained
F:	Documentation/x86/
F:	arch/x86/

X86 PLATFORM DRIVERS
M:	Matthew Garrett <mjg@redhat.com>
L:	platform-driver-x86@vger.kernel.org
S:	Maintained
F:	drivers/platform/x86

XEN HYPERVISOR INTERFACE
M:	Jeremy Fitzhardinge <jeremy@xensource.com>
M:	Chris Wright <chrisw@sous-sol.org>
+1 −0
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ config DELL_LAPTOP
	depends on BACKLIGHT_CLASS_DEVICE
	depends on RFKILL || RFKILL = n
	depends on POWER_SUPPLY
	depends on SERIO_I8042
	default n
	---help---
	This driver adds support for rfkill and backlight control to Dell
+21 −10
Original line number Diff line number Diff line
@@ -34,6 +34,11 @@ struct cmpc_accel {
#define CMPC_ACCEL_SENSITIVITY_DEFAULT		5


#define CMPC_ACCEL_HID		"ACCE0000"
#define CMPC_TABLET_HID		"TBLT0000"
#define CMPC_BL_HID		"IPML200"
#define CMPC_KEYS_HID		"FnBT0000"

/*
 * Generic input device code.
 */
@@ -282,10 +287,9 @@ static int cmpc_accel_remove(struct acpi_device *acpi, int type)
}

static const struct acpi_device_id cmpc_accel_device_ids[] = {
	{"ACCE0000", 0},
	{CMPC_ACCEL_HID, 0},
	{"", 0}
};
MODULE_DEVICE_TABLE(acpi, cmpc_accel_device_ids);

static struct acpi_driver cmpc_accel_acpi_driver = {
	.owner = THIS_MODULE,
@@ -366,10 +370,9 @@ static int cmpc_tablet_resume(struct acpi_device *acpi)
}

static const struct acpi_device_id cmpc_tablet_device_ids[] = {
	{"TBLT0000", 0},
	{CMPC_TABLET_HID, 0},
	{"", 0}
};
MODULE_DEVICE_TABLE(acpi, cmpc_tablet_device_ids);

static struct acpi_driver cmpc_tablet_acpi_driver = {
	.owner = THIS_MODULE,
@@ -477,17 +480,16 @@ static int cmpc_bl_remove(struct acpi_device *acpi, int type)
	return 0;
}

static const struct acpi_device_id cmpc_device_ids[] = {
	{"IPML200", 0},
static const struct acpi_device_id cmpc_bl_device_ids[] = {
	{CMPC_BL_HID, 0},
	{"", 0}
};
MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);

static struct acpi_driver cmpc_bl_acpi_driver = {
	.owner = THIS_MODULE,
	.name = "cmpc",
	.class = "cmpc",
	.ids = cmpc_device_ids,
	.ids = cmpc_bl_device_ids,
	.ops = {
		.add = cmpc_bl_add,
		.remove = cmpc_bl_remove
@@ -540,10 +542,9 @@ static int cmpc_keys_remove(struct acpi_device *acpi, int type)
}

static const struct acpi_device_id cmpc_keys_device_ids[] = {
	{"FnBT0000", 0},
	{CMPC_KEYS_HID, 0},
	{"", 0}
};
MODULE_DEVICE_TABLE(acpi, cmpc_keys_device_ids);

static struct acpi_driver cmpc_keys_acpi_driver = {
	.owner = THIS_MODULE,
@@ -607,3 +608,13 @@ static void cmpc_exit(void)

module_init(cmpc_init);
module_exit(cmpc_exit);

static const struct acpi_device_id cmpc_device_ids[] = {
	{CMPC_ACCEL_HID, 0},
	{CMPC_TABLET_HID, 0},
	{CMPC_BL_HID, 0},
	{CMPC_KEYS_HID, 0},
	{"", 0}
};

MODULE_DEVICE_TABLE(acpi, cmpc_device_ids);
+109 −138
Original line number Diff line number Diff line
@@ -26,17 +26,8 @@
/*
 * comapl-laptop.c - Compal laptop support.
 *
 * This driver exports a few files in /sys/devices/platform/compal-laptop/:
 *
 *   wlan - wlan subsystem state: contains 0 or 1 (rw)
 *
 *   bluetooth - Bluetooth subsystem state: contains 0 or 1 (rw)
 *
 *   raw - raw value taken from embedded controller register (ro)
 *
 * In addition to these platform device attributes the driver
 * registers itself in the Linux backlight control subsystem and is
 * available to userspace under /sys/class/backlight/compal-laptop/.
 * The driver registers itself with the rfkill subsystem and
 * the Linux backlight control subsystem.
 *
 * This driver might work on other laptops produced by Compal. If you
 * want to try it you can pass force=1 as argument to the module which
@@ -51,6 +42,7 @@
#include <linux/dmi.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>

#define COMPAL_DRIVER_VERSION "0.2.6"

@@ -63,6 +55,10 @@
#define WLAN_MASK	0x01
#define BT_MASK 	0x02

static struct rfkill *wifi_rfkill;
static struct rfkill *bt_rfkill;
static struct platform_device *compal_device;

static int force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
@@ -88,65 +84,75 @@ static int get_lcd_level(void)
	return (int) result;
}

static int set_wlan_state(int state)
static int compal_rfkill_set(void *data, bool blocked)
{
	unsigned long radio = (unsigned long) data;
	u8 result, value;

	ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);

	if ((result & KILLSWITCH_MASK) == 0)
		return -EINVAL;
	else {
		if (state)
			value = (u8) (result | WLAN_MASK);
	if (!blocked)
		value = (u8) (result | radio);
	else
			value = (u8) (result & ~WLAN_MASK);
		value = (u8) (result & ~radio);
	ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
	}

	return 0;
}

static int set_bluetooth_state(int state)
static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
{
	u8 result, value;
	u8 result;
	bool hw_blocked;

	ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);

	if ((result & KILLSWITCH_MASK) == 0)
		return -EINVAL;
	else {
		if (state)
			value = (u8) (result | BT_MASK);
		else
			value = (u8) (result & ~BT_MASK);
		ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
	hw_blocked = !(result & KILLSWITCH_MASK);
	rfkill_set_hw_state(rfkill, hw_blocked);
}

	return 0;
}
static const struct rfkill_ops compal_rfkill_ops = {
	.poll = compal_rfkill_poll,
	.set_block = compal_rfkill_set,
};

static int get_wireless_state(int *wlan, int *bluetooth)
static int setup_rfkill(void)
{
	u8 result;
	int ret;

	ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
	wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
				RFKILL_TYPE_WLAN, &compal_rfkill_ops,
				(void *) WLAN_MASK);
	if (!wifi_rfkill)
		return -ENOMEM;

	if (wlan) {
		if ((result & KILLSWITCH_MASK) == 0)
			*wlan = 0;
		else
			*wlan = result & WLAN_MASK;
	}
	ret = rfkill_register(wifi_rfkill);
	if (ret)
		goto err_wifi;

	if (bluetooth) {
		if ((result & KILLSWITCH_MASK) == 0)
			*bluetooth = 0;
		else
			*bluetooth = (result & BT_MASK) >> 1;
	bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
				RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
				(void *) BT_MASK);
	if (!bt_rfkill) {
		ret = -ENOMEM;
		goto err_allocate_bt;
	}
	ret = rfkill_register(bt_rfkill);
	if (ret)
		goto err_register_bt;

	return 0;

err_register_bt:
	rfkill_destroy(bt_rfkill);

err_allocate_bt:
	rfkill_unregister(wifi_rfkill);

err_wifi:
	rfkill_destroy(wifi_rfkill);

	return ret;
}

/* Backlight device stuff */
@@ -169,86 +175,6 @@ static struct backlight_ops compalbl_ops = {

static struct backlight_device *compalbl_device;

/* Platform device */

static ssize_t show_wlan(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	int ret, enabled;

	ret = get_wireless_state(&enabled, NULL);
	if (ret < 0)
		return ret;

	return sprintf(buf, "%i\n", enabled);
}

static ssize_t show_raw(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	u8 result;

	ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);

	return sprintf(buf, "%i\n", result);
}

static ssize_t show_bluetooth(struct device *dev,
	struct device_attribute *attr, char *buf)
{
	int ret, enabled;

	ret = get_wireless_state(NULL, &enabled);
	if (ret < 0)
		return ret;

	return sprintf(buf, "%i\n", enabled);
}

static ssize_t store_wlan_state(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	int state, ret;

	if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
		return -EINVAL;

	ret = set_wlan_state(state);
	if (ret < 0)
		return ret;

	return count;
}

static ssize_t store_bluetooth_state(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	int state, ret;

	if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
		return -EINVAL;

	ret = set_bluetooth_state(state);
	if (ret < 0)
		return ret;

	return count;
}

static DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth_state);
static DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan_state);
static DEVICE_ATTR(raw, 0444, show_raw, NULL);

static struct attribute *compal_attributes[] = {
	&dev_attr_bluetooth.attr,
	&dev_attr_wlan.attr,
	&dev_attr_raw.attr,
	NULL
};

static struct attribute_group compal_attribute_group = {
	.attrs = compal_attributes
};

static struct platform_driver compal_driver = {
	.driver = {
@@ -257,8 +183,6 @@ static struct platform_driver compal_driver = {
	}
};

static struct platform_device *compal_device;

/* Initialization */

static int dmi_check_cb(const struct dmi_system_id *id)
@@ -310,6 +234,47 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
		},
		.callback = dmi_check_cb
	},
	{
		.ident = "Dell Mini 9",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
		},
		.callback = dmi_check_cb
	},
	{
		.ident = "Dell Mini 10",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
		},
		.callback = dmi_check_cb
	},
	{
		.ident = "Dell Mini 10v",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
		},
		.callback = dmi_check_cb
	},
	{
		.ident = "Dell Inspiron 11z",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
		},
		.callback = dmi_check_cb
	},
	{
		.ident = "Dell Mini 12",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
		},
		.callback = dmi_check_cb
	},

	{ }
};

@@ -348,23 +313,21 @@ static int __init compal_init(void)

	ret = platform_device_add(compal_device);
	if (ret)
		goto fail_platform_device1;
		goto fail_platform_device;

	ret = sysfs_create_group(&compal_device->dev.kobj,
		&compal_attribute_group);
	ret = setup_rfkill();
	if (ret)
		goto fail_platform_device2;
		goto fail_rfkill;

	printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION
		" successfully loaded.\n");

	return 0;

fail_platform_device2:

fail_rfkill:
	platform_device_del(compal_device);

fail_platform_device1:
fail_platform_device:

	platform_device_put(compal_device);

@@ -382,10 +345,13 @@ fail_backlight:
static void __exit compal_cleanup(void)
{

	sysfs_remove_group(&compal_device->dev.kobj, &compal_attribute_group);
	platform_device_unregister(compal_device);
	platform_driver_unregister(&compal_driver);
	backlight_device_unregister(compalbl_device);
	rfkill_unregister(wifi_rfkill);
	rfkill_destroy(wifi_rfkill);
	rfkill_unregister(bt_rfkill);
	rfkill_destroy(bt_rfkill);

	printk(KERN_INFO "compal-laptop: driver unloaded.\n");
}
@@ -403,3 +369,8 @@ MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");
+219 −37
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@
#include <linux/rfkill.h>
#include <linux/power_supply.h>
#include <linux/acpi.h>
#include <linux/mm.h>
#include <linux/i8042.h>
#include "../../firmware/dcdbas.h"

#define BRIGHTNESS_TOKEN 0x7d
@@ -79,9 +81,73 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
			DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
		},
	},
	{
		.ident = "Dell Computer Corporation",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
			DMI_MATCH(DMI_CHASSIS_TYPE, "8"),
		},
	},
	{ }
};

static struct dmi_system_id __devinitdata dell_blacklist[] = {
	/* Supported by compal-laptop */
	{
		.ident = "Dell Mini 9",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
		},
	},
	{
		.ident = "Dell Mini 10",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
		},
	},
	{
		.ident = "Dell Mini 10v",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
		},
	},
	{
		.ident = "Dell Inspiron 11z",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
		},
	},
	{
		.ident = "Dell Mini 12",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
			DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
		},
	},
	{}
};

static struct calling_interface_buffer *buffer;
struct page *bufferpage;
DEFINE_MUTEX(buffer_mutex);

static int hwswitch_state;

static void get_buffer(void)
{
	mutex_lock(&buffer_mutex);
	memset(buffer, 0, sizeof(struct calling_interface_buffer));
}

static void release_buffer(void)
{
	mutex_unlock(&buffer_mutex);
}

static void __init parse_da_table(const struct dmi_header *dm)
{
	/* Final token is a terminator, so we don't want to copy it */
@@ -160,6 +226,8 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
/* Derived from information in DellWirelessCtl.cpp:
   Class 17, select 11 is radio control. It returns an array of 32-bit values.

   Input byte 0 = 0: Wireless information

   result[0]: return code
   result[1]:
     Bit 0:      Hardware switch supported
@@ -180,32 +248,61 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
     Bits 20-31: Reserved
   result[2]: NVRAM size in bytes
   result[3]: NVRAM format version number

   Input byte 0 = 2: Wireless switch configuration
   result[0]: return code
   result[1]:
     Bit 0:      Wifi controlled by switch
     Bit 1:      Bluetooth controlled by switch
     Bit 2:      WWAN controlled by switch
     Bits 3-6:   Reserved
     Bit 7:      Wireless switch config locked
     Bit 8:      Wifi locator enabled
     Bits 9-14:  Reserved
     Bit 15:     Wifi locator setting locked
     Bits 16-31: Reserved
*/

static int dell_rfkill_set(void *data, bool blocked)
{
	struct calling_interface_buffer buffer;
	int disable = blocked ? 1 : 0;
	unsigned long radio = (unsigned long)data;
	int hwswitch_bit = (unsigned long)data - 1;
	int ret = 0;

	get_buffer();
	dell_send_request(buffer, 17, 11);

	/* If the hardware switch controls this radio, and the hardware
	   switch is disabled, don't allow changing the software state */
	if ((hwswitch_state & BIT(hwswitch_bit)) &&
	    !(buffer->output[1] & BIT(16))) {
		ret = -EINVAL;
		goto out;
	}

	memset(&buffer, 0, sizeof(struct calling_interface_buffer));
	buffer.input[0] = (1 | (radio<<8) | (disable << 16));
	dell_send_request(&buffer, 17, 11);
	buffer->input[0] = (1 | (radio<<8) | (disable << 16));
	dell_send_request(buffer, 17, 11);

	return 0;
out:
	release_buffer();
	return ret;
}

static void dell_rfkill_query(struct rfkill *rfkill, void *data)
{
	struct calling_interface_buffer buffer;
	int status;
	int bit = (unsigned long)data + 16;
	int hwswitch_bit = (unsigned long)data - 1;

	memset(&buffer, 0, sizeof(struct calling_interface_buffer));
	dell_send_request(&buffer, 17, 11);
	status = buffer.output[1];
	get_buffer();
	dell_send_request(buffer, 17, 11);
	status = buffer->output[1];
	release_buffer();

	rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));

	if (hwswitch_state & (BIT(hwswitch_bit)))
		rfkill_set_hw_state(rfkill, !(status & BIT(16)));
}

@@ -214,15 +311,36 @@ static const struct rfkill_ops dell_rfkill_ops = {
	.query = dell_rfkill_query,
};

static void dell_update_rfkill(struct work_struct *ignored)
{
	if (wifi_rfkill)
		dell_rfkill_query(wifi_rfkill, (void *)1);
	if (bluetooth_rfkill)
		dell_rfkill_query(bluetooth_rfkill, (void *)2);
	if (wwan_rfkill)
		dell_rfkill_query(wwan_rfkill, (void *)3);
}
static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);


static int __init dell_setup_rfkill(void)
{
	struct calling_interface_buffer buffer;
	int status;
	int ret;

	memset(&buffer, 0, sizeof(struct calling_interface_buffer));
	dell_send_request(&buffer, 17, 11);
	status = buffer.output[1];
	if (dmi_check_system(dell_blacklist)) {
		printk(KERN_INFO "dell-laptop: Blacklisted hardware detected - "
				"not enabling rfkill\n");
		return 0;
	}

	get_buffer();
	dell_send_request(buffer, 17, 11);
	status = buffer->output[1];
	buffer->input[0] = 0x2;
	dell_send_request(buffer, 17, 11);
	hwswitch_state = buffer->output[1];
	release_buffer();

	if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
		wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
@@ -298,39 +416,49 @@ static void dell_cleanup_rfkill(void)

static int dell_send_intensity(struct backlight_device *bd)
{
	struct calling_interface_buffer buffer;
	int ret = 0;

	memset(&buffer, 0, sizeof(struct calling_interface_buffer));
	buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
	buffer.input[1] = bd->props.brightness;
	get_buffer();
	buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
	buffer->input[1] = bd->props.brightness;

	if (buffer.input[0] == -1)
		return -ENODEV;
	if (buffer->input[0] == -1) {
		ret = -ENODEV;
		goto out;
	}

	if (power_supply_is_system_supplied() > 0)
		dell_send_request(&buffer, 1, 2);
		dell_send_request(buffer, 1, 2);
	else
		dell_send_request(&buffer, 1, 1);
		dell_send_request(buffer, 1, 1);

out:
	release_buffer();
	return 0;
}

static int dell_get_intensity(struct backlight_device *bd)
{
	struct calling_interface_buffer buffer;
	int ret = 0;

	memset(&buffer, 0, sizeof(struct calling_interface_buffer));
	buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);
	get_buffer();
	buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);

	if (buffer.input[0] == -1)
		return -ENODEV;
	if (buffer->input[0] == -1) {
		ret = -ENODEV;
		goto out;
	}

	if (power_supply_is_system_supplied() > 0)
		dell_send_request(&buffer, 0, 2);
		dell_send_request(buffer, 0, 2);
	else
		dell_send_request(&buffer, 0, 1);
		dell_send_request(buffer, 0, 1);

	return buffer.output[1];
out:
	release_buffer();
	if (ret)
		return ret;
	return buffer->output[1];
}

static struct backlight_ops dell_ops = {
@@ -338,9 +466,32 @@ static struct backlight_ops dell_ops = {
	.update_status  = dell_send_intensity,
};

bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
			      struct serio *port)
{
	static bool extended;

	if (str & 0x20)
		return false;

	if (unlikely(data == 0xe0)) {
		extended = true;
		return false;
	} else if (unlikely(extended)) {
		switch (data) {
		case 0x8:
			schedule_delayed_work(&dell_rfkill_work,
					      round_jiffies_relative(HZ));
			break;
		}
		extended = false;
	}

	return false;
}

static int __init dell_init(void)
{
	struct calling_interface_buffer buffer;
	int max_intensity = 0;
	int ret;

@@ -366,6 +517,17 @@ static int __init dell_init(void)
	if (ret)
		goto fail_platform_device2;

	/*
	 * Allocate buffer below 4GB for SMI data--only 32-bit physical addr
	 * is passed to SMI handler.
	 */
	bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32);

	if (!bufferpage)
		goto fail_buffer;
	buffer = page_address(bufferpage);
	mutex_init(&buffer_mutex);

	ret = dell_setup_rfkill();

	if (ret) {
@@ -373,6 +535,13 @@ static int __init dell_init(void)
		goto fail_rfkill;
	}

	ret = i8042_install_filter(dell_laptop_i8042_filter);
	if (ret) {
		printk(KERN_WARNING
		       "dell-laptop: Unable to install key filter\n");
		goto fail_filter;
	}

#ifdef CONFIG_ACPI
	/* In the event of an ACPI backlight being available, don't
	 * register the platform controller.
@@ -381,13 +550,13 @@ static int __init dell_init(void)
		return 0;
#endif

	memset(&buffer, 0, sizeof(struct calling_interface_buffer));
	buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN);

	if (buffer.input[0] != -1) {
		dell_send_request(&buffer, 0, 2);
		max_intensity = buffer.output[3];
	get_buffer();
	buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
	if (buffer->input[0] != -1) {
		dell_send_request(buffer, 0, 2);
		max_intensity = buffer->output[3];
	}
	release_buffer();

	if (max_intensity) {
		dell_backlight_device = backlight_device_register(
@@ -410,8 +579,12 @@ static int __init dell_init(void)
	return 0;

fail_backlight:
	i8042_remove_filter(dell_laptop_i8042_filter);
fail_filter:
	dell_cleanup_rfkill();
fail_rfkill:
	free_page((unsigned long)bufferpage);
fail_buffer:
	platform_device_del(platform_device);
fail_platform_device2:
	platform_device_put(platform_device);
@@ -424,8 +597,16 @@ fail_platform_driver:

static void __exit dell_exit(void)
{
	cancel_delayed_work_sync(&dell_rfkill_work);
	i8042_remove_filter(dell_laptop_i8042_filter);
	backlight_device_unregister(dell_backlight_device);
	dell_cleanup_rfkill();
	if (platform_device) {
		platform_device_del(platform_device);
		platform_driver_unregister(&platform_driver);
	}
	kfree(da_tokens);
	free_page((unsigned long)buffer);
}

module_init(dell_init);
@@ -435,3 +616,4 @@ MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
MODULE_DESCRIPTION("Dell laptop driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
Loading