Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.21 507 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, cent = 0; 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_alarm) 91 /* ACPI spec: only low 6 its should be cared */ 92 day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F; 93 else 94 day = CMOS_READ(RTC_DAY_OF_MONTH); 95 if (acpi_gbl_FADT.month_alarm) 96 mo = CMOS_READ(acpi_gbl_FADT.month_alarm); 97 else 98 mo = CMOS_READ(RTC_MONTH); 99 if (acpi_gbl_FADT.century) 100 cent = CMOS_READ(acpi_gbl_FADT.century); 101 102 yr = CMOS_READ(RTC_YEAR); 103 104 spin_unlock_irqrestore(&rtc_lock, flags); 105 106 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 107 BCD_TO_BIN(sec); 108 BCD_TO_BIN(min); 109 BCD_TO_BIN(hr); 110 BCD_TO_BIN(day); 111 BCD_TO_BIN(mo); 112 BCD_TO_BIN(yr); 113 BCD_TO_BIN(cent); 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 else 138 yr += cent * 100; 139 140 seq_printf(seq, "%4.4u-", yr); 141 (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); 142 (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day); 143 (hr > 23) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", hr); 144 (min > 59) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", min); 145 (sec > 59) ? seq_puts(seq, "**\n") : seq_printf(seq, "%2.2u\n", sec); 146 147 return 0; 148} 149 150static int acpi_system_alarm_open_fs(struct inode *inode, struct file *file) 151{ 152 return single_open(file, acpi_system_alarm_seq_show, PDE(inode)->data); 153} 154 155static int get_date_field(char **p, u32 * value) 156{ 157 char *next = NULL; 158 char *string_end = NULL; 159 int result = -EINVAL; 160 161 /* 162 * Try to find delimeter, only to insert null. The end of the 163 * string won't have one, but is still valid. 164 */ 165 next = strpbrk(*p, "- :"); 166 if (next) 167 *next++ = '\0'; 168 169 *value = simple_strtoul(*p, &string_end, 10); 170 171 /* Signal success if we got a good digit */ 172 if (string_end != *p) 173 result = 0; 174 175 if (next) 176 *p = next; 177 178 return result; 179} 180 181static ssize_t 182acpi_system_write_alarm(struct file *file, 183 const char __user * buffer, size_t count, loff_t * ppos) 184{ 185 int result = 0; 186 char alarm_string[30] = { '\0' }; 187 char *p = alarm_string; 188 u32 sec, min, hr, day, mo, yr; 189 int adjust = 0; 190 unsigned char rtc_control = 0; 191 192 ACPI_FUNCTION_TRACE("acpi_system_write_alarm"); 193 194 if (count > sizeof(alarm_string) - 1) 195 return_VALUE(-EINVAL); 196 197 if (copy_from_user(alarm_string, buffer, count)) 198 return_VALUE(-EFAULT); 199 200 alarm_string[count] = '\0'; 201 202 /* check for time adjustment */ 203 if (alarm_string[0] == '+') { 204 p++; 205 adjust = 1; 206 } 207 208 if ((result = get_date_field(&p, &yr))) 209 goto end; 210 if ((result = get_date_field(&p, &mo))) 211 goto end; 212 if ((result = get_date_field(&p, &day))) 213 goto end; 214 if ((result = get_date_field(&p, &hr))) 215 goto end; 216 if ((result = get_date_field(&p, &min))) 217 goto end; 218 if ((result = get_date_field(&p, &sec))) 219 goto end; 220 221 if (sec > 59) { 222 min += 1; 223 sec -= 60; 224 } 225 if (min > 59) { 226 hr += 1; 227 min -= 60; 228 } 229 if (hr > 23) { 230 day += 1; 231 hr -= 24; 232 } 233 if (day > 31) { 234 mo += 1; 235 day -= 31; 236 } 237 if (mo > 12) { 238 yr += 1; 239 mo -= 12; 240 } 241 242 spin_lock_irq(&rtc_lock); 243 244 rtc_control = CMOS_READ(RTC_CONTROL); 245 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 246 BIN_TO_BCD(yr); 247 BIN_TO_BCD(mo); 248 BIN_TO_BCD(day); 249 BIN_TO_BCD(hr); 250 BIN_TO_BCD(min); 251 BIN_TO_BCD(sec); 252 } 253 254 if (adjust) { 255 yr += CMOS_READ(RTC_YEAR); 256 mo += CMOS_READ(RTC_MONTH); 257 day += CMOS_READ(RTC_DAY_OF_MONTH); 258 hr += CMOS_READ(RTC_HOURS); 259 min += CMOS_READ(RTC_MINUTES); 260 sec += CMOS_READ(RTC_SECONDS); 261 } 262 263 spin_unlock_irq(&rtc_lock); 264 265 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 266 BCD_TO_BIN(yr); 267 BCD_TO_BIN(mo); 268 BCD_TO_BIN(day); 269 BCD_TO_BIN(hr); 270 BCD_TO_BIN(min); 271 BCD_TO_BIN(sec); 272 } 273 274 if (sec > 59) { 275 min++; 276 sec -= 60; 277 } 278 if (min > 59) { 279 hr++; 280 min -= 60; 281 } 282 if (hr > 23) { 283 day++; 284 hr -= 24; 285 } 286 if (day > 31) { 287 mo++; 288 day -= 31; 289 } 290 if (mo > 12) { 291 yr++; 292 mo -= 12; 293 } 294 if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 295 BIN_TO_BCD(yr); 296 BIN_TO_BCD(mo); 297 BIN_TO_BCD(day); 298 BIN_TO_BCD(hr); 299 BIN_TO_BCD(min); 300 BIN_TO_BCD(sec); 301 } 302 303 spin_lock_irq(&rtc_lock); 304 /* 305 * Disable alarm interrupt before setting alarm timer or else 306 * when ACPI_EVENT_RTC is enabled, a spurious ACPI interrupt occurs 307 */ 308 rtc_control &= ~RTC_AIE; 309 CMOS_WRITE(rtc_control, RTC_CONTROL); 310 CMOS_READ(RTC_INTR_FLAGS); 311 312 /* write the fields the rtc knows about */ 313 CMOS_WRITE(hr, RTC_HOURS_ALARM); 314 CMOS_WRITE(min, RTC_MINUTES_ALARM); 315 CMOS_WRITE(sec, RTC_SECONDS_ALARM); 316 317 /* 318 * If the system supports an enhanced alarm it will have non-zero 319 * offsets into the CMOS RAM here -- which for some reason are pointing 320 * to the RTC area of memory. 321 */ 322 if (acpi_gbl_FADT.day_alarm) 323 CMOS_WRITE(day, acpi_gbl_FADT.day_alarm); 324 if (acpi_gbl_FADT.month_alarm) 325 CMOS_WRITE(mo, acpi_gbl_FADT.month_alarm); 326 if (acpi_gbl_FADT.century) 327 CMOS_WRITE(yr / 100, acpi_gbl_FADT.century); 328 /* enable the rtc alarm interrupt */ 329 rtc_control |= RTC_AIE; 330 CMOS_WRITE(rtc_control, RTC_CONTROL); 331 CMOS_READ(RTC_INTR_FLAGS); 332 333 spin_unlock_irq(&rtc_lock); 334 335 acpi_clear_event(ACPI_EVENT_RTC); 336 acpi_enable_event(ACPI_EVENT_RTC, 0); 337 338 *ppos += count; 339 340 result = 0; 341 end: 342 return_VALUE(result ? result : count); 343} 344 345extern struct list_head acpi_wakeup_device_list; 346extern spinlock_t acpi_device_lock; 347 348static int 349acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) 350{ 351 struct list_head *node, *next; 352 353 seq_printf(seq, "Device Sleep state Status\n"); 354 355 spin_lock(&acpi_device_lock); 356 list_for_each_safe(node, next, &acpi_wakeup_device_list) { 357 struct acpi_device *dev = 358 container_of(node, struct acpi_device, wakeup_list); 359 360 if (!dev->wakeup.flags.valid) 361 continue; 362 spin_unlock(&acpi_device_lock); 363 seq_printf(seq, "%4s %4d %s%8s\n", 364 dev->pnp.bus_id, 365 (u32) dev->wakeup.sleep_state, 366 dev->wakeup.flags.run_wake ? "*" : "", 367 dev->wakeup.state.enabled ? "enabled" : "disabled"); 368 spin_lock(&acpi_device_lock); 369 } 370 spin_unlock(&acpi_device_lock); 371 return 0; 372} 373 374static ssize_t 375acpi_system_write_wakeup_device(struct file *file, 376 const char __user * buffer, 377 size_t count, loff_t * ppos) 378{ 379 struct list_head *node, *next; 380 char strbuf[5]; 381 char str[5] = ""; 382 int len = count; 383 struct acpi_device *found_dev = NULL; 384 385 if (len > 4) 386 len = 4; 387 388 if (copy_from_user(strbuf, buffer, len)) 389 return -EFAULT; 390 strbuf[len] = '\0'; 391 sscanf(strbuf, "%s", str); 392 393 spin_lock(&acpi_device_lock); 394 list_for_each_safe(node, next, &acpi_wakeup_device_list) { 395 struct acpi_device *dev = 396 container_of(node, struct acpi_device, wakeup_list); 397 if (!dev->wakeup.flags.valid) 398 continue; 399 400 if (!strncmp(dev->pnp.bus_id, str, 4)) { 401 dev->wakeup.state.enabled = 402 dev->wakeup.state.enabled ? 0 : 1; 403 found_dev = dev; 404 break; 405 } 406 } 407 if (found_dev) { 408 list_for_each_safe(node, next, &acpi_wakeup_device_list) { 409 struct acpi_device *dev = container_of(node, 410 struct 411 acpi_device, 412 wakeup_list); 413 414 if ((dev != found_dev) && 415 (dev->wakeup.gpe_number == 416 found_dev->wakeup.gpe_number) 417 && (dev->wakeup.gpe_device == 418 found_dev->wakeup.gpe_device)) { 419 printk(KERN_WARNING 420 "ACPI: '%s' and '%s' have the same GPE, " 421 "can't disable/enable one seperately\n", 422 dev->pnp.bus_id, found_dev->pnp.bus_id); 423 dev->wakeup.state.enabled = 424 found_dev->wakeup.state.enabled; 425 } 426 } 427 } 428 spin_unlock(&acpi_device_lock); 429 return count; 430} 431 432static int 433acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file) 434{ 435 return single_open(file, acpi_system_wakeup_device_seq_show, 436 PDE(inode)->data); 437} 438 439static const struct file_operations acpi_system_wakeup_device_fops = { 440 .open = acpi_system_wakeup_device_open_fs, 441 .read = seq_read, 442 .write = acpi_system_write_wakeup_device, 443 .llseek = seq_lseek, 444 .release = single_release, 445}; 446 447#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP 448static const struct file_operations acpi_system_sleep_fops = { 449 .open = acpi_system_sleep_open_fs, 450 .read = seq_read, 451 .write = acpi_system_write_sleep, 452 .llseek = seq_lseek, 453 .release = single_release, 454}; 455#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ 456 457static const struct file_operations acpi_system_alarm_fops = { 458 .open = acpi_system_alarm_open_fs, 459 .read = seq_read, 460 .write = acpi_system_write_alarm, 461 .llseek = seq_lseek, 462 .release = single_release, 463}; 464 465static u32 rtc_handler(void *context) 466{ 467 acpi_clear_event(ACPI_EVENT_RTC); 468 acpi_disable_event(ACPI_EVENT_RTC, 0); 469 470 return ACPI_INTERRUPT_HANDLED; 471} 472 473static int acpi_sleep_proc_init(void) 474{ 475 struct proc_dir_entry *entry = NULL; 476 477 if (acpi_disabled) 478 return 0; 479 480#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP 481 /* 'sleep' [R/W] */ 482 entry = 483 create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR, 484 acpi_root_dir); 485 if (entry) 486 entry->proc_fops = &acpi_system_sleep_fops; 487#endif 488 489 /* 'alarm' [R/W] */ 490 entry = 491 create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR, 492 acpi_root_dir); 493 if (entry) 494 entry->proc_fops = &acpi_system_alarm_fops; 495 496 /* 'wakeup device' [R/W] */ 497 entry = 498 create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR, 499 acpi_root_dir); 500 if (entry) 501 entry->proc_fops = &acpi_system_wakeup_device_fops; 502 503 acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); 504 return 0; 505} 506 507late_initcall(acpi_sleep_proc_init);