summaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig51
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/acer-wmi.c53
-rw-r--r--drivers/misc/atmel-ssc.c2
-rw-r--r--drivers/misc/atmel_pwm.c1
-rw-r--r--drivers/misc/atmel_tclib.c161
-rw-r--r--drivers/misc/enclosure.c118
-rw-r--r--drivers/misc/fujitsu-laptop.c2
-rw-r--r--drivers/misc/hdpuftrs/hdpu_cpustate.c2
-rw-r--r--drivers/misc/hdpuftrs/hdpu_nexus.c2
-rw-r--r--drivers/misc/ibmasm/module.c2
-rw-r--r--drivers/misc/intel_menlow.c13
-rw-r--r--drivers/misc/kgdbts.c1090
-rw-r--r--drivers/misc/lkdtm.c2
-rw-r--r--drivers/misc/sony-laptop.c2
-rw-r--r--drivers/misc/thinkpad_acpi.c124
-rw-r--r--drivers/misc/tifm_7xx1.c2
17 files changed, 1534 insertions, 95 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1abc95ca9df..bb94ce78a6d 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -22,6 +22,39 @@ config ATMEL_PWM
purposes including software controlled power-efficent backlights
on LCD displays, motor control, and waveform generation.
+config ATMEL_TCLIB
+ bool "Atmel AT32/AT91 Timer/Counter Library"
+ depends on (AVR32 || ARCH_AT91)
+ help
+ Select this if you want a library to allocate the Timer/Counter
+ blocks found on many Atmel processors. This facilitates using
+ these blocks by different drivers despite processor differences.
+
+config ATMEL_TCB_CLKSRC
+ bool "TC Block Clocksource"
+ depends on ATMEL_TCLIB && GENERIC_TIME
+ default y
+ help
+ Select this to get a high precision clocksource based on a
+ TC block with a 5+ MHz base clock rate. Two timer channels
+ are combined to make a single 32-bit timer.
+
+ When GENERIC_CLOCKEVENTS is defined, the third timer channel
+ may be used as a clock event device supporting oneshot mode
+ (delays of up to two seconds) based on the 32 KiHz clock.
+
+config ATMEL_TCB_CLKSRC_BLOCK
+ int
+ depends on ATMEL_TCB_CLKSRC
+ prompt "TC Block" if ARCH_AT91RM9200 || ARCH_AT91SAM9260 || CPU_AT32AP700X
+ default 0
+ range 0 1
+ help
+ Some chips provide more than one TC block, so you have the
+ choice of which one to use for the clock framework. The other
+ TC can be used for other purposes, such as PWM generation and
+ interval timing.
+
config IBM_ASM
tristate "Device driver for IBM RSA service processor"
depends on X86 && PCI && INPUT && EXPERIMENTAL
@@ -108,6 +141,7 @@ config ACER_WMI
depends on ACPI
depends on LEDS_CLASS
depends on BACKLIGHT_CLASS_DEVICE
+ depends on SERIO_I8042
select ACPI_WMI
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
@@ -258,6 +292,23 @@ config THINKPAD_ACPI_BAY
If you are not sure, say Y here.
+config THINKPAD_ACPI_VIDEO
+ bool "Video output control support"
+ depends on THINKPAD_ACPI
+ default y
+ ---help---
+ Allows the thinkpad_acpi driver to provide an interface to control
+ the various video output ports.
+
+ This feature often won't work well, depending on ThinkPad model,
+ display state, video output devices in use, whether there is a X
+ server running, phase of the moon, and the current mood of
+ Schroedinger's cat. If you can use X.org's RandR to control
+ your ThinkPad's video output ports instead of this feature,
+ don't think twice: do it and say N here to save some memory.
+
+ If you are not sure, say Y here.
+
config THINKPAD_ACPI_HOTKEY_POLL
bool "Suport NVRAM polling for hot keys"
depends on THINKPAD_ACPI
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 3b12f5da856..4581b253311 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
+obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o
@@ -22,3 +23,4 @@ obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o
+obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c
index d7aea93081f..dd13a374992 100644
--- a/drivers/misc/acer-wmi.c
+++ b/drivers/misc/acer-wmi.c
@@ -219,6 +219,15 @@ static struct dmi_system_id acer_quirks[] = {
},
{
.callback = dmi_matched,
+ .ident = "Acer Aspire 3610",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"),
+ },
+ .driver_data = &quirk_acer_travelmate_2490,
+ },
+ {
+ .callback = dmi_matched,
.ident = "Acer Aspire 5100",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -228,6 +237,15 @@ static struct dmi_system_id acer_quirks[] = {
},
{
.callback = dmi_matched,
+ .ident = "Acer Aspire 5610",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
+ },
+ .driver_data = &quirk_acer_travelmate_2490,
+ },
+ {
+ .callback = dmi_matched,
.ident = "Acer Aspire 5630",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -273,6 +291,15 @@ static struct dmi_system_id acer_quirks[] = {
},
{
.callback = dmi_matched,
+ .ident = "Acer TravelMate 4200",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
+ },
+ .driver_data = &quirk_acer_travelmate_2490,
+ },
+ {
+ .callback = dmi_matched,
.ident = "Medion MD 98300",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
@@ -752,11 +779,11 @@ enum led_brightness value)
}
static struct led_classdev mail_led = {
- .name = "acer-mail:green",
+ .name = "acer-wmi::mail",
.brightness_set = mail_led_set,
};
-static int __init acer_led_init(struct device *dev)
+static int __devinit acer_led_init(struct device *dev)
{
return led_classdev_register(dev, &mail_led);
}
@@ -789,7 +816,7 @@ static struct backlight_ops acer_bl_ops = {
.update_status = update_bl_status,
};
-static int __init acer_backlight_init(struct device *dev)
+static int __devinit acer_backlight_init(struct device *dev)
{
struct backlight_device *bd;
@@ -808,7 +835,7 @@ static int __init acer_backlight_init(struct device *dev)
return 0;
}
-static void __exit acer_backlight_exit(void)
+static void acer_backlight_exit(void)
{
backlight_device_unregister(acer_backlight_device);
}
@@ -1043,11 +1070,12 @@ static int __init acer_wmi_init(void)
if (wmi_has_guid(WMID_GUID2) && interface) {
if (ACPI_FAILURE(WMID_set_capabilities())) {
- printk(ACER_ERR "Unable to detect available devices\n");
+ printk(ACER_ERR "Unable to detect available WMID "
+ "devices\n");
return -ENODEV;
}
} else if (!wmi_has_guid(WMID_GUID2) && interface) {
- printk(ACER_ERR "Unable to detect available devices\n");
+ printk(ACER_ERR "No WMID device detection method found\n");
return -ENODEV;
}
@@ -1055,21 +1083,20 @@ static int __init acer_wmi_init(void)
interface = &AMW0_interface;
if (ACPI_FAILURE(AMW0_set_capabilities())) {
- printk(ACER_ERR "Unable to detect available devices\n");
+ printk(ACER_ERR "Unable to detect available AMW0 "
+ "devices\n");
return -ENODEV;
}
}
- if (wmi_has_guid(AMW0_GUID1)) {
- if (ACPI_FAILURE(AMW0_find_mailled()))
- printk(ACER_ERR "Unable to detect mail LED\n");
- }
+ if (wmi_has_guid(AMW0_GUID1))
+ AMW0_find_mailled();
find_quirks();
if (!interface) {
- printk(ACER_ERR "No or unsupported WMI interface, unable to ");
- printk(KERN_CONT "load.\n");
+ printk(ACER_ERR "No or unsupported WMI interface, unable to "
+ "load\n");
return -ENODEV;
}
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c
index 058ccac700d..e171650766c 100644
--- a/drivers/misc/atmel-ssc.c
+++ b/drivers/misc/atmel-ssc.c
@@ -154,6 +154,7 @@ static struct platform_driver ssc_driver = {
.remove = __devexit_p(ssc_remove),
.driver = {
.name = "ssc",
+ .owner = THIS_MODULE,
},
};
@@ -172,3 +173,4 @@ module_exit(ssc_exit);
MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
MODULE_DESCRIPTION("SSC driver for Atmel AVR32 and AT91");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ssc");
diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c
index f8d3b9a76cb..0d5ce03cdff 100644
--- a/drivers/misc/atmel_pwm.c
+++ b/drivers/misc/atmel_pwm.c
@@ -407,3 +407,4 @@ module_exit(pwm_exit);
MODULE_DESCRIPTION("Driver for AT32/AT91 PWM module");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:atmel_pwm");
diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c
new file mode 100644
index 00000000000..05dc8a31f28
--- /dev/null
+++ b/drivers/misc/atmel_tclib.c
@@ -0,0 +1,161 @@
+#include <linux/atmel_tc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+/* Number of bytes to reserve for the iomem resource */
+#define ATMEL_TC_IOMEM_SIZE 256
+
+
+/*
+ * This is a thin library to solve the problem of how to portably allocate
+ * one of the TC blocks. For simplicity, it doesn't currently expect to
+ * share individual timers between different drivers.
+ */
+
+#if defined(CONFIG_AVR32)
+/* AVR32 has these divide PBB */
+const u8 atmel_tc_divisors[5] = { 0, 4, 8, 16, 32, };
+EXPORT_SYMBOL(atmel_tc_divisors);
+
+#elif defined(CONFIG_ARCH_AT91)
+/* AT91 has these divide MCK */
+const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, };
+EXPORT_SYMBOL(atmel_tc_divisors);
+
+#endif
+
+static DEFINE_SPINLOCK(tc_list_lock);
+static LIST_HEAD(tc_list);
+
+/**
+ * atmel_tc_alloc - allocate a specified TC block
+ * @block: which block to allocate
+ * @name: name to be associated with the iomem resource
+ *
+ * Caller allocates a block. If it is available, a pointer to a
+ * pre-initialized struct atmel_tc is returned. The caller can access
+ * the registers directly through the "regs" field.
+ */
+struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name)
+{
+ struct atmel_tc *tc;
+ struct platform_device *pdev = NULL;
+ struct resource *r;
+
+ spin_lock(&tc_list_lock);
+ list_for_each_entry(tc, &tc_list, node) {
+ if (tc->pdev->id == block) {
+ pdev = tc->pdev;
+ break;
+ }
+ }
+
+ if (!pdev || tc->iomem)
+ goto fail;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ r = request_mem_region(r->start, ATMEL_TC_IOMEM_SIZE, name);
+ if (!r)
+ goto fail;
+
+ tc->regs = ioremap(r->start, ATMEL_TC_IOMEM_SIZE);
+ if (!tc->regs)
+ goto fail_ioremap;
+
+ tc->iomem = r;
+
+out:
+ spin_unlock(&tc_list_lock);
+ return tc;
+
+fail_ioremap:
+ release_resource(r);
+fail:
+ tc = NULL;
+ goto out;
+}
+EXPORT_SYMBOL_GPL(atmel_tc_alloc);
+
+/**
+ * atmel_tc_free - release a specified TC block
+ * @tc: Timer/counter block that was returned by atmel_tc_alloc()
+ *
+ * This reverses the effect of atmel_tc_alloc(), unmapping the I/O
+ * registers, invalidating the resource returned by that routine and
+ * making the TC available to other drivers.
+ */
+void atmel_tc_free(struct atmel_tc *tc)
+{
+ spin_lock(&tc_list_lock);
+ if (tc->regs) {
+ iounmap(tc->regs);
+ release_resource(tc->iomem);
+ tc->regs = NULL;
+ tc->iomem = NULL;
+ }
+ spin_unlock(&tc_list_lock);
+}
+EXPORT_SYMBOL_GPL(atmel_tc_free);
+
+static int __init tc_probe(struct platform_device *pdev)
+{
+ struct atmel_tc *tc;
+ struct clk *clk;
+ int irq;
+
+ if (!platform_get_resource(pdev, IORESOURCE_MEM, 0))
+ return -EINVAL;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -EINVAL;
+
+ tc = kzalloc(sizeof(struct atmel_tc), GFP_KERNEL);
+ if (!tc)
+ return -ENOMEM;
+
+ tc->pdev = pdev;
+
+ clk = clk_get(&pdev->dev, "t0_clk");
+ if (IS_ERR(clk)) {
+ kfree(tc);
+ return -EINVAL;
+ }
+
+ tc->clk[0] = clk;
+ tc->clk[1] = clk_get(&pdev->dev, "t1_clk");
+ if (IS_ERR(tc->clk[1]))
+ tc->clk[1] = clk;
+ tc->clk[2] = clk_get(&pdev->dev, "t2_clk");
+ if (IS_ERR(tc->clk[2]))
+ tc->clk[2] = clk;
+
+ tc->irq[0] = irq;
+ tc->irq[1] = platform_get_irq(pdev, 1);
+ if (tc->irq[1] < 0)
+ tc->irq[1] = irq;
+ tc->irq[2] = platform_get_irq(pdev, 2);
+ if (tc->irq[2] < 0)
+ tc->irq[2] = irq;
+
+ spin_lock(&tc_list_lock);
+ list_add_tail(&tc->node, &tc_list);
+ spin_unlock(&tc_list_lock);
+
+ return 0;
+}
+
+static struct platform_driver tc_driver = {
+ .driver.name = "atmel_tcb",
+};
+
+static int __init tc_init(void)
+{
+ return platform_driver_probe(&tc_driver, tc_probe);
+}
+arch_initcall(tc_init);
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 6fcb0e96adf..fafb57fed76 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -40,16 +40,16 @@ static struct class enclosure_component_class;
* Looks through the list of registered enclosures to see
* if it can find a match for a device. Returns NULL if no
* enclosure is found. Obtains a reference to the enclosure class
- * device which must be released with class_device_put().
+ * device which must be released with device_put().
*/
struct enclosure_device *enclosure_find(struct device *dev)
{
- struct enclosure_device *edev = NULL;
+ struct enclosure_device *edev;
mutex_lock(&container_list_lock);
list_for_each_entry(edev, &container_list, node) {
- if (edev->cdev.dev == dev) {
- class_device_get(&edev->cdev);
+ if (edev->edev.parent == dev) {
+ get_device(&edev->edev);
mutex_unlock(&container_list_lock);
return edev;
}
@@ -117,11 +117,11 @@ enclosure_register(struct device *dev, const char *name, int components,
edev->components = components;
- edev->cdev.class = &enclosure_class;
- edev->cdev.dev = get_device(dev);
+ edev->edev.class = &enclosure_class;
+ edev->edev.parent = get_device(dev);
edev->cb = cb;
- snprintf(edev->cdev.class_id, BUS_ID_SIZE, "%s", name);
- err = class_device_register(&edev->cdev);
+ snprintf(edev->edev.bus_id, BUS_ID_SIZE, "%s", name);
+ err = device_register(&edev->edev);
if (err)
goto err;
@@ -135,7 +135,7 @@ enclosure_register(struct device *dev, const char *name, int components,
return edev;
err:
- put_device(edev->cdev.dev);
+ put_device(edev->edev.parent);
kfree(edev);
return ERR_PTR(err);
}
@@ -158,27 +158,28 @@ void enclosure_unregister(struct enclosure_device *edev)
for (i = 0; i < edev->components; i++)
if (edev->component[i].number != -1)
- class_device_unregister(&edev->component[i].cdev);
+ device_unregister(&edev->component[i].cdev);
/* prevent any callbacks into service user */
edev->cb = &enclosure_null_callbacks;
- class_device_unregister(&edev->cdev);
+ device_unregister(&edev->edev);
}
EXPORT_SYMBOL_GPL(enclosure_unregister);
-static void enclosure_release(struct class_device *cdev)
+static void enclosure_release(struct device *cdev)
{
struct enclosure_device *edev = to_enclosure_device(cdev);
- put_device(cdev->dev);
+ put_device(cdev->parent);
kfree(edev);
}
-static void enclosure_component_release(struct class_device *cdev)
+static void enclosure_component_release(struct device *dev)
{
- if (cdev->dev)
- put_device(cdev->dev);
- class_device_put(cdev->parent);
+ struct enclosure_component *cdev = to_enclosure_component(dev);
+
+ put_device(cdev->dev);
+ put_device(dev->parent);
}
/**
@@ -201,7 +202,7 @@ enclosure_component_register(struct enclosure_device *edev,
const char *name)
{
struct enclosure_component *ecomp;
- struct class_device *cdev;
+ struct device *cdev;
int err;
if (number >= edev->components)
@@ -215,14 +216,14 @@ enclosure_component_register(struct enclosure_device *edev,
ecomp->type = type;
ecomp->number = number;
cdev = &ecomp->cdev;
- cdev->parent = class_device_get(&edev->cdev);
+ cdev->parent = get_device(&edev->edev);
cdev->class = &enclosure_component_class;
if (name)
- snprintf(cdev->class_id, BUS_ID_SIZE, "%s", name);
+ snprintf(cdev->bus_id, BUS_ID_SIZE, "%s", name);
else
- snprintf(cdev->class_id, BUS_ID_SIZE, "%u", number);
+ snprintf(cdev->bus_id, BUS_ID_SIZE, "%u", number);
- err = class_device_register(cdev);
+ err = device_register(cdev);
if (err)
ERR_PTR(err);
@@ -247,18 +248,17 @@ EXPORT_SYMBOL_GPL(enclosure_component_register);
int enclosure_add_device(struct enclosure_device *edev, int component,
struct device *dev)
{
- struct class_device *cdev;
+ struct enclosure_component *cdev;
if (!edev || component >= edev->components)
return -EINVAL;
- cdev = &edev->component[component].cdev;
+ cdev = &edev->component[component];
- class_device_del(cdev);
- if (cdev->dev)
- put_device(cdev->dev);
+ device_del(&cdev->cdev);
+ put_device(cdev->dev);
cdev->dev = get_device(dev);
- return class_device_add(cdev);
+ return device_add(&cdev->cdev);
}
EXPORT_SYMBOL_GPL(enclosure_add_device);
@@ -272,18 +272,17 @@ EXPORT_SYMBOL_GPL(enclosure_add_device);
*/
int enclosure_remove_device(struct enclosure_device *edev, int component)
{
- struct class_device *cdev;
+ struct enclosure_component *cdev;
if (!edev || component >= edev->components)
return -EINVAL;
- cdev = &edev->component[component].cdev;
+ cdev = &edev->component[component];
- class_device_del(cdev);
- if (cdev->dev)
- put_device(cdev->dev);
+ device_del(&cdev->cdev);
+ put_device(cdev->dev);
cdev->dev = NULL;
- return class_device_add(cdev);
+ return device_add(&cdev->cdev);
}
EXPORT_SYMBOL_GPL(enclosure_remove_device);
@@ -291,14 +290,16 @@ EXPORT_SYMBOL_GPL(enclosure_remove_device);
* sysfs pieces below
*/
-static ssize_t enclosure_show_components(struct class_device *cdev, char *buf)
+static ssize_t enclosure_show_components(struct device *cdev,
+ struct device_attribute *attr,
+ char *buf)
{
struct enclosure_device *edev = to_enclosure_device(cdev);
return snprintf(buf, 40, "%d\n", edev->components);
}
-static struct class_device_attribute enclosure_attrs[] = {
+static struct device_attribute enclosure_attrs[] = {
__ATTR(components, S_IRUGO, enclosure_show_components, NULL),
__ATTR_NULL
};
@@ -306,8 +307,8 @@ static struct class_device_attribute enclosure_attrs[] = {
static struct class enclosure_class = {
.name = "enclosure",
.owner = THIS_MODULE,
- .release = enclosure_release,
- .class_dev_attrs = enclosure_attrs,
+ .dev_release = enclosure_release,
+ .dev_attrs = enclosure_attrs,
};
static const char *const enclosure_status [] = {
@@ -326,7 +327,8 @@ static const char *const enclosure_type [] = {
[ENCLOSURE_COMPONENT_ARRAY_DEVICE] = "array device",
};
-static ssize_t get_component_fault(struct class_device *cdev, char *buf)
+static ssize_t get_component_fault(struct device *cdev,
+ struct device_attribute *attr, char *buf)
{
struct enclosure_device *edev = to_enclosure_device(cdev->parent);
struct enclosure_component *ecomp = to_enclosure_component(cdev);
@@ -336,8 +338,9 @@ static ssize_t get_component_fault(struct class_device *cdev, char *buf)
return snprintf(buf, 40, "%d\n", ecomp->fault);
}
-static ssize_t set_component_fault(struct class_device *cdev, const char *buf,
- size_t count)
+static ssize_t set_component_fault(struct device *cdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct enclosure_device *edev = to_enclosure_device(cdev->parent);
struct enclosure_component *ecomp = to_enclosure_component(cdev);
@@ -348,7 +351,8 @@ static ssize_t set_component_fault(struct class_device *cdev, const char *buf,
return count;
}
-static ssize_t get_component_status(struct class_device *cdev, char *buf)
+static ssize_t get_component_status(struct device *cdev,
+ struct device_attribute *attr,char *buf)
{
struct enclosure_device *edev = to_enclosure_device(cdev->parent);
struct enclosure_component *ecomp = to_enclosure_component(cdev);
@@ -358,8 +362,9 @@ static ssize_t get_component_status(struct class_device *cdev, char *buf)
return snprintf(buf, 40, "%s\n", enclosure_status[ecomp->status]);
}
-static ssize_t set_component_status(struct class_device *cdev, const char *buf,
- size_t count)
+static ssize_t set_component_status(struct device *cdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct enclosure_device *edev = to_enclosure_device(cdev->parent);
struct enclosure_component *ecomp = to_enclosure_component(cdev);
@@ -380,7 +385,8 @@ static ssize_t set_component_status(struct class_device *cdev, const char *buf,
return -EINVAL;
}
-static ssize_t get_component_active(struct class_device *cdev, char *buf)
+static ssize_t get_component_active(struct device *cdev,
+ struct device_attribute *attr, char *buf)
{
struct enclosure_device *edev = to_enclosure_device(cdev->parent);
struct enclosure_component *ecomp = to_enclosure_component(cdev);
@@ -390,8 +396,9 @@ static ssize_t get_component_active(struct class_device *cdev, char *buf)
return snprintf(buf, 40, "%d\n", ecomp->active);
}
-static ssize_t set_component_active(struct class_device *cdev, const char *buf,
- size_t count)
+static ssize_t set_component_active(struct device *cdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct enclosure_device *edev = to_enclosure_device(cdev->parent);
struct enclosure_component *ecomp = to_enclosure_component(cdev);
@@ -402,7 +409,8 @@ static ssize_t set_component_active(struct class_device *cdev, const char *buf,
return count;
}
-static ssize_t get_component_locate(struct class_device *cdev, char *buf)
+static ssize_t get_component_locate(struct device *cdev,
+ struct device_attribute *attr, char *buf)
{
struct enclosure_device *edev = to_enclosure_device(cdev->parent);
struct enclosure_component *ecomp = to_enclosure_component(cdev);
@@ -412,8 +420,9 @@ static ssize_t get_component_locate(struct class_device *cdev, char *buf)
return snprintf(buf, 40, "%d\n", ecomp->locate);
}
-static ssize_t set_component_locate(struct class_device *cdev, const char *buf,
- size_t count)
+static ssize_t set_component_locate(struct device *cdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct enclosure_device *edev = to_enclosure_device(cdev->parent);
struct enclosure_component *ecomp = to_enclosure_component(cdev);
@@ -424,7 +433,8 @@ static ssize_t set_component_locate(struct class_device *cdev, const char *buf,
return count;
}
-static ssize_t get_component_type(struct class_device *cdev, char *buf)
+static ssize_t get_component_type(struct device *cdev,
+ struct device_attribute *attr, char *buf)
{
struct enclosure_component *ecomp = to_enclosure_component(cdev);
@@ -432,7 +442,7 @@ static ssize_t get_component_type(struct class_device *cdev, char *buf)
}
-static struct class_device_attribute enclosure_component_attrs[] = {
+static struct device_attribute enclosure_component_attrs[] = {
__ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
set_component_fault),
__ATTR(status, S_IRUGO | S_IWUSR, get_component_status,
@@ -448,8 +458,8 @@ static struct class_device_attribute enclosure_component_attrs[] = {
static struct class enclosure_component_class = {
.name = "enclosure_component",
.owner = THIS_MODULE,
- .class_dev_attrs = enclosure_component_attrs,
- .release = enclosure_component_release,
+ .dev_attrs = enclosure_component_attrs,
+ .dev_release = enclosure_component_release,
};
static int __init enclosure_init(void)
diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c
index 1cfd7f3f129..e2e7c05a147 100644
--- a/drivers/misc/fujitsu-laptop.c
+++ b/drivers/misc/fujitsu-laptop.c
@@ -231,7 +231,7 @@ static int acpi_fujitsu_remove(struct acpi_device *device, int type)
if (!device || !acpi_driver_data(device))
return -EINVAL;
- fujitsu->acpi_handle = 0;
+ fujitsu->acpi_handle = NULL;
return 0;
}
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index aa8ce7abe92..302e92418bb 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -164,6 +164,7 @@ static struct platform_driver hdpu_cpustate_driver = {
.remove = hdpu_cpustate_remove,
.driver = {
.name = HDPU_CPUSTATE_NAME,
+ .owner = THIS_MODULE,
},
};
@@ -248,3 +249,4 @@ module_exit(cpustate_exit);
MODULE_AUTHOR("Brian Waite");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" HDPU_CPUSTATE_NAME);
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 2887b214798..2fa36f7a6eb 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -55,6 +55,7 @@ static struct platform_driver hdpu_nexus_driver = {
.remove = hdpu_nexus_remove,
.driver = {
.name = HDPU_NEXUS_NAME,
+ .owner = THIS_MODULE,
},
};
@@ -151,3 +152,4 @@ module_exit(nexus_exit);
MODULE_AUTHOR("Brian Waite");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" HDPU_NEXUS_NAME);
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c
index 4f9d4a9da98..b5f6add34b0 100644
--- a/drivers/misc/ibmasm/module.c
+++ b/drivers/misc/ibmasm/module.c
@@ -106,7 +106,7 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi
sp->irq = pdev->irq;
sp->base_address = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
- if (sp->base_address == 0) {
+ if (!sp->base_address) {
dev_err(sp->dev, "Failed to ioremap pci memory\n");
result = -ENODEV;
goto error_ioremap;
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
index f70984ab1e1..0c0bb3093e0 100644
--- a/drivers/misc/intel_menlow.c
+++ b/drivers/misc/intel_menlow.c
@@ -170,10 +170,13 @@ static int intel_menlow_memory_add(struct acpi_device *device)
cdev = thermal_cooling_device_register("Memory controller", device,
&memory_cooling_ops);
- acpi_driver_data(device) = cdev;
- if (!cdev)
- result = -ENODEV;
- else {
+ if (IS_ERR(cdev)) {
+ result = PTR_ERR(cdev);
+ goto end;
+ }
+
+ if (cdev) {
+ acpi_driver_data(device) = cdev;
result = sysfs_create_link(&device->dev.kobj,
&cdev->device.kobj, "thermal_cooling");
if (result)
@@ -210,7 +213,7 @@ static int intel_menlow_memory_remove(struct acpi_device *device, int type)
return 0;
}
-const static struct acpi_device_id intel_menlow_memory_ids[] = {
+static const struct acpi_device_id intel_menlow_memory_ids[] = {
{"INT0002", 0},
{"", 0},
};
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
new file mode 100644
index 00000000000..6d6286c4eea
--- /dev/null
+++ b/drivers/misc/kgdbts.c
@@ -0,0 +1,1090 @@
+/*
+ * kgdbts is a test suite for kgdb for the sole purpose of validating
+ * that key pieces of the kgdb internals are working properly such as
+ * HW/SW breakpoints, single stepping, and NMI.
+ *
+ * Created by: Jason Wessel <jason.wessel@windriver.com>
+ *
+ * Copyright (c) 2008 Wind River Systems, Inc.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+/* Information about the kgdb test suite.
+ * -------------------------------------
+ *
+ * The kgdb test suite is designed as a KGDB I/O module which
+ * simulates the communications that a debugger would have with kgdb.
+ * The tests are broken up in to a line by line and referenced here as
+ * a "get" which is kgdb requesting input and "put" which is kgdb
+ * sending a response.
+ *
+ * The kgdb suite can be invoked from the kernel command line
+ * arguments system or executed dynamically at run time. The test
+ * suite uses the variable "kgdbts" to obtain the information about
+ * which tests to run and to configure the verbosity level. The
+ * following are the various characters you can use with the kgdbts=
+ * line:
+ *
+ * When using the "kgdbts=" you only choose one of the following core
+ * test types:
+ * A = Run all the core tests silently
+ * V1 = Run all the core tests with minimal output
+ * V2 = Run all the core tests in debug mode
+ *
+ * You can also specify optional tests:
+ * N## = Go to sleep with interrupts of for ## seconds
+ * to test the HW NMI watchdog
+ * F## = Break at do_fork for ## iterations
+ * S## = Break at sys_open for ## iterations
+ *
+ * NOTE: that the do_fork and sys_open tests are mutually exclusive.
+ *
+ * To invoke the kgdb test suite from boot you use a kernel start
+ * argument as follows:
+ * kgdbts=V1 kgdbwait
+ * Or if you wanted to perform the NMI test for 6 seconds and do_fork
+ * test for 100 forks, you could use:
+ * kgdbts=V1N6F100 kgdbwait
+ *
+ * The test suite can also be invoked at run time with:
+ * echo kgdbts=V1N6F100 > /sys/module/kgdbts/parameters/kgdbts
+ * Or as another example:
+ * echo kgdbts=V2 > /sys/module/kgdbts/parameters/kgdbts
+ *
+ * When developing a new kgdb arch specific implementation or
+ * using these tests for the purpose of regression testing,
+ * several invocations are required.
+ *
+ * 1) Boot with the test suite enabled by using the kernel arguments
+ * "kgdbts=V1F100 kgdbwait"
+ * ## If kgdb arch specific implementation has NMI use
+ * "kgdbts=V1N6F100
+ *
+ * 2) After the system boot run the basic test.
+ * echo kgdbts=V1 > /sys/module/kgdbts/parameters/kgdbts
+ *
+ * 3) Run the concurrency tests. It is best to use n+1
+ * while loops where n is the number of cpus you have
+ * in your system. The example below uses only two
+ * loops.
+ *
+ * ## This tests break points on sys_open
+ * while [ 1 ] ; do find / > /dev/null 2>&1 ; done &
+ * while [ 1 ] ; do find / > /dev/null 2>&1 ; done &
+ * echo kgdbts=V1S10000 > /sys/module/kgdbts/parameters/kgdbts
+ * fg # and hit control-c
+ * fg # and hit control-c
+ * ## This tests break points on do_fork
+ * while [ 1 ] ; do date > /dev/null ; done &
+ * while [ 1 ] ; do date > /dev/null ; done &
+ * echo kgdbts=V1F1000 > /sys/module/kgdbts/parameters/kgdbts
+ * fg # and hit control-c
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/kgdb.h>
+#include <linux/ctype.h>
+#include <linux/uaccess.h>
+#include <linux/syscalls.h>
+#include <linux/nmi.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+
+#define v1printk(a...) do { \
+ if (verbose) \
+ printk(KERN_INFO a); \
+ } while (0)
+#define v2printk(a...) do { \
+ if (verbose > 1) \
+ printk(KERN_INFO a); \
+ touch_nmi_watchdog(); \
+ } while (0)
+#define eprintk(a...) do { \
+ printk(KERN_ERR a); \
+ WARN_ON(1); \
+ } while (0)
+#define MAX_CONFIG_LEN 40
+
+static const char hexchars[] = "0123456789abcdef";
+static struct kgdb_io kgdbts_io_ops;
+static char get_buf[BUFMAX];
+static int get_buf_cnt;
+static char put_buf[BUFMAX];
+static int put_buf_cnt;
+static char scratch_buf[BUFMAX];
+static int verbose;
+static int repeat_test;
+static int test_complete;
+static int send_ack;
+static int final_ack;
+static int hw_break_val;
+static int hw_break_val2;
+#if defined(CONFIG_ARM) || defined(CONFIG_MIPS)
+static int arch_needs_sstep_emulation = 1;
+#else
+static int arch_needs_sstep_emulation;
+#endif
+static unsigned long sstep_addr;
+static int sstep_state;
+
+/* Storage for the registers, in GDB format. */
+static unsigned long kgdbts_gdb_regs[(NUMREGBYTES +
+ sizeof(unsigned long) - 1) /
+ sizeof(unsigned long)];
+static struct pt_regs kgdbts_regs;
+
+/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */
+static int configured = -1;
+
+#ifdef CONFIG_KGDB_TESTS_BOOT_STRING
+static char config[MAX_CONFIG_LEN] = CONFIG_KGDB_TESTS_BOOT_STRING;
+#else
+static char config[MAX_CONFIG_LEN];
+#endif
+static struct kparam_string kps = {
+ .string = config,
+ .maxlen = MAX_CONFIG_LEN,
+};
+
+static void fill_get_buf(char *buf);
+
+struct test_struct {
+ char *get;
+ char *put;
+ void (*get_handler)(char *);
+ int (*put_handler)(char *, char *);
+};
+
+struct test_state {
+ char *name;
+ struct test_struct *tst;
+ int idx;
+ int (*run_test) (int, int);
+ int (*validate_put) (char *);
+};
+
+static struct test_state ts;
+
+static int kgdbts_unreg_thread(void *ptr)
+{
+ /* Wait until the tests are complete and then ungresiter the I/O
+ * driver.
+ */
+ while (!final_ack)
+ msleep_interruptible(1500);
+
+ if (configured)
+ kgdb_unregister_io_module(&kgdbts_io_ops);
+ configured = 0;
+
+ return 0;
+}
+
+/* This is noinline such that it can be used for a single location to
+ * place a breakpoint
+ */
+static noinline void kgdbts_break_test(void)
+{
+ v2printk("kgdbts: breakpoint complete\n");
+}
+
+/* Lookup symbol info in the kernel */
+static unsigned long lookup_addr(char *arg)
+{
+ unsigned long addr = 0;
+
+ if (!strcmp(arg, "kgdbts_break_test"))
+ addr = (unsigned long)kgdbts_break_test;
+ else if (!strcmp(arg, "sys_open"))
+ addr = (unsigned long)sys_open;
+ else if (!strcmp(arg, "do_fork"))
+ addr = (unsigned long)do_fork;
+ else if (!strcmp(arg, "hw_break_val"))
+ addr = (unsigned long)&hw_break_val;
+ return addr;
+}
+
+static void break_helper(char *bp_type, char *arg, unsigned long vaddr)
+{
+ unsigned long addr;
+
+ if (arg)
+ addr = lookup_addr(arg);
+ else
+ addr = vaddr;
+
+ sprintf(scratch_buf, "%s,%lx,%i", bp_type, addr,
+ BREAK_INSTR_SIZE);
+ fill_get_buf(scratch_buf);
+}
+
+static void sw_break(char *arg)
+{
+ break_helper("Z0", arg, 0);
+}
+
+static void sw_rem_break(char *arg)
+{
+ break_helper("z0", arg, 0);
+}
+
+static void hw_break(char *arg)
+{
+ break_helper("Z1", arg, 0);
+}
+
+static void hw_rem_break(char *arg)
+{
+ break_helper("z1", arg, 0);
+}
+
+static void hw_write_break(char *arg)
+{
+ break_helper("Z2", arg, 0);
+}
+
+static void hw_rem_write_break(char *arg)
+{
+ break_helper("z2", arg, 0);
+}
+
+static void hw_access_break(char *arg)
+{
+ break_helper("Z4", arg, 0);
+}
+
+static void hw_rem_access_break(char *arg)
+{
+ break_helper("z4", arg, 0);
+}
+
+static void hw_break_val_access(void)
+{
+ hw_break_val2 = hw_break_val;
+}
+
+static void hw_break_val_write(void)
+{
+ hw_break_val++;
+}
+
+static int check_and_rewind_pc(char *put_str, char *arg)
+{
+ unsigned long addr = lookup_addr(arg);
+ int offset = 0;
+
+ kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs,
+ NUMREGBYTES);
+ gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
+ v2printk("Stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs));
+#ifdef CONFIG_X86
+ /* On x86 a breakpoint stop requires it to be decremented */
+ if (addr + 1 == kgdbts_regs.ip)
+ offset = -1;
+#endif
+ if (strcmp(arg, "silent") &&
+ instruction_pointer(&kgdbts_regs) + offset != addr) {
+ eprintk("kgdbts: BP mismatch %lx expected %lx\n",
+ instruction_pointer(&kgdbts_regs) + offset, addr);
+ return 1;
+ }
+#ifdef CONFIG_X86
+ /* On x86 adjust the instruction pointer if needed */
+ kgdbts_regs.ip += offset;
+#endif
+ return 0;
+}
+
+static int check_single_step(char *put_str, char *arg)
+{
+ unsigned long addr = lookup_addr(arg);
+ /*
+ * From an arch indepent point of view the instruction pointer
+ * should be on a different instruction
+ */
+ kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs,
+ NUMREGBYTES);
+ gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
+ v2printk("Singlestep stopped at IP: %lx\n",
+ instruction_pointer(&kgdbts_regs));
+ if (instruction_pointer(&kgdbts_regs) == addr) {
+ eprintk("kgdbts: SingleStep failed at %lx\n",
+ instruction_pointer(&kgdbts_regs));
+ return 1;
+ }
+
+ return 0;
+}
+
+static void write_regs(char *arg)
+{
+ memset(scratch_buf, 0, sizeof(scratch_buf));
+ scratch_buf[0] = 'G';
+ pt_regs_to_gdb_regs(kgdbts_gdb_regs, &kgdbts_regs);
+ kgdb_mem2hex((char *)kgdbts_gdb_regs, &scratch_buf[1], NUMREGBYTES);
+ fill_get_buf(scratch_buf);
+}
+
+static void skip_back_repeat_test(char *arg)
+{
+ int go_back = simple_strtol(arg, NULL, 10);
+
+ repeat_test--;
+ if (repeat_test <= 0)
+ ts.idx++;
+ else
+ ts.idx -= go_back;
+ fill_get_buf(ts.tst[ts.idx].get);
+}
+
+static int got_break(char *put_str, char *arg)
+{
+ test_complete = 1;
+ if (!strncmp(put_str+1, arg, 2)) {
+ if (!strncmp(arg, "T0", 2))
+ test_complete = 2;
+ return 0;
+ }
+ return 1;
+}
+
+static void emul_sstep_get(char *arg)
+{
+ if (!arch_needs_sstep_emulation) {
+ fill_get_buf(arg);
+ return;
+ }
+ switch (sstep_state) {
+ case 0:
+ v2printk("Emulate single step\n");
+ /* Start by looking at the current PC */
+ fill_get_buf("g");
+ break;
+ case 1:
+ /* set breakpoint */
+ break_helper("Z0", 0, sstep_addr);
+ break;
+ case 2:
+ /* Continue */
+ fill_get_buf("c");
+ break;
+ case 3:
+ /* Clear breakpoint */
+ break_helper("z0", 0, sstep_addr);
+ break;
+ default:
+ eprintk("kgdbts: ERROR failed sstep get emulation\n");
+ }
+ sstep_state++;
+}
+
+static int emul_sstep_put(char *put_str, char *arg)
+{
+ if (!arch_needs_sstep_emulation) {
+ if (!strncmp(put_str+1, arg, 2))
+ return 0;
+ return 1;
+ }
+ switch (sstep_state) {
+ case 1:
+ /* validate the "g" packet to get the IP */
+ kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs,
+ NUMREGBYTES);
+ gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
+ v2printk("Stopped at IP: %lx\n",
+ instruction_pointer(&kgdbts_regs));
+ /* Want to stop at IP + break instruction size by default */
+ sstep_addr = instruction_pointer(&kgdbts_regs) +
+ BREAK_INSTR_SIZE;
+ break;
+ case 2:
+ if (strncmp(put_str, "$OK", 3)) {
+ eprintk("kgdbts: failed sstep break set\n");
+ return 1;
+ }
+ break;
+ case 3:
+ if (strncmp(put_str, "$T0", 3)) {
+ eprintk("kgdbts: failed continue sstep\n");
+ return 1;
+ }
+ break;
+ case 4:
+ if (strncmp(put_str, "$OK", 3)) {
+ eprintk("kgdbts: failed sstep break unset\n");
+ return 1;
+ }
+ /* Single step is complete so continue on! */
+ sstep_state = 0;
+ return 0;
+ default:
+ eprintk("kgdbts: ERROR failed sstep put emulation\n");
+ }
+
+ /* Continue on the same test line until emulation is complete */
+ ts.idx--;
+ return 0;
+}
+
+static int final_ack_set(char *put_str, char *arg)
+{
+ if (strncmp(put_str+1, arg, 2))
+ return 1;
+ final_ack = 1;
+ return 0;
+}
+/*
+ * Test to plant a breakpoint and detach, which should clear out the
+ * breakpoint and restore the original instruction.
+ */
+static struct test_struct plant_and_detach_test[] = {
+ { "?", "S0*" }, /* Clear break points */
+ { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
+ { "D", "OK" }, /* Detach */
+ { "", "" },
+};
+
+/*
+ * Simple test to write in a software breakpoint, check for the
+ * correct stop location and detach.
+ */
+static struct test_struct sw_breakpoint_test[] = {
+ { "?", "S0*" }, /* Clear break points */
+ { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
+ { "c", "T0*", }, /* Continue */
+ { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "write", "OK", write_regs },
+ { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
+ { "D", "OK" }, /* Detach */
+ { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "", "" },
+};
+
+/*
+ * Test a known bad memory read location to test the fault handler and
+ * read bytes 1-8 at the bad address
+ */
+static struct test_struct bad_read_test[] = {
+ { "?", "S0*" }, /* Clear break points */
+ { "m0,1", "E*" }, /* read 1 byte at address 1 */
+ { "m0,2", "E*" }, /* read 1 byte at address 2 */
+ { "m0,3", "E*" }, /* read 1 byte at address 3 */
+ { "m0,4", "E*" }, /* read 1 byte at address 4 */
+ { "m0,5", "E*" }, /* read 1 byte at address 5 */
+ { "m0,6", "E*" }, /* read 1 byte at address 6 */
+ { "m0,7", "E*" }, /* read 1 byte at address 7 */
+ { "m0,8", "E*" }, /* read 1 byte at address 8 */
+ { "D", "OK" }, /* Detach which removes all breakpoints and continues */
+ { "", "" },
+};
+
+/*
+ * Test for hitting a breakpoint, remove it, single step, plant it
+ * again and detach.
+ */
+static struct test_struct singlestep_break_test[] = {
+ { "?", "S0*" }, /* Clear break points */
+ { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
+ { "c", "T0*", }, /* Continue */
+ { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "write", "OK", write_regs }, /* Write registers */
+ { "kgdbts_break_test", "OK", sw_rem_break }, /*remove breakpoint */
+ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
+ { "g", "kgdbts_break_test", 0, check_single_step },
+ { "kgdbts_break_test", "OK", sw_break, }, /* set sw breakpoint */
+ { "c", "T0*", }, /* Continue */
+ { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "write", "OK", write_regs }, /* Write registers */
+ { "D", "OK" }, /* Remove all breakpoints and continues */
+ { "", "" },
+};
+
+/*
+ * Test for hitting a breakpoint at do_fork for what ever the number
+ * of iterations required by the variable repeat_test.
+ */
+static struct test_struct do_fork_test[] = {
+ { "?", "S0*" }, /* Clear break points */
+ { "do_fork", "OK", sw_break, }, /* set sw breakpoint */
+ { "c", "T0*", }, /* Continue */
+ { "g", "do_fork", 0, check_and_rewind_pc }, /* check location */
+ { "write", "OK", write_regs }, /* Write registers */
+ { "do_fork", "OK", sw_rem_break }, /*remove breakpoint */
+ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
+ { "g", "do_fork", 0, check_single_step },
+ { "do_fork", "OK", sw_break, }, /* set sw breakpoint */
+ { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
+ { "D", "OK", 0, final_ack_set }, /* detach and unregister I/O */
+ { "", "" },
+};
+
+/* Test for hitting a breakpoint at sys_open for what ever the number
+ * of iterations required by the variable repeat_test.
+ */
+static struct test_struct sys_open_test[] = {
+ { "?", "S0*" }, /* Clear break points */
+ { "sys_open", "OK", sw_break, }, /* set sw breakpoint */
+ { "c", "T0*", }, /* Continue */
+ { "g", "sys_open", 0, check_and_rewind_pc }, /* check location */
+ { "write", "OK", write_regs }, /* Write registers */
+ { "sys_open", "OK", sw_rem_break }, /*remove breakpoint */
+ { "s", "T0*", emul_sstep_get, emul_sstep_put }, /* Single step */
+ { "g", "sys_open", 0, check_single_step },
+ { "sys_open", "OK", sw_break, }, /* set sw breakpoint */
+ { "7", "T0*", skip_back_repeat_test }, /* Loop based on repeat_test */
+ { "D", "OK", 0, final_ack_set }, /* detach and unregister I/O */
+ { "", "" },
+};
+
+/*
+ * Test for hitting a simple hw breakpoint
+ */
+static struct test_struct hw_breakpoint_test[] = {
+ { "?", "S0*" }, /* Clear break points */
+ { "kgdbts_break_test", "OK", hw_break, }, /* set hw breakpoint */
+ { "c", "T0*", }, /* Continue */
+ { "g", "kgdbts_break_test", 0, check_and_rewind_pc },
+ { "write", "OK", write_regs },
+ { "kgdbts_break_test", "OK", hw_rem_break }, /*remove breakpoint */
+ { "D", "OK" }, /* Detach */
+ { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "", "" },
+};
+
+/*
+ * Test for hitting a hw write breakpoint
+ */
+static struct test_struct hw_write_break_test[] = {
+ { "?", "S0*" }, /* Clear break points */
+ { "hw_break_val", "OK", hw_write_break, }, /* set hw breakpoint */
+ { "c", "T0*", 0, got_break }, /* Continue */
+ { "g", "silent", 0, check_and_rewind_pc },
+ { "write", "OK", write_regs },
+ { "hw_break_val", "OK", hw_rem_write_break }, /*remove breakpoint */
+ { "D", "OK" }, /* Detach */
+ { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "", "" },
+};
+
+/*
+ * Test for hitting a hw access breakpoint
+ */
+static struct test_struct hw_access_break_test[] = {
+ { "?", "S0*" }, /* Clear break points */
+ { "hw_break_val", "OK", hw_access_break, }, /* set hw breakpoint */
+ { "c", "T0*", 0, got_break }, /* Continue */
+ { "g", "silent", 0, check_and_rewind_pc },
+ { "write", "OK", write_regs },
+ { "hw_break_val", "OK", hw_rem_access_break }, /*remove breakpoint */
+ { "D", "OK" }, /* Detach */
+ { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "", "" },
+};
+
+/*
+ * Test for hitting a hw access breakpoint
+ */
+static struct test_struct nmi_sleep_test[] = {
+ { "?", "S0*" }, /* Clear break points */
+ { "c", "T0*", 0, got_break }, /* Continue */
+ { "D", "OK" }, /* Detach */
+ { "D", "OK", 0, got_break }, /* If the test worked we made it here */
+ { "", "" },
+};
+
+static void fill_get_buf(char *buf)
+{
+ unsigned char checksum = 0;
+ int count = 0;
+ char ch;
+
+ strcpy(get_buf, "$");
+ strcat(get_buf, buf);
+ while ((ch = buf[count])) {
+ checksum += ch;
+ count++;
+ }
+ strcat(get_buf, "#");
+ get_buf[count + 2] = hexchars[checksum >> 4];
+ get_buf[count + 3] = hexchars[checksum & 0xf];
+ get_buf[count + 4] = '\0';
+ v2printk("get%i: %s\n", ts.idx, get_buf);
+}
+
+static int validate_simple_test(char *put_str)
+{
+ char *chk_str;
+
+ if (ts.tst[ts.idx].put_handler)
+ return ts.tst[ts.idx].put_handler(put_str,
+ ts.tst[ts.idx].put);
+
+ chk_str = ts.tst[ts.idx].put;
+ if (*put_str == '$')
+ put_str++;
+
+ while (*chk_str != '\0' && *put_str != '\0') {
+ /* If someone does a * to match the rest of the string, allow
+ * it, or stop if the recieved string is complete.
+ */
+ if (*put_str == '#' || *chk_str == '*')
+ return 0;
+ if (*put_str != *chk_str)
+ return 1;
+
+ chk_str++;
+ put_str++;
+ }
+ if (*chk_str == '\0' && (*put_str == '\0' || *put_str == '#'))
+ return 0;
+
+ return 1;
+}
+
+static int run_simple_test(int is_get_char, int chr)
+{
+ int ret = 0;
+ if (is_get_char) {
+ /* Send an ACK on the get if a prior put completed and set the
+ * send ack variable
+ */
+ if (send_ack) {
+ send_ack = 0;
+ return '+';
+ }
+ /* On the first get char, fill the transmit buffer and then
+ * take from the get_string.
+ */
+ if (get_buf_cnt == 0) {
+ if (ts.tst[ts.idx].get_handler)
+ ts.tst[ts.idx].get_handler(ts.tst[ts.idx].get);
+ else
+ fill_get_buf(ts.tst[ts.idx].get);
+ }
+
+ if (get_buf[get_buf_cnt] == '\0') {
+ eprintk("kgdbts: ERROR GET: EOB on '%s' at %i\n",
+ ts.name, ts.idx);
+ get_buf_cnt = 0;
+ fill_get_buf("D");
+ }
+ ret = get_buf[get_buf_cnt];
+ get_buf_cnt++;
+ return ret;
+ }
+
+ /* This callback is a put char which is when kgdb sends data to
+ * this I/O module.
+ */
+ if (ts.tst[ts.idx].get[0] == '\0' &&
+ ts.tst[ts.idx].put[0] == '\0') {
+ eprintk("kgdbts: ERROR: beyond end of test on"
+ " '%s' line %i\n", ts.name, ts.idx);
+ return 0;
+ }
+
+ if (put_buf_cnt >= BUFMAX) {
+ eprintk("kgdbts: ERROR: put buffer overflow on"
+ " '%s' line %i\n", ts.name, ts.idx);
+ put_buf_cnt = 0;
+ return 0;
+ }
+ /* Ignore everything until the first valid packet start '$' */
+ if (put_buf_cnt == 0 && chr != '$')
+ return 0;
+
+ put_buf[put_buf_cnt] = chr;
+ put_buf_cnt++;
+
+ /* End of packet == #XX so look for the '#' */
+ if (put_buf_cnt > 3 && put_buf[put_buf_cnt - 3] == '#') {
+ put_buf[put_buf_cnt] = '\0';
+ v2printk("put%i: %s\n", ts.idx, put_buf);
+ /* Trigger check here */
+ if (ts.validate_put && ts.validate_put(put_buf)) {
+ eprintk("kgdbts: ERROR PUT: end of test "
+ "buffer on '%s' line %i expected %s got %s\n",
+ ts.name, ts.idx, ts.tst[ts.idx].put, put_buf);
+ }
+ ts.idx++;
+ put_buf_cnt = 0;
+ get_buf_cnt = 0;
+ send_ack = 1;
+ }
+ return 0;
+}
+
+static void init_simple_test(void)
+{
+ memset(&ts, 0, sizeof(ts));
+ ts.run_test = run_simple_test;
+ ts.validate_put = validate_simple_test;
+}
+
+static void run_plant_and_detach_test(int is_early)
+{
+ char before[BREAK_INSTR_SIZE];
+ char after[BREAK_INSTR_SIZE];
+
+ probe_kernel_read(before, (char *)kgdbts_break_test,
+ BREAK_INSTR_SIZE);
+ init_simple_test();
+ ts.tst = plant_and_detach_test;
+ ts.name = "plant_and_detach_test";
+ /* Activate test with initial breakpoint */
+ if (!is_early)
+ kgdb_breakpoint();
+ probe_kernel_read(after, (char *)kgdbts_break_test,
+ BREAK_INSTR_SIZE);
+ if (memcmp(before, after, BREAK_INSTR_SIZE)) {
+ printk(KERN_CRIT "kgdbts: ERROR kgdb corrupted memory\n");
+ panic("kgdb memory corruption");
+ }
+
+ /* complete the detach test */
+ if (!is_early)
+ kgdbts_break_test();
+}
+
+static void run_breakpoint_test(int is_hw_breakpoint)
+{
+ test_complete = 0;
+ init_simple_test();
+ if (is_hw_breakpoint) {
+ ts.tst = hw_breakpoint_test;
+ ts.name = "hw_breakpoint_test";
+ } else {
+ ts.tst = sw_breakpoint_test;
+ ts.name = "sw_breakpoint_test";
+ }
+ /* Activate test with initial breakpoint */
+ kgdb_breakpoint();
+ /* run code with the break point in it */
+ kgdbts_break_test();
+ kgdb_breakpoint();
+
+ if (test_complete)
+ return;
+
+ eprintk("kgdbts: ERROR %s test failed\n", ts.name);
+}
+
+static void run_hw_break_test(int is_write_test)
+{
+ test_complete = 0;
+ init_simple_test();
+ if (is_write_test) {
+ ts.tst = hw_write_break_test;
+ ts.name = "hw_write_break_test";
+ } else {
+ ts.tst = hw_access_break_test;
+ ts.name = "hw_access_break_test";
+ }
+ /* Activate test with initial breakpoint */
+ kgdb_breakpoint();
+ hw_break_val_access();
+ if (is_write_test) {
+ if (test_complete == 2)
+ eprintk("kgdbts: ERROR %s broke on access\n",
+ ts.name);
+ hw_break_val_write();
+ }
+ kgdb_breakpoint();
+
+ if (test_complete == 1)
+ return;
+
+ eprintk("kgdbts: ERROR %s test failed\n", ts.name);
+}
+
+static void run_nmi_sleep_test(int nmi_sleep)
+{
+ unsigned long flags;
+
+ init_simple_test();
+ ts.tst = nmi_sleep_test;
+ ts.name = "nmi_sleep_test";
+ /* Activate test with initial breakpoint */
+ kgdb_breakpoint();
+ local_irq_save(flags);
+ mdelay(nmi_sleep*1000);
+ touch_nmi_watchdog();
+ local_irq_restore(flags);
+ if (test_complete != 2)
+ eprintk("kgdbts: ERROR nmi_test did not hit nmi\n");
+ kgdb_breakpoint();
+ if (test_complete == 1)
+ return;
+
+ eprintk("kgdbts: ERROR %s test failed\n", ts.name);
+}
+
+static void run_bad_read_test(void)
+{
+ init_simple_test();
+ ts.tst = bad_read_test;
+ ts.name = "bad_read_test";
+ /* Activate test with initial breakpoint */
+ kgdb_breakpoint();
+}
+
+static void run_do_fork_test(void)
+{
+ init_simple_test();
+ ts.tst = do_fork_test;
+ ts.name = "do_fork_test";
+ /* Activate test with initial breakpoint */
+ kgdb_breakpoint();
+}
+
+static void run_sys_open_test(void)
+{
+ init_simple_test();
+ ts.tst = sys_open_test;
+ ts.name = "sys_open_test";
+ /* Activate test with initial breakpoint */
+ kgdb_breakpoint();
+}
+
+static void run_singlestep_break_test(void)
+{
+ init_simple_test();
+ ts.tst = singlestep_break_test;
+ ts.name = "singlestep_breakpoint_test";
+ /* Activate test with initial breakpoint */
+ kgdb_breakpoint();
+ kgdbts_break_test();
+ kgdbts_break_test();
+}
+
+static void kgdbts_run_tests(void)
+{
+ char *ptr;
+ int fork_test = 0;
+ int sys_open_test = 0;
+ int nmi_sleep = 0;
+
+ ptr = strstr(config, "F");
+ if (ptr)
+ fork_test = simple_strtol(ptr+1, NULL, 10);
+ ptr = strstr(config, "S");
+ if (ptr)
+ sys_open_test = simple_strtol(ptr+1, NULL, 10);
+ ptr = strstr(config, "N");
+ if (ptr)
+ nmi_sleep = simple_strtol(ptr+1, NULL, 10);
+
+ /* required internal KGDB tests */
+ v1printk("kgdbts:RUN plant and detach test\n");
+ run_plant_and_detach_test(0);
+ v1printk("kgdbts:RUN sw breakpoint test\n");
+ run_breakpoint_test(0);
+ v1printk("kgdbts:RUN bad memory access test\n");
+ run_bad_read_test();
+ v1printk("kgdbts:RUN singlestep breakpoint test\n");
+ run_singlestep_break_test();
+
+ /* ===Optional tests=== */
+
+ /* All HW break point tests */
+ if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT) {
+ v1printk("kgdbts:RUN hw breakpoint test\n");
+ run_breakpoint_test(1);
+ v1printk("kgdbts:RUN hw write breakpoint test\n");
+ run_hw_break_test(1);
+ v1printk("kgdbts:RUN access write breakpoint test\n");
+ run_hw_break_test(0);
+ }
+
+ if (nmi_sleep) {
+ v1printk("kgdbts:RUN NMI sleep %i seconds test\n", nmi_sleep);
+ run_nmi_sleep_test(nmi_sleep);
+ }
+
+ /* If the do_fork test is run it will be the last test that is
+ * executed because a kernel thread will be spawned at the very
+ * end to unregister the debug hooks.
+ */
+ if (fork_test) {
+ repeat_test = fork_test;
+ printk(KERN_INFO "kgdbts:RUN do_fork for %i breakpoints\n",
+ repeat_test);
+ kthread_run(kgdbts_unreg_thread, 0, "kgdbts_unreg");
+ run_do_fork_test();
+ return;
+ }
+
+ /* If the sys_open test is run it will be the last test that is
+ * executed because a kernel thread will be spawned at the very
+ * end to unregister the debug hooks.
+ */
+ if (sys_open_test) {
+ repeat_test = sys_open_test;
+ printk(KERN_INFO "kgdbts:RUN sys_open for %i breakpoints\n",
+ repeat_test);
+ kthread_run(kgdbts_unreg_thread, 0, "kgdbts_unreg");
+ run_sys_open_test();
+ return;
+ }
+ /* Shutdown and unregister */
+ kgdb_unregister_io_module(&kgdbts_io_ops);
+ configured = 0;
+}
+
+static int kgdbts_option_setup(char *opt)
+{
+ if (strlen(opt) > MAX_CONFIG_LEN) {
+ printk(KERN_ERR "kgdbts: config string too long\n");
+ return -ENOSPC;
+ }
+ strcpy(config, opt);
+
+ verbose = 0;
+ if (strstr(config, "V1"))
+ verbose = 1;
+ if (strstr(config, "V2"))
+ verbose = 2;
+
+ return 0;
+}
+
+__setup("kgdbts=", kgdbts_option_setup);
+
+static int configure_kgdbts(void)
+{
+ int err = 0;
+
+ if (!strlen(config) || isspace(config[0]))
+ goto noconfig;
+ err = kgdbts_option_setup(config);
+ if (err)
+ goto noconfig;
+
+ final_ack = 0;
+ run_plant_and_detach_test(1);
+
+ err = kgdb_register_io_module(&kgdbts_io_ops);
+ if (err) {
+ configured = 0;
+ return err;
+ }
+ configured = 1;
+ kgdbts_run_tests();
+
+ return err;
+
+noconfig:
+ config[0] = 0;
+ configured = 0;
+
+ return err;
+}
+
+static int __init init_kgdbts(void)
+{
+ /* Already configured? */
+ if (configured == 1)
+ return 0;
+
+ return configure_kgdbts();
+}
+
+static void cleanup_kgdbts(void)
+{
+ if (configured == 1)
+ kgdb_unregister_io_module(&kgdbts_io_ops);
+}
+
+static int kgdbts_get_char(void)
+{
+ int val = 0;
+
+ if (ts.run_test)
+ val = ts.run_test(1, 0);
+
+ return val;
+}
+
+static void kgdbts_put_char(u8 chr)
+{
+ if (ts.run_test)
+ ts.run_test(0, chr);
+}
+
+static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp)
+{
+ int len = strlen(kmessage);
+
+ if (len >= MAX_CONFIG_LEN) {
+ printk(KERN_ERR "kgdbts: config string too long\n");
+ return -ENOSPC;
+ }
+
+ /* Only copy in the string if the init function has not run yet */
+ if (configured < 0) {
+ strcpy(config, kmessage);
+ return 0;
+ }
+
+ if (kgdb_connected) {
+ printk(KERN_ERR
+ "kgdbts: Cannot reconfigure while KGDB is connected.\n");
+
+ return -EBUSY;
+ }
+
+ strcpy(config, kmessage);
+ /* Chop out \n char as a result of echo */
+ if (config[len - 1] == '\n')
+ config[len - 1] = '\0';
+
+ if (configured == 1)
+ cleanup_kgdbts();
+
+ /* Go and configure with the new params. */
+ return configure_kgdbts();
+}
+
+static void kgdbts_pre_exp_handler(void)
+{
+ /* Increment the module count when the debugger is active */
+ if (!kgdb_connected)
+ try_module_get(THIS_MODULE);
+}
+
+static void kgdbts_post_exp_handler(void)
+{
+ /* decrement the module count when the debugger detaches */
+ if (!kgdb_connected)
+ module_put(THIS_MODULE);
+}
+
+static struct kgdb_io kgdbts_io_ops = {
+ .name = "kgdbts",
+ .read_char = kgdbts_get_char,
+ .write_char = kgdbts_put_char,
+ .pre_exception = kgdbts_pre_exp_handler,
+ .post_exception = kgdbts_post_exp_handler,
+};
+
+module_init(init_kgdbts);
+module_exit(cleanup_kgdbts);
+module_param_call(kgdbts, param_set_kgdbts_var, param_get_string, &kps, 0644);
+MODULE_PARM_DESC(kgdbts, "<A|V1|V2>[F#|S#][N#]");
+MODULE_DESCRIPTION("KGDB Test Suite");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Wind River Systems, Inc.");
+
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index c884730c5ea..1bfe5d16963 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -197,7 +197,7 @@ static int lkdtm_parse_commandline(void)
{
int i;
- if (cpoint_name == INVALID || cpoint_type == NONE ||
+ if (cpoint_name == NULL || cpoint_type == NULL ||
cpoint_count < 1 || recur_count < 1)
return -EINVAL;
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index 899e3f75f28..02ff3d19b1c 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -315,7 +315,7 @@ static void sony_laptop_report_input_event(u8 event)
break;
default:
- if (event > ARRAY_SIZE(sony_laptop_input_index)) {
+ if (event >= ARRAY_SIZE(sony_laptop_input_index)) {
dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
break;
}
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index e2c7edd206a..6cb781262f9 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -221,6 +221,7 @@ static struct {
u32 hotkey:1;
u32 hotkey_mask:1;
u32 hotkey_wlsw:1;
+ u32 hotkey_tablet:1;
u32 light:1;
u32 light_status:1;
u32 bright_16levels:1;
@@ -301,6 +302,13 @@ TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
"HKEY", /* all others */
); /* 570 */
+TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
+ "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
+ "\\_SB.PCI0.VID0", /* 770e */
+ "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
+ "\\_SB.PCI0.AGP.VID", /* all others */
+ ); /* R30, R31 */
+
/*************************************************************************
* ACPI helpers
@@ -1053,6 +1061,9 @@ static struct attribute_set *hotkey_dev_attributes;
#define HOTKEY_CONFIG_CRITICAL_END
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+/* HKEY.MHKG() return bits */
+#define TP_HOTKEY_TABLET_MASK (1 << 3)
+
static int hotkey_get_wlsw(int *status)
{
if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
@@ -1060,6 +1071,17 @@ static int hotkey_get_wlsw(int *status)
return 0;
}
+static int hotkey_get_tablet_mode(int *status)
+{
+ int s;
+
+ if (!acpi_evalf(hkey_handle, &s, "MHKG", "d"))
+ return -EIO;
+
+ *status = ((s & TP_HOTKEY_TABLET_MASK) != 0);
+ return 0;
+}
+
/*
* Call with hotkey_mutex held
*/
@@ -1154,15 +1176,31 @@ static void tpacpi_input_send_radiosw(void)
{
int wlsw;
- mutex_lock(&tpacpi_inputdev_send_mutex);
-
if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
+ mutex_lock(&tpacpi_inputdev_send_mutex);
+
input_report_switch(tpacpi_inputdev,
SW_RADIO, !!wlsw);
input_sync(tpacpi_inputdev);
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
}
+}
+
+static void tpacpi_input_send_tabletsw(void)
+{
+ int state;
+
+ if (tp_features.hotkey_tablet &&
+ !hotkey_get_tablet_mode(&state)) {
+ mutex_lock(&tpacpi_inputdev_send_mutex);
- mutex_unlock(&tpacpi_inputdev_send_mutex);
+ input_report_switch(tpacpi_inputdev,
+ SW_TABLET_MODE, !!state);
+ input_sync(tpacpi_inputdev);
+
+ mutex_unlock(&tpacpi_inputdev_send_mutex);
+ }
}
static void tpacpi_input_send_key(unsigned int scancode)
@@ -1417,6 +1455,14 @@ static void hotkey_poll_setup_safe(int may_warn)
mutex_unlock(&hotkey_mutex);
}
+#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
+static void hotkey_poll_setup_safe(int __unused)
+{
+}
+
+#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
+
static int hotkey_inputdev_open(struct input_dev *dev)
{
switch (tpacpi_lifecycle) {
@@ -1444,7 +1490,6 @@ static void hotkey_inputdev_close(struct input_dev *dev)
if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
hotkey_poll_setup_safe(0);
}
-#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
/* sysfs hotkey enable ------------------------------------------------- */
static ssize_t hotkey_enable_show(struct device *dev,
@@ -1666,6 +1711,29 @@ static void hotkey_radio_sw_notify_change(void)
"hotkey_radio_sw");
}
+/* sysfs hotkey tablet mode (pollable) --------------------------------- */
+static ssize_t hotkey_tablet_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int res, s;
+ res = hotkey_get_tablet_mode(&s);
+ if (res < 0)
+ return res;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
+}
+
+static struct device_attribute dev_attr_hotkey_tablet_mode =
+ __ATTR(hotkey_tablet_mode, S_IRUGO, hotkey_tablet_mode_show, NULL);
+
+static void hotkey_tablet_mode_notify_change(void)
+{
+ if (tp_features.hotkey_tablet)
+ sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
+ "hotkey_tablet_mode");
+}
+
/* sysfs hotkey report_mode -------------------------------------------- */
static ssize_t hotkey_report_mode_show(struct device *dev,
struct device_attribute *attr,
@@ -1878,7 +1946,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
str_supported(tp_features.hotkey));
if (tp_features.hotkey) {
- hotkey_dev_attributes = create_attr_set(12, NULL);
+ hotkey_dev_attributes = create_attr_set(13, NULL);
if (!hotkey_dev_attributes)
return -ENOMEM;
res = add_many_to_attr_set(hotkey_dev_attributes,
@@ -1957,6 +2025,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
&dev_attr_hotkey_radio_sw.attr);
}
+ /* For X41t, X60t, X61t Tablets... */
+ if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
+ tp_features.hotkey_tablet = 1;
+ printk(TPACPI_INFO
+ "possible tablet mode switch found; "
+ "ThinkPad in %s mode\n",
+ (status & TP_HOTKEY_TABLET_MASK)?
+ "tablet" : "laptop");
+ res = add_to_attr_set(hotkey_dev_attributes,
+ &dev_attr_hotkey_tablet_mode.attr);
+ }
+
if (!res)
res = register_attr_set_with_sysfs(
hotkey_dev_attributes,
@@ -2006,6 +2086,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
set_bit(EV_SW, tpacpi_inputdev->evbit);
set_bit(SW_RADIO, tpacpi_inputdev->swbit);
}
+ if (tp_features.hotkey_tablet) {
+ set_bit(EV_SW, tpacpi_inputdev->evbit);
+ set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
+ }
dbg_printk(TPACPI_DBG_INIT,
"enabling hot key handling\n");
@@ -2023,12 +2107,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
(hotkey_report_mode < 2) ?
"enabled" : "disabled");
-#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
tpacpi_inputdev->open = &hotkey_inputdev_open;
tpacpi_inputdev->close = &hotkey_inputdev_close;
hotkey_poll_setup_safe(1);
-#endif
+ tpacpi_input_send_radiosw();
+ tpacpi_input_send_tabletsw();
}
return (tp_features.hotkey)? 0 : 1;
@@ -2156,11 +2240,15 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
/* 0x5000-0x5FFF: human interface helpers */
switch (hkey) {
case 0x5010: /* Lenovo new BIOS: brightness changed */
- case 0x5009: /* X61t: swivel up (tablet mode) */
- case 0x500a: /* X61t: swivel down (normal mode) */
case 0x500b: /* X61t: tablet pen inserted into bay */
case 0x500c: /* X61t: tablet pen removed from bay */
break;
+ case 0x5009: /* X41t-X61t: swivel up (tablet mode) */
+ case 0x500a: /* X41t-X61t: swivel down (normal mode) */
+ tpacpi_input_send_tabletsw();
+ hotkey_tablet_mode_notify_change();
+ send_acpi_ev = 0;
+ break;
case 0x5001:
case 0x5002:
/* LID switch events. Do not propagate */
@@ -2219,11 +2307,10 @@ static void hotkey_resume(void)
"from firmware\n");
tpacpi_input_send_radiosw();
hotkey_radio_sw_notify_change();
+ hotkey_tablet_mode_notify_change();
hotkey_wakeup_reason_notify_change();
hotkey_wakeup_hotunplug_complete_notify_change();
-#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
hotkey_poll_setup_safe(0);
-#endif
}
/* procfs -------------------------------------------------------------- */
@@ -2676,6 +2763,8 @@ static struct ibm_struct wan_driver_data = {
* Video subdriver
*/
+#ifdef CONFIG_THINKPAD_ACPI_VIDEO
+
enum video_access_mode {
TPACPI_VIDEO_NONE = 0,
TPACPI_VIDEO_570, /* 570 */
@@ -2703,13 +2792,6 @@ static int video_orig_autosw;
static int video_autosw_get(void);
static int video_autosw_set(int enable);
-TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
- "\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
- "\\_SB.PCI0.VID0", /* 770e */
- "\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
- "\\_SB.PCI0.AGP.VID", /* all others */
- ); /* R30, R31 */
-
TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
static int __init video_init(struct ibm_init_struct *iibm)
@@ -3019,6 +3101,8 @@ static struct ibm_struct video_driver_data = {
.exit = video_exit,
};
+#endif /* CONFIG_THINKPAD_ACPI_VIDEO */
+
/*************************************************************************
* Light (thinklight) subdriver
*/
@@ -5803,10 +5887,12 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = wan_init,
.data = &wan_driver_data,
},
+#ifdef CONFIG_THINKPAD_ACPI_VIDEO
{
.init = video_init,
.data = &video_driver_data,
},
+#endif
{
.init = light_init,
.data = &light_driver_data,
@@ -5918,7 +6004,7 @@ MODULE_PARM_DESC(hotkey_report_mode,
#define TPACPI_PARAM(feature) \
module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
- MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \
+ MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \
"at module load, see documentation")
TPACPI_PARAM(hotkey);
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
index 63a089b2954..67503ea71d2 100644
--- a/drivers/misc/tifm_7xx1.c
+++ b/drivers/misc/tifm_7xx1.c
@@ -368,6 +368,8 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
goto err_out_irq;
writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
fm->addr + FM_SET_INTERRUPT_ENABLE);
return 0;