diff options
Diffstat (limited to 'drivers/acpi/button.c')
-rw-r--r-- | drivers/acpi/button.c | 183 |
1 files changed, 74 insertions, 109 deletions
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 1575a9b51f1d..d27d072472f9 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c | |||
@@ -78,8 +78,6 @@ static int acpi_button_add(struct acpi_device *device); | |||
78 | static int acpi_button_remove(struct acpi_device *device, int type); | 78 | static int acpi_button_remove(struct acpi_device *device, int type); |
79 | static int acpi_button_resume(struct acpi_device *device); | 79 | static int acpi_button_resume(struct acpi_device *device); |
80 | static void acpi_button_notify(struct acpi_device *device, u32 event); | 80 | static void acpi_button_notify(struct acpi_device *device, u32 event); |
81 | static int acpi_button_info_open_fs(struct inode *inode, struct file *file); | ||
82 | static int acpi_button_state_open_fs(struct inode *inode, struct file *file); | ||
83 | 81 | ||
84 | static struct acpi_driver acpi_button_driver = { | 82 | static struct acpi_driver acpi_button_driver = { |
85 | .name = "button", | 83 | .name = "button", |
@@ -98,22 +96,7 @@ struct acpi_button { | |||
98 | struct input_dev *input; | 96 | struct input_dev *input; |
99 | char phys[32]; /* for input device */ | 97 | char phys[32]; /* for input device */ |
100 | unsigned long pushed; | 98 | unsigned long pushed; |
101 | }; | 99 | bool wakeup_enabled; |
102 | |||
103 | static const struct file_operations acpi_button_info_fops = { | ||
104 | .owner = THIS_MODULE, | ||
105 | .open = acpi_button_info_open_fs, | ||
106 | .read = seq_read, | ||
107 | .llseek = seq_lseek, | ||
108 | .release = single_release, | ||
109 | }; | ||
110 | |||
111 | static const struct file_operations acpi_button_state_fops = { | ||
112 | .owner = THIS_MODULE, | ||
113 | .open = acpi_button_state_open_fs, | ||
114 | .read = seq_read, | ||
115 | .llseek = seq_lseek, | ||
116 | .release = single_release, | ||
117 | }; | 100 | }; |
118 | 101 | ||
119 | static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); | 102 | static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); |
@@ -124,20 +107,7 @@ static struct acpi_device *lid_device; | |||
124 | -------------------------------------------------------------------------- */ | 107 | -------------------------------------------------------------------------- */ |
125 | 108 | ||
126 | static struct proc_dir_entry *acpi_button_dir; | 109 | static struct proc_dir_entry *acpi_button_dir; |
127 | 110 | static struct proc_dir_entry *acpi_lid_dir; | |
128 | static int acpi_button_info_seq_show(struct seq_file *seq, void *offset) | ||
129 | { | ||
130 | struct acpi_device *device = seq->private; | ||
131 | |||
132 | seq_printf(seq, "type: %s\n", | ||
133 | acpi_device_name(device)); | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int acpi_button_info_open_fs(struct inode *inode, struct file *file) | ||
138 | { | ||
139 | return single_open(file, acpi_button_info_seq_show, PDE(inode)->data); | ||
140 | } | ||
141 | 111 | ||
142 | static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) | 112 | static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) |
143 | { | 113 | { |
@@ -157,77 +127,85 @@ static int acpi_button_state_open_fs(struct inode *inode, struct file *file) | |||
157 | return single_open(file, acpi_button_state_seq_show, PDE(inode)->data); | 127 | return single_open(file, acpi_button_state_seq_show, PDE(inode)->data); |
158 | } | 128 | } |
159 | 129 | ||
160 | static struct proc_dir_entry *acpi_power_dir; | 130 | static const struct file_operations acpi_button_state_fops = { |
161 | static struct proc_dir_entry *acpi_sleep_dir; | 131 | .owner = THIS_MODULE, |
162 | static struct proc_dir_entry *acpi_lid_dir; | 132 | .open = acpi_button_state_open_fs, |
133 | .read = seq_read, | ||
134 | .llseek = seq_lseek, | ||
135 | .release = single_release, | ||
136 | }; | ||
163 | 137 | ||
164 | static int acpi_button_add_fs(struct acpi_device *device) | 138 | static int acpi_button_add_fs(struct acpi_device *device) |
165 | { | 139 | { |
166 | struct acpi_button *button = acpi_driver_data(device); | 140 | struct acpi_button *button = acpi_driver_data(device); |
167 | struct proc_dir_entry *entry = NULL; | 141 | struct proc_dir_entry *entry = NULL; |
142 | int ret = 0; | ||
168 | 143 | ||
169 | switch (button->type) { | 144 | /* procfs I/F for ACPI lid device only */ |
170 | case ACPI_BUTTON_TYPE_POWER: | 145 | if (button->type != ACPI_BUTTON_TYPE_LID) |
171 | if (!acpi_power_dir) | 146 | return 0; |
172 | acpi_power_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER, | 147 | |
173 | acpi_button_dir); | 148 | if (acpi_button_dir || acpi_lid_dir) { |
174 | entry = acpi_power_dir; | 149 | printk(KERN_ERR PREFIX "More than one Lid device found!\n"); |
175 | break; | 150 | return -EEXIST; |
176 | case ACPI_BUTTON_TYPE_SLEEP: | ||
177 | if (!acpi_sleep_dir) | ||
178 | acpi_sleep_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP, | ||
179 | acpi_button_dir); | ||
180 | entry = acpi_sleep_dir; | ||
181 | break; | ||
182 | case ACPI_BUTTON_TYPE_LID: | ||
183 | if (!acpi_lid_dir) | ||
184 | acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, | ||
185 | acpi_button_dir); | ||
186 | entry = acpi_lid_dir; | ||
187 | break; | ||
188 | } | 151 | } |
189 | 152 | ||
190 | if (!entry) | 153 | /* create /proc/acpi/button */ |
154 | acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); | ||
155 | if (!acpi_button_dir) | ||
191 | return -ENODEV; | 156 | return -ENODEV; |
192 | 157 | ||
193 | acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry); | 158 | /* create /proc/acpi/button/lid */ |
194 | if (!acpi_device_dir(device)) | 159 | acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); |
195 | return -ENODEV; | 160 | if (!acpi_lid_dir) { |
161 | ret = -ENODEV; | ||
162 | goto remove_button_dir; | ||
163 | } | ||
196 | 164 | ||
197 | /* 'info' [R] */ | 165 | /* create /proc/acpi/button/lid/LID/ */ |
198 | entry = proc_create_data(ACPI_BUTTON_FILE_INFO, | 166 | acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_lid_dir); |
199 | S_IRUGO, acpi_device_dir(device), | 167 | if (!acpi_device_dir(device)) { |
200 | &acpi_button_info_fops, device); | 168 | ret = -ENODEV; |
201 | if (!entry) | 169 | goto remove_lid_dir; |
202 | return -ENODEV; | 170 | } |
203 | 171 | ||
204 | /* show lid state [R] */ | 172 | /* create /proc/acpi/button/lid/LID/state */ |
205 | if (button->type == ACPI_BUTTON_TYPE_LID) { | 173 | entry = proc_create_data(ACPI_BUTTON_FILE_STATE, |
206 | entry = proc_create_data(ACPI_BUTTON_FILE_STATE, | 174 | S_IRUGO, acpi_device_dir(device), |
207 | S_IRUGO, acpi_device_dir(device), | 175 | &acpi_button_state_fops, device); |
208 | &acpi_button_state_fops, device); | 176 | if (!entry) { |
209 | if (!entry) | 177 | ret = -ENODEV; |
210 | return -ENODEV; | 178 | goto remove_dev_dir; |
211 | } | 179 | } |
212 | 180 | ||
213 | return 0; | 181 | done: |
182 | return ret; | ||
183 | |||
184 | remove_dev_dir: | ||
185 | remove_proc_entry(acpi_device_bid(device), | ||
186 | acpi_lid_dir); | ||
187 | acpi_device_dir(device) = NULL; | ||
188 | remove_lid_dir: | ||
189 | remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); | ||
190 | remove_button_dir: | ||
191 | remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); | ||
192 | goto done; | ||
214 | } | 193 | } |
215 | 194 | ||
216 | static int acpi_button_remove_fs(struct acpi_device *device) | 195 | static int acpi_button_remove_fs(struct acpi_device *device) |
217 | { | 196 | { |
218 | struct acpi_button *button = acpi_driver_data(device); | 197 | struct acpi_button *button = acpi_driver_data(device); |
219 | 198 | ||
220 | if (acpi_device_dir(device)) { | 199 | if (button->type != ACPI_BUTTON_TYPE_LID) |
221 | if (button->type == ACPI_BUTTON_TYPE_LID) | 200 | return 0; |
222 | remove_proc_entry(ACPI_BUTTON_FILE_STATE, | ||
223 | acpi_device_dir(device)); | ||
224 | remove_proc_entry(ACPI_BUTTON_FILE_INFO, | ||
225 | acpi_device_dir(device)); | ||
226 | 201 | ||
227 | remove_proc_entry(acpi_device_bid(device), | 202 | remove_proc_entry(ACPI_BUTTON_FILE_STATE, |
228 | acpi_device_dir(device)->parent); | 203 | acpi_device_dir(device)); |
229 | acpi_device_dir(device) = NULL; | 204 | remove_proc_entry(acpi_device_bid(device), |
230 | } | 205 | acpi_lid_dir); |
206 | acpi_device_dir(device) = NULL; | ||
207 | remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); | ||
208 | remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); | ||
231 | 209 | ||
232 | return 0; | 210 | return 0; |
233 | } | 211 | } |
@@ -279,6 +257,9 @@ static int acpi_lid_send_state(struct acpi_device *device) | |||
279 | input_report_switch(button->input, SW_LID, !state); | 257 | input_report_switch(button->input, SW_LID, !state); |
280 | input_sync(button->input); | 258 | input_sync(button->input); |
281 | 259 | ||
260 | if (state) | ||
261 | pm_wakeup_event(&device->dev, 0); | ||
262 | |||
282 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); | 263 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); |
283 | if (ret == NOTIFY_DONE) | 264 | if (ret == NOTIFY_DONE) |
284 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, | 265 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, |
@@ -314,6 +295,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event) | |||
314 | input_sync(input); | 295 | input_sync(input); |
315 | input_report_key(input, keycode, 0); | 296 | input_report_key(input, keycode, 0); |
316 | input_sync(input); | 297 | input_sync(input); |
298 | |||
299 | pm_wakeup_event(&device->dev, 0); | ||
317 | } | 300 | } |
318 | 301 | ||
319 | acpi_bus_generate_proc_event(device, event, ++button->pushed); | 302 | acpi_bus_generate_proc_event(device, event, ++button->pushed); |
@@ -338,7 +321,8 @@ static int acpi_button_add(struct acpi_device *device) | |||
338 | { | 321 | { |
339 | struct acpi_button *button; | 322 | struct acpi_button *button; |
340 | struct input_dev *input; | 323 | struct input_dev *input; |
341 | char *hid, *name, *class; | 324 | const char *hid = acpi_device_hid(device); |
325 | char *name, *class; | ||
342 | int error; | 326 | int error; |
343 | 327 | ||
344 | button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL); | 328 | button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL); |
@@ -353,7 +337,6 @@ static int acpi_button_add(struct acpi_device *device) | |||
353 | goto err_free_button; | 337 | goto err_free_button; |
354 | } | 338 | } |
355 | 339 | ||
356 | hid = acpi_device_hid(device); | ||
357 | name = acpi_device_name(device); | 340 | name = acpi_device_name(device); |
358 | class = acpi_device_class(device); | 341 | class = acpi_device_class(device); |
359 | 342 | ||
@@ -425,8 +408,10 @@ static int acpi_button_add(struct acpi_device *device) | |||
425 | /* Button's GPE is run-wake GPE */ | 408 | /* Button's GPE is run-wake GPE */ |
426 | acpi_enable_gpe(device->wakeup.gpe_device, | 409 | acpi_enable_gpe(device->wakeup.gpe_device, |
427 | device->wakeup.gpe_number); | 410 | device->wakeup.gpe_number); |
428 | device->wakeup.run_wake_count++; | 411 | if (!device_may_wakeup(&device->dev)) { |
429 | device->wakeup.state.enabled = 1; | 412 | device_set_wakeup_enable(&device->dev, true); |
413 | button->wakeup_enabled = true; | ||
414 | } | ||
430 | } | 415 | } |
431 | 416 | ||
432 | printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); | 417 | printk(KERN_INFO PREFIX "%s [%s]\n", name, acpi_device_bid(device)); |
@@ -448,8 +433,8 @@ static int acpi_button_remove(struct acpi_device *device, int type) | |||
448 | if (device->wakeup.flags.valid) { | 433 | if (device->wakeup.flags.valid) { |
449 | acpi_disable_gpe(device->wakeup.gpe_device, | 434 | acpi_disable_gpe(device->wakeup.gpe_device, |
450 | device->wakeup.gpe_number); | 435 | device->wakeup.gpe_number); |
451 | device->wakeup.run_wake_count--; | 436 | if (button->wakeup_enabled) |
452 | device->wakeup.state.enabled = 0; | 437 | device_set_wakeup_enable(&device->dev, false); |
453 | } | 438 | } |
454 | 439 | ||
455 | acpi_button_remove_fs(device); | 440 | acpi_button_remove_fs(device); |
@@ -460,32 +445,12 @@ static int acpi_button_remove(struct acpi_device *device, int type) | |||
460 | 445 | ||
461 | static int __init acpi_button_init(void) | 446 | static int __init acpi_button_init(void) |
462 | { | 447 | { |
463 | int result; | 448 | return acpi_bus_register_driver(&acpi_button_driver); |
464 | |||
465 | acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); | ||
466 | if (!acpi_button_dir) | ||
467 | return -ENODEV; | ||
468 | |||
469 | result = acpi_bus_register_driver(&acpi_button_driver); | ||
470 | if (result < 0) { | ||
471 | remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); | ||
472 | return -ENODEV; | ||
473 | } | ||
474 | |||
475 | return 0; | ||
476 | } | 449 | } |
477 | 450 | ||
478 | static void __exit acpi_button_exit(void) | 451 | static void __exit acpi_button_exit(void) |
479 | { | 452 | { |
480 | acpi_bus_unregister_driver(&acpi_button_driver); | 453 | acpi_bus_unregister_driver(&acpi_button_driver); |
481 | |||
482 | if (acpi_power_dir) | ||
483 | remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER, acpi_button_dir); | ||
484 | if (acpi_sleep_dir) | ||
485 | remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP, acpi_button_dir); | ||
486 | if (acpi_lid_dir) | ||
487 | remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); | ||
488 | remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); | ||
489 | } | 454 | } |
490 | 455 | ||
491 | module_init(acpi_button_init); | 456 | module_init(acpi_button_init); |