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 + -
显示快捷键?