📄 sm_osl.c
字号:
/****************************************************************************** * * Module Name: sm_osl.c * $Revision: 16 $ * *****************************************************************************//* * Copyright (C) 2000, 2001 Andrew Grover * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/proc_fs.h>#include <linux/pm.h>#include <asm/uaccess.h>#include <linux/acpi.h>#include <asm/io.h>#include <linux/mc146818rtc.h>#include <linux/delay.h>#include <acpi.h>#include "sm.h"MODULE_AUTHOR("Andrew Grover");MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI System Driver");MODULE_LICENSE("GPL");#define SM_PROC_INFO "info"#define SM_PROC_DSDT "dsdt"extern struct proc_dir_entry *bm_proc_root;struct proc_dir_entry *sm_proc_root = NULL;static void (*sm_pm_power_off)(void) = NULL;static ssize_t sm_osl_read_dsdt(struct file *, char *, size_t, loff_t *);static struct file_operations proc_dsdt_operations = { read: sm_osl_read_dsdt,};static acpi_status sm_osl_suspend(u32 state);struct proc_dir_entry *bm_proc_sleep;struct proc_dir_entry *bm_proc_alarm;struct proc_dir_entry *bm_proc_gpe;static intsm_osl_proc_read_sleep ( char *page, char **start, off_t off, int count, int *eof, void *context){ SM_CONTEXT *system = (SM_CONTEXT*) context; char *str = page; int len; int i; if (!system) goto end; if (off != 0) goto end; for (i = 0; i <= ACPI_S5; i++) { if (system->states[i]) str += sprintf(str,"S%d ", i); } str += sprintf(str, "\n");end: len = (str - page); if (len < (off + count)) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return (len);}int sm_osl_proc_write_sleep (struct file *file, const char *buffer, unsigned long count, void *data){ SM_CONTEXT *system = (SM_CONTEXT*) data; char str[10]; char *strend; unsigned long value; if (count > (sizeof(str) - 1)) return -EINVAL; if (copy_from_user(str,buffer,count)) return -EFAULT; str[count] = '\0'; value = simple_strtoul(str,&strend,0); if (str == strend) return -EINVAL; if (value == 0 || value >= ACPI_S5) return -EINVAL; /* * make sure that the sleep state is supported */ if (system->states[value] != TRUE) return -EINVAL; sm_osl_suspend(value); return (count);}/**************************************************************************** * * FUNCTION: sm_osl_proc_read_info * ****************************************************************************/static intsm_osl_proc_read_info ( char *page, char **start, off_t off, int count, int *eof, void *context){ acpi_status status = AE_OK; SM_CONTEXT *system = NULL; char *p = page; int len; acpi_system_info system_info; acpi_buffer buffer; u32 i = 0; if (!context) { goto end; } system = (SM_CONTEXT*) context; /* don't get status more than once for a single proc read */ if (off != 0) { goto end; } /* * Get ACPI CA Information. */ buffer.length = sizeof(system_info); buffer.pointer = &system_info; status = acpi_get_system_info(&buffer); if (ACPI_FAILURE(status)) { p += sprintf(p, "ACPI-CA Version: unknown\n"); } else { p += sprintf(p, "ACPI-CA Version: %x\n", system_info.acpi_ca_version); } p += sprintf(p, "Sx States Supported: "); for (i=0; i<SM_MAX_SYSTEM_STATES; i++) { if (system->states[i]) { p += sprintf(p, "S%d ", i); } } p += sprintf(p, "\n");end: len = (p - page); if (len <= off+count) *eof = 1; *start = page + off; len -= off; if (len>count) len = count; if (len<0) len = 0; return(len);}/**************************************************************************** * * FUNCTION: sm_osl_read_dsdt * ****************************************************************************/static ssize_tsm_osl_read_dsdt( struct file *file, char *buf, size_t count, loff_t *ppos){ acpi_buffer acpi_buf; void *data; size_t size = 0; acpi_buf.length = 0; acpi_buf.pointer = NULL; /* determine what buffer size we will need */ if (acpi_get_table(ACPI_TABLE_DSDT, 1, &acpi_buf) != AE_BUFFER_OVERFLOW) { return 0; } acpi_buf.pointer = kmalloc(acpi_buf.length, GFP_KERNEL); if (!acpi_buf.pointer) { return -ENOMEM; } /* get the table for real */ if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_DSDT, 1, &acpi_buf))) { kfree(acpi_buf.pointer); return 0; } if (*ppos < acpi_buf.length) { data = acpi_buf.pointer + file->f_pos; size = acpi_buf.length - file->f_pos; if (size > count) size = count; if (copy_to_user(buf, data, size)) { kfree(acpi_buf.pointer); return -EFAULT; } } kfree(acpi_buf.pointer); *ppos += size; return size;}static intsm_osl_proc_read_alarm ( char *page, char **start, off_t off, int count, int *eof, void *context){ char *str = page; int len; u32 sec,min,hr; u32 day,mo,yr; if (off != 0) goto out; spin_lock(&rtc_lock); sec = CMOS_READ(RTC_SECONDS_ALARM); min = CMOS_READ(RTC_MINUTES_ALARM); hr = CMOS_READ(RTC_HOURS_ALARM);#if 0 /* if I ever get an FACP with proper values, maybe I'll enable this code */ if (acpi_gbl_FADT->day_alrm) day = CMOS_READ(acpi_gbl_FADT->day_alrm); else 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); 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); str += sprintf(str,"%4.4u-",yr); str += (mo > 12) ? sprintf(str,"**-") : sprintf(str,"%2.2u-",mo); str += (day > 31) ? sprintf(str,"** ") : sprintf(str,"%2.2u ",day); str += (hr > 23) ? sprintf(str,"**:") : sprintf(str,"%2.2u:",hr); str += (min > 59) ? sprintf(str,"**:") : sprintf(str,"%2.2u:",min); str += (sec > 59) ? sprintf(str,"**\n") : sprintf(str,"%2.2u\n",sec); out: len = str - page; if (len < count) *eof = 1; else if (len > count) len = count; if (len < 0) len = 0; *start = page; return len;}static int get_date_field(char **str, u32 *value){ char *next,*strend; int error = -EINVAL; /* try to find delimeter, only to insert null; * the end of string won't have one, but is still valid */ next = strpbrk(*str,"- :"); if (next) *next++ = '\0'; *value = simple_strtoul(*str,&strend,10); /* signal success if we got a good digit */ if (strend != *str) error = 0; if (next) *str = next; return error;}int sm_osl_proc_write_alarm ( struct file *file, const char *buffer, unsigned long count, void *data){ char buf[30]; char *str = buf; u32 sec,min,hr; u32 day,mo,yr; int adjust = 0; unsigned char rtc_control; int error = -EINVAL; if (count > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(str,buffer,count)) return -EFAULT; str[count] = '\0'; /* check for time adjustment */ if (str[0] == '+') { str++; adjust = 1; } if ((error = get_date_field(&str,&yr))) goto out; if ((error = get_date_field(&str,&mo))) goto out; if ((error = get_date_field(&str,&day))) goto out; if ((error = get_date_field(&str,&hr))) goto out; if ((error = get_date_field(&str,&min))) goto out; if ((error = get_date_field(&str,&sec))) goto out; if (sec > 59) { min += 1; sec -= 60; } if (min > 59) { hr += 1; min -= 60; } if (hr > 23) { day += 1; hr -= 24; } if (day > 31) { mo += 1; day -= 31; } if (mo > 12) { yr += 1; mo -= 12; } spin_lock_irq(&rtc_lock); rtc_control = CMOS_READ(RTC_CONTROL); if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BIN_TO_BCD(yr); BIN_TO_BCD(mo); BIN_TO_BCD(day); BIN_TO_BCD(hr); BIN_TO_BCD(min); BIN_TO_BCD(sec); } if (adjust) { yr += CMOS_READ(RTC_YEAR); mo += CMOS_READ(RTC_MONTH); day += CMOS_READ(RTC_DAY_OF_MONTH); hr += CMOS_READ(RTC_HOURS); min += CMOS_READ(RTC_MINUTES); sec += CMOS_READ(RTC_SECONDS); } spin_unlock_irq(&rtc_lock); if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(yr); BCD_TO_BIN(mo); BCD_TO_BIN(day); BCD_TO_BIN(hr); BCD_TO_BIN(min); BCD_TO_BIN(sec); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -