diff options
Diffstat (limited to 'drivers/staging/quickstart/quickstart.c')
| -rw-r--r-- | drivers/staging/quickstart/quickstart.c | 384 | 
1 files changed, 185 insertions, 199 deletions
diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c index d746715d3d8..a85c3d68c46 100644 --- a/drivers/staging/quickstart/quickstart.c +++ b/drivers/staging/quickstart/quickstart.c @@ -4,8 +4,8 @@   *   *  Copyright (C) 2007-2010 Angelo Arrifano <miknix@gmail.com>   * - *  Information gathered from disassebled dsdt and from here: - *  <http://www.microsoft.com/whdc/system/platform/firmware/DirAppLaunch.mspx>  + *  Information gathered from disassembled dsdt and from here: + *  <http://www.microsoft.com/whdc/system/platform/firmware/DirAppLaunch.mspx>   *   *  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 @@ -23,13 +23,15 @@   *   */ -#define QUICKSTART_VERSION "1.03" +#define QUICKSTART_VERSION "1.04" + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/init.h>  #include <linux/types.h> -#include <acpi/acpi_drivers.h> +#include <linux/acpi.h>  #include <linux/platform_device.h>  #include <linux/input.h> @@ -37,117 +39,71 @@ MODULE_AUTHOR("Angelo Arrifano");  MODULE_DESCRIPTION("ACPI Direct App Launch driver");  MODULE_LICENSE("GPL"); -#define QUICKSTART_ACPI_DEVICE_NAME   "quickstart" -#define QUICKSTART_ACPI_CLASS         "quickstart" -#define QUICKSTART_ACPI_HID           "PNP0C32" - -#define QUICKSTART_PF_DRIVER_NAME     "quickstart" -#define QUICKSTART_PF_DEVICE_NAME     "quickstart" -#define QUICKSTART_PF_DEVATTR_NAME    "pressed_button" +#define QUICKSTART_ACPI_DEVICE_NAME	"quickstart" +#define QUICKSTART_ACPI_CLASS		"quickstart" +#define QUICKSTART_ACPI_HID		"PNP0C32" -#define QUICKSTART_MAX_BTN_NAME_LEN   16 +#define QUICKSTART_PF_DRIVER_NAME	"quickstart" +#define QUICKSTART_PF_DEVICE_NAME	"quickstart" -/* There will be two events: -	 * 0x02 - A hot button was pressed while device was off/sleeping. -	 * 0x80 - A hot button was pressed while device was up. */ -#define QUICKSTART_EVENT_WAKE         0x02 -#define QUICKSTART_EVENT_RUNTIME      0x80 +/* + * There will be two events: + * 0x02 - A hot button was pressed while device was off/sleeping. + * 0x80 - A hot button was pressed while device was up. + */ +#define QUICKSTART_EVENT_WAKE		0x02 +#define QUICKSTART_EVENT_RUNTIME	0x80 -struct quickstart_btn { +struct quickstart_button {  	char *name;  	unsigned int id; -	struct quickstart_btn *next; +	struct list_head list;  }; -static struct quickstart_driver_data { -	struct quickstart_btn *btn_lst; -	struct quickstart_btn *pressed; -} quickstart_data; - -/* ACPI driver Structs */  struct quickstart_acpi {  	struct acpi_device *device; -	struct quickstart_btn *btn; -}; -static int quickstart_acpi_add(struct acpi_device *device); -static int quickstart_acpi_remove(struct acpi_device *device, int type); -static const struct acpi_device_id  quickstart_device_ids[] = { -	{QUICKSTART_ACPI_HID, 0}, -	{"", 0}, +	struct quickstart_button *button;  }; -static struct acpi_driver quickstart_acpi_driver = { -	.name = "quickstart", -	.class = QUICKSTART_ACPI_CLASS, -	.ids = quickstart_device_ids, -	.ops = { -			.add = quickstart_acpi_add, -			.remove = quickstart_acpi_remove, -		}, -}; - -/* Input device structs */ -struct input_dev *quickstart_input; +static LIST_HEAD(buttons); +static struct quickstart_button *pressed; -/* Platform driver structs */ -static ssize_t buttons_show(struct device *dev, -					struct device_attribute *attr, -					char *buf); -static ssize_t pressed_button_show(struct device *dev, -					struct device_attribute *attr, -					char *buf); -static ssize_t pressed_button_store(struct device *dev, -					struct device_attribute *attr, -					 const char *buf, -					 size_t count); -static DEVICE_ATTR(pressed_button, 0666, pressed_button_show, -					 pressed_button_store); -static DEVICE_ATTR(buttons, 0444, buttons_show, NULL); -static struct platform_device *pf_device; -static struct platform_driver pf_driver = { -	.driver = { -		.name = QUICKSTART_PF_DRIVER_NAME, -		.owner = THIS_MODULE, -	} -}; +static struct input_dev *quickstart_input; -/* - * Platform driver functions - */ -static ssize_t buttons_show(struct device *dev, -					 struct device_attribute *attr, -					 char *buf) +/* Platform driver functions */ +static ssize_t buttons_show(struct device *dev, struct device_attribute *attr, +			    char *buf)  {  	int count = 0; -	struct quickstart_btn *ptr = quickstart_data.btn_lst; +	struct quickstart_button *b; -	if (!ptr) +	if (list_empty(&buttons))  		return snprintf(buf, PAGE_SIZE, "none"); -	while (ptr && (count < PAGE_SIZE)) { -		if (ptr->name) { -			count += snprintf(buf + count, -					PAGE_SIZE - count, -					"%d\t%s\n", ptr->id, ptr->name); +	list_for_each_entry(b, &buttons, list) { +		count += snprintf(buf + count, PAGE_SIZE - count, "%u\t%s\n", +							b->id, b->name); + +		if (count >= PAGE_SIZE) { +			count = PAGE_SIZE; +			break;  		} -		ptr = ptr->next;  	}  	return count;  }  static ssize_t pressed_button_show(struct device *dev, -					struct device_attribute *attr, -					char *buf) +				   struct device_attribute *attr, char *buf)  { -	return snprintf(buf, PAGE_SIZE, "%s\n", -		(quickstart_data.pressed?quickstart_data.pressed->name:"none")); +	return scnprintf(buf, PAGE_SIZE, "%s\n", +					(pressed ? pressed->name : "none"));  }  static ssize_t pressed_button_store(struct device *dev, -					 struct device_attribute *attr, -					 const char *buf, size_t count) +				    struct device_attribute *attr, +				    const char *buf, size_t count)  {  	if (count < 2)  		return -EINVAL; @@ -155,60 +111,40 @@ static ssize_t pressed_button_store(struct device *dev,  	if (strncasecmp(buf, "none", 4) != 0)  		return -EINVAL; -	quickstart_data.pressed = NULL; +	pressed = NULL;  	return count;  } -/* Hotstart Helper functions */ -static int quickstart_btnlst_add(struct quickstart_btn **data) +/* Helper functions */ +static struct quickstart_button *quickstart_buttons_add(void)  { -	struct quickstart_btn **ptr = &quickstart_data.btn_lst; +	struct quickstart_button *b; -	while (*ptr) -		ptr = &((*ptr)->next); +	b = kzalloc(sizeof(*b), GFP_KERNEL); +	if (!b) +		return NULL; -	*ptr = kzalloc(sizeof(struct quickstart_btn), GFP_KERNEL); -	if (!*ptr) { -		*data = NULL; -		return -ENOMEM; -	} -	*data = *ptr; +	list_add_tail(&b->list, &buttons); -	return 0; +	return b;  } -static void quickstart_btnlst_del(struct quickstart_btn *data) +static void quickstart_button_del(struct quickstart_button *data)  { -	struct quickstart_btn **ptr = &quickstart_data.btn_lst; -  	if (!data)  		return; -	while (*ptr) { -		if (*ptr == data) { -			*ptr = (*ptr)->next; -			kfree(data); -			return; -		} -		ptr = &((*ptr)->next); -	} - -	return; +	list_del(&data->list); +	kfree(data->name); +	kfree(data);  } -static void quickstart_btnlst_free(void) +static void quickstart_buttons_free(void)  { -	struct quickstart_btn *ptr = quickstart_data.btn_lst; -	struct quickstart_btn *lptr = NULL; - -	while (ptr) { -		lptr = ptr; -		ptr = ptr->next; -		kfree(lptr->name); -		kfree(lptr); -	} +	struct quickstart_button *b, *n; -	return; +	list_for_each_entry_safe(b, n, &buttons, list) +		quickstart_button_del(b);  }  /* ACPI Driver functions */ @@ -219,107 +155,137 @@ static void quickstart_acpi_notify(acpi_handle handle, u32 event, void *data)  	if (!quickstart)  		return; -	if (event == QUICKSTART_EVENT_WAKE) -		quickstart_data.pressed = quickstart->btn; -	else if (event == QUICKSTART_EVENT_RUNTIME) { -		input_report_key(quickstart_input, quickstart->btn->id, 1); +	switch (event) { +	case QUICKSTART_EVENT_WAKE: +		pressed = quickstart->button; +		break; +	case QUICKSTART_EVENT_RUNTIME: +		input_report_key(quickstart_input, quickstart->button->id, 1);  		input_sync(quickstart_input); -		input_report_key(quickstart_input, quickstart->btn->id, 0); +		input_report_key(quickstart_input, quickstart->button->id, 0);  		input_sync(quickstart_input); +		break; +	default: +		pr_err("Unexpected ACPI event notify (%u)\n", event); +		break;  	} -	return;  } -static void quickstart_acpi_ghid(struct quickstart_acpi *quickstart) +static int quickstart_acpi_ghid(struct quickstart_acpi *quickstart)  {  	acpi_status status;  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; -	uint32_t usageid = 0; - -	if (!quickstart) -		return; +	int ret = 0; -	/* This returns a buffer telling the button usage ID, -	 * and triggers pending notify events (The ones before booting). */ -	status = acpi_evaluate_object(quickstart->device->handle, -					"GHID", NULL, &buffer); -	if (ACPI_FAILURE(status) || !buffer.pointer) { -		printk(KERN_ERR "quickstart: %s GHID method failed.\n", -		       quickstart->btn->name); -		return; +	/* +	 * This returns a buffer telling the button usage ID, +	 * and triggers pending notify events (The ones before booting). +	 */ +	status = acpi_evaluate_object(quickstart->device->handle, "GHID", NULL, +								&buffer); +	if (ACPI_FAILURE(status)) { +		pr_err("%s GHID method failed\n", quickstart->button->name); +		return -EINVAL;  	} -	if (buffer.length < 8) -		return; - -	/* <<The GHID method can return a BYTE, WORD, or DWORD. +	/* +	 * <<The GHID method can return a BYTE, WORD, or DWORD.  	 * The value must be encoded in little-endian byte -	 * order (least significant byte first).>> */ -	usageid = *((uint32_t *)(buffer.pointer + (buffer.length - 8))); -	quickstart->btn->id = usageid; +	 * order (least significant byte first).>> +	 */ +	switch (buffer.length) { +	case 1: +		quickstart->button->id = *(uint8_t *)buffer.pointer; +		break; +	case 2: +		quickstart->button->id = *(uint16_t *)buffer.pointer; +		break; +	case 4: +		quickstart->button->id = *(uint32_t *)buffer.pointer; +		break; +	case 8: +		quickstart->button->id = *(uint64_t *)buffer.pointer; +		break; +	default: +		pr_err("%s GHID method returned buffer of unexpected length %lu\n", +				quickstart->button->name, +				(unsigned long)buffer.length); +		ret = -EINVAL; +		break; +	}  	kfree(buffer.pointer); + +	return ret;  } -static int quickstart_acpi_config(struct quickstart_acpi *quickstart, char *bid) +static int quickstart_acpi_config(struct quickstart_acpi *quickstart)  { -	int len = strlen(bid); -	int ret; +	char *bid = acpi_device_bid(quickstart->device); +	char *name; -	/* Add button to list */ -	ret = quickstart_btnlst_add(&quickstart->btn); -	if (ret) -		return ret; +	name = kmalloc(strlen(bid) + 1, GFP_KERNEL); +	if (!name) +		return -ENOMEM; -	quickstart->btn->name = kzalloc(len + 1, GFP_KERNEL); -	if (!quickstart->btn->name) { -		quickstart_btnlst_free(); +	/* Add new button to list */ +	quickstart->button = quickstart_buttons_add(); +	if (!quickstart->button) { +		kfree(name);  		return -ENOMEM;  	} -	strcpy(quickstart->btn->name, bid); + +	quickstart->button->name = name; +	strcpy(quickstart->button->name, bid);  	return 0;  }  static int quickstart_acpi_add(struct acpi_device *device)  { -	int ret = 0; -	acpi_status status = AE_OK; -	struct quickstart_acpi *quickstart = NULL; +	int ret; +	acpi_status status; +	struct quickstart_acpi *quickstart;  	if (!device)  		return -EINVAL; -	quickstart = kzalloc(sizeof(struct quickstart_acpi), GFP_KERNEL); +	quickstart = kzalloc(sizeof(*quickstart), GFP_KERNEL);  	if (!quickstart)  		return -ENOMEM;  	quickstart->device = device; +  	strcpy(acpi_device_name(device), QUICKSTART_ACPI_DEVICE_NAME);  	strcpy(acpi_device_class(device), QUICKSTART_ACPI_CLASS);  	device->driver_data = quickstart;  	/* Add button to list and initialize some stuff */ -	ret = quickstart_acpi_config(quickstart, acpi_device_bid(device)); -	if (ret) +	ret = quickstart_acpi_config(quickstart); +	if (ret < 0)  		goto fail_config; -	status = acpi_install_notify_handler(device->handle, -						ACPI_ALL_NOTIFY, +	status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY,  						quickstart_acpi_notify,  						quickstart);  	if (ACPI_FAILURE(status)) { -		printk(KERN_ERR "quickstart: Notify handler install error\n"); +		pr_err("Notify handler install error\n");  		ret = -ENODEV;  		goto fail_installnotify;  	} -	quickstart_acpi_ghid(quickstart); +	ret = quickstart_acpi_ghid(quickstart); +	if (ret < 0) +		goto fail_ghid;  	return 0; +fail_ghid: +	acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, +						quickstart_acpi_notify); +  fail_installnotify: -	quickstart_btnlst_del(quickstart->btn); +	quickstart_button_del(quickstart->button);  fail_config: @@ -328,34 +294,58 @@ fail_config:  	return ret;  } -static int quickstart_acpi_remove(struct acpi_device *device, int type) +static int quickstart_acpi_remove(struct acpi_device *device)  { -	acpi_status status = 0; -	struct quickstart_acpi *quickstart = NULL; +	acpi_status status; +	struct quickstart_acpi *quickstart; -	if (!device || !acpi_driver_data(device)) +	if (!device)  		return -EINVAL;  	quickstart = acpi_driver_data(device); +	if (!quickstart) +		return -EINVAL; -	status = acpi_remove_notify_handler(device->handle, -						 ACPI_ALL_NOTIFY, -					    quickstart_acpi_notify); +	status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, +						quickstart_acpi_notify);  	if (ACPI_FAILURE(status)) -		printk(KERN_ERR "quickstart: Error removing notify handler\n"); - +		pr_err("Error removing notify handler\n");  	kfree(quickstart);  	return 0;  } -/* Module functions */ +/* Platform driver structs */ +static DEVICE_ATTR_RW(pressed_button); +static DEVICE_ATTR_RO(buttons); +static struct platform_device *pf_device; +static struct platform_driver pf_driver = { +	.driver = { +		.name = QUICKSTART_PF_DRIVER_NAME, +		.owner = THIS_MODULE, +	} +}; +static const struct acpi_device_id quickstart_device_ids[] = { +	{QUICKSTART_ACPI_HID, 0}, +	{"", 0}, +}; + +static struct acpi_driver quickstart_acpi_driver = { +	.name = "quickstart", +	.class = QUICKSTART_ACPI_CLASS, +	.ids = quickstart_device_ids, +	.ops = { +			.add = quickstart_acpi_add, +			.remove = quickstart_acpi_remove, +		}, +}; + +/* Module functions */  static void quickstart_exit(void)  {  	input_unregister_device(quickstart_input); -	input_free_device(quickstart_input);  	device_remove_file(&pf_device->dev, &dev_attr_pressed_button);  	device_remove_file(&pf_device->dev, &dev_attr_buttons); @@ -366,15 +356,13 @@ static void quickstart_exit(void)  	acpi_bus_unregister_driver(&quickstart_acpi_driver); -	quickstart_btnlst_free(); - -	return; +	quickstart_buttons_free();  }  static int __init quickstart_init_input(void)  { -	struct quickstart_btn **ptr = &quickstart_data.btn_lst; -	int count; +	struct quickstart_button *b; +	int ret;  	quickstart_input = input_allocate_device(); @@ -384,31 +372,31 @@ static int __init quickstart_init_input(void)  	quickstart_input->name = "Quickstart ACPI Buttons";  	quickstart_input->id.bustype = BUS_HOST; -	while (*ptr) { -		count++; +	list_for_each_entry(b, &buttons, list) {  		set_bit(EV_KEY, quickstart_input->evbit); -		set_bit((*ptr)->id, quickstart_input->keybit); -		ptr = &((*ptr)->next); +		set_bit(b->id, quickstart_input->keybit);  	} -	return input_register_device(quickstart_input); +	ret = input_register_device(quickstart_input); +	if (ret) { +		input_free_device(quickstart_input); +		return ret; +	} + +	return 0;  }  static int __init quickstart_init(void)  {  	int ret; -	/* ACPI Check */ -	if (acpi_disabled) -		return -ENODEV; -  	/* ACPI driver register */  	ret = acpi_bus_register_driver(&quickstart_acpi_driver);  	if (ret)  		return ret;  	/* If existing bus with no devices */ -	if (!quickstart_data.btn_lst) { +	if (list_empty(&buttons)) {  		ret = -ENODEV;  		goto fail_pfdrv_reg;  	} @@ -437,14 +425,12 @@ static int __init quickstart_init(void)  	if (ret)  		goto fail_dev_file2; -  	/* Input device */  	ret = quickstart_init_input();  	if (ret)  		goto fail_input; -	printk(KERN_INFO "quickstart: ACPI Direct App Launch ver %s\n", -						QUICKSTART_VERSION); +	pr_info("ACPI Direct App Launch ver %s\n", QUICKSTART_VERSION);  	return 0;  fail_input:  | 
