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

📄 apm.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
#	define APM_DECL_SEGS#	define APM_DO_SAVE_SEGS#	define APM_DO_ZERO_SEGS#	define APM_DO_POP_SEGS#	define APM_DO_RESTORE_SEGS#endifstatic u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,	u32 *eax, u32 *ebx, u32 *ecx, u32 *edx, u32 *esi){	APM_DECL_SEGS	unsigned long	flags;	__save_flags(flags);	APM_DO_CLI;	APM_DO_SAVE_SEGS;	/*	 * N.B. We do NOT need a cld after the BIOS call	 * because we always save and restore the flags.	 */	__asm__ __volatile__(APM_DO_ZERO_SEGS		"pushl %%edi\n\t"		"pushl %%ebp\n\t"		"lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"		"setc %%al\n\t"		"popl %%ebp\n\t"		"popl %%edi\n\t"		APM_DO_POP_SEGS		: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx),		  "=S" (*esi)		: "a" (func), "b" (ebx_in), "c" (ecx_in)		: "memory", "cc");	APM_DO_RESTORE_SEGS;	__restore_flags(flags);	return *eax & 0xff;}/* * This version only returns one value (usually an error code) */static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax){	u8		error;	APM_DECL_SEGS	unsigned long	flags;	__save_flags(flags);	APM_DO_CLI;	APM_DO_SAVE_SEGS;	{		int	cx, dx, si;		/*		 * N.B. We do NOT need a cld after the BIOS call		 * because we always save and restore the flags.		 */		__asm__ __volatile__(APM_DO_ZERO_SEGS			"pushl %%edi\n\t"			"pushl %%ebp\n\t"			"lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t"			"setc %%bl\n\t"			"popl %%ebp\n\t"			"popl %%edi\n\t"			APM_DO_POP_SEGS			: "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx),			  "=S" (si)			: "a" (func), "b" (ebx_in), "c" (ecx_in)			: "memory", "cc");	}	APM_DO_RESTORE_SEGS;	__restore_flags(flags);	return error;}static int __init apm_driver_version(u_short *val){	u32	eax;	if (apm_bios_call_simple(APM_FUNC_VERSION, 0, *val, &eax))		return (eax >> 8) & 0xff;	*val = eax;	return APM_SUCCESS;}static int apm_get_event(apm_event_t *event, apm_eventinfo_t *info){	u32	eax;	u32	ebx;	u32	ecx;	u32	dummy;	if (apm_bios_call(APM_FUNC_GET_EVENT, 0, 0, &eax, &ebx, &ecx,			&dummy, &dummy))		return (eax >> 8) & 0xff;	*event = ebx;	if (apm_info.connection_version < 0x0102)		*info = ~0; /* indicate info not valid */	else		*info = ecx;	return APM_SUCCESS;}static int set_power_state(u_short what, u_short state){	u32	eax;	if (apm_bios_call_simple(APM_FUNC_SET_STATE, what, state, &eax))		return (eax >> 8) & 0xff;	return APM_SUCCESS;}static int apm_set_power_state(u_short state){	return set_power_state(APM_DEVICE_ALL, state);}#ifdef CONFIG_APM_CPU_IDLEstatic int apm_do_idle(void){	u32	dummy;	if (apm_bios_call_simple(APM_FUNC_IDLE, 0, 0, &dummy))		return 0;#ifdef ALWAYS_CALL_BUSY	clock_slowed = 1;#else	clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;#endif	return 1;}static void apm_do_busy(void){	u32	dummy;	if (clock_slowed) {		(void) apm_bios_call_simple(APM_FUNC_BUSY, 0, 0, &dummy);		clock_slowed = 0;	}}#if 0extern int hlt_counter;/* * If no process has been interested in this * CPU for some time, we want to wake up the * power management thread - we probably want * to conserve power. */#define HARD_IDLE_TIMEOUT (HZ/3)/* This should wake up kapmd and ask it to slow the CPU */#define powermanagement_idle()  do { } while (0)/* * This is the idle thing. */static void apm_cpu_idle(void){	unsigned int start_idle;	start_idle = jiffies;	while (1) {		if (!current->need_resched) {			if (jiffies - start_idle < HARD_IDLE_TIMEOUT) {				if (!current_cpu_data.hlt_works_ok)					continue;				if (hlt_counter)					continue;				__cli();				if (!current->need_resched)					safe_halt();				else					__sti();				continue;			}			/*			 * Ok, do some power management - we've been idle for too long			 */			powermanagement_idle();		}		schedule();		check_pgt_cache();		start_idle = jiffies;	}}#endif#endif#ifdef CONFIG_SMPstatic int apm_magic(void * unused){	while (1)		schedule();}#endifstatic void apm_power_off(void){#ifdef CONFIG_APM_REAL_MODE_POWER_OFF	unsigned char	po_bios_call[] = {		0xb8, 0x00, 0x10,	/* movw  $0x1000,ax  */		0x8e, 0xd0,		/* movw  ax,ss       */		0xbc, 0x00, 0xf0,	/* movw  $0xf000,sp  */		0xb8, 0x07, 0x53,	/* movw  $0x5307,ax  */		0xbb, 0x01, 0x00,	/* movw  $0x0001,bx  */		0xb9, 0x03, 0x00,	/* movw  $0x0003,cx  */		0xcd, 0x15		/* int   $0x15       */	};#endif	/*	 * This may be called on an SMP machine.	 */#ifdef CONFIG_SMP	/* Some bioses don't like being called from CPU != 0 */	while (cpu_number_map(smp_processor_id()) != 0) {		kernel_thread(apm_magic, NULL,			CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);		schedule();	}#endif#ifdef CONFIG_APM_REAL_MODE_POWER_OFF	machine_real_restart(po_bios_call, sizeof(po_bios_call));#else	(void) apm_set_power_state(APM_STATE_OFF);#endif}#ifdef CONFIG_APM_DO_ENABLEstatic int apm_enable_power_management(int enable){	u32	eax;	if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))		return APM_NOT_ENGAGED;	if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,			enable, &eax))		return (eax >> 8) & 0xff;	if (enable)		apm_info.bios.flags &= ~APM_BIOS_DISABLED;	else		apm_info.bios.flags |= APM_BIOS_DISABLED;	return APM_SUCCESS;}#endifstatic int apm_get_power_status(u_short *status, u_short *bat, u_short *life){	u32	eax;	u32	ebx;	u32	ecx;	u32	edx;	u32	dummy;	if (apm_info.get_power_status_broken)		return APM_32_UNSUPPORTED;	if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,			&eax, &ebx, &ecx, &edx, &dummy))		return (eax >> 8) & 0xff;	*status = ebx;	*bat = ecx;	*life = edx;	return APM_SUCCESS;}#if 0static int apm_get_battery_status(u_short which, u_short *status,				  u_short *bat, u_short *life, u_short *nbat){	u32	eax;	u32	ebx;	u32	ecx;	u32	edx;	u32	esi;	if (apm_info.connection_version < 0x0102) {		/* pretend we only have one battery. */		if (which != 1)			return APM_BAD_DEVICE;		*nbat = 1;		return apm_get_power_status(status, bat, life);	}	if (apm_bios_call(APM_FUNC_GET_STATUS, (0x8000 | (which)), 0, &eax,			&ebx, &ecx, &edx, &esi))		return (eax >> 8) & 0xff;	*status = ebx;	*bat = ecx;	*life = edx;	*nbat = esi;	return APM_SUCCESS;}#endifstatic int apm_engage_power_management(u_short device, int enable){	u32	eax;	if ((enable == 0) && (device == APM_DEVICE_ALL)	    && (apm_info.bios.flags & APM_BIOS_DISABLED))		return APM_DISABLED;	if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))		return (eax >> 8) & 0xff;	if (device == APM_DEVICE_ALL) {		if (enable)			apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;		else			apm_info.bios.flags |= APM_BIOS_DISENGAGED;	}	return APM_SUCCESS;}static void apm_error(char *str, int err){	int	i;	for (i = 0; i < ERROR_COUNT; i++)		if (error_table[i].key == err) break;	if (i < ERROR_COUNT)		printk(KERN_NOTICE "apm: %s: %s\n", str, error_table[i].msg);	else		printk(KERN_NOTICE "apm: %s: unknown error code %#2.2x\n",			str, err);}#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT)static int apm_console_blank(int blank){	int	error;	u_short	state;	state = blank ? APM_STATE_STANDBY : APM_STATE_READY;	/* Blank the first display device */	error = set_power_state(0x100, state);	if ((error != APM_SUCCESS) && (error != APM_NO_ERROR)) {		/* try to blank them all instead */		error = set_power_state(0x1ff, state);		if ((error != APM_SUCCESS) && (error != APM_NO_ERROR))			/* try to blank device one instead */			error = set_power_state(0x101, state);	}	if ((error == APM_SUCCESS) || (error == APM_NO_ERROR))		return 1;	apm_error("set display", error);	return 0;}#endifstatic int queue_empty(struct apm_user *as){	return as->event_head == as->event_tail;}static apm_event_t get_queued_event(struct apm_user *as){	as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;	return as->events[as->event_tail];}static void queue_event(apm_event_t event, struct apm_user *sender){	struct apm_user *	as;	if (user_list == NULL)		return;	for (as = user_list; as != NULL; as = as->next) {		if (as == sender)			continue;		as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;		if (as->event_head == as->event_tail) {			static int notified;			if (notified++ == 0)			    printk(KERN_ERR "apm: an event queue overflowed\n");			as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;		}		as->events[as->event_head] = event;		if (!as->suser)			continue;		switch (event) {		case APM_SYS_SUSPEND:		case APM_USER_SUSPEND:			as->suspends_pending++;			suspends_pending++;			break;		case APM_SYS_STANDBY:		case APM_USER_STANDBY:			as->standbys_pending++;			standbys_pending++;			break;		}	}	wake_up_interruptible(&apm_waitqueue);}static void set_time(void){	unsigned long	flags;	if (got_clock_diff) {	/* Must know time zone in order to set clock */		save_flags(flags);		cli();		CURRENT_TIME = get_cmos_time() + clock_cmos_diff;		restore_flags(flags);	}}static void get_time_diff(void){#ifndef CONFIG_APM_RTC_IS_GMT	unsigned long	flags;	/*	 * Estimate time zone so that set_time can update the clock	 */	save_flags(flags);	clock_cmos_diff = -get_cmos_time();	cli();	clock_cmos_diff += CURRENT_TIME;	got_clock_diff = 1;	restore_flags(flags);#endif}static void reinit_timer(void){#ifdef INIT_TIMER_AFTER_SUSPEND	unsigned long	flags;	save_flags(flags);

⌨️ 快捷键说明

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