Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.18-rc2 505 lines 12 kB view raw
1#include <linux/proc_fs.h> 2#include <linux/seq_file.h> 3#include <linux/suspend.h> 4#include <linux/bcd.h> 5#include <asm/uaccess.h> 6 7#include <acpi/acpi_bus.h> 8#include <acpi/acpi_drivers.h> 9 10#ifdef CONFIG_X86 11#include <linux/mc146818rtc.h> 12#endif 13 14#include "sleep.h" 15 16#define _COMPONENT ACPI_SYSTEM_COMPONENT 17ACPI_MODULE_NAME("sleep") 18#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP 19static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) 20{ 21 int i; 22 23 ACPI_FUNCTION_TRACE("acpi_system_sleep_seq_show"); 24 25 for (i = 0; i <= ACPI_STATE_S5; i++) { 26 if (sleep_states[i]) { 27 seq_printf(seq, "S%d ", i); 28 } 29 } 30 31 seq_puts(seq, "\n"); 32 33 return 0; 34} 35 36static int acpi_system_sleep_open_fs(struct inode *inode, struct file *file) 37{ 38 return single_open(file, acpi_system_sleep_seq_show, PDE(inode)->data); 39} 40 41static ssize_t 42acpi_system_write_sleep(struct file *file, 43 const char __user * buffer, size_t count, loff_t * ppos) 44{ 45 char str[12]; 46 u32 state = 0; 47 int error = 0; 48 49 if (count > sizeof(str) - 1) 50 goto Done; 51 memset(str, 0, sizeof(str)); 52 if (copy_from_user(str, buffer, count)) 53 return -EFAULT; 54 55 /* Check for S4 bios request */ 56 if (!strcmp(str, "4b")) { 57 error = acpi_suspend(4); 58 goto Done; 59 } 60 state = simple_strtoul(str, NULL, 0); 61#ifdef CONFIG_SOFTWARE_SUSPEND 62 if (state == 4) { 63 error = software_suspend(); 64 goto Done; 65 } 66#endif 67 error = acpi_suspend(state); 68 Done: 69 return error ? error : count; 70} 71#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ 72 73static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) 74{ 75 u32 sec, min, hr; 76 u32 day, mo, yr; 77 unsigned char rtc_control = 0; 78 unsigned long flags; 79 80 ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show"); 81 82 spin_lock_irqsave(&rtc_lock, flags); 83 84 sec = CMOS_READ(RTC_SECONDS_ALARM); 85 min = CMOS_READ(RTC_MINUTES_ALARM); 86 hr = CMOS_READ(RTC_HOURS_ALARM); 87 rtc_control = CMOS_READ(RTC_CONTROL); 88 89 /* If we ever get an FACP with proper values... */ 90 if (acpi_gbl_FADT->day_alrm) 91 /* ACPI spec: only low 6 its should be cared */ 92 day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F; 93 else 94 day = CMOS_READ(RTC_DAY_OF_MONTH); 95 if (acpi_gbl_FADT->mon_alrm) 96 mo = CMOS_READ(acpi_gbl_FADT->mon_alrm); 97 else 98 mo = CMOS_READ(RTC_MONTH); 99 if (acpi_gbl_FADT->century) 100 yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + 101 CMOS_READ(RTC_YEAR); 102 else 103 yr = CMOS_READ(RTC_YEAR); 104 105 spin_unlock_irqrestore(&rtc_lock, flags); 106 107 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 108 BCD_TO_BIN(sec); 109 BCD_TO_BIN(min); 110 BCD_TO_BIN(hr); 111 BCD_TO_BIN(day); 112 BCD_TO_BIN(mo); 113 BCD_TO_BIN(yr); 114 } 115 116 /* we're trusting the FADT (see above) */ 117 if (!acpi_gbl_FADT->century) 118 /* If we're not trusting the FADT, we should at least make it 119 * right for _this_ century... ehm, what is _this_ century? 120 * 121 * TBD: 122 * ASAP: find piece of code in the kernel, e.g. star tracker driver, 123 * which we can trust to determine the century correctly. Atom 124 * watch driver would be nice, too... 125 * 126 * if that has not happened, change for first release in 2050: 127 * if (yr<50) 128 * yr += 2100; 129 * else 130 * yr += 2000; // current line of code 131 * 132 * if that has not happened either, please do on 2099/12/31:23:59:59 133 * s/2000/2100 134 * 135 */ 136 yr += 2000; 137 138 seq_printf(seq, "%4.4u-", yr); 139 (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); 140 (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day); 141 (hr > 23) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", hr); 142 (min > 59) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", min); 143 (sec > 59) ? seq_puts(seq, "**\n") : seq_printf(seq, "%2.2u\n", sec); 144 145 return 0; 146} 147 148static int acpi_system_alarm_open_fs(struct inode *inode, struct file *file) 149{ 150 return single_open(file, acpi_system_alarm_seq_show, PDE(inode)->data); 151} 152 153static int get_date_field(char **p, u32 * value) 154{ 155 char *next = NULL; 156 char *string_end = NULL; 157 int result = -EINVAL; 158 159 /* 160 * Try to find delimeter, only to insert null. The end of the 161 * string won't have one, but is still valid. 162 */ 163 next = strpbrk(*p, "- :"); 164 if (next) 165 *next++ = '\0'; 166 167 *value = simple_strtoul(*p, &string_end, 10); 168 169 /* Signal success if we got a good digit */ 170 if (string_end != *p) 171 result = 0; 172 173 if (next) 174 *p = next; 175 176 return result; 177} 178 179static ssize_t 180acpi_system_write_alarm(struct file *file, 181 const char __user * buffer, size_t count, loff_t * ppos) 182{ 183 int result = 0; 184 char alarm_string[30] = { '\0' }; 185 char *p = alarm_string; 186 u32 sec, min, hr, day, mo, yr; 187 int adjust = 0; 188 unsigned char rtc_control = 0; 189 190 ACPI_FUNCTION_TRACE("acpi_system_write_alarm"); 191 192 if (count > sizeof(alarm_string) - 1) 193 return_VALUE(-EINVAL); 194 195 if (copy_from_user(alarm_string, buffer, count)) 196 return_VALUE(-EFAULT); 197 198 alarm_string[count] = '\0'; 199 200 /* check for time adjustment */ 201 if (alarm_string[0] == '+') { 202 p++; 203 adjust = 1; 204 } 205 206 if ((result = get_date_field(&p, &yr))) 207 goto end; 208 if ((result = get_date_field(&p, &mo))) 209 goto end; 210 if ((result = get_date_field(&p, &day))) 211 goto end; 212 if ((result = get_date_field(&p, &hr))) 213 goto end; 214 if ((result = get_date_field(&p, &min))) 215 goto end; 216 if ((result = get_date_field(&p, &sec))) 217 goto end; 218 219 if (sec > 59) { 220 min += 1; 221 sec -= 60; 222 } 223 if (min > 59) { 224 hr += 1; 225 min -= 60; 226 } 227 if (hr > 23) { 228 day += 1; 229 hr -= 24; 230 } 231 if (day > 31) { 232 mo += 1; 233 day -= 31; 234 } 235 if (mo > 12) { 236 yr += 1; 237 mo -= 12; 238 } 239 240 spin_lock_irq(&rtc_lock); 241 242 rtc_control = CMOS_READ(RTC_CONTROL); 243 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 244 BIN_TO_BCD(yr); 245 BIN_TO_BCD(mo); 246 BIN_TO_BCD(day); 247 BIN_TO_BCD(hr); 248 BIN_TO_BCD(min); 249 BIN_TO_BCD(sec); 250 } 251 252 if (adjust) { 253 yr += CMOS_READ(RTC_YEAR); 254 mo += CMOS_READ(RTC_MONTH); 255 day += CMOS_READ(RTC_DAY_OF_MONTH); 256 hr += CMOS_READ(RTC_HOURS); 257 min += CMOS_READ(RTC_MINUTES); 258 sec += CMOS_READ(RTC_SECONDS); 259 } 260 261 spin_unlock_irq(&rtc_lock); 262 263 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 264 BCD_TO_BIN(yr); 265 BCD_TO_BIN(mo); 266 BCD_TO_BIN(day); 267 BCD_TO_BIN(hr); 268 BCD_TO_BIN(min); 269 BCD_TO_BIN(sec); 270 } 271 272 if (sec > 59) { 273 min++; 274 sec -= 60; 275 } 276 if (min > 59) { 277 hr++; 278 min -= 60; 279 } 280 if (hr > 23) { 281 day++; 282 hr -= 24; 283 } 284 if (day > 31) { 285 mo++; 286 day -= 31; 287 } 288 if (mo > 12) { 289 yr++; 290 mo -= 12; 291 } 292 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 293 BIN_TO_BCD(yr); 294 BIN_TO_BCD(mo); 295 BIN_TO_BCD(day); 296 BIN_TO_BCD(hr); 297 BIN_TO_BCD(min); 298 BIN_TO_BCD(sec); 299 } 300 301 spin_lock_irq(&rtc_lock); 302 /* 303 * Disable alarm interrupt before setting alarm timer or else 304 * when ACPI_EVENT_RTC is enabled, a spurious ACPI interrupt occurs 305 */ 306 rtc_control &= ~RTC_AIE; 307 CMOS_WRITE(rtc_control, RTC_CONTROL); 308 CMOS_READ(RTC_INTR_FLAGS); 309 310 /* write the fields the rtc knows about */ 311 CMOS_WRITE(hr, RTC_HOURS_ALARM); 312 CMOS_WRITE(min, RTC_MINUTES_ALARM); 313 CMOS_WRITE(sec, RTC_SECONDS_ALARM); 314 315 /* 316 * If the system supports an enhanced alarm it will have non-zero 317 * offsets into the CMOS RAM here -- which for some reason are pointing 318 * to the RTC area of memory. 319 */ 320 if (acpi_gbl_FADT->day_alrm) 321 CMOS_WRITE(day, acpi_gbl_FADT->day_alrm); 322 if (acpi_gbl_FADT->mon_alrm) 323 CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm); 324 if (acpi_gbl_FADT->century) 325 CMOS_WRITE(yr / 100, acpi_gbl_FADT->century); 326 /* enable the rtc alarm interrupt */ 327 rtc_control |= RTC_AIE; 328 CMOS_WRITE(rtc_control, RTC_CONTROL); 329 CMOS_READ(RTC_INTR_FLAGS); 330 331 spin_unlock_irq(&rtc_lock); 332 333 acpi_clear_event(ACPI_EVENT_RTC); 334 acpi_enable_event(ACPI_EVENT_RTC, 0); 335 336 *ppos += count; 337 338 result = 0; 339 end: 340 return_VALUE(result ? result : count); 341} 342 343extern struct list_head acpi_wakeup_device_list; 344extern spinlock_t acpi_device_lock; 345 346static int 347acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) 348{ 349 struct list_head *node, *next; 350 351 seq_printf(seq, "Device Sleep state Status\n"); 352 353 spin_lock(&acpi_device_lock); 354 list_for_each_safe(node, next, &acpi_wakeup_device_list) { 355 struct acpi_device *dev = 356 container_of(node, struct acpi_device, wakeup_list); 357 358 if (!dev->wakeup.flags.valid) 359 continue; 360 spin_unlock(&acpi_device_lock); 361 seq_printf(seq, "%4s %4d %s%8s\n", 362 dev->pnp.bus_id, 363 (u32) dev->wakeup.sleep_state, 364 dev->wakeup.flags.run_wake ? "*" : "", 365 dev->wakeup.state.enabled ? "enabled" : "disabled"); 366 spin_lock(&acpi_device_lock); 367 } 368 spin_unlock(&acpi_device_lock); 369 return 0; 370} 371 372static ssize_t 373acpi_system_write_wakeup_device(struct file *file, 374 const char __user * buffer, 375 size_t count, loff_t * ppos) 376{ 377 struct list_head *node, *next; 378 char strbuf[5]; 379 char str[5] = ""; 380 int len = count; 381 struct acpi_device *found_dev = NULL; 382 383 if (len > 4) 384 len = 4; 385 386 if (copy_from_user(strbuf, buffer, len)) 387 return -EFAULT; 388 strbuf[len] = '\0'; 389 sscanf(strbuf, "%s", str); 390 391 spin_lock(&acpi_device_lock); 392 list_for_each_safe(node, next, &acpi_wakeup_device_list) { 393 struct acpi_device *dev = 394 container_of(node, struct acpi_device, wakeup_list); 395 if (!dev->wakeup.flags.valid) 396 continue; 397 398 if (!strncmp(dev->pnp.bus_id, str, 4)) { 399 dev->wakeup.state.enabled = 400 dev->wakeup.state.enabled ? 0 : 1; 401 found_dev = dev; 402 break; 403 } 404 } 405 if (found_dev) { 406 list_for_each_safe(node, next, &acpi_wakeup_device_list) { 407 struct acpi_device *dev = container_of(node, 408 struct 409 acpi_device, 410 wakeup_list); 411 412 if ((dev != found_dev) && 413 (dev->wakeup.gpe_number == 414 found_dev->wakeup.gpe_number) 415 && (dev->wakeup.gpe_device == 416 found_dev->wakeup.gpe_device)) { 417 printk(KERN_WARNING 418 "ACPI: '%s' and '%s' have the same GPE, " 419 "can't disable/enable one seperately\n", 420 dev->pnp.bus_id, found_dev->pnp.bus_id); 421 dev->wakeup.state.enabled = 422 found_dev->wakeup.state.enabled; 423 } 424 } 425 } 426 spin_unlock(&acpi_device_lock); 427 return count; 428} 429 430static int 431acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file) 432{ 433 return single_open(file, acpi_system_wakeup_device_seq_show, 434 PDE(inode)->data); 435} 436 437static const struct file_operations acpi_system_wakeup_device_fops = { 438 .open = acpi_system_wakeup_device_open_fs, 439 .read = seq_read, 440 .write = acpi_system_write_wakeup_device, 441 .llseek = seq_lseek, 442 .release = single_release, 443}; 444 445#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP 446static const struct file_operations acpi_system_sleep_fops = { 447 .open = acpi_system_sleep_open_fs, 448 .read = seq_read, 449 .write = acpi_system_write_sleep, 450 .llseek = seq_lseek, 451 .release = single_release, 452}; 453#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ 454 455static const struct file_operations acpi_system_alarm_fops = { 456 .open = acpi_system_alarm_open_fs, 457 .read = seq_read, 458 .write = acpi_system_write_alarm, 459 .llseek = seq_lseek, 460 .release = single_release, 461}; 462 463static u32 rtc_handler(void *context) 464{ 465 acpi_clear_event(ACPI_EVENT_RTC); 466 acpi_disable_event(ACPI_EVENT_RTC, 0); 467 468 return ACPI_INTERRUPT_HANDLED; 469} 470 471static int acpi_sleep_proc_init(void) 472{ 473 struct proc_dir_entry *entry = NULL; 474 475 if (acpi_disabled) 476 return 0; 477 478#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP 479 /* 'sleep' [R/W] */ 480 entry = 481 create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR, 482 acpi_root_dir); 483 if (entry) 484 entry->proc_fops = &acpi_system_sleep_fops; 485#endif 486 487 /* 'alarm' [R/W] */ 488 entry = 489 create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR, 490 acpi_root_dir); 491 if (entry) 492 entry->proc_fops = &acpi_system_alarm_fops; 493 494 /* 'wakeup device' [R/W] */ 495 entry = 496 create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR, 497 acpi_root_dir); 498 if (entry) 499 entry->proc_fops = &acpi_system_wakeup_device_fops; 500 501 acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); 502 return 0; 503} 504 505late_initcall(acpi_sleep_proc_init);