16da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano/*
26da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  quickstart.c - ACPI Direct App Launch driver
36da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *
46da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *
56da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  Copyright (C) 2007-2010 Angelo Arrifano <miknix@gmail.com>
66da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *
76da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  Information gathered from disassebled dsdt and from here:
8f94fdeaa58e54c41eb6a2d8b86585e858d44c88fTimo von Holtz *  <http://www.microsoft.com/whdc/system/platform/firmware/DirAppLaunch.mspx>
96da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *
106da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  This program is free software; you can redistribute it and/or modify
116da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  it under the terms of the GNU General Public License as published by
126da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  the Free Software Foundation; either version 2 of the License, or
136da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  (at your option) any later version.
146da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *
156da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  This program is distributed in the hope that it will be useful,
166da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  but WITHOUT ANY WARRANTY; without even the implied warranty of
176da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
186da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  GNU General Public License for more details.
196da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *
206da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  You should have received a copy of the GNU General Public License
216da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  along with this program; if not, write to the Free Software
226da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
236da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano *
246da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano */
256da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
266da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#define QUICKSTART_VERSION "1.03"
276da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
286da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#include <linux/kernel.h>
296da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#include <linux/module.h>
306da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#include <linux/init.h>
316da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#include <linux/types.h>
326da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#include <acpi/acpi_drivers.h>
336da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#include <linux/platform_device.h>
346da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#include <linux/input.h>
356da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
366da4cd46902973f267fcc93325f65a93eca52ad5Angelo ArrifanoMODULE_AUTHOR("Angelo Arrifano");
376da4cd46902973f267fcc93325f65a93eca52ad5Angelo ArrifanoMODULE_DESCRIPTION("ACPI Direct App Launch driver");
386da4cd46902973f267fcc93325f65a93eca52ad5Angelo ArrifanoMODULE_LICENSE("GPL");
396da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
406da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#define QUICKSTART_ACPI_DEVICE_NAME   "quickstart"
416da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#define QUICKSTART_ACPI_CLASS         "quickstart"
426da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#define QUICKSTART_ACPI_HID           "PNP0C32"
436da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
446da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#define QUICKSTART_PF_DRIVER_NAME     "quickstart"
456da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#define QUICKSTART_PF_DEVICE_NAME     "quickstart"
466da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#define QUICKSTART_PF_DEVATTR_NAME    "pressed_button"
476da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
486da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#define QUICKSTART_MAX_BTN_NAME_LEN   16
496da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
506da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano/* There will be two events:
516da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	 * 0x02 - A hot button was pressed while device was off/sleeping.
526da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	 * 0x80 - A hot button was pressed while device was up. */
536da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#define QUICKSTART_EVENT_WAKE         0x02
546da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano#define QUICKSTART_EVENT_RUNTIME      0x80
556da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
566da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostruct quickstart_btn {
576da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	char *name;
586da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	unsigned int id;
596da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_btn *next;
606da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano};
616da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
626da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic struct quickstart_driver_data {
636da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_btn *btn_lst;
646da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_btn *pressed;
656da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano} quickstart_data;
666da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
676da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano/* ACPI driver Structs */
686da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostruct quickstart_acpi {
696da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct acpi_device *device;
706da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_btn *btn;
716da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano};
726da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic int quickstart_acpi_add(struct acpi_device *device);
736da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic int quickstart_acpi_remove(struct acpi_device *device, int type);
746da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic const struct acpi_device_id  quickstart_device_ids[] = {
756da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	{QUICKSTART_ACPI_HID, 0},
766da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	{"", 0},
776da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano};
786da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
796da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic struct acpi_driver quickstart_acpi_driver = {
806da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	.name = "quickstart",
816da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	.class = QUICKSTART_ACPI_CLASS,
826da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	.ids = quickstart_device_ids,
836da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	.ops = {
846da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano			.add = quickstart_acpi_add,
856da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano			.remove = quickstart_acpi_remove,
866da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		},
876da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano};
886da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
896da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano/* Input device structs */
906da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostruct input_dev *quickstart_input;
916da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
926da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano/* Platform driver structs */
936da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic ssize_t buttons_show(struct device *dev,
946da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					struct device_attribute *attr,
956da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					char *buf);
966da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic ssize_t pressed_button_show(struct device *dev,
976da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					struct device_attribute *attr,
986da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					char *buf);
996da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic ssize_t pressed_button_store(struct device *dev,
1006da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					struct device_attribute *attr,
1016da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					 const char *buf,
1026da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					 size_t count);
1036da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic DEVICE_ATTR(pressed_button, 0666, pressed_button_show,
1046da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					 pressed_button_store);
1056da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic DEVICE_ATTR(buttons, 0444, buttons_show, NULL);
1066da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic struct platform_device *pf_device;
1076da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic struct platform_driver pf_driver = {
1086da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	.driver = {
1096da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		.name = QUICKSTART_PF_DRIVER_NAME,
1106da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		.owner = THIS_MODULE,
1116da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
1126da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano};
1136da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1146da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano/*
1156da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano * Platform driver functions
1166da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano */
1176da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic ssize_t buttons_show(struct device *dev,
1186da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					 struct device_attribute *attr,
1196da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					 char *buf)
1206da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
1216da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	int count = 0;
1226da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_btn *ptr = quickstart_data.btn_lst;
1236da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1246da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!ptr)
1256da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return snprintf(buf, PAGE_SIZE, "none");
1266da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1276da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	while (ptr && (count < PAGE_SIZE)) {
1286da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		if (ptr->name) {
1296da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano			count += snprintf(buf + count,
1306da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					PAGE_SIZE - count,
1316da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					"%d\t%s\n", ptr->id, ptr->name);
1326da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		}
1336da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		ptr = ptr->next;
1346da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
1356da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1366da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return count;
1376da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
1386da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1396da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic ssize_t pressed_button_show(struct device *dev,
1406da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					struct device_attribute *attr,
1416da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					char *buf)
1426da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
1436da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return snprintf(buf, PAGE_SIZE, "%s\n",
144f94fdeaa58e54c41eb6a2d8b86585e858d44c88fTimo von Holtz			(quickstart_data.pressed ?
145f94fdeaa58e54c41eb6a2d8b86585e858d44c88fTimo von Holtz			 quickstart_data.pressed->name : "none"));
1466da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
1476da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1486da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1496da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic ssize_t pressed_button_store(struct device *dev,
1506da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					 struct device_attribute *attr,
1516da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					 const char *buf, size_t count)
1526da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
1536da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (count < 2)
1546da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return -EINVAL;
1556da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1566da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (strncasecmp(buf, "none", 4) != 0)
1576da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return -EINVAL;
1586da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1596da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart_data.pressed = NULL;
1606da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return count;
1616da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
1626da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1636da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano/* Hotstart Helper functions */
1646da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic int quickstart_btnlst_add(struct quickstart_btn **data)
1656da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
1666da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_btn **ptr = &quickstart_data.btn_lst;
1676da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1686da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	while (*ptr)
1696da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		ptr = &((*ptr)->next);
1706da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1716da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	*ptr = kzalloc(sizeof(struct quickstart_btn), GFP_KERNEL);
1726da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!*ptr) {
1736da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		*data = NULL;
1746da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return -ENOMEM;
1756da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
1766da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	*data = *ptr;
1776da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1786da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return 0;
1796da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
1806da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1816da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic void quickstart_btnlst_del(struct quickstart_btn *data)
1826da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
1836da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_btn **ptr = &quickstart_data.btn_lst;
1846da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1856da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!data)
1866da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return;
1876da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1886da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	while (*ptr) {
1896da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		if (*ptr == data) {
1906da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano			*ptr = (*ptr)->next;
1916da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano			kfree(data);
1926da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano			return;
1936da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		}
1946da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		ptr = &((*ptr)->next);
1956da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
1966da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
1976da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return;
1986da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
1996da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2006da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic void quickstart_btnlst_free(void)
2016da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
2026da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_btn *ptr = quickstart_data.btn_lst;
2036da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_btn *lptr = NULL;
2046da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2056da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	while (ptr) {
2066da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		lptr = ptr;
2076da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		ptr = ptr->next;
2086da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		kfree(lptr->name);
2096da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		kfree(lptr);
2106da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
2116da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2126da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return;
2136da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
2146da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2156da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano/* ACPI Driver functions */
2166da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic void quickstart_acpi_notify(acpi_handle handle, u32 event, void *data)
2176da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
2186da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_acpi *quickstart = data;
2196da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2206da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!quickstart)
2216da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return;
2226da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2236da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (event == QUICKSTART_EVENT_WAKE)
2246da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		quickstart_data.pressed = quickstart->btn;
2256da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	else if (event == QUICKSTART_EVENT_RUNTIME) {
2266da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		input_report_key(quickstart_input, quickstart->btn->id, 1);
2276da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		input_sync(quickstart_input);
2286da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		input_report_key(quickstart_input, quickstart->btn->id, 0);
2296da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		input_sync(quickstart_input);
2306da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
2316da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return;
2326da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
2336da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2346da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic void quickstart_acpi_ghid(struct quickstart_acpi *quickstart)
2356da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
2366da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	acpi_status status;
2376da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
2386da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	uint32_t usageid = 0;
2396da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2406da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!quickstart)
2416da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return;
2426da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2436da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* This returns a buffer telling the button usage ID,
2446da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	 * and triggers pending notify events (The ones before booting). */
2456da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	status = acpi_evaluate_object(quickstart->device->handle,
2466da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					"GHID", NULL, &buffer);
2476da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (ACPI_FAILURE(status) || !buffer.pointer) {
2486da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		printk(KERN_ERR "quickstart: %s GHID method failed.\n",
2496da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		       quickstart->btn->name);
2506da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return;
2516da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
2526da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2536da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (buffer.length < 8)
2546da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return;
2556da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2566da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* <<The GHID method can return a BYTE, WORD, or DWORD.
2576da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	 * The value must be encoded in little-endian byte
2586da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	 * order (least significant byte first).>> */
2596da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	usageid = *((uint32_t *)(buffer.pointer + (buffer.length - 8)));
2606da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart->btn->id = usageid;
2616da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2626da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	kfree(buffer.pointer);
2636da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
2646da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2656da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic int quickstart_acpi_config(struct quickstart_acpi *quickstart, char *bid)
2666da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
2676da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	int len = strlen(bid);
2686da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	int ret;
2696da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2706da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* Add button to list */
2716da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	ret = quickstart_btnlst_add(&quickstart->btn);
2726da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (ret)
2736da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return ret;
2746da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2756da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart->btn->name = kzalloc(len + 1, GFP_KERNEL);
2766da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!quickstart->btn->name) {
2776da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		quickstart_btnlst_free();
2786da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return -ENOMEM;
2796da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
2806da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	strcpy(quickstart->btn->name, bid);
2816da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2826da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return 0;
2836da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
2846da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2856da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic int quickstart_acpi_add(struct acpi_device *device)
2866da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
2876da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	int ret = 0;
2886da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	acpi_status status = AE_OK;
2896da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_acpi *quickstart = NULL;
2906da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2916da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!device)
2926da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return -EINVAL;
2936da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2946da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart = kzalloc(sizeof(struct quickstart_acpi), GFP_KERNEL);
2956da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!quickstart)
2966da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return -ENOMEM;
2976da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
2986da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart->device = device;
2996da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	strcpy(acpi_device_name(device), QUICKSTART_ACPI_DEVICE_NAME);
3006da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	strcpy(acpi_device_class(device), QUICKSTART_ACPI_CLASS);
3016da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	device->driver_data = quickstart;
3026da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3036da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* Add button to list and initialize some stuff */
3046da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	ret = quickstart_acpi_config(quickstart, acpi_device_bid(device));
3056da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (ret)
3066da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		goto fail_config;
3076da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3086da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	status = acpi_install_notify_handler(device->handle,
3096da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano						ACPI_ALL_NOTIFY,
3106da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano						quickstart_acpi_notify,
3116da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano						quickstart);
3126da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (ACPI_FAILURE(status)) {
3136da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		printk(KERN_ERR "quickstart: Notify handler install error\n");
3146da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		ret = -ENODEV;
3156da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		goto fail_installnotify;
3166da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
3176da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3186da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart_acpi_ghid(quickstart);
3196da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3206da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return 0;
3216da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3226da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanofail_installnotify:
3236da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart_btnlst_del(quickstart->btn);
3246da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3256da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanofail_config:
3266da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3276da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	kfree(quickstart);
3286da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3296da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return ret;
3306da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
3316da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3326da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic int quickstart_acpi_remove(struct acpi_device *device, int type)
3336da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
3346da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	acpi_status status = 0;
3356da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_acpi *quickstart = NULL;
3366da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3376da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!device || !acpi_driver_data(device))
3386da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return -EINVAL;
3396da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3406da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart = acpi_driver_data(device);
3416da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3426da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	status = acpi_remove_notify_handler(device->handle,
3436da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano						 ACPI_ALL_NOTIFY,
3446da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano					    quickstart_acpi_notify);
3456da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (ACPI_FAILURE(status))
3466da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		printk(KERN_ERR "quickstart: Error removing notify handler\n");
3476da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3486da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3496da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	kfree(quickstart);
3506da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3516da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return 0;
3526da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
3536da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3546da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano/* Module functions */
3556da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3566da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic void quickstart_exit(void)
3576da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
3586da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	input_unregister_device(quickstart_input);
3596da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3606da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	device_remove_file(&pf_device->dev, &dev_attr_pressed_button);
3616da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	device_remove_file(&pf_device->dev, &dev_attr_buttons);
3626da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3636da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	platform_device_unregister(pf_device);
3646da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3656da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	platform_driver_unregister(&pf_driver);
3666da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3676da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	acpi_bus_unregister_driver(&quickstart_acpi_driver);
3686da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3696da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart_btnlst_free();
3706da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3716da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return;
3726da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
3736da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3746da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic int __init quickstart_init_input(void)
3756da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
3766da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	struct quickstart_btn **ptr = &quickstart_data.btn_lst;
3776da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	int count;
378ebba26f4a8d0c137a2d365b6bded2a0d7fcd1d06Dan Carpenter	int ret;
3796da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3806da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart_input = input_allocate_device();
3816da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3826da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!quickstart_input)
3836da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return -ENOMEM;
3846da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3856da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart_input->name = "Quickstart ACPI Buttons";
3866da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	quickstart_input->id.bustype = BUS_HOST;
3876da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
3886da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	while (*ptr) {
3896da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		count++;
3906da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		set_bit(EV_KEY, quickstart_input->evbit);
3916da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		set_bit((*ptr)->id, quickstart_input->keybit);
3926da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		ptr = &((*ptr)->next);
3936da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
3946da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
395ebba26f4a8d0c137a2d365b6bded2a0d7fcd1d06Dan Carpenter	ret = input_register_device(quickstart_input);
396ebba26f4a8d0c137a2d365b6bded2a0d7fcd1d06Dan Carpenter	if (ret) {
397ebba26f4a8d0c137a2d365b6bded2a0d7fcd1d06Dan Carpenter		input_free_device(quickstart_input);
398ebba26f4a8d0c137a2d365b6bded2a0d7fcd1d06Dan Carpenter		return ret;
399ebba26f4a8d0c137a2d365b6bded2a0d7fcd1d06Dan Carpenter	}
400ebba26f4a8d0c137a2d365b6bded2a0d7fcd1d06Dan Carpenter
401ebba26f4a8d0c137a2d365b6bded2a0d7fcd1d06Dan Carpenter	return 0;
4026da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
4036da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4046da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanostatic int __init quickstart_init(void)
4056da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano{
4066da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	int ret;
4076da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4086da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* ACPI Check */
4096da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (acpi_disabled)
4106da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		return -ENODEV;
4116da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4126da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* ACPI driver register */
413f0903863099668d6b03c7ea90b2e58a7ad1be6a3Dan Carpenter	ret = acpi_bus_register_driver(&quickstart_acpi_driver);
414f0903863099668d6b03c7ea90b2e58a7ad1be6a3Dan Carpenter	if (ret)
415f0903863099668d6b03c7ea90b2e58a7ad1be6a3Dan Carpenter		return ret;
4166da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4176da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* If existing bus with no devices */
4186da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!quickstart_data.btn_lst) {
4196da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		ret = -ENODEV;
4206da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		goto fail_pfdrv_reg;
4216da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
4226da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4236da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* Platform driver register */
4246da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	ret = platform_driver_register(&pf_driver);
4256da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (ret)
4266da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		goto fail_pfdrv_reg;
4276da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4286da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* Platform device register */
4296da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	pf_device = platform_device_alloc(QUICKSTART_PF_DEVICE_NAME, -1);
4306da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (!pf_device) {
4316da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		ret = -ENOMEM;
4326da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		goto fail_pfdev_alloc;
4336da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	}
4346da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	ret = platform_device_add(pf_device);
4356da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (ret)
4366da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		goto fail_pfdev_add;
4376da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4386da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* Create device sysfs file */
4396da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	ret = device_create_file(&pf_device->dev, &dev_attr_pressed_button);
4406da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (ret)
4416da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		goto fail_dev_file;
4426da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4436da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	ret = device_create_file(&pf_device->dev, &dev_attr_buttons);
4446da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (ret)
4456da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		goto fail_dev_file2;
4466da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4476da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4486da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	/* Input device */
4496da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	ret = quickstart_init_input();
4506da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	if (ret)
4516da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano		goto fail_input;
4526da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4536da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	printk(KERN_INFO "quickstart: ACPI Direct App Launch ver %s\n",
4546da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano						QUICKSTART_VERSION);
4556da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4566da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return 0;
4576da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanofail_input:
4586da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	device_remove_file(&pf_device->dev, &dev_attr_buttons);
4596da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4606da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanofail_dev_file2:
4616da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	device_remove_file(&pf_device->dev, &dev_attr_pressed_button);
4626da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4636da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanofail_dev_file:
4646da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	platform_device_del(pf_device);
4656da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4666da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanofail_pfdev_add:
4676da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	platform_device_put(pf_device);
4686da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4696da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanofail_pfdev_alloc:
4706da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	platform_driver_unregister(&pf_driver);
4716da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4726da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanofail_pfdrv_reg:
4736da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	acpi_bus_unregister_driver(&quickstart_acpi_driver);
4746da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4756da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano	return ret;
4766da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano}
4776da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifano
4786da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanomodule_init(quickstart_init);
4796da4cd46902973f267fcc93325f65a93eca52ad5Angelo Arrifanomodule_exit(quickstart_exit);
480