⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 driver.c

📁 讲述linux的初始化过程
💻 C
字号:
/* *  driver.c - ACPI driver * *  Copyright (C) 2000 Andrew Henroid * *  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 *//* * Changes * David Woodhouse <dwmw2@redhat.com> 2000-12-6 * - Fix interruptible_sleep_on() races */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/proc_fs.h>#include <linux/sysctl.h>#include <linux/pm.h>#include <linux/acpi.h>#include <asm/uaccess.h>#include "acpi.h"#include "driver.h"#ifdef CONFIG_ACPI_KERNEL_CONFIG#include <asm/efi.h>#define ACPI_CAN_USE_EFI_STRUCT#endif#define _COMPONENT	OS_DEPENDENT	MODULE_NAME	("driver")struct acpi_run_entry{	void (*callback)(void*);	void *context;	struct tq_struct task;};static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED;static volatile u32 acpi_event_status = 0;static volatile acpi_sstate_t acpi_event_state = ACPI_S0;static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait);static volatile int acpi_thread_pid = -1;/************************************************//* DECLARE_TASK_QUEUE is defined in             *//* /usr/src/linux/include/linux/tqueue.h        *//* So, acpi_thread_run is a pointer to a        *//* tq_struct structure,defined in the same file.*//************************************************/static DECLARE_TASK_QUEUE(acpi_thread_run);static DECLARE_WAIT_QUEUE_HEAD(acpi_thread_wait);static struct ctl_table_header *acpi_sysctl = NULL;/* * Examine/modify value */static int acpi_do_ulong(ctl_table * ctl,	      int write,	      struct file *file,	      void *buffer,	      size_t * len){	char str[2 * sizeof(unsigned long) + 4], *strend;	unsigned long val;	int size;	if (!write) {		if (file->f_pos) {			*len = 0;			return 0;		}		val = *(unsigned long *) ctl->data;		size = sprintf(str, "0x%08lx\n", val);		if (*len >= size) {			copy_to_user(buffer, str, size);			*len = size;		}		else			*len = 0;	}	else {		size = sizeof(str) - 1;		if (size > *len)			size = *len;		copy_from_user(str, buffer, size);		str[size] = '\0';		val = simple_strtoul(str, &strend, 0);		if (strend == str)			return -EINVAL;		*(unsigned long *) ctl->data = val;	}	file->f_pos += *len;	return 0;}static int acpi_do_pm_timer(ctl_table * ctl,	      int write,	      struct file *file,	      void *buffer,	      size_t * len){	int size;	u32 val = 0;	char str[12];	if (file->f_pos) {		*len = 0;		return 0;	}	val = acpi_read_pm_timer();	size = sprintf(str, "0x%08x\n", val);	if (*len >= size) {		copy_to_user(buffer, str, size);		*len = size;	}	else		*len = 0;	file->f_pos += *len;	return 0;}/* * Handle ACPI event */static u32acpi_event(void *context){	unsigned long flags;	int event = (int)(long)context;	int mask = 0;	switch (event) {	case ACPI_EVENT_POWER_BUTTON:		mask = ACPI_PWRBTN;		break;	case ACPI_EVENT_SLEEP_BUTTON:		mask = ACPI_SLPBTN;		break;	default:		return AE_ERROR;	}	if (mask) {		// notify process waiting on /dev/acpi		spin_lock_irqsave(&acpi_event_lock, flags);		acpi_event_status |= mask;		spin_unlock_irqrestore(&acpi_event_lock, flags);		acpi_event_state = acpi_sleep_state;		wake_up_interruptible(&acpi_event_wait);	}	return AE_OK;}/* * Wait for next event */static intacpi_do_event(ctl_table * ctl,	      int write,	      struct file *file,	      void *buffer,	      size_t * len){	u32 event_status = 0;	acpi_sstate_t event_state = 0;	char str[27];	int size;	if (write)		return -EPERM;	if (*len < sizeof(str)) {		*len = 0;		return 0;	}	while (!event_status) {		unsigned long flags;		DECLARE_WAITQUEUE(wait, current);		set_current_state(TASK_INTERRUPTIBLE);		add_wait_queue(&acpi_event_wait, &wait);		// we need an atomic exchange here		spin_lock_irqsave(&acpi_event_lock, flags);		event_status = acpi_event_status;		acpi_event_status = 0;		spin_unlock_irqrestore(&acpi_event_lock, flags);		event_state = acpi_event_state;		if (!event_status)			schedule();		remove_wait_queue(&acpi_event_wait, &wait);		set_current_state(TASK_RUNNING);		if (signal_pending(current))			return -ERESTARTSYS;	}	size = sprintf(str,		       "0x%08x 0x%08x 0x%01x\n",		       event_status,		       0,		       event_state);	copy_to_user(buffer, str, size);	*len = size;	file->f_pos += size;	return 0;}/* * Enter system sleep state */static int acpi_do_sleep(ctl_table * ctl,	      int write,	      struct file *file,	      void *buffer,	      size_t * len){	if (!write) {		if (file->f_pos) {			*len = 0;			return 0;		}	}	else {		int status = acpi_enter_sx(ACPI_S1);		if (status)			return status;	}	file->f_pos += *len;	return 0;}/* * Output important ACPI tables to proc */static int acpi_do_table(ctl_table * ctl,	      int write,	      struct file *file,	      void *buffer,	      size_t * len){	u32 table_type;	size_t size;	ACPI_BUFFER buf;	u8* data;	table_type = (u32) ctl->data;	size = 0;	buf.length = 0;	buf.pointer = NULL;	/* determine what buffer size we will need */	if (acpi_get_table(table_type, 1, &buf) != AE_BUFFER_OVERFLOW) {		*len = 0;		return 0;	}	buf.pointer = kmalloc(buf.length, GFP_KERNEL);	if (!buf.pointer) {		return -ENOMEM;	}	/* get the table for real */	if (!ACPI_SUCCESS(acpi_get_table(table_type, 1, &buf))) {		kfree(buf.pointer);		*len = 0;		return 0;	}	if (file->f_pos < buf.length) {		data = buf.pointer + file->f_pos;		size = buf.length - file->f_pos;		if (size > *len)			size = *len;		if (copy_to_user(buffer, data, size))			return -EFAULT;	}	kfree(buf.pointer);	*len = size;	file->f_pos += size;	return 0;}/********************************************************************//*              R U N    Q U E U E D   C A L L B A C K              *//*                                                                  *//* The "callback" function address that was tramped through via     *//* "acpi_run" below is finally called and executed. If we trace all *//* this down, the function is acpi_ev_asynch_execute_gpe_method, in */ /* evevent.c   The only other function that is ever queued is       *//* acpi_ev_global_lock_thread in evmisc.c.                          *//********************************************************************/static voidacpi_run_exec(void *context){	struct acpi_run_entry *entry		= (struct acpi_run_entry*) context;	(*entry->callback)(entry->context);	kfree(entry);}/* * Queue for execution by the ACPI thread */intacpi_run(void (*callback)(void*), void *context){	struct acpi_run_entry *entry;	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);	if (!entry)		return -1;	memset(entry, 0, sizeof(entry));	entry->callback = callback;	entry->context = context;	entry->task.routine = acpi_run_exec;	entry->task.data = entry;	queue_task(&entry->task, &acpi_thread_run);	if (waitqueue_active(&acpi_thread_wait))		wake_up(&acpi_thread_wait);	return 0;}static struct ctl_table acpi_table[] ={	{ACPI_P_LVL2_LAT, "c2_exit_latency",	 &acpi_c2_exit_latency, sizeof(acpi_c2_exit_latency),	 0644, NULL, &acpi_do_ulong},	{ACPI_ENTER_LVL2_LAT, "c2_enter_latency",	 &acpi_c2_enter_latency, sizeof(acpi_c2_enter_latency),	 0644, NULL, &acpi_do_ulong},	{ACPI_P_LVL3_LAT, "c3_exit_latency",	 &acpi_c3_exit_latency, sizeof(acpi_c3_exit_latency),	 0644, NULL, &acpi_do_ulong},	{ACPI_ENTER_LVL3_LAT, "c3_enter_latency",	 &acpi_c3_enter_latency, sizeof(acpi_c3_enter_latency),	 0644, NULL, &acpi_do_ulong},	{ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep},	{ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event},	{ACPI_FADT, "fadt", (void *) ACPI_TABLE_FADT, sizeof(int),	 0444, NULL, &acpi_do_table},		{ACPI_DSDT, "dsdt", (void *) ACPI_TABLE_DSDT, sizeof(int),	 0444, NULL, &acpi_do_table},	{ACPI_FACS, "facs", (void *) ACPI_TABLE_FACS, sizeof(int),	 0444, NULL, &acpi_do_table},	{ACPI_XSDT, "xsdt", (void *) ACPI_TABLE_XSDT, sizeof(int),	 0444, NULL, &acpi_do_table},	{ACPI_PMTIMER, "pm_timer", NULL, 0, 0444, NULL, &acpi_do_pm_timer},		{0}};static struct ctl_table acpi_dir_table[] ={	{CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table},	{0}};/* * Initialize and run interpreter within a kernel thread */static intacpi_thread(void *context){	ACPI_PHYSICAL_ADDRESS rsdp_phys;	/*	 * initialize	 */	daemonize();	strcpy(current->comm, "kacpid");	if (!ACPI_SUCCESS(acpi_initialize_subsystem())) {		printk(KERN_ERR "ACPI: Driver initialization failed\n");		return -ENODEV;	}#ifndef ACPI_CAN_USE_EFI_STRUCT	if (!ACPI_SUCCESS(acpi_find_root_pointer(&rsdp_phys))) {		printk(KERN_ERR "ACPI: System description tables not found\n");		return -ENODEV;	}#else	rsdp_phys = efi.acpi;#endif			printk(KERN_ERR "ACPI: System description tables found\n");		if (!ACPI_SUCCESS(acpi_find_and_load_tables(rsdp_phys)))		return -ENODEV;	if (PM_IS_ACTIVE()) {		printk(KERN_NOTICE "ACPI: APM is already active, exiting\n");		acpi_terminate();		return -ENODEV;	}	if (!ACPI_SUCCESS(acpi_enable_subsystem(ACPI_FULL_INITIALIZATION))) {		printk(KERN_ERR "ACPI: Subsystem enable failed\n");		acpi_terminate();		return -ENODEV;	}	printk(KERN_ERR "ACPI: Subsystem enabled\n");	pm_active = 1;	acpi_cpu_init();	acpi_sys_init();	acpi_ec_init();	acpi_power_init();	/* 	 * Non-intuitive: 0 means pwr and sleep are implemented using the fixed	 * feature model, so we install handlers. 1 means a control method	 * implementation, or none at all, so do nothing. See ACPI spec.	 */	if (acpi_fadt.pwr_button == 0) {		if (!ACPI_SUCCESS(acpi_install_fixed_event_handler(			ACPI_EVENT_POWER_BUTTON,			acpi_event,			(void *) ACPI_EVENT_POWER_BUTTON))) {			printk(KERN_ERR "ACPI: power button enable failed\n");		}	}	if (acpi_fadt.sleep_button == 0) {		if (!ACPI_SUCCESS(acpi_install_fixed_event_handler(			ACPI_EVENT_SLEEP_BUTTON,			acpi_event,			(void *) ACPI_EVENT_SLEEP_BUTTON))) {			printk(KERN_ERR "ACPI: sleep button enable failed\n");		}	}	acpi_sysctl = register_sysctl_table(acpi_dir_table, 1);	/*	 * run	 */	for (;;) {		DECLARE_WAITQUEUE(wait, current);		set_current_state(TASK_INTERRUPTIBLE);		add_wait_queue(&acpi_thread_wait, &wait);		if (list_empty(&acpi_thread_run))			schedule();		remove_wait_queue(&acpi_thread_wait, &wait);		set_current_state(TASK_RUNNING);		if (signal_pending(current))			break;		run_task_queue(&acpi_thread_run);	}	/*	 * terminate	 */	unregister_sysctl_table(acpi_sysctl);	/* do not terminate, because we need acpi in order to shut down */	/*acpi_terminate();*/	acpi_thread_pid = -1;	return 0;}/* * Start the interpreter */int __initacpi_init(void){	acpi_thread_pid = kernel_thread(acpi_thread,					NULL,					(CLONE_FS | CLONE_FILES					 | CLONE_SIGHAND | SIGCHLD));	return ((acpi_thread_pid >= 0) ? 0:-ENODEV);}/* * Terminate the interpreter */void __exitacpi_exit(void){	int count;	if (!kill_proc(acpi_thread_pid, SIGTERM, 1)) {		// wait until thread terminates (at most 5 seconds)		count = 5 * HZ;		while (acpi_thread_pid >= 0 && --count) {			current->state = TASK_INTERRUPTIBLE;			schedule_timeout(1);		}	}	pm_idle = NULL;	pm_power_off = NULL;	pm_active = 0;}module_init(acpi_init);module_exit(acpi_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -