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

📄 apm.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	cli();	/* set the clock to 100 Hz */	outb_p(0x34,0x43);		/* binary, mode 2, LSB/MSB, ch 0 */	udelay(10);	outb_p(LATCH & 0xff , 0x40);	/* LSB */	udelay(10);	outb(LATCH >> 8 , 0x40);	/* MSB */	udelay(10);	restore_flags(flags);#endif}static int send_event(apm_event_t event){	switch (event) {	case APM_SYS_SUSPEND:	case APM_CRITICAL_SUSPEND:	case APM_USER_SUSPEND:		/* map all suspends to ACPI D3 */		if (pm_send_all(PM_SUSPEND, (void *)3)) {			if (event == APM_CRITICAL_SUSPEND) {				printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armageddon\n" );				return 0;			}			if (apm_info.connection_version > 0x100)				apm_set_power_state(APM_STATE_REJECT);			return 0;		}		break;	case APM_NORMAL_RESUME:	case APM_CRITICAL_RESUME:		/* map all resumes to ACPI D0 */		(void) pm_send_all(PM_RESUME, (void *)0);		break;	}	return 1;}static int suspend(void){	int		err;	struct apm_user	*as;	get_time_diff();	cli();	err = apm_set_power_state(APM_STATE_SUSPEND);	reinit_timer();	set_time();	if (err == APM_NO_ERROR)		err = APM_SUCCESS;	if (err != APM_SUCCESS)		apm_error("suspend", err);	send_event(APM_NORMAL_RESUME);	sti();	queue_event(APM_NORMAL_RESUME, NULL);	for (as = user_list; as != NULL; as = as->next) {		as->suspend_wait = 0;		as->suspend_result = ((err == APM_SUCCESS) ? 0 : -EIO);	}	ignore_normal_resume = 1;	wake_up_interruptible(&apm_suspend_waitqueue);	return err;}static void standby(void){	int	err;	get_time_diff();	err = apm_set_power_state(APM_STATE_STANDBY);	if ((err != APM_SUCCESS) && (err != APM_NO_ERROR))		apm_error("standby", err);}static apm_event_t get_event(void){	int		error;	apm_event_t	event;	apm_eventinfo_t	info;	static int notified;	/* we don't use the eventinfo */	error = apm_get_event(&event, &info);	if (error == APM_SUCCESS)		return event;	if ((error != APM_NO_EVENTS) && (notified++ == 0))		apm_error("get_event", error);	return 0;}static void check_events(void){	apm_event_t		event;	static unsigned long	last_resume;	static int		ignore_bounce;	while ((event = get_event()) != 0) {		if (debug) {			if (event <= NR_APM_EVENT_NAME)				printk(KERN_DEBUG "apm: received %s notify\n",				       apm_event_name[event - 1]);			else				printk(KERN_DEBUG "apm: received unknown "				       "event 0x%02x\n", event);		}		if (ignore_bounce		    && ((jiffies - last_resume) > bounce_interval))			ignore_bounce = 0;		if (ignore_normal_resume && (event != APM_NORMAL_RESUME))			ignore_normal_resume = 0;		switch (event) {		case APM_SYS_STANDBY:		case APM_USER_STANDBY:			if (send_event(event)) {				queue_event(event, NULL);				if (standbys_pending <= 0)					standby();			}			break;		case APM_USER_SUSPEND:#ifdef CONFIG_APM_IGNORE_USER_SUSPEND			if (apm_info.connection_version > 0x100)				apm_set_power_state(APM_STATE_REJECT);			break;#endif		case APM_SYS_SUSPEND:			if (ignore_bounce) {				if (apm_info.connection_version > 0x100)					apm_set_power_state(APM_STATE_REJECT);				break;			}			/*			 * If we are already processing a SUSPEND,			 * then further SUSPEND events from the BIOS			 * will be ignored.  We also return here to			 * cope with the fact that the Thinkpads keep			 * sending a SUSPEND event until something else			 * happens!			 */			if (waiting_for_resume)				return;			if (send_event(event)) {				queue_event(event, NULL);				waiting_for_resume = 1;				if (suspends_pending <= 0)					(void) suspend();			}			break;		case APM_NORMAL_RESUME:		case APM_CRITICAL_RESUME:		case APM_STANDBY_RESUME:			waiting_for_resume = 0;			last_resume = jiffies;			ignore_bounce = 1;			if ((event != APM_NORMAL_RESUME)			    || (ignore_normal_resume == 0)) {				set_time();				send_event(event);				queue_event(event, NULL);			}			break;		case APM_CAPABILITY_CHANGE:		case APM_LOW_BATTERY:		case APM_POWER_STATUS_CHANGE:			send_event(event);			queue_event(event, NULL);			break;		case APM_UPDATE_TIME:			set_time();			break;		case APM_CRITICAL_SUSPEND:			send_event(event);			/*			 * We can only hope it worked - we are not allowed			 * to reject a critical suspend.			 */			(void) suspend();			break;		}	}}static void apm_event_handler(void){	static int	pending_count = 4;	int		err;	if ((standbys_pending > 0) || (suspends_pending > 0)) {		if ((apm_info.connection_version > 0x100) && (pending_count-- <= 0)) {			pending_count = 4;			if (debug)				printk(KERN_DEBUG "apm: setting state busy\n");			err = apm_set_power_state(APM_STATE_BUSY);			if (err)				apm_error("busy", err);		}	} else		pending_count = 4;	check_events();}/* * This is the APM thread main loop. * * Check whether we're the only running process to * decide if we should just power down. * */#define system_idle() (nr_running == 1)static void apm_mainloop(void){	int timeout = HZ;	DECLARE_WAITQUEUE(wait, current);	add_wait_queue(&apm_waitqueue, &wait);	set_current_state(TASK_INTERRUPTIBLE);	for (;;) {		/* Nothing to do, just sleep for the timeout */		timeout = 2*timeout;		if (timeout > APM_CHECK_TIMEOUT)			timeout = APM_CHECK_TIMEOUT;		schedule_timeout(timeout);		if (exit_kapmd)			break;		/*		 * Ok, check all events, check for idle (and mark us sleeping		 * so as not to count towards the load average)..		 */		set_current_state(TASK_INTERRUPTIBLE);		apm_event_handler();#ifdef CONFIG_APM_CPU_IDLE		if (!system_idle())			continue;		if (apm_do_idle()) {			unsigned long start = jiffies;			while ((!exit_kapmd) && system_idle()) {				apm_do_idle();				if ((jiffies - start) > APM_CHECK_TIMEOUT) {					apm_event_handler();					start = jiffies;				}			}			apm_do_busy();			apm_event_handler();			timeout = 1;		}#endif	}	remove_wait_queue(&apm_waitqueue, &wait);}static int check_apm_user(struct apm_user *as, const char *func){	if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {		printk(KERN_ERR "apm: %s passed bad filp\n", func);		return 1;	}	return 0;}static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos){	struct apm_user *	as;	int			i;	apm_event_t		event;	DECLARE_WAITQUEUE(wait, current);	as = fp->private_data;	if (check_apm_user(as, "read"))		return -EIO;	if (count < sizeof(apm_event_t))		return -EINVAL;	if (queue_empty(as)) {		if (fp->f_flags & O_NONBLOCK)			return -EAGAIN;		add_wait_queue(&apm_waitqueue, &wait);repeat:		set_current_state(TASK_INTERRUPTIBLE);		if (queue_empty(as) && !signal_pending(current)) {			schedule();			goto repeat;		}		set_current_state(TASK_RUNNING);		remove_wait_queue(&apm_waitqueue, &wait);	}	i = count;	while ((i >= sizeof(event)) && !queue_empty(as)) {		event = get_queued_event(as);		if (copy_to_user(buf, &event, sizeof(event))) {			if (i < count)				break;			return -EFAULT;		}		switch (event) {		case APM_SYS_SUSPEND:		case APM_USER_SUSPEND:			as->suspends_read++;			break;		case APM_SYS_STANDBY:		case APM_USER_STANDBY:			as->standbys_read++;			break;		}		buf += sizeof(event);		i -= sizeof(event);	}	if (i < count)		return count - i;	if (signal_pending(current))		return -ERESTARTSYS;	return 0;}static unsigned int do_poll(struct file *fp, poll_table * wait){	struct apm_user * as;	as = fp->private_data;	if (check_apm_user(as, "poll"))		return 0;	poll_wait(fp, &apm_waitqueue, wait);	if (!queue_empty(as))		return POLLIN | POLLRDNORM;	return 0;}static int do_ioctl(struct inode * inode, struct file *filp,		    u_int cmd, u_long arg){	struct apm_user *	as;	DECLARE_WAITQUEUE(wait, current);	as = filp->private_data;	if (check_apm_user(as, "ioctl"))		return -EIO;	if (!as->suser)		return -EPERM;	switch (cmd) {	case APM_IOC_STANDBY:		if (as->standbys_read > 0) {			as->standbys_read--;			as->standbys_pending--;			standbys_pending--;		} else if (!send_event(APM_USER_STANDBY))			return -EAGAIN;		else			queue_event(APM_USER_STANDBY, as);		if (standbys_pending <= 0)			standby();		break;	case APM_IOC_SUSPEND:		if (as->suspends_read > 0) {			as->suspends_read--;			as->suspends_pending--;			suspends_pending--;		} else if (!send_event(APM_USER_SUSPEND))			return -EAGAIN;		else			queue_event(APM_USER_SUSPEND, as);		if (suspends_pending <= 0) {			if (suspend() != APM_SUCCESS)				return -EIO;		} else {			as->suspend_wait = 1;			add_wait_queue(&apm_suspend_waitqueue, &wait);			while (1) {				set_current_state(TASK_INTERRUPTIBLE);				if ((as->suspend_wait == 0)				    || signal_pending(current))					break;				schedule();			}			set_current_state(TASK_RUNNING);			remove_wait_queue(&apm_suspend_waitqueue, &wait);			return as->suspend_result;		}		break;	default:		return -EINVAL;	}	return 0;}static int do_release(struct inode * inode, struct file * filp){	struct apm_user *	as;	as = filp->private_data;	if (check_apm_user(as, "release"))		return 0;	filp->private_data = NULL;	lock_kernel();	if (as->standbys_pending > 0) {		standbys_pending -= as->standbys_pending;		if (standbys_pending <= 0)			standby();	}	if (as->suspends_pending > 0) {		suspends_pending -= as->suspends_pending;		if (suspends_pending <= 0)			(void) suspend();	}	if (user_list == as)		user_list = as->next;	else {		struct apm_user *	as1;		for (as1 = user_list;		     (as1 != NULL) && (as1->next != as);		     as1 = as1->next)			;		if (as1 == NULL)			printk(KERN_ERR "apm: filp not in user list\n");		else			as1->next = as->next;	}	unlock_kernel();	kfree(as);	return 0;}static int do_open(struct inode * inode, struct file * filp){	struct apm_user *	as;

⌨️ 快捷键说明

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