megarac.c

来自「这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自」· C语言 代码 · 共 1,979 行 · 第 1/5 页

C
1,979
字号
/***************************************************************************** * *  MegaRacDrvrLx.c : MegaRac device driver for Linux * *  VisualStudio printing format: courier, 12, landscape * ****************************************************************************/#include <linux/module.h>#include <linux/config.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/pci.h>#include <linux/reboot.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/types.h>#include <linux/tqueue.h>#include <linux/unistd.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/interrupt.h>#include "MegaRacDrvr.h"#include "MegaRacDrvrLx.h"#include "MegaRacDLL.h"/* This is defined in 2.2.x series linux kernels, but not in 2.4.x *//* andrewm@ami.com 6/8/2001 */#ifndef copy_from_user_ret#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })#endif/* Added some macros for proper compilation on different versions of linux *//* andrewm@ami.com 6/18/2001 */#define PCI_BASE resource[0].start#warning wrongMODULE_AUTHOR("American Megatrends Inc");MODULE_LICENSE("GPL");#if   (OEM == MEGARAC_OEM_AMI)#define MR_REGION_NAME "MegaRAC"MODULE_DESCRIPTION("AMI MegaRAC driver");#elif (OEM == MEGARAC_OEM_DELL)#define MR_REGION_NAME "DRAC"MODULE_DESCRIPTION("DELL Remote Assistant Card driver");#else#define MR_REGION_NAME "RAC"MODULE_DESCRIPTION("Remote Assistant Card driver");#endiftypedef enum {	MR_IO_IDLE,	MR_IO_WRITE_OUT,	MR_IO_WRITE_COMPLETE} MR_IO;typedef struct _RAC_OS_INFO {	struct _RAC_INFO *pRacInfo;	struct pci_dev pciDev;	struct timer_list timerUOW;	struct tq_struct isrBHqueue;	unsigned char *pContiguousBuffer;	unsigned int contiguousBufferLength;	/* Different handling of wait queues in 2.4.x series kernels */	/* andrewm@ami.com 6/18/2001 */	wait_queue_head_t writeQ, readQ, ioctlQ;	MEGARAC_IO_BUFS ioCB;	volatile MR_IO ioState;	BOOL bIRQ, bChrDev, bRegion;	RAC_EVENT_NOTIFICATION events;} RAC_OS_INFO;typedef struct _MEGARAC_DEVICE_INFO {	RAC_INFO racInfo;	RAC_OS_INFO osInfo;} MEGARAC_DEVICE_INFO;static MEGARAC_DEVICE_INFO devInfo;static const char regionName[] = MR_REGION_NAME;static const unsigned long regionExtent = 0x0080;static int racDebugFlag = 0;	/* modify at load time with insmod command */static int racSupport = 0;	/* disable cursor support for Dell */#define RAC_MAJOR 170		/* officially designated as Linux device major 170 per hpa@zytor.com */#define RAC_MINOR 0		/* ...see /usr/doc/kernel-doc-.../devices.txt *//*---------------------------------------------------------------------------- *   *--------------------------------------------------------------------------*/#if _DEBUG#define DEBUG_PRINT		/* turn debug printing on */#define DEBUG_PRINT_FUNCTION megaOutputFunc#endif#include "MegaRacDebug.h"DebugFlagDeclare(mega, static);DebugOutputFuncLX(mega, static);/*---------------------------------------------------------------------------- *  macros required to support MegaRacDrvr.c *--------------------------------------------------------------------------*//* use PCI API here I think */#define MALLOC_CONTIGUOUS(raci,ptr,cast,cnt) ptr=(cast)kmalloc(cnt,GFP_ATOMIC)#define   FREE_CONTIGUOUS(raci,ptr)                    kfree(ptr)#define VIRTUAL_TO_PHYSICAL(raci,physAddr,virtAddr) physAddr = (void*)virt_to_phys(virtAddr);/* Modified macro works with new and old versions of gcc *//* andrewm@ami.com 6/18/2001 */#define  READ_RAC_UCHAR( raci,addr)         inb (     (unsigned long)raci addr )#define  READ_RAC_ULONG( raci,addr)         inl (     (unsigned long)raci addr )#define WRITE_RAC_UCHAR(raci,addr,val)      outb( val,(unsigned long)raci addr )#define WRITE_RAC_ULONG(raci,addr,val)      outl( val,(unsigned long)raci addr )/***************************************************************************** *     *   The linux kernel makes a feeble attempt to limit shared access *   to i/o ports by the check_region() function. *   If check_region() is used by this driver, a error return will *   occur because the 'vga+' driver has already reserved the ports  *   we want to access. *   Currently the kernel does not actually modify the  *   "x86 TSS I/O Permissions Bit Map", so we can skip using *   check_region() and request_region(), and just blindly  *   access the ports.  However, if in the future the kernel *   does start checking the TSS then the following code is *   a starting point for a work around. *      typedef int (*sysfun_p)(); *      extern long sys_call_table[]; *      int error; *      void *kfunc; *      kfunc=(void*)sys_call_table[__NR_ioperm]; //sys_ioperm 101 *      error=((sysfun_p)kfunc)(0x3d4,2,1); * ****************************************************************************/static unsigned shortgetHardwareCursor(void){	unsigned int save3D4, highByte, lowByte;	unsigned long flags = 0;	/* =0 makes compiler happy */	save_flags(flags);	cli();	save3D4 = inb(0x3d4);	outb(0x0e, 0x3d4);	highByte = inb(0x3d5);	highByte &= 0x00ff;	outb(0x0f, 0x3d4);	lowByte = inb(0x3d5);	lowByte &= 0x00ff;	outb(save3D4, 0x3d4);	restore_flags(flags);	return ((highByte << 8) | lowByte);}				/* end of getHardwareCursor() *//***************************************************************************** * ****************************************************************************/static voidissueEvent(RAC_INFO * pRAC, RAC_EVENT rawEvent, RAC_EVENT firmEvent){	RAC_OS_INFO *pOSI = pRAC->pOsInfo;	DebugFlagPrint(mega, MEGA_EVENT,		       ("issueEvent    : rawEvent=%#x, firmEvent=%#x, count=%d\n",			rawEvent, firmEvent, pOSI->events.eventHandle[racEventFirmwareRequest]));	if (rawEvent == racEventFirmwareRequest) {		pOSI->events.eventHandle[firmEvent] = 1;	/* this event has occurred */		pOSI->events.eventHandle[racEventFirmwareRequest]++;	/* this is our 'dirty' flag */	}	/* Same command, different arguments on different kernels */	/* andrewm@ami.com 6/18/2001 */	wake_up_interruptible(&pOSI->ioctlQ);}				/* end of issueEvent() *//***************************************************************************** * ****************************************************************************/static intracOpenDev(struct inode *ip, struct file *fp){	DebugFlagPrint(mega, MEGA_ENTRY, ("racOpenDev    : ip=%p, fp=%p <<<<<<<<<<<\n", ip, fp));	fp->private_data = &devInfo;	MOD_INC_USE_COUNT;	return 0;}				/* end of racOpenDev() *//***************************************************************************** * ****************************************************************************/static intracCloseDev(struct inode *ip, struct file *fp){	DebugFlagPrint(mega, MEGA_ENTRY, ("racCloseDev   : ip=%p, fp=%p >>>>>>>>>>>\n", ip, fp));	fp->private_data = NULL;	MOD_DEC_USE_COUNT;	return 0;}				/* end of racCloseDev() *//***************************************************************************** * ****************************************************************************/static intracPciInit(MEGARAC_DEVICE_INFO * pMDI){	static void racISR(int irq, void *dev_id, struct pt_regs *regs);	static int racRead(struct file *, char *, size_t, loff_t *);	static int racWrite(struct file *, const char *, size_t, loff_t *);	static int racIoctl(struct inode *, struct file *, unsigned int, unsigned long);	//andrewm@ami.com	static struct file_operations racFops = {		/* 2.4.x series kernels include an owner field in this struct */		/* It should always be the THIS_MODULE macro for our uses.    */		/* andrewm@ami.com 6/18/2001                                  */		owner:THIS_MODULE,		llseek:NULL,		read:racRead,		write:racWrite,		readdir:NULL,		poll:NULL,		ioctl:racIoctl,		mmap:NULL,		open:racOpenDev,		flush:NULL,		release:racCloseDev	};	RAC_INFO *pRAC = &pMDI->racInfo;	RAC_OS_INFO *pOSI = &pMDI->osInfo;	struct pci_dev *pPCI = &pOSI->pciDev;	int result;	{		struct pci_dev *tempDev;		tempDev = pci_find_device(AMI_VENDOR_ID, AMI_MEGA_RAC_ID, NULL);		if (tempDev == NULL) {			printk(KERN_ERR "%s not found on PCI bus\n", regionName);			return (-ENODEV);		}		*pPCI = *tempDev;		DebugFlagPrint(mega, MEGA_ENTRY,			       ("racPciInit    : found MegaRac: base=%#lx, irq=%d ==========\n",				pci_resource_start(pPCI, 0), pPCI->irq));	}	/* Get IO region.... */	/* Changed PCI base references to a macro based on kernel version */	/* andrewm@ami.com 6/18/2001 */	result = check_region(pci_resource_start(pPCI, 0), regionExtent);	if (result) {		printk(KERN_ERR "%s can't get reserved region %#lx\n", regionName, pci_resource_start(pPCI, 0));		return result;	}	/* Changed PCI base references to a macro based on kernel version */	/* andrewm@ami.com 6/18/2001 */	request_region(pci_resource_start(pPCI, 0), regionExtent, regionName);	pOSI->bRegion = TRUE;	/* disable any interrupt from the MegaRac until ready */	/* Changed PCI base references to a macro based on kernel version */	/* andrewm@ami.com 6/18/2001 */	racSetAddrs(pRAC, (void *) pci_resource_start(pPCI, 0));	#warning wrong type	WRITE_RAC_UCHAR(pRAC->, portAddrHIMR, HIMR_DISABLE_ALL);	WRITE_RAC_UCHAR(pRAC->, portAddrHCR, HCR_INTR_RESET);	/* register device with kernel */	result = register_chrdev(RAC_MAJOR, regionName, &racFops);	if (result < 0) {		printk(KERN_ERR "%s can't get reserved major device %d\n", regionName, RAC_MAJOR);		return result;	}	pOSI->bChrDev = TRUE;	/* attach the IRQ to the driver */	result = request_irq(pPCI->irq, racISR, SA_SHIRQ, regionName, pMDI);	if (result) {		printk(KERN_ERR "%s can't register IRQ\n", regionName);		return result;	}	pOSI->bIRQ = TRUE;	/* all done */	return 0;}				/* end of racPciInit() *//***************************************************************************** *  module entry point for driver ****************************************************************************/intinit_module(void){	extern void cleanup_module(void);	static void racTimeout(unsigned long);	static void racIsrBottomHalf(void *);	MEGARAC_DEVICE_INFO *pMDI = &devInfo;	RAC_INFO *pRAC = &pMDI->racInfo;	RAC_OS_INFO *pOSI = &pMDI->osInfo;	int retval;	DebugFlagSet(mega, racDebugFlag);	/* turn on debugging */	if (!pci_present()) {		racDebugFlag++;	/* prevent compiler warning */		printk(KERN_ERR "PCI BIOS not present\n");		return -ENODEV;	}	/* Initialize wait queue heads */	/* Kernels before 2.4.x don't use wait queue heads in the same way */	/* andrewm@ami.com 6/18/2001 */	init_waitqueue_head(&pOSI->readQ);	init_waitqueue_head(&pOSI->writeQ);	init_waitqueue_head(&pOSI->ioctlQ);	/* allocate resources, ISR's, etc. */	pMDI->osInfo.pRacInfo = &pMDI->racInfo;	pMDI->racInfo.pOsInfo = &pMDI->osInfo;	pOSI->isrBHqueue.routine = racIsrBottomHalf;	pOSI->isrBHqueue.data = pMDI;	pOSI->contiguousBufferLength = max(MAX_DMI_BUFFER, MOUSE_DATA_BUFFER_SIZE);	pOSI->contiguousBufferLength += sizeof(CCB_Header);	pOSI->pContiguousBuffer = kmalloc(pOSI->contiguousBufferLength, GFP_KERNEL);	#warning PCI DMA ?	if (pOSI->pContiguousBuffer == NULL)		return -ENOMEM;	retval = racPciInit(pMDI);	if (retval) {		DebugFlagPrint(mega, MEGA_ENTRY, ("init_module    :  Error initializing %#x\n", retval));		cleanup_module();		return retval;	}	/* register special support functions for use by the common driver code */	if (racSupport & MEGARAC_SUPPORT_CURSOR)		racGetHardwareCursor = getHardwareCursor;	/* work around for ASIC bug */	racOsEventProc = issueEvent;	/* Tell card it's ready */	racStartupFinal(pRAC);	/* interrupts are now active */	/* setup timer for racTimeout function */	init_timer(&pOSI->timerUOW);	pOSI->timerUOW.function = racTimeout;	pOSI->timerUOW.data = (unsigned long) pMDI;	pOSI->timerUOW.expires = jiffies + HZ;	/* one second */	add_timer(&pOSI->timerUOW);	/* start timer */	return 0;}				/* end of init_module() *//***************************************************************************** * ****************************************************************************/voidcleanup_module(void){	MEGARAC_DEVICE_INFO *pMDI = &devInfo;	RAC_INFO *pRAC = &pMDI->racInfo;	RAC_OS_INFO *pOSI = &pMDI->osInfo;

⌨️ 快捷键说明

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