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

📄 pnp_bios.c

📁 pcmcia source code
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * PnP bios services *  * Originally (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de) * Modifications (c) 1998 Tom Lees <tom@lpsg.demon.co.uk> * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net> * * 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, 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 * *   Reference: *   Compaq Computer Corporation, Phoenix Technologies Ltd., Intel  *   Corporation.  *   Plug and Play BIOS Specification, Version 1.0A, May 5, 1994 *   Plug and Play BIOS Clarification Paper, October 6, 1994 * */#define __NO_VERSION__#include <linux/types.h>#include <linux/module.h>#include <linux/linkage.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/pnp_bios.h>#include <linux/spinlock.h>#include <linux/sched.h>#include <asm/page.h>#include <asm/system.h>#include <asm/desc.h>/* PnP bios signature: "$PnP" */#define PNP_SIGNATURE   (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))#ifdef MODULEstatic struct desc_struct *gdt;#endif/* * This is the standard structure used to identify the entry point * to the Plug and Play bios */#pragma pack(1)union pnpbios {	struct {		u32 signature;    /* "$PnP" */		u8 version;	  /* in BCD */		u8 length;	  /* length in bytes, currently 21h */		u16 control;	  /* system capabilities */		u8 checksum;	  /* all bytes must add up to 0 */		u32 eventflag;    /* phys. address of the event flag */		u16 rmoffset;     /* real mode entry point */		u16 rmcseg;		u16 pm16offset;   /* 16 bit protected mode entry */		u32 pm16cseg;		u32 deviceID;	  /* EISA encoded system ID or 0 */		u16 rmdseg;	  /* real mode data segment */		u32 pm16dseg;	  /* 16 bit pm data segment base */	} fields;	char chars[0x21];	  /* To calculate the checksum */};#pragma pack()/* * Local Variables */static struct {	u32	offset;	u16	segment;} pnp_bios_callpoint;static union pnpbios * pnp_bios_inst_struc = NULL;/* The PnP entries in the GDT */#define PNP_GDT		0x0038#define PNP_CS32	(PNP_GDT+0x00)	/* segment for calling fn */#define PNP_CS16	(PNP_GDT+0x08)	/* code segment for bios */#define PNP_DS		(PNP_GDT+0x10)	/* data segment for bios */#define PNP_TS1		(PNP_GDT+0x18)	/* transfer data segment */#define PNP_TS2		(PNP_GDT+0x20)	/* another data segment */static struct desc_struct saved_gdt[5];static struct desc_struct pnp_gdt[] = {	{ 0, 0x00c09a00 },	/* 32-bit code */	{ 0, 0x00809a00 },	/* 16-bit code */	{ 0, 0x00809200 },	/* 16-bit data */	{ 0, 0x00809200 },	/* 16-bit data */	{ 0, 0x00809200 }	/* 16-bit data */};/* * GDT abuse: since we want this to work when loaded as a module on a * normal kernel, we drop the PnP GDT entries on top of the APM stuff * and protect it with a spin lock ( */static long gdt_flags;#ifdef USE_SPIN_LOCKSstatic spinlock_t gdt_lock = SPIN_LOCK_UNLOCKED;#endifstatic void push_pnp_gdt(void){	spin_lock_irqsave(&gdt_lock, gdt_flags);	memcpy(saved_gdt, &gdt[PNP_GDT >> 3], sizeof(saved_gdt));	memcpy(&gdt[PNP_GDT >> 3], pnp_gdt, sizeof(pnp_gdt));}static void pop_pnp_gdt(void){	memcpy(pnp_gdt, &gdt[PNP_GDT >> 3], sizeof(pnp_gdt));	memcpy(&gdt[PNP_GDT >> 3], saved_gdt, sizeof(saved_gdt));	spin_unlock_irqrestore(&gdt_lock, gdt_flags);}/*  * These are some opcodes for a "static asmlinkage" * As this code is *not* executed inside the linux kernel segment, but in a * alias at offset 0, we need a far return that can not be compiled by * default (please, prove me wrong! this is *really* ugly!)  * This is the only way to get the bios to return into the kernel code, * because the bios code runs in 16 bit protected mode and therefore can only * return to the caller if the call is within the first 64kB, and the linux * kernel begins at offset 1MB... */static u8 pnp_bios_callfunc[] ={	0x52,			              /* push edx */	0x51,			              /* push ecx */	0x53,			              /* push ebx */	0x50,			              /* push eax */	0x66, 0x9a, 0, 0,	              /* call far pnp_cs16:0, offset */	(PNP_CS16) & 0xff, (PNP_CS16) >> 8,   /* becomes fixed up later */	0x83, 0xc4, 0x10,	              /* add esp, 16 */	0xcb};			              /* retf */#define Q_SET_SEL(selname, address, size) \set_base (gdt [(selname) >> 3], __va((u32)(address))); \set_limit (gdt [(selname) >> 3], size)#define Q2_SET_SEL(selname, address, size) \set_base (gdt [(selname) >> 3], (u32)(address)); \set_limit (gdt [(selname) >> 3], size)/* * Callable Functions */#define PNP_GET_NUM_SYS_DEV_NODES       0x00#define PNP_GET_SYS_DEV_NODE            0x01#define PNP_SET_SYS_DEV_NODE            0x02#define PNP_GET_EVENT                   0x03#define PNP_SEND_MESSAGE                0x04#define PNP_GET_DOCKING_STATION_INFORMATION 0x05#define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09#define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a#define PNP_GET_APM_ID_TABLE            0x0b#define PNP_GET_PNP_ISA_CONFIG_STRUC    0x40#define PNP_GET_ESCD_INFO               0x41#define PNP_READ_ESCD                   0x42#define PNP_WRITE_ESCD                  0x43/* * Call pnp bios with function 0x00, "get number of system device nodes" */int pnp_bios_dev_node_info(struct pnp_dev_node_info *data){	u16 status;	if (!pnp_bios_present ())		return PNP_FUNCTION_NOT_SUPPORTED;	push_pnp_gdt();	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info));	__asm__ __volatile__          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"           :"=a"(status)           :"a"(PNP_GET_NUM_SYS_DEV_NODES),            "b"((2 << 16) | PNP_TS1),            "c"((PNP_DS << 16) | PNP_TS1)           :"memory");	data->no_nodes &= 0xff;	pop_pnp_gdt();	return status;}/*  * Call pnp bios with function 0x01, "get system device node" * Input:  *nodenum=desired node,  *         static=1: config (dynamic) config, else boot (static) config, * Output: *nodenum=next node or 0xff if no more nodes */int pnp_bios_get_dev_node(u8 *nodenum, char config, struct pnp_bios_node *data){	u16 status;	if (!pnp_bios_present ())		return PNP_FUNCTION_NOT_SUPPORTED;	push_pnp_gdt();	Q2_SET_SEL(PNP_TS1, nodenum, sizeof(char));	Q2_SET_SEL(PNP_TS2, data, 64 * 1024);	__asm__ __volatile__          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"           :"=a"(status)           :"a"(PNP_GET_SYS_DEV_NODE),            "b"(PNP_TS1),            "c"(((config ? 1 : 2) <<16) | PNP_TS2),            "d"(PNP_DS)           :"memory");	pop_pnp_gdt();	return status;}/* * Call pnp bios with function 0x02, "set system device node" * Input: nodenum=desired node,  *        static=1: config (dynamic) config, else boot (static) config, */int pnp_bios_set_dev_node(u8 nodenum, char config, struct pnp_bios_node *data){	u16 status;	if (!pnp_bios_present ())		return PNP_FUNCTION_NOT_SUPPORTED;	push_pnp_gdt();	Q2_SET_SEL(PNP_TS1, data, /* *((u16 *) data)*/ 65536);	__asm__ __volatile__          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"           :"=a"(status)           :"a"(((u32) nodenum << 16) | PNP_SET_SYS_DEV_NODE),            "b"(PNP_TS1 << 16),            "c"((PNP_DS << 16) | (config ? 1 : 2))           :"memory");	pop_pnp_gdt();	return status;}/* * Call pnp bios with function 0x03, "get event" */#if neededint pnp_bios_get_event(u16 *event){	u16 status;	if (!pnp_bios_present ())		return PNP_FUNCTION_NOT_SUPPORTED;	push_pnp_gdt();	Q2_SET_SEL(PNP_TS1, event, sizeof(u16));	__asm__ __volatile__          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"           :"=a"(status)           :"a"(PNP_GET_EVENT),            "b"((PNP_DS << 16) | PNP_TS1)           :"memory");	pop_pnp_gdt();	return status;}#endif/*  * Call pnp bios with function 0x04, "send message"

⌨️ 快捷键说明

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