Staging: quickstart: Remove unused defines
[firefly-linux-kernel-4.4.55.git] / drivers / staging / quickstart / quickstart.c
1 /*
2  *  quickstart.c - ACPI Direct App Launch driver
3  *
4  *
5  *  Copyright (C) 2007-2010 Angelo Arrifano <miknix@gmail.com>
6  *
7  *  Information gathered from disassembled dsdt and from here:
8  *  <http://www.microsoft.com/whdc/system/platform/firmware/DirAppLaunch.mspx>
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License as published by
12  *  the Free Software Foundation; either version 2 of the License, or
13  *  (at your option) any later version.
14  *
15  *  This program is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public License
21  *  along with this program; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  */
25
26 #define QUICKSTART_VERSION "1.03"
27
28 #include <linux/kernel.h>
29 #include <linux/module.h>
30 #include <linux/init.h>
31 #include <linux/types.h>
32 #include <acpi/acpi_drivers.h>
33 #include <linux/platform_device.h>
34 #include <linux/input.h>
35
36 MODULE_AUTHOR("Angelo Arrifano");
37 MODULE_DESCRIPTION("ACPI Direct App Launch driver");
38 MODULE_LICENSE("GPL");
39
40 #define QUICKSTART_ACPI_DEVICE_NAME     "quickstart"
41 #define QUICKSTART_ACPI_CLASS           "quickstart"
42 #define QUICKSTART_ACPI_HID             "PNP0C32"
43
44 #define QUICKSTART_PF_DRIVER_NAME       "quickstart"
45 #define QUICKSTART_PF_DEVICE_NAME       "quickstart"
46
47 /*
48  * There will be two events:
49  * 0x02 - A hot button was pressed while device was off/sleeping.
50  * 0x80 - A hot button was pressed while device was up.
51  */
52 #define QUICKSTART_EVENT_WAKE           0x02
53 #define QUICKSTART_EVENT_RUNTIME        0x80
54
55 struct quickstart_btn {
56         char *name;
57         unsigned int id;
58         struct quickstart_btn *next;
59 };
60
61 struct quickstart_acpi {
62         struct acpi_device *device;
63         struct quickstart_btn *btn;
64 };
65
66 static struct quickstart_driver_data {
67         struct quickstart_btn *btn_lst;
68         struct quickstart_btn *pressed;
69 } quickstart_data;
70
71 static struct input_dev *quickstart_input;
72
73 /* Platform driver functions */
74 static ssize_t quickstart_buttons_show(struct device *dev,
75                                         struct device_attribute *attr,
76                                         char *buf)
77 {
78         int count = 0;
79         struct quickstart_btn *ptr = quickstart_data.btn_lst;
80
81         if (!ptr)
82                 return snprintf(buf, PAGE_SIZE, "none");
83
84         while (ptr && (count < PAGE_SIZE)) {
85                 if (ptr->name) {
86                         count += snprintf(buf + count,
87                                         PAGE_SIZE - count,
88                                         "%d\t%s\n", ptr->id, ptr->name);
89                 }
90                 ptr = ptr->next;
91         }
92
93         return count;
94 }
95
96 static ssize_t quickstart_pressed_button_show(struct device *dev,
97                                                 struct device_attribute *attr,
98                                                 char *buf)
99 {
100         return snprintf(buf, PAGE_SIZE, "%s\n",
101                         (quickstart_data.pressed ?
102                          quickstart_data.pressed->name : "none"));
103 }
104
105
106 static ssize_t quickstart_pressed_button_store(struct device *dev,
107                                                 struct device_attribute *attr,
108                                                 const char *buf, size_t count)
109 {
110         if (count < 2)
111                 return -EINVAL;
112
113         if (strncasecmp(buf, "none", 4) != 0)
114                 return -EINVAL;
115
116         quickstart_data.pressed = NULL;
117         return count;
118 }
119
120 /* Helper functions */
121 static int quickstart_btnlst_add(struct quickstart_btn **data)
122 {
123         struct quickstart_btn **ptr = &quickstart_data.btn_lst;
124
125         while (*ptr)
126                 ptr = &((*ptr)->next);
127
128         *ptr = kzalloc(sizeof(struct quickstart_btn), GFP_KERNEL);
129         if (!*ptr) {
130                 *data = NULL;
131                 return -ENOMEM;
132         }
133         *data = *ptr;
134
135         return 0;
136 }
137
138 static void quickstart_btnlst_del(struct quickstart_btn *data)
139 {
140         struct quickstart_btn **ptr = &quickstart_data.btn_lst;
141
142         if (!data)
143                 return;
144
145         while (*ptr) {
146                 if (*ptr == data) {
147                         *ptr = (*ptr)->next;
148                         kfree(data);
149                         return;
150                 }
151                 ptr = &((*ptr)->next);
152         }
153
154         return;
155 }
156
157 static void quickstart_btnlst_free(void)
158 {
159         struct quickstart_btn *ptr = quickstart_data.btn_lst;
160         struct quickstart_btn *lptr = NULL;
161
162         while (ptr) {
163                 lptr = ptr;
164                 ptr = ptr->next;
165                 kfree(lptr->name);
166                 kfree(lptr);
167         }
168
169         return;
170 }
171
172 /* ACPI Driver functions */
173 static void quickstart_acpi_notify(acpi_handle handle, u32 event, void *data)
174 {
175         struct quickstart_acpi *quickstart = data;
176
177         if (!quickstart)
178                 return;
179
180         switch (event) {
181         case QUICKSTART_EVENT_WAKE:
182                 quickstart_data.pressed = quickstart->btn;
183                 break;
184         case QUICKSTART_EVENT_RUNTIME:
185                 input_report_key(quickstart_input, quickstart->btn->id, 1);
186                 input_sync(quickstart_input);
187                 input_report_key(quickstart_input, quickstart->btn->id, 0);
188                 input_sync(quickstart_input);
189                 break;
190         default:
191                 break;
192         }
193 }
194
195 static int quickstart_acpi_ghid(struct quickstart_acpi *quickstart)
196 {
197         acpi_status status;
198         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
199         int ret = 0;
200
201         /*
202          * This returns a buffer telling the button usage ID,
203          * and triggers pending notify events (The ones before booting).
204          */
205         status = acpi_evaluate_object(quickstart->device->handle, "GHID", NULL,
206                                                                 &buffer);
207         if (ACPI_FAILURE(status)) {
208                 printk(KERN_ERR "quickstart: %s GHID method failed.\n",
209                                                 quickstart->btn->name);
210                 return -EINVAL;
211         }
212
213         /*
214          * <<The GHID method can return a BYTE, WORD, or DWORD.
215          * The value must be encoded in little-endian byte
216          * order (least significant byte first).>>
217          */
218         switch (buffer.length) {
219         case 1:
220                 quickstart->btn->id = *(uint8_t *)buffer.pointer;
221                 break;
222         case 2:
223                 quickstart->btn->id = *(uint16_t *)buffer.pointer;
224                 break;
225         case 4:
226                 quickstart->btn->id = *(uint32_t *)buffer.pointer;
227                 break;
228         case 8:
229                 quickstart->btn->id = *(uint64_t *)buffer.pointer;
230                 break;
231         default:
232                 printk(KERN_ERR "quickstart: %s GHID method returned buffer "
233                                 "of unexpected length %u\n",
234                                 quickstart->btn->name, buffer.length);
235                 ret = -EINVAL;
236                 break;
237         }
238
239         kfree(buffer.pointer);
240
241         return ret;
242 }
243
244 static int quickstart_acpi_config(struct quickstart_acpi *quickstart)
245 {
246         char *bid = acpi_device_bid(quickstart->device);
247         char *name;
248         int ret;
249
250         name = kmalloc(strlen(bid) + 1, GFP_KERNEL);
251         if (!name)
252                 return -ENOMEM;
253
254         /* Add button to list */
255         ret = quickstart_btnlst_add(&quickstart->btn);
256         if (ret < 0) {
257                 kfree(name);
258                 return ret;
259         }
260
261         quickstart->btn->name = name;
262         strcpy(quickstart->btn->name, bid);
263
264         return 0;
265 }
266
267 static int quickstart_acpi_add(struct acpi_device *device)
268 {
269         int ret;
270         acpi_status status;
271         struct quickstart_acpi *quickstart;
272
273         if (!device)
274                 return -EINVAL;
275
276         quickstart = kzalloc(sizeof(*quickstart), GFP_KERNEL);
277         if (!quickstart)
278                 return -ENOMEM;
279
280         quickstart->device = device;
281
282         strcpy(acpi_device_name(device), QUICKSTART_ACPI_DEVICE_NAME);
283         strcpy(acpi_device_class(device), QUICKSTART_ACPI_CLASS);
284         device->driver_data = quickstart;
285
286         /* Add button to list and initialize some stuff */
287         ret = quickstart_acpi_config(quickstart);
288         if (ret < 0)
289                 goto fail_config;
290
291         status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY,
292                                                 quickstart_acpi_notify,
293                                                 quickstart);
294         if (ACPI_FAILURE(status)) {
295                 printk(KERN_ERR "quickstart: Notify handler install error\n");
296                 ret = -ENODEV;
297                 goto fail_installnotify;
298         }
299
300         ret = quickstart_acpi_ghid(quickstart);
301         if (ret < 0)
302                 goto fail_ghid;
303
304         return 0;
305
306 fail_ghid:
307         acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY,
308                                                 quickstart_acpi_notify);
309
310 fail_installnotify:
311         quickstart_btnlst_del(quickstart->btn);
312
313 fail_config:
314
315         kfree(quickstart);
316
317         return ret;
318 }
319
320 static int quickstart_acpi_remove(struct acpi_device *device, int type)
321 {
322         acpi_status status;
323         struct quickstart_acpi *quickstart;
324
325         if (!device)
326                 return -EINVAL;
327
328         quickstart = acpi_driver_data(device);
329         if (!quickstart)
330                 return -EINVAL;
331
332         status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY,
333                                                 quickstart_acpi_notify);
334         if (ACPI_FAILURE(status))
335                 printk(KERN_ERR "quickstart: Error removing notify handler\n");
336
337         kfree(quickstart);
338
339         return 0;
340 }
341
342 /* Platform driver structs */
343 static DEVICE_ATTR(pressed_button, 0666, quickstart_pressed_button_show,
344                                          quickstart_pressed_button_store);
345 static DEVICE_ATTR(buttons, 0444, quickstart_buttons_show, NULL);
346 static struct platform_device *pf_device;
347 static struct platform_driver pf_driver = {
348         .driver = {
349                 .name = QUICKSTART_PF_DRIVER_NAME,
350                 .owner = THIS_MODULE,
351         }
352 };
353
354 static const struct acpi_device_id quickstart_device_ids[] = {
355         {QUICKSTART_ACPI_HID, 0},
356         {"", 0},
357 };
358
359 static struct acpi_driver quickstart_acpi_driver = {
360         .name = "quickstart",
361         .class = QUICKSTART_ACPI_CLASS,
362         .ids = quickstart_device_ids,
363         .ops = {
364                         .add = quickstart_acpi_add,
365                         .remove = quickstart_acpi_remove,
366                 },
367 };
368
369 /* Module functions */
370 static void quickstart_exit(void)
371 {
372         input_unregister_device(quickstart_input);
373
374         device_remove_file(&pf_device->dev, &dev_attr_pressed_button);
375         device_remove_file(&pf_device->dev, &dev_attr_buttons);
376
377         platform_device_unregister(pf_device);
378
379         platform_driver_unregister(&pf_driver);
380
381         acpi_bus_unregister_driver(&quickstart_acpi_driver);
382
383         quickstart_btnlst_free();
384 }
385
386 static int __init quickstart_init_input(void)
387 {
388         struct quickstart_btn **ptr = &quickstart_data.btn_lst;
389         int count;
390         int ret;
391
392         quickstart_input = input_allocate_device();
393
394         if (!quickstart_input)
395                 return -ENOMEM;
396
397         quickstart_input->name = "Quickstart ACPI Buttons";
398         quickstart_input->id.bustype = BUS_HOST;
399
400         while (*ptr) {
401                 count++;
402                 set_bit(EV_KEY, quickstart_input->evbit);
403                 set_bit((*ptr)->id, quickstart_input->keybit);
404                 ptr = &((*ptr)->next);
405         }
406
407         ret = input_register_device(quickstart_input);
408         if (ret) {
409                 input_free_device(quickstart_input);
410                 return ret;
411         }
412
413         return 0;
414 }
415
416 static int __init quickstart_init(void)
417 {
418         int ret;
419
420         /* ACPI Check */
421         if (acpi_disabled)
422                 return -ENODEV;
423
424         /* ACPI driver register */
425         ret = acpi_bus_register_driver(&quickstart_acpi_driver);
426         if (ret)
427                 return ret;
428
429         /* If existing bus with no devices */
430         if (!quickstart_data.btn_lst) {
431                 ret = -ENODEV;
432                 goto fail_pfdrv_reg;
433         }
434
435         /* Platform driver register */
436         ret = platform_driver_register(&pf_driver);
437         if (ret)
438                 goto fail_pfdrv_reg;
439
440         /* Platform device register */
441         pf_device = platform_device_alloc(QUICKSTART_PF_DEVICE_NAME, -1);
442         if (!pf_device) {
443                 ret = -ENOMEM;
444                 goto fail_pfdev_alloc;
445         }
446         ret = platform_device_add(pf_device);
447         if (ret)
448                 goto fail_pfdev_add;
449
450         /* Create device sysfs file */
451         ret = device_create_file(&pf_device->dev, &dev_attr_pressed_button);
452         if (ret)
453                 goto fail_dev_file;
454
455         ret = device_create_file(&pf_device->dev, &dev_attr_buttons);
456         if (ret)
457                 goto fail_dev_file2;
458
459         /* Input device */
460         ret = quickstart_init_input();
461         if (ret)
462                 goto fail_input;
463
464         printk(KERN_INFO "quickstart: ACPI Direct App Launch ver %s\n",
465                                                         QUICKSTART_VERSION);
466
467         return 0;
468 fail_input:
469         device_remove_file(&pf_device->dev, &dev_attr_buttons);
470
471 fail_dev_file2:
472         device_remove_file(&pf_device->dev, &dev_attr_pressed_button);
473
474 fail_dev_file:
475         platform_device_del(pf_device);
476
477 fail_pfdev_add:
478         platform_device_put(pf_device);
479
480 fail_pfdev_alloc:
481         platform_driver_unregister(&pf_driver);
482
483 fail_pfdrv_reg:
484         acpi_bus_unregister_driver(&quickstart_acpi_driver);
485
486         return ret;
487 }
488
489 module_init(quickstart_init);
490 module_exit(quickstart_exit);