X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Facpi%2Fsleep%2Fproc.c;h=4696a85a98b92b34c2789e52fae6a6122039b447;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=a64ef154db0808a62e55b2cf5c398d1764311ba7;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index a64ef154d..4696a85a9 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -13,24 +13,18 @@ #include "sleep.h" -#define ACPI_SYSTEM_FILE_SLEEP "sleep" -#define ACPI_SYSTEM_FILE_ALARM "alarm" - #define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME ("sleep") - - +ACPI_MODULE_NAME("sleep") +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) { - int i; + int i; ACPI_FUNCTION_TRACE("acpi_system_sleep_seq_show"); for (i = 0; i <= ACPI_STATE_S5; i++) { if (sleep_states[i]) { - seq_printf(seq,"S%d ", i); - if (i == ACPI_STATE_S4 && acpi_gbl_FACS->S4bios_f) - seq_printf(seq, "S4bios "); + seq_printf(seq, "S%d ", i); } } @@ -45,109 +39,107 @@ static int acpi_system_sleep_open_fs(struct inode *inode, struct file *file) } static ssize_t -acpi_system_write_sleep ( - struct file *file, - const char __user *buffer, - size_t count, - loff_t *ppos) +acpi_system_write_sleep(struct file *file, + const char __user * buffer, size_t count, loff_t * ppos) { - char str[12]; - u32 state = 0; - int error = 0; + char str[12]; + u32 state = 0; + int error = 0; if (count > sizeof(str) - 1) goto Done; - memset(str,0,sizeof(str)); + memset(str, 0, sizeof(str)); if (copy_from_user(str, buffer, count)) return -EFAULT; /* Check for S4 bios request */ - if (!strcmp(str,"4b")) { + if (!strcmp(str, "4b")) { error = acpi_suspend(4); goto Done; } state = simple_strtoul(str, NULL, 0); #ifdef CONFIG_SOFTWARE_SUSPEND if (state == 4) { - software_suspend(); + error = software_suspend(); goto Done; } #endif error = acpi_suspend(state); - Done: + Done: return error ? error : count; } +#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) { - u32 sec, min, hr; - u32 day, mo, yr; + u32 sec, min, hr; + u32 day, mo, yr; + unsigned char rtc_control = 0; + unsigned long flags; ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show"); - spin_lock(&rtc_lock); + spin_lock_irqsave(&rtc_lock, flags); sec = CMOS_READ(RTC_SECONDS_ALARM); min = CMOS_READ(RTC_MINUTES_ALARM); hr = CMOS_READ(RTC_HOURS_ALARM); + rtc_control = CMOS_READ(RTC_CONTROL); -#if 0 /* If we ever get an FACP with proper values... */ + /* If we ever get an FACP with proper values... */ if (acpi_gbl_FADT->day_alrm) - day = CMOS_READ(acpi_gbl_FADT->day_alrm); + /* ACPI spec: only low 6 its should be cared */ + day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F; else - day = CMOS_READ(RTC_DAY_OF_MONTH); + day = CMOS_READ(RTC_DAY_OF_MONTH); if (acpi_gbl_FADT->mon_alrm) mo = CMOS_READ(acpi_gbl_FADT->mon_alrm); else mo = CMOS_READ(RTC_MONTH); if (acpi_gbl_FADT->century) - yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR); + yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + + CMOS_READ(RTC_YEAR); else yr = CMOS_READ(RTC_YEAR); -#else - day = CMOS_READ(RTC_DAY_OF_MONTH); - mo = CMOS_READ(RTC_MONTH); - yr = CMOS_READ(RTC_YEAR); -#endif - spin_unlock(&rtc_lock); - - BCD_TO_BIN(sec); - BCD_TO_BIN(min); - BCD_TO_BIN(hr); - BCD_TO_BIN(day); - BCD_TO_BIN(mo); - BCD_TO_BIN(yr); - -#if 0 - /* we're trusting the FADT (see above)*/ -#else - /* If we're not trusting the FADT, we should at least make it - * right for _this_ century... ehm, what is _this_ century? - * - * TBD: - * ASAP: find piece of code in the kernel, e.g. star tracker driver, - * which we can trust to determine the century correctly. Atom - * watch driver would be nice, too... - * - * if that has not happened, change for first release in 2050: - * if (yr<50) - * yr += 2100; - * else - * yr += 2000; // current line of code - * - * if that has not happened either, please do on 2099/12/31:23:59:59 - * s/2000/2100 - * - */ - yr += 2000; -#endif + spin_unlock_irqrestore(&rtc_lock, flags); + + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hr); + BCD_TO_BIN(day); + BCD_TO_BIN(mo); + BCD_TO_BIN(yr); + } - seq_printf(seq,"%4.4u-", yr); - (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); - (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day); - (hr > 23) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", hr); - (min > 59) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", min); + /* we're trusting the FADT (see above) */ + if (!acpi_gbl_FADT->century) + /* If we're not trusting the FADT, we should at least make it + * right for _this_ century... ehm, what is _this_ century? + * + * TBD: + * ASAP: find piece of code in the kernel, e.g. star tracker driver, + * which we can trust to determine the century correctly. Atom + * watch driver would be nice, too... + * + * if that has not happened, change for first release in 2050: + * if (yr<50) + * yr += 2100; + * else + * yr += 2000; // current line of code + * + * if that has not happened either, please do on 2099/12/31:23:59:59 + * s/2000/2100 + * + */ + yr += 2000; + + seq_printf(seq, "%4.4u-", yr); + (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); + (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day); + (hr > 23) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", hr); + (min > 59) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", min); (sec > 59) ? seq_puts(seq, "**\n") : seq_printf(seq, "%2.2u\n", sec); return 0; @@ -158,15 +150,11 @@ static int acpi_system_alarm_open_fs(struct inode *inode, struct file *file) return single_open(file, acpi_system_alarm_seq_show, PDE(inode)->data); } - -static int -get_date_field ( - char **p, - u32 *value) +static int get_date_field(char **p, u32 * value) { - char *next = NULL; - char *string_end = NULL; - int result = -EINVAL; + char *next = NULL; + char *string_end = NULL; + int result = -EINVAL; /* * Try to find delimeter, only to insert null. The end of the @@ -188,26 +176,22 @@ get_date_field ( return result; } - static ssize_t -acpi_system_write_alarm ( - struct file *file, - const char __user *buffer, - size_t count, - loff_t *ppos) +acpi_system_write_alarm(struct file *file, + const char __user * buffer, size_t count, loff_t * ppos) { - int result = 0; - char alarm_string[30] = {'\0'}; - char *p = alarm_string; - u32 sec, min, hr, day, mo, yr; - int adjust = 0; - unsigned char rtc_control = 0; + int result = 0; + char alarm_string[30] = { '\0' }; + char *p = alarm_string; + u32 sec, min, hr, day, mo, yr; + int adjust = 0; + unsigned char rtc_control = 0; ACPI_FUNCTION_TRACE("acpi_system_write_alarm"); if (count > sizeof(alarm_string) - 1) return_VALUE(-EINVAL); - + if (copy_from_user(alarm_string, buffer, count)) return_VALUE(-EFAULT); @@ -266,10 +250,10 @@ acpi_system_write_alarm ( } if (adjust) { - yr += CMOS_READ(RTC_YEAR); - mo += CMOS_READ(RTC_MONTH); + yr += CMOS_READ(RTC_YEAR); + mo += CMOS_READ(RTC_MONTH); day += CMOS_READ(RTC_DAY_OF_MONTH); - hr += CMOS_READ(RTC_HOURS); + hr += CMOS_READ(RTC_HOURS); min += CMOS_READ(RTC_MINUTES); sec += CMOS_READ(RTC_SECONDS); } @@ -315,6 +299,13 @@ acpi_system_write_alarm ( } spin_lock_irq(&rtc_lock); + /* + * Disable alarm interrupt before setting alarm timer or else + * when ACPI_EVENT_RTC is enabled, a spurious ACPI interrupt occurs + */ + rtc_control &= ~RTC_AIE; + CMOS_WRITE(rtc_control, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); /* write the fields the rtc knows about */ CMOS_WRITE(hr, RTC_HOURS_ALARM); @@ -326,68 +317,188 @@ acpi_system_write_alarm ( * offsets into the CMOS RAM here -- which for some reason are pointing * to the RTC area of memory. */ -#if 0 if (acpi_gbl_FADT->day_alrm) CMOS_WRITE(day, acpi_gbl_FADT->day_alrm); if (acpi_gbl_FADT->mon_alrm) CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm); if (acpi_gbl_FADT->century) - CMOS_WRITE(yr/100, acpi_gbl_FADT->century); -#endif + CMOS_WRITE(yr / 100, acpi_gbl_FADT->century); /* enable the rtc alarm interrupt */ - if (!(rtc_control & RTC_AIE)) { - rtc_control |= RTC_AIE; - CMOS_WRITE(rtc_control,RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - } + rtc_control |= RTC_AIE; + CMOS_WRITE(rtc_control, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); spin_unlock_irq(&rtc_lock); - acpi_set_register(ACPI_BITREG_RT_CLOCK_ENABLE, 1, ACPI_MTX_LOCK); + acpi_clear_event(ACPI_EVENT_RTC); + acpi_enable_event(ACPI_EVENT_RTC, 0); - file->f_pos += count; + *ppos += count; result = 0; -end: + end: return_VALUE(result ? result : count); } +extern struct list_head acpi_wakeup_device_list; +extern spinlock_t acpi_device_lock; +static int +acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset) +{ + struct list_head *node, *next; + + seq_printf(seq, "Device Sleep state Status\n"); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device *dev = + container_of(node, struct acpi_device, wakeup_list); + + if (!dev->wakeup.flags.valid) + continue; + spin_unlock(&acpi_device_lock); + seq_printf(seq, "%4s %4d %s%8s\n", + dev->pnp.bus_id, + (u32) dev->wakeup.sleep_state, + dev->wakeup.flags.run_wake ? "*" : "", + dev->wakeup.state.enabled ? "enabled" : "disabled"); + spin_lock(&acpi_device_lock); + } + spin_unlock(&acpi_device_lock); + return 0; +} + +static ssize_t +acpi_system_write_wakeup_device(struct file *file, + const char __user * buffer, + size_t count, loff_t * ppos) +{ + struct list_head *node, *next; + char strbuf[5]; + char str[5] = ""; + int len = count; + struct acpi_device *found_dev = NULL; + + if (len > 4) + len = 4; + + if (copy_from_user(strbuf, buffer, len)) + return -EFAULT; + strbuf[len] = '\0'; + sscanf(strbuf, "%s", str); + + spin_lock(&acpi_device_lock); + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device *dev = + container_of(node, struct acpi_device, wakeup_list); + if (!dev->wakeup.flags.valid) + continue; + + if (!strncmp(dev->pnp.bus_id, str, 4)) { + dev->wakeup.state.enabled = + dev->wakeup.state.enabled ? 0 : 1; + found_dev = dev; + break; + } + } + if (found_dev) { + list_for_each_safe(node, next, &acpi_wakeup_device_list) { + struct acpi_device *dev = container_of(node, + struct + acpi_device, + wakeup_list); + + if ((dev != found_dev) && + (dev->wakeup.gpe_number == + found_dev->wakeup.gpe_number) + && (dev->wakeup.gpe_device == + found_dev->wakeup.gpe_device)) { + printk(KERN_WARNING + "ACPI: '%s' and '%s' have the same GPE, " + "can't disable/enable one seperately\n", + dev->pnp.bus_id, found_dev->pnp.bus_id); + dev->wakeup.state.enabled = + found_dev->wakeup.state.enabled; + } + } + } + spin_unlock(&acpi_device_lock); + return count; +} + +static int +acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file) +{ + return single_open(file, acpi_system_wakeup_device_seq_show, + PDE(inode)->data); +} + +static struct file_operations acpi_system_wakeup_device_fops = { + .open = acpi_system_wakeup_device_open_fs, + .read = seq_read, + .write = acpi_system_write_wakeup_device, + .llseek = seq_lseek, + .release = single_release, +}; + +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP static struct file_operations acpi_system_sleep_fops = { - .open = acpi_system_sleep_open_fs, - .read = seq_read, - .write = acpi_system_write_sleep, - .llseek = seq_lseek, - .release = single_release, + .open = acpi_system_sleep_open_fs, + .read = seq_read, + .write = acpi_system_write_sleep, + .llseek = seq_lseek, + .release = single_release, }; +#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */ static struct file_operations acpi_system_alarm_fops = { - .open = acpi_system_alarm_open_fs, - .read = seq_read, - .write = acpi_system_write_alarm, - .llseek = seq_lseek, - .release = single_release, + .open = acpi_system_alarm_open_fs, + .read = seq_read, + .write = acpi_system_write_alarm, + .llseek = seq_lseek, + .release = single_release, }; +static u32 rtc_handler(void *context) +{ + acpi_clear_event(ACPI_EVENT_RTC); + acpi_disable_event(ACPI_EVENT_RTC, 0); + + return ACPI_INTERRUPT_HANDLED; +} static int acpi_sleep_proc_init(void) { - struct proc_dir_entry *entry = NULL; + struct proc_dir_entry *entry = NULL; if (acpi_disabled) return 0; - - /* 'sleep' [R/W]*/ - entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP, - S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); + +#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP + /* 'sleep' [R/W] */ + entry = + create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir); if (entry) entry->proc_fops = &acpi_system_sleep_fops; +#endif /* 'alarm' [R/W] */ - entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM, - S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir); + entry = + create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir); if (entry) entry->proc_fops = &acpi_system_alarm_fops; + + /* 'wakeup device' [R/W] */ + entry = + create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir); + if (entry) + entry->proc_fops = &acpi_system_wakeup_device_fops; + + acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); return 0; }