mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 18:11:56 +00:00
51fac8388a
The second argument of ACPI driver .remove() operation is only used by the ACPI processor driver and the value passed to that driver through it is always available from the given struct acpi_device object's removal_type field. For this reason, the second ACPI driver .remove() argument is in fact useless, so drop it. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Jiang Liu <jiang.liu@huawei.com> Acked-by: Toshi Kani <toshi.kani@hp.com> Acked-by: Yinghai Lu <yinghai@kernel.org>
174 lines
4.0 KiB
C
174 lines
4.0 KiB
C
/*
|
|
* OLPC XO-1.5 ebook switch driver
|
|
* (based on generic ACPI button driver)
|
|
*
|
|
* Copyright (C) 2009 Paul Fox <pgf@laptop.org>
|
|
* Copyright (C) 2010 One Laptop per Child
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or (at
|
|
* your option) any later version.
|
|
*/
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/types.h>
|
|
#include <linux/input.h>
|
|
#include <acpi/acpi_bus.h>
|
|
#include <acpi/acpi_drivers.h>
|
|
|
|
#define MODULE_NAME "xo15-ebook"
|
|
|
|
#define XO15_EBOOK_CLASS MODULE_NAME
|
|
#define XO15_EBOOK_TYPE_UNKNOWN 0x00
|
|
#define XO15_EBOOK_NOTIFY_STATUS 0x80
|
|
|
|
#define XO15_EBOOK_SUBCLASS "ebook"
|
|
#define XO15_EBOOK_HID "XO15EBK"
|
|
#define XO15_EBOOK_DEVICE_NAME "EBook Switch"
|
|
|
|
ACPI_MODULE_NAME(MODULE_NAME);
|
|
|
|
MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
static const struct acpi_device_id ebook_device_ids[] = {
|
|
{ XO15_EBOOK_HID, 0 },
|
|
{ "", 0 },
|
|
};
|
|
MODULE_DEVICE_TABLE(acpi, ebook_device_ids);
|
|
|
|
struct ebook_switch {
|
|
struct input_dev *input;
|
|
char phys[32]; /* for input device */
|
|
};
|
|
|
|
static int ebook_send_state(struct acpi_device *device)
|
|
{
|
|
struct ebook_switch *button = acpi_driver_data(device);
|
|
unsigned long long state;
|
|
acpi_status status;
|
|
|
|
status = acpi_evaluate_integer(device->handle, "EBK", NULL, &state);
|
|
if (ACPI_FAILURE(status))
|
|
return -EIO;
|
|
|
|
/* input layer checks if event is redundant */
|
|
input_report_switch(button->input, SW_TABLET_MODE, !state);
|
|
input_sync(button->input);
|
|
return 0;
|
|
}
|
|
|
|
static void ebook_switch_notify(struct acpi_device *device, u32 event)
|
|
{
|
|
switch (event) {
|
|
case ACPI_FIXED_HARDWARE_EVENT:
|
|
case XO15_EBOOK_NOTIFY_STATUS:
|
|
ebook_send_state(device);
|
|
break;
|
|
default:
|
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
|
"Unsupported event [0x%x]\n", event));
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_PM_SLEEP
|
|
static int ebook_switch_resume(struct device *dev)
|
|
{
|
|
return ebook_send_state(to_acpi_device(dev));
|
|
}
|
|
#endif
|
|
|
|
static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume);
|
|
|
|
static int ebook_switch_add(struct acpi_device *device)
|
|
{
|
|
struct ebook_switch *button;
|
|
struct input_dev *input;
|
|
const char *hid = acpi_device_hid(device);
|
|
char *name, *class;
|
|
int error;
|
|
|
|
button = kzalloc(sizeof(struct ebook_switch), GFP_KERNEL);
|
|
if (!button)
|
|
return -ENOMEM;
|
|
|
|
device->driver_data = button;
|
|
|
|
button->input = input = input_allocate_device();
|
|
if (!input) {
|
|
error = -ENOMEM;
|
|
goto err_free_button;
|
|
}
|
|
|
|
name = acpi_device_name(device);
|
|
class = acpi_device_class(device);
|
|
|
|
if (strcmp(hid, XO15_EBOOK_HID)) {
|
|
pr_err("Unsupported hid [%s]\n", hid);
|
|
error = -ENODEV;
|
|
goto err_free_input;
|
|
}
|
|
|
|
strcpy(name, XO15_EBOOK_DEVICE_NAME);
|
|
sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS);
|
|
|
|
snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
|
|
|
|
input->name = name;
|
|
input->phys = button->phys;
|
|
input->id.bustype = BUS_HOST;
|
|
input->dev.parent = &device->dev;
|
|
|
|
input->evbit[0] = BIT_MASK(EV_SW);
|
|
set_bit(SW_TABLET_MODE, input->swbit);
|
|
|
|
error = input_register_device(input);
|
|
if (error)
|
|
goto err_free_input;
|
|
|
|
ebook_send_state(device);
|
|
|
|
if (device->wakeup.flags.valid) {
|
|
/* Button's GPE is run-wake GPE */
|
|
acpi_enable_gpe(device->wakeup.gpe_device,
|
|
device->wakeup.gpe_number);
|
|
device_set_wakeup_enable(&device->dev, true);
|
|
}
|
|
|
|
return 0;
|
|
|
|
err_free_input:
|
|
input_free_device(input);
|
|
err_free_button:
|
|
kfree(button);
|
|
return error;
|
|
}
|
|
|
|
static int ebook_switch_remove(struct acpi_device *device)
|
|
{
|
|
struct ebook_switch *button = acpi_driver_data(device);
|
|
|
|
input_unregister_device(button->input);
|
|
kfree(button);
|
|
return 0;
|
|
}
|
|
|
|
static struct acpi_driver xo15_ebook_driver = {
|
|
.name = MODULE_NAME,
|
|
.class = XO15_EBOOK_CLASS,
|
|
.ids = ebook_device_ids,
|
|
.ops = {
|
|
.add = ebook_switch_add,
|
|
.remove = ebook_switch_remove,
|
|
.notify = ebook_switch_notify,
|
|
},
|
|
.drv.pm = &ebook_switch_pm,
|
|
};
|
|
module_acpi_driver(xo15_ebook_driver);
|