linux下的fpga驱动
- 格式:docx
- 大小:20.20 KB
- 文档页数:11
Linuxlinux硬件驱动架构linux硬件驱动(usb)??模块:模块用来装载到内核中,用来实现设备驱动程序。
??linux对于一个硬件的驱动,采用两种方式读取:??1.直接加载到内核代码中,启动内核时就会驱动此硬件设备??2.以模块方式读取,编程分解成一个.o的文件,当应用程序须要时读取入内核空间运转??so(通常说的硬件驱动其实就是一个硬件驱动模块及.o文件)??设备文件(设备节点):??设备文件(设备节点)指定(主设备号)&&(次设备号)??主设备号:对应着确认的驱动程序。
??(声明设备所使用的驱动程序,设备号相当于硬件驱动程序的一个标识)??次设备号:区分相同属性,相同采用方法,相同边线,相同操作方式??设备号从/proc/drives中获取,so先有驱动程序在内核中,才有设备节点在目录中。
??scsi(并口):通常采用的的usb存储设备,就是演示scsi硬盘而展开设计的。
??linux硬件驱动架构:??.o驱动模块文件--(如果须要采用这个驱动程序,首先必须读取运转它)-->insmod*.o--(驱动程序根据字符设备类型或块设备类型(鼠标属字符设备,硬盘属块设备))向系统登记注册-->登记注册顺利之后系统回到一个主设备号---(根据主设备号建立一个置放在/dev目录下的设备文件)-->(mknod用以建立设备文件须要使用设备号这个参数)----->我们出访硬件时,就可以对设备文件通过open,read,write等命令展开,而驱动就可以发送至适当的read,write操作方式而根据自己模块中的适当函数展开。
??上层调用api.o驱动drive.o??与模块有关的一些东西:??1./lib/modules/2.6.**目录,下面是针对当前内核版本的模块。
??2.查阅模块的倚赖关系与否恰当(depmod设置)??3.加载模块而不需要知道具体的模块位置(modprobe)??4.文件/etc/modules.conf文件,当kernel须要时轻易回去该文件中搜寻别称读取??modprobe用于加载系统已经通过depmod登记过的模块,insmod一般是针对具体的.o进行文件的加载。
Linux设备驱动程序原理及框架-内核模块入门篇内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块内核模块介绍Linux采用的是整体式的内核结构,这种结构采用的是整体式的内核结构,采用的是整体式的内核结构的内核一般不能动态的增加新的功能。
为此,的内核一般不能动态的增加新的功能。
为此,Linux提供了一种全新的机制,叫(可安装) 提供了一种全新的机制,可安装) 提供了一种全新的机制模块” )。
利用这个机制“模块”(module)。
利用这个机制,可以)。
利用这个机制,根据需要,根据需要,在不必对内核重新编译链接的条件将可安装模块动态的插入运行中的内核,下,将可安装模块动态的插入运行中的内核,成为内核的一个有机组成部分;成为内核的一个有机组成部分;或者从内核移走已经安装的模块。
正是这种机制,走已经安装的模块。
正是这种机制,使得内核的内存映像保持最小,的内存映像保持最小,但却具有很大的灵活性和可扩充性。
和可扩充性。
内核模块内核模块介绍可安装模块是可以在系统运行时动态地安装和卸载的内核软件。
严格来说,卸载的内核软件。
严格来说,这种软件的作用并不限于设备驱动,并不限于设备驱动,例如有些文件系统就是以可安装模块的形式实现的。
但是,另一方面,可安装模块的形式实现的。
但是,另一方面,它主要用来实现设备驱动程序或者与设备驱动密切相关的部分(如文件系统等)。
密切相关的部分(如文件系统等)。
课程内容内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块应用层加载模块操作过程内核引导的过程中,会识别出所有已经安装的硬件设备,内核引导的过程中,会识别出所有已经安装的硬件设备,并且创建好该系统中的硬件设备的列表树:文件系统。
且创建好该系统中的硬件设备的列表树:/sys 文件系统。
(udev 服务就是通过读取该文件系统内容来创建必要的设备文件的。
)。
如何在Linux系统中安装驱动程序Linux系统作为一个开源的操作系统,广泛应用于各种设备和领域。
而安装驱动程序是在Linux系统中使用外部硬件设备的关键步骤之一。
在本文中,我们将学习如何在Linux系统中安装驱动程序的方法和步骤。
1. 检查硬件设备在安装驱动程序之前,首先需要确定硬件设备的型号和制造商。
可以通过查询设备的型号或者查看设备的相关文档来获取这些信息。
这是非常重要的,因为不同的设备可能需要不同的驱动程序来正确地工作。
2. 更新系统在安装驱动程序之前,确保你的Linux系统已经是最新的状态。
可以通过在终端中运行以下命令来更新系统:```sudo apt-get updatesudo apt-get upgrade```更新系统可以确保你拥有最新的软件包和驱动程序,以获得更好的兼容性和性能。
3. 查找合适的驱动程序一般来说,大部分硬件设备的驱动程序都可以在Linux系统的软件仓库中找到。
可以通过使用包管理器(如apt、yum等)来查找并安装合适的驱动程序。
运行以下命令来搜索并安装特定的驱动程序:```sudo apt-cache search 驱动程序名称sudo apt-get install 驱动程序名称```注意替换“驱动程序名称”为具体的驱动程序名称。
安装驱动程序可能需要输入管理员密码和确认安装。
如果你无法在软件仓库中找到合适的驱动程序,可以转向设备的制造商网站或者开源社区来获取。
下载驱动程序后,根据驱动程序提供的文档和说明来安装。
4. 编译和安装驱动程序有些驱动程序可能需要手动编译和安装。
在这种情况下,你需要确保你的系统已经安装了编译工具(如GCC、make等)。
在终端中切换到驱动程序所在的目录,并按照以下步骤进行编译和安装:```./configuremakesudo make install```以上命令将分别进行配置、编译和安装驱动程序。
在进行安装之前,可能需要输入一些配置选项或者确认安装。
// (c) Copyright 2009 聳2009 Xilinx, Inc. All rights reserved.//// This file contains confidential and proprietary information// of Xilinx, Inc. and is protected under U.S. and// international copyright and other intellectual property// laws.//// DISCLAIMER// This disclaimer is not a license and does not grant any// rights to the materials distributed herewith. Except as// otherwise provided in a valid license issued to you by// Xilinx, and to the maximum extent permitted by applicable// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and// (2) Xilinx shall not be liable (whether in contract or tort,// including negligence, or under any other theory of// liability) for any loss or damage of any kind or nature// related to, arising under or in connection with these// materials, including for any direct, or any indirect,// special, incidental, or consequential loss or damage// (including loss of data, profits, goodwill, or any type of// loss or damage suffered as a result of any action brought// by a third party) even if such damage or loss was// reasonably foreseeable or Xilinx had been advised of the// possibility of the same.//// CRITICAL APPLICATIONS// Xilinx products are not designed or intended to be fail-// safe, or for use in any application requiring fail-safe// performance, such as life-support or safety devices or// systems, Class III medical devices, nuclear facilities,// applications related to the deployment of airbags, or any// other applications that could lead to death, personal// injury, or severe property or environmental damage// (individually and collectively, "Critical// Applications"). Customer assumes the sole risk and// liability of any use of Xilinx products in Critical// Applications, subject only to applicable laws and// regulations governing limitations on product liability.//// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS// PART OF THIS FILE AT ALL TIMES.//-------------------------------------------------------------------------------- //-- Filename: xbmd.c//--//-- Description: XBMD device driver.//--//-- XBMD is an example Red Hat device driver which exercises XBMD design//-- Device driver has been tested on Red Hat Fedora FC9 2.6.15.//--------------------------------------------------------------------------------#include<linux/init.h>#include<linux/module.h>#include<linux/pci.h>#include<linux/interrupt.h>#include<linux/fs.h>//#include <linux/pci-aspm.h>//#include <linux/pci_regs.h>#include<asm/uaccess.h>/* copy_to_user */ #include"xbmd.h"// semaphoresenum {SEM_READ,SEM_WRITE,SEM_WRITEREG,SEM_READREG,SEM_WAITFOR,SEM_DMA,NUM_SEMS};#define SUCCESS 0#define CRIT_ERR -1// Debug - define will output more info#define Verbose 1// Max DMA Buffer Size#define BUF_SIZE (4096 * 1024) enum {INITCARD, // 0INITRST,DISPREGS,RDDCSR,RDDDMACR,RDWDMATLPA, // 5RDWDMATLPS,RDWDMATLPC,RDWDMATLPP,RDRDMATLPP,RDRDMATLPA, // 10RDRDMATLPS,RDRDMATLPC,RDWDMAPERF,RDRDMAPERF,RDRDMASTAT, // 15RDNRDCOMP,RDRCOMPDSIZE,RDDLWSTAT,RDDLTRSSTAT,RDDMISCCONT, // 20RDDMISCONT,RDDLNKC,DFCCTL,DFCPINFO,DFCNPINFO, // 25DFCINFO,RDCFGREG,WRCFGREG,RDBMDREG,WRBMDREG, // 30WRDDMACR,WRWDMATLPS,WRWDMATLPC,WRWDMATLPP,WRRDMATLPS,WRRDMATLPC,WRRDMATLPP,WRDMISCCONT,WRDDLNKC,NUMCOMMANDS};//semaphoresstruct semaphore gSem[NUM_SEMS];MODULE_LICENSE("Dual BSD/GPL");// Defines the Vendor ID. Must be changed if core generated did not set the Vendor ID to the same value#define PCI_VENDOR_ID_XILINX 0x10ee// Defines the Device ID. Must be changed if core generated did not set the Device ID to the same value#define PCI_DEVICE_ID_XILINX_PCIE 0x0007// Defining#define XBMD_REGISTER_SIZE (4*8) // There are eight registers, and each is 4 bytes wide. #define HAVE_REGION 0x01 // I/O Memory region#define HAVE_IRQ 0x02 // Interupt//Status Flags:// 1 = Resouce successfully acquired// 0 = Resource not acquired.#define HAVE_REGION 0x01 // I/O Memory region#define HAVE_IRQ 0x02 // Interupt#define HAVE_KREG 0x04 // Kernel registrationint gDrvrMajor = 241; // Major number not dynamic.unsigned int gStatFlags = 0x00; // Status flags used for cleanup.unsigned long gBaseHdwr; // Base register address (Hardware address) unsigned long gBaseLen; // Base register address Lengthvoid *gBaseVirt = NULL; // Base register address (Virtual address, for I/O). char gDrvrName[]= "xbmd"; // Name of driver in proc.struct pci_dev *gDev = NULL; // PCI device structure.int gIrq; // IRQ assigned by PCI system.char *gBufferUnaligned = NULL; // Pointer to Unaligned DMA buffer.char *gReadBuffer = NULL; // Pointer to dword aligned DMA buffer.char *gWriteBuffer = NULL; // Pointer to dword aligned DMA buffer.dma_addr_t gReadHWAddr;dma_addr_t gWriteHWAddr;unsigned long SA_SHIRQ = 0;unsigned long SA_SAMPLE_RANDOM = 0;int pos;// Struct Used for Writing CFG Register. Holds value and register to be writtentypedef struct cfgwrite {int reg;int value;} cfgwr;// Struct Used for Writing BMD Register. Holds value and register to be writtentypedef struct bmdwrite {int reg;int value;} bmdwr;//-----------------------------------------------------------------------------// Prototypes//-----------------------------------------------------------------------------void XPCIe_IRQHandler (int irq, void *dev_id, struct pt_regs *regs);u32 XPCIe_ReadReg (u32 dw_offset);void XPCIe_WriteReg (u32 dw_offset, u32 val);void XPCIe_InitCard (void);void XPCIe_InitiatorReset (void);u32 XPCIe_ReadCfgReg (u32 byte);u32 XPCIe_WriteCfgReg (u32 byte, u32 value);//---------------------------------------------------------------------------// Name: XPCIe_Open//// Description: Book keeping routine invoked each time the device is opened.//// Arguments: inode :// filp ://// Returns: 0 on success, error code on failure.//// Modification log:// Date Who Description////---------------------------------------------------------------------------int XPCIe_Open(struct inode *inode, struct file *filp){printk(KERN_INFO"%s: Open: module opened\n",gDrvrName);return SUCCESS;}//---------------------------------------------------------------------------// Name: XPCIe_Release//// Description: Book keeping routine invoked each time the device is closed. //// Arguments: inode :// filp ://// Returns: 0 on success, error code on failure.//// Modification log:// Date Who Description////---------------------------------------------------------------------------int XPCIe_Release(struct inode *inode, struct file *filp){printk(KERN_INFO"%s: Release: module released\n",gDrvrName);return(SUCCESS);}//---------------------------------------------------------------------------// Name: XPCIe_Write//// Description: This routine is invoked from user space to write data to// the PCIe device.//// Arguments: filp : file pointer to opened device.// buf : pointer to location in users space, where data is to// be acquired.// count : Amount of data in bytes user wishes to send.//// Returns: SUCCESS = Success// CRIT_ERR = Critical failure//// Modification log:// Date Who Description////---------------------------------------------------------------------------ssize_t XPCIe_Write(struct file *filp, const char *buf, size_t count, loff_t *f_pos){int ret = SUCCESS;memcpy((char *)gWriteBuffer, buf, count);printk(KERN_INFO"%s: XPCIe_Write: %d bytes have been written...\n", gDrvrName, count); memcpy((char *)gReadBuffer, buf, count);printk(KERN_INFO"%s: XPCIe_Write: %d bytes have been written...\n", gDrvrName, count);return (ret);}//---------------------------------------------------------------------------// Name: XPCIe_Read//// Description: This routine is invoked from user space to read data from// the PCIe device. ***NOTE: This routine returns the entire// buffer, (BUF_SIZE), count is ignored!. The user App must// do any needed processing on the buffer.//// Arguments: filp : file pointer to opened device.// buf : pointer to location in users space, where data is to// be placed.// count : Amount of data in bytes user wishes to read.//// Returns: SUCCESS = Success// CRIT_ERR = Critical failure//// Modification log:// Date Who Description//----------------------------------------------------------------------------ssize_t XPCIe_Read(struct file *filp, char *buf, size_t count, loff_t *f_pos){memcpy(buf, (char *)gWriteBuffer, count);printk(KERN_INFO"%s: XPCIe_Read: %d bytes have been read...\n", gDrvrName, count);return (0);}//---------------------------------------------------------------------------// Name: XPCIe_Ioctl//// Description: This routine is invoked from user space to configure the// running driver.//// Arguments: inode :// filp : File pointer to opened device.// cmd : Ioctl command to execute.// arg : Argument to Ioctl command.//// Returns: 0 on success, error code on failure.//// Modification log:// Date Who Description////---------------------------------------------------------------------------int XPCIe_Ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg){u32 regx;int ret = SUCCESS;/*寄存器相关说明在xapp1052.pdf的附录里*/switch (cmd){case INITCARD: // Initailizes XBMD applicationXPCIe_InitCard();break;case INITRST: // Resets XBMD applicationsXPCIe_InitiatorReset();break;case DISPREGS:break;case RDDCSR: // Read: Device Control Status Register regx = XPCIe_ReadReg(0);*((u32 *)arg) = regx;break;case RDDDMACR: // Read: DMA Control Status Registerregx = XPCIe_ReadReg(1);*((u32 *)arg) = regx;break;case RDWDMATLPA: // Read: Write DMA TLP Address Register regx = XPCIe_ReadReg(2);*((u32 *)arg) = regx;break;case RDWDMATLPS: // Read: Write DMA TLP Size Registerregx = XPCIe_ReadReg(3);*((u32 *)arg) = regx;break;case RDWDMATLPC: // Read: Write DMA TLP Count Register regx = XPCIe_ReadReg(4);*((u32 *)arg) = regx;break;case RDWDMATLPP: // Read: Write DMA TLP Pattern Register regx = XPCIe_ReadReg(5);*((u32 *)arg) = regx;break;case RDRDMATLPP: // Read: Read DMA TLP Pattern Register regx = XPCIe_ReadReg(6);*((u32 *)arg) = regx;break;case RDRDMATLPA: // Read: Read DMA TLP Address Register regx = XPCIe_ReadReg(7);*((u32 *)arg) = regx;break;case RDRDMATLPS: // Read: Read DMA TLP Size Registerregx = XPCIe_ReadReg(8);*((u32 *)arg) = regx;break;case RDRDMATLPC: // Read: Read DMA TLP Count Registerregx = XPCIe_ReadReg(9);*((u32 *)arg) = regx;break;case RDWDMAPERF: // Read: Write DMA Performance Register regx = XPCIe_ReadReg(10);*((u32 *)arg) = regx;break;case RDRDMAPERF: // Read: Read DMA Performance Register regx = XPCIe_ReadReg(11);*((u32 *)arg) = regx;break;case RDRDMASTAT: // Read: Read DMA Status Registerregx = XPCIe_ReadReg(12);*((u32 *)arg) = regx;break;case RDNRDCOMP: // Read: Number of Read Completion w/ Data Register regx = XPCIe_ReadReg(13);*((u32 *)arg) = regx;break;case RDRCOMPDSIZE: // Read: Read Completion Size Registerregx = XPCIe_ReadReg(14);*((u32 *)arg) = regx;break;case RDDLWSTAT: // Read: Device Link Width Status Registerregx = XPCIe_ReadReg(15);*((u32 *)arg) = regx;break;case RDDLTRSSTAT: // Read: Device Link Transaction Size Status Register regx = XPCIe_ReadReg(16);*((u32 *)arg) = regx;break;case RDDMISCCONT: // Read: Device Miscellaneous Control Registerregx = XPCIe_ReadReg(17);*((u32 *)arg) = regx;break;case RDDMISCONT: // Read: Device MSI Controlregx = XPCIe_ReadReg(18);*((u32 *)arg) = regx;break;case RDDLNKC: // Read: Device Directed Link Change Registerregx = XPCIe_ReadReg(19);*((u32 *)arg) = regx;break;case DFCCTL: // Read: Device FC Control Registerregx = XPCIe_ReadReg(20);*((u32 *)arg) = regx;break;case DFCPINFO: // Read: Device FC Posted Informationregx = XPCIe_ReadReg(21);*((u32 *)arg) = regx;break;case DFCNPINFO: // Read: Device FC Non Posted Informationregx = XPCIe_ReadReg(22);*((u32 *)arg) = regx;break;case DFCINFO: // Read: Device FC Completion Informationregx = XPCIe_ReadReg(23);*((u32 *)arg) = regx;break;case WRDDMACR: // Write: DMA Control Status RegisterXPCIe_WriteReg(1, arg);break;case WRWDMATLPS: // Write: Write DMA TLP Size RegisterXPCIe_WriteReg(3, arg);break;case WRWDMATLPC: // Write: Write DMA TLP Count RegisterXPCIe_WriteReg(4, arg);break;case WRWDMATLPP: // Write: Write DMA TLP Pattern RegisterXPCIe_WriteReg(5, arg);break;case WRRDMATLPS: // Write: Read DMA TLP Size RegisterXPCIe_WriteReg(8, arg);break;case WRRDMATLPC: // Write: Read DMA TLP Count RegisterXPCIe_WriteReg(9, arg);break;case WRRDMATLPP: // Write: Read DMA TLP Pattern RegisterXPCIe_WriteReg(6, arg);break;case WRDMISCCONT: // Write: Device Miscellaneous Control RegisterXPCIe_WriteReg(18, arg);break;case WRDDLNKC: // Write: Device Directed Link Change RegisterXPCIe_WriteReg(19, arg);break;case RDBMDREG: // Read: Any XBMD Reg. Added generic functionality so all register can be readregx = XPCIe_ReadReg(*(u32 *)arg);*((u32 *)arg) = regx;break;case RDCFGREG: // Read: Any CFG Reg. Added generic functionality so all register can be readregx = XPCIe_ReadCfgReg(*(u32 *)arg);*((u32 *)arg) = regx;break;case WRBMDREG: // Write: Any BMD Reg. Added generic functionality so all register can be readXPCIe_WriteReg((*(bmdwr *)arg).reg,(*(bmdwr *)arg).value);printk(KERN_WARNING"%d: Write Register.\n", (*(bmdwr *)arg).reg);printk(KERN_WARNING"%d: Write Value\n", (*(bmdwr *)arg).value);break;case WRCFGREG: // Write: Any CFG Reg. Added generic functionality so all register can be readregx = XPCIe_WriteCfgReg((*(cfgwr *)arg).reg,(*(cfgwr *)arg).value);printk(KERN_WARNING"%d: Write Register.\n", (*(cfgwr *)arg).reg);printk(KERN_WARNING"%d: Write Value\n", (*(cfgwr *)arg).value);break;default:break;}return ret;}// Aliasing write, read, ioctl, etc...struct file_operations XPCIe_Intf = {read: XPCIe_Read,write: XPCIe_Write,ioctl: XPCIe_Ioctl,open: XPCIe_Open,release: XPCIe_Release,};static int XPCIe_init(void){// Find the Xilinx EP device. The device is found by matching device and vendor ID's which is defined// at the top of this file. Be default, the driver will look for 10EE & 0007. If the core is generated// with other settings, the defines at the top must be changed or the driver will not loadgDev = pci_find_device (PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_XILINX_PCIE, gDev);if (NULL == gDev){// If a matching device or vendor ID is not found, return failure and update kernel log.// NOTE: In fedora systems, the kernel log is located at: /var/log/messagesprintk(KERN_WARNING"%s: Init: Hardware not found.\n", gDrvrName);return (CRIT_ERR);}// Get Base Address of registers from pci structure. Should come from pci_dev// structure, but that element seems to be missing on the development system.gBaseHdwr = pci_resource_start (gDev, 0);if (gBaseHdwr < 0){printk(KERN_WARNING"%s: Init: Base Address not set.\n", gDrvrName);return (CRIT_ERR);}// Print Base Address to kernel logprintk(KERN_INFO"%s: Init: Base hw val %X\n", gDrvrName, (unsigned int)gBaseHdwr);// Get the Base Address LengthgBaseLen = pci_resource_len (gDev, 0);// Print the Base Address Length to Kernel Logprintk(KERN_INFO"%s: Init: Base hw len %d\n", gDrvrName, (unsigned int)gBaseLen);// Remap the I/O register block so that it can be safely accessed.// I/O register block starts at gBaseHdwr and is 32 bytes long.// It is cast to char because that is the way Linus does it.// Reference "/usr/src/Linux-2.4/Documentation/IO-mapping.txt".gBaseVirt = ioremap(gBaseHdwr, gBaseLen);if (!gBaseVirt){printk(KERN_WARNING"%s: Init: Could not remap memory.\n", gDrvrName);return (CRIT_ERR);}// Print out the aquired virtual base addresssprintk(KERN_INFO"%s: Init: Virt HW address %X\n", gDrvrName, (unsigned int)gBaseVirt);// Get IRQ from pci_dev structure. It may have been remapped by the kernel,// and this value will be the correct one.gIrq = gDev->irq;// 这个中断号是怎么来的,难道是pci_find_device函数分配的?printk(KERN_INFO"%s: Init: Device IRQ: %X\n",gDrvrName, gIrq);//---START: Initialize Hardware// Check the memory region to see if it is in useif (check_mem_region(gBaseHdwr, XBMD_REGISTER_SIZE) < 0){printk(KERN_WARNING"%s: Init: Memory in use.\n", gDrvrName);return (CRIT_ERR);}// Try to gain exclusive control of memory for demo hardware.request_mem_region(gBaseHdwr, XBMD_REGISTER_SIZE, "3GIO_Demo_Drv");// Update flagsgStatFlags = gStatFlags | HAVE_REGION;printk(KERN_INFO"%s: Init: Initialize Hardware Done..\n",gDrvrName);// Request IRQ from OS.// In past architectures, the SHARED and SAMPLE_RANDOM flags were called: SA_SHIRQ andSA_SAMPLE_RANDOM// respectively. In older Fedora core installations, the request arguments may need to be reverted back.// SA_SHIRQ | SA_SAMPLE_RANDOMprintk(KERN_INFO"%s: ISR Setup..\n", gDrvrName);if (request_irq(gIrq, &XPCIe_IRQHandler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, gDrvrName, gDev) < 0){printk(KERN_WARNING"%s: Init: Unable to allocate IRQ",gDrvrName);return (CRIT_ERR);}// Update flags stating IRQ was successfully obtainedgStatFlags = gStatFlags | HAVE_IRQ;// Bus Master Enableif (pci_enable_device(gDev) < 0){printk(KERN_WARNING"%s: Init: Device not enabled.\n", gDrvrName);return (CRIT_ERR);}//--- END: Initialize Hardware//--- START: Allocate Buffers// Allocate the read buffer with size BUF_SIZE and return the starting addressgReadBuffer = pci_alloc_consistent(gDev, BUF_SIZE, &gReadHWAddr);if (NULL == gReadBuffer){printk(KERN_CRIT"%s: Init: Unable to allocate gBuffer.\n",gDrvrName);return (CRIT_ERR);}// Print Read buffer size and address to kernel logprintk(KERN_INFO"%s: Read Buffer Allocation: %X->%X\n", gDrvrName, (unsigned int)gReadBuffer,(unsigned int)gReadHWAddr);// Allocate the write buffer with size BUF_SIZE and return the starting addressgWriteBuffer = pci_alloc_consistent(gDev, BUF_SIZE, &gWriteHWAddr);if (NULL == gWriteBuffer){printk(KERN_CRIT"%s: Init: Unable to allocate gBuffer.\n",gDrvrName);return (CRIT_ERR);}// Print Write buffer size and address to kernel logprintk(KERN_INFO"%s: Write Buffer Allocation: %X->%X\n", gDrvrName, (unsigned int)gWriteBuffer, (unsigned int)gWriteHWAddr);//--- END: Allocate Buffers//--- START: Register Driver// Register with the kernel as a character device.if (register_chrdev(gDrvrMajor, gDrvrName, &XPCIe_Intf) < 0){printk(KERN_WARNING"%s: Init: will not register\n", gDrvrName);return (CRIT_ERR);}printk(KERN_INFO"%s: Init: module registered\n", gDrvrName);gStatFlags = gStatFlags | HAVE_KREG;//--- END: Register Driver// The driver is now successfully loaded. All HW is initialized, IRQ's assigned, and buffers allocatedprintk("%s driver is loaded\n", gDrvrName);// Initializing card registersXPCIe_InitCard();return 0;}//--- XPCIe_InitiatorReset(): Resets the XBMD reference design//--- Arguments: None//--- Return Value: None//--- Detailed Description: Writes a 1 to the DCSR register which resets the XBMD designvoid XPCIe_InitiatorReset(){XPCIe_WriteReg(0, 1); // Write: DCSR (offset 0) with value of 1 (Reset Device) XPCIe_WriteReg(0, 0); // Write: DCSR (offset 0) with value of 0 (Make Active) }//--- XPCIe_InitCard(): Initializes XBMD descriptor registers to default values//--- Arguments: None//--- Return Value: None//--- Detailed Description: 1) Resets device//--- 2) Writes specific values into the XBMD registers inside the EPvoid XPCIe_InitCard(){XPCIe_WriteReg(0, 1); // Write: DCSR (offset 0) with value of 1 (Reset Device) XPCIe_WriteReg(0, 0); // Write: DCSR (offset 0) with value of 0 (Make Active)XPCIe_WriteReg(2, gWriteHWAddr); // Write: Write DMA TLP Address register with starting addressXPCIe_WriteReg(3, 0x20); // Write: Write DMA TLP Size register with default value (32dwords)XPCIe_WriteReg(4, 0x2000); // Write: Write DMA TLP Count register with default value (2000)XPCIe_WriteReg(5, 0x00000000); // Write: Write DMA TLP Pattern register with default value (0x0)XPCIe_WriteReg(6, 0xfeedbeef); // Write: Read DMA Expected Data Pattern with default value (feedbeef)XPCIe_WriteReg(7, gReadHWAddr); // Write: Read DMA TLP Address register with starting address.XPCIe_WriteReg(8, 0x20); // Write: Read DMA TLP Size register with default value (32dwords)XPCIe_WriteReg(9, 0x2000); // Write: Read DMA TLP Count register with default value (2000)}//--- XPCIe_exit(): Performs any cleanup required before releasing the device//--- Arguments: None//--- Return Value: None//--- Detailed Description: Performs all cleanup functions required before releasing device static void XPCIe_exit(void){// Check if we have a memory region and free itif (gStatFlags & HAVE_REGION){(void) release_mem_region(gBaseHdwr, XBMD_REGISTER_SIZE);}// Check if we have an IRQ and free itif (gStatFlags & HAVE_IRQ){(void) free_irq(gIrq, gDev);}// Free Write and Read buffers allocated to useif (NULL != gReadBuffer){(void) kfree(gReadBuffer);}if (NULL != gWriteBuffer){(void) kfree(gWriteBuffer);}// Free memory allocated to our Endpointpci_free_consistent(gDev, BUF_SIZE, gReadBuffer, gReadHWAddr);pci_free_consistent(gDev, BUF_SIZE, gWriteBuffer, gWriteHWAddr);gReadBuffer = NULL;gWriteBuffer = NULL;// Free up memory pointed to by virtual addressif (gBaseVirt != NULL){iounmap(gBaseVirt);}gBaseVirt = NULL;// Unregister Device Driverif (gStatFlags & HAVE_KREG){unregister_chrdev(gDrvrMajor, gDrvrName);}gStatFlags = 0;// Update Kernel log stating driver is unloadedprintk(KERN_ALERT"%s driver is unloaded\n", gDrvrName);}// Driver Entry Pointmodule_init(XPCIe_init);// Driver Exit Pointmodule_exit(XPCIe_exit);void XPCIe_IRQHandler(int irq, void *dev_id, struct pt_regs *regs){u32 i, regx;printk(KERN_WARNING"%s: Interrupt Handler Start ..",gDrvrName);for (i = 0; i < 32; i++){regx = XPCIe_ReadReg(i);printk(KERN_WARNING"%s : REG<%d> : 0x%X\n", gDrvrName, i, regx); }printk(KERN_WARNING"%s Interrupt Handler End ..\n", gDrvrName);}u32 XPCIe_ReadReg (u32 dw_offset){u32 ret = 0;//u32 reg_addr = (u32)(gBaseVirt + (4 * dw_offset));//ret = readl(reg_addr);ret = readl(gBaseVirt + (4 * dw_offset));return ret;}void XPCIe_WriteReg (u32 dw_offset, u32 val){//u32 reg_addr = (u32)(gBaseVirt + (4 * dw_offset));writel(val, (gBaseVirt + (4 * dw_offset)));}ssize_t* XPCIe_ReadMem(char *buf, size_t count){int ret = 0;dma_addr_t dma_addr;//make sure passed in buffer is large enoughif ( count < BUF_SIZE ){printk("%s: XPCIe_Read: passed in buffer too small.\n", gDrvrName);ret = -1;return ret;//goto exit;}down(&gSem[SEM_DMA]);// pci_map_single return the physical address corresponding to// the virtual address passed to it as the 2nd parameter// 获取DMA总线地址,底层调用的是pci_map_singledma_addr = pci_map_single(gDev, gReadBuffer, BUF_SIZE, PCI_DMA_FROMDEVICE);if ( 0 == dma_addr ){printk("%s: XPCIe_Read: Map error.\n",gDrvrName);ret = -1;up(&gSem[SEM_DMA]);return ret;//goto exit; // return 之前要释放互斥量,不能直接return}// Now pass the physical address to the device hardware. This is now// the destination physical address for the DMA and hence the to be// put on Memory Transactions// Do DMA transfer here....// 直接调用read write 函数进行传输?// 宋宝华第页流程图printk("%s: XPCIe_Read: ReadBuf Virt Addr = %x Phy Addr = %x.\n",gDrvrName, (unsigned int)gReadBuffer, (unsigned int)dma_addr);// Unmap the DMA buffer so it is safe for normal access again.pci_unmap_single(gDev, dma_addr, BUF_SIZE, PCI_DMA_FROMDEVICE);up(&gSem[SEM_DMA]);// Now it is safe to copy the data to user space.if ( copy_to_user(buf, gReadBuffer, BUF_SIZE) ){ret = -1;printk("%s: XPCIe_Read: Failed copy to user.\n",gDrvrName);goto exit;}exit:return ret;}ssize_t XPCIe_WriteMem(const char *buf, size_t count){int ret = 0;dma_addr_t dma_addr;if ( (count % 4) != 0 ){printk("%s: XPCIe_Write: Buffer length not dword aligned.\n",gDrvrName); ret = -1;return ret;//goto exit;}// Now it is safe to copy the data from user space.if ( copy_from_user(gWriteBuffer, buf, count) ){ret = -1;printk("%s: XPCIe_Write: Failed copy to user.\n",gDrvrName);return ret;//goto exit;}//set DMA semaphore if in loopbackdown(&gSem[SEM_DMA]);// pci_map_single return the physical address corresponding to// the virtual address passed to it as the 2nd parameterdma_addr = pci_map_single(gDev, gWriteBuffer, BUF_SIZE, PCI_DMA_FROMDEVICE);if ( 0 == dma_addr ){printk("%s: XPCIe_Write: Map error.\n",gDrvrName);ret = -1;up(&gSem[SEM_DMA]);return ret;//goto exit; // return 之前要释放互斥量,不能直接return}// Now pass the physical address to the device hardware. This is now// the source physical address for the DMA and hence the to be// put on Memory Transactions// Do DMA transfer here....// 直接调用read write 函数进行传输?// 宋宝华第页流程图printk("%s: XPCIe_Write: WriteBuf Virt Addr = %x Phy Addr = %x.\n",gDrvrName, (unsigned int)gReadBuffer, (unsigned int)dma_addr);// Unmap the DMA buffer so it is safe for normal access again.pci_unmap_single(gDev, dma_addr, BUF_SIZE, PCI_DMA_FROMDEVICE);up(&gSem[SEM_DMA]);exit:return (ret);}u32 XPCIe_ReadCfgReg (u32 byte){u32 pciReg;if (pci_read_config_dword(gDev, byte, &pciReg) < 0){printk("%s: XPCIe_ReadCfgReg: Reading PCI interface failed.",gDrvrName);return (-1);}return (pciReg);}u32 XPCIe_WriteCfgReg (u32 byte, u32 val){if (pci_write_config_dword(gDev, byte, val) < 0){printk("%s: XPCIe_Read Device Control: Reading PCI interface failed.",gDrvrName);return (-1);}return 1;}。
Linux命令行中的硬件信息查看和驱动管理在Linux命令行中,我们可以通过一些命令来查看硬件信息和管理驱动,这对于系统维护和故障排除非常重要。
本文将介绍几个常用的命令及其用法,帮助您快速获取硬件信息和管理驱动。
1. 查看硬件信息1.1 lshw命令lshw(或者lswhw)是一个用于查看硬件信息的命令,可以列出系统中所有硬件的详细信息,包括处理器、内存、硬盘、网卡等。
使用示例:```$ sudo lshw```运行以上命令后,您将看到完整的硬件信息列表,可以通过滚动查看或者使用管道和grep命令过滤感兴趣的部分。
1.2 lspci命令lspci命令用于列出系统中所有PCI设备的信息,包括显卡、网卡、声卡等。
使用示例:```$ lspci```该命令会输出PCI设备的详细信息,可以通过管道和grep进行过滤。
1.3 lsusb命令lsusb命令用于列出系统中所有USB设备的信息。
使用示例:```$ lsusb```该命令会输出USB设备的详细信息,可以通过管道和grep进行过滤。
2. 管理驱动2.1 modprobe命令modprobe命令用于加载和卸载Linux内核模块,包括驱动程序。
使用示例:```$ sudo modprobe <module_name> // 加载模块$ sudo modprobe -r <module_name> // 卸载模块```其中,`<module_name>`为要加载或卸载的模块名称。
2.2 lsmod命令lsmod命令用于列出当前已加载的内核模块。
使用示例:```$ lsmod```该命令会输出已加载模块的列表,包括模块名称、使用次数等信息。
2.3 rmmod命令rmmod命令用于卸载已加载的内核模块。
使用示例:```$ sudo rmmod <module_name>```其中,`<module_name>`为要卸载的模块名称。
linux安装网卡驱动教程在Linux系统中,网卡驱动是一个必需的组件,它允许计算机与网络相连,进行数据的传输和通信。
虽然大多数Linux发行版会自动安装一些常用的网卡驱动,但某些特殊型号的网卡可能需要手动安装对应的驱动程序。
下面是一个详细的Linux安装网卡驱动的教程,帮助你完成这个过程。
1. 首先,你需要确定你的网卡型号和型号。
可以通过以下命令获取:```lspci | grep Ethernet```这将列出系统中所有的以太网适配器,包括网卡的型号和型号。
2. 一旦你确定了网卡的型号和型号,你可以在厂商的官方网站或者第三方驱动程序网站上查找和下载对应的驱动程序。
确保选择与你的Linux发行版和内核版本兼容的驱动程序。
3. 下载驱动程序后,将其保存在你的计算机上的一个可访问的位置,比如家目录。
4. 打开终端,在命令行中输入以下命令以进入驱动程序所在目录:```cd ~/下载```这里假设你将驱动程序保存在`~/下载`目录下。
如果你将其保存在其他目录,请将命令中的路径替换为实际位置。
5. 解压驱动程序文件。
这可以通过以下命令完成:```tar zxvf 驱动程序文件名.tar.gz```这里的`驱动程序文件名`应该是你下载的驱动程序文件的实际名称。
6. 进入驱动程序文件夹。
这可以通过以下命令完成:```cd 驱动程序文件夹名```这里的`驱动程序文件夹名`是解压后的驱动程序文件夹的实际名称。
7. 阅读驱动程序的安装说明文档。
通常情况下,驱动程序的文件夹中都会包含一个README文件或者INSTALL文件,其中提供了安装驱动程序所需的具体步骤和说明。
8. 一般来说,安装驱动程序的第一步是编译驱动程序的源代码。
在终端中输入以下命令以编译驱动程序:```make```这将根据驱动程序的源代码编译出可执行的二进制文件。
9. 安装编译好的驱动程序。
在终端中输入以下命令以安装驱动程序:```sudo make install```这需要管理员权限,所以你可能需要输入管理员密码。
ZYNQFLASH+EMMC⼿动移植LINUX启动前⾔虽可使⽤Petalinux进⾏移植,简单⽅便,但为了更清楚明⽩的了解整个流程,还是尝试了⼀波⼿动移植。
参考资料流程对于⼿动移植,所需的⽂件为:BOOT.bin(FSBL+fpga_bit⽂件+u_boot.elf)、uImage、devicetree.dtb、uEnv.txt、⽂件系统⽂件放置位置说明:FLASH:BOOT.bin(FSBL+fpga_bit⽂件+u_boot.elf)EMMC:第⼀个分区放置:uImage、devicetree.dtb、uEnv.txt第⼆个分区放置:⽂件系统启动流程为:板⼦设置为QSPI启动模式,FSBL执⾏调u-boot执⾏,u-boot根据uEnv.txt调EMMC分区1中的内核执⾏,内核最后跳到分区⼆中的⽂件系统。
FSBL、bit⽂件、uImage、⽂件系统都可复⽤SD卡移植模式下的内容:参考参考资料第⼀个链接。
本⽂章主要讲述的重点在于:u-boot、设备树、uEnv.txt的更改部分板⼦主要信息说明:板⼦芯⽚:ZYNQ7035,板⼦的调试打印串⼝为PS0,板⼦上有SD卡(SD0)、EMMC(SD1),板⼦上有FLASH。
其他外设不赘述。
u-boot移植说明:NOTE:u-boot xilinx-v2018.3版本的zynq-common.h跟xilinx-v2018.1版本的不⼀样,这⾥检出v2018.1版本使⽤。
主要是CONFIG_EXTRA_ENV_SETTINGS环境变量不⼀致。
默认的如下所⽰:/* Default environment */#ifndef CONFIG_EXTRA_ENV_SETTINGS#define CONFIG_EXTRA_ENV_SETTINGS \"ethaddr=00:0a:35:00:01:22\0" \"kernel_image=uImage\0" \"kernel_load_address=0x2080000\0" \"ramdisk_image=uramdisk.image.gz\0" \"ramdisk_load_address=0x4000000\0" \"devicetree_image=devicetree.dtb\0" \"devicetree_load_address=0x2000000\0" \"bitstream_image=system.bit.bin\0" \"boot_image=BOOT.bin\0" \"loadbit_addr=0x100000\0" \"loadbootenv_addr=0x2000000\0" \"kernel_size=0x500000\0" \"devicetree_size=0x20000\0" \"ramdisk_size=0x5E0000\0" \"boot_size=0xF00000\0" \"fdt_high=0x20000000\0" \"initrd_high=0x20000000\0" \"bootenv=uEnv.txt\0" \"loadbootenv=load mmc 0 ${loadbootenv_addr} ${bootenv}\0" \"importbootenv=echo Importing environment from SD ...; " \"env import -t ${loadbootenv_addr} $filesize\0" \"sd_uEnvtxt_existence_test=test -e mmc 0 /uEnv.txt\0" \"preboot=if test $modeboot = sdboot && env run sd_uEnvtxt_existence_test; " \"then if env run loadbootenv; " \"then env run importbootenv; " \"fi; " \"fi; \0" \"mmc_loadbit=echo Loading bitstream from SD/MMC/eMMC to RAM.. && " \"mmcinfo && " \"load mmc 0 ${loadbit_addr} ${bitstream_image} && " \"fpga load 0 ${loadbit_addr} ${filesize}\0" \"norboot=echo Copying Linux from NOR flash to RAM... && " \"cp.b 0xE2100000 ${kernel_load_address} ${kernel_size} && " \"cp.b 0xE2600000 ${devicetree_load_address} ${devicetree_size} && " \"echo Copying ramdisk... && " \"cp.b 0xE2620000 ${ramdisk_load_address} ${ramdisk_size} && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \"qspiboot=echo Copying Linux from QSPI flash to RAM... && " \"sf probe 0 0 0 && " \"sf read ${kernel_load_address} 0x100000 ${kernel_size} && " \"sf read ${devicetree_load_address} 0x600000 ${devicetree_size} && " \"echo Copying ramdisk... && " \"sf read ${ramdisk_load_address} 0x620000 ${ramdisk_size} && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \"uenvboot=" \"if run loadbootenv; then " \"echo Loaded environment from ${bootenv}; " \"run importbootenv; " \"fi; " \"if test -n $uenvcmd; then " \"echo Running uenvcmd ...; " \"run uenvcmd; " \"fi\0" \"sdboot=if mmcinfo; then " \"run uenvboot; " \"echo Copying Linux from SD to RAM... && " \"load mmc 0 ${kernel_load_address} ${kernel_image} && " \"load mmc 0 ${devicetree_load_address} ${devicetree_image} && " \"load mmc 0 ${ramdisk_load_address} ${ramdisk_image} && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}; " \"fi\0" \"usbboot=if usb start; then " \"run uenvboot; " \"echo Copying Linux from USB to RAM... && " \"load usb 0 ${kernel_load_address} ${kernel_image} && " \"load usb 0 ${devicetree_load_address} ${devicetree_image} && " \"load usb 0 ${ramdisk_load_address} ${ramdisk_image} && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}; " \"fi\0" \"nandboot=echo Copying Linux from NAND flash to RAM... && " \"nand read ${kernel_load_address} 0x100000 ${kernel_size} && " \"nand read ${devicetree_load_address} 0x600000 ${devicetree_size} && " \"echo Copying ramdisk... && " \"nand read ${ramdisk_load_address} 0x620000 ${ramdisk_size} && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \"jtagboot=echo TFTPing Linux to RAM... && " \"tftpboot ${kernel_load_address} ${kernel_image} && " \"tftpboot ${devicetree_load_address} ${devicetree_image} && " \"tftpboot ${ramdisk_load_address} ${ramdisk_image} && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \"rsa_norboot=echo Copying Image from NOR flash to RAM... && " \"cp.b 0xE2100000 0x100000 ${boot_size} && " \"zynqrsa 0x100000 && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \"rsa_nandboot=echo Copying Image from NAND flash to RAM... && " \"nand read 0x100000 0x0 ${boot_size} && " \"zynqrsa 0x100000 && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \"rsa_qspiboot=echo Copying Image from QSPI flash to RAM... && " \"sf probe 0 0 0 && " \"sf read 0x100000 0x0 ${boot_size} && " \"zynqrsa 0x100000 && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \"rsa_sdboot=echo Copying Image from SD to RAM... && " \"load mmc 0 0x100000 ${boot_image} && " \"zynqrsa 0x100000 && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \"rsa_jtagboot=echo TFTPing Image to RAM... && " \"tftpboot 0x100000 ${boot_image} && " \"zynqrsa 0x100000 && " \"bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address}\0" \DFU_ALT_INFO \BOOTENV#endif可以看到其上定义了⼀堆的东西及不同的启动指令。
#ifndef _FPGA_H_#define _FPGA_H_#define INTMSK (0x4A000008)#define EINTMASK (0x560000A4)#define S3C2410_ENABLE_EINT8_23 (~(1<<5))#define S3C2410_ENABLE_EINT18 (~(1<<18))#undef PDEBUG /* undef it, just in case */#define DEBUG //调试时添加此行程序,实际产品中需要注释掉#ifdef DEBUG# define PDEBUG(fmt, args...) printk( KERN_WARNING "fpga: " fmt, ## args)#else# define PDEBUG(fmt, args...) /* not debugging: nothing */#endif#define DEVICE_NAME "FPGA"#ifndef FPGA_NR_DEVS#define FPGA_NR_DEVS 1 /*设备数*/#endif#define FPGAMEM_SIZE 1024/*FPGA每次产生中断可以读取到缓存的数据大小*/#define FPGACMD_SIZE 3 /*FPGA每次产生中断可以读取到缓存的数据大小*/#define FPGA_ADDR_START (0x08000000) //nGCS1地址#define FPGA_ADDR_SIZE 0x30 //申请IO内存的大小#define FPGA_ADDR_DATA 0x10 //FPGA数据寄存器偏移地址#define FPGA_ADDR_CMD 0x14 //FPGA命令寄存器偏移地址/* 定义幻数,定义一个字符,8位,用于检测是否是这类设备,ioctl-number.txt中给出了已经使用的幻数,定义的时候注意避免冲突*/#define FPGA_IOC 'k'/* 定义命令,这里的命令都是unsigned int类型*/#define FPGA_IOC_ALLON _IO(FPGA_IOC, 0) //#define FPGA_IOC_ALLDOWN _IO(FPGA_IOC, 1) //#define FPGA_IOC_SET _IOW(FPGA_IOC, 2, int) //#define FPGA_IOC_CLEAR _IOW(FPGA_IOC, 3, int)//#define FPGA_IOC_MAXNR 4 //定义命令的最大序列号/* Per-device (per-bank) structure */struct fpga_dev {struct cdev cdev; /* The cdev structure */unsigned int readlength; /* 每次中断从FPGA读取数据的实际字节数*/ char bus_data[FPGAMEM_SIZE]; /* 缓存从FPGA读取的数据*/char cmd_data[FPGACMD_SIZE]; /* 缓存发送给FPGA的命令*/// struct fasync_struct *async_queue;/* 异步结构体指针,用于读*//* ... */ /* Mutexes, spinlocks, waitqueues, .. */wait_queue_head_t r_wait; /* 阻塞读用的等待队列头*/} *fpga_devp;#endif /* _FPGA_H_ */#include <linux/delay.h>//#include <asm/irq.h>#include <asm/io.h>#include <asm/signal.h>#include <asm-generic/siginfo.h>#include <asm/irq.h>#include <mach/regs-gpio.h>#include <mach/regs-mem.h>#include <mach/hardware.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/interrupt.h>#include <linux/mm.h>#include <linux/fs.h>#include <linux/irq.h>#include <linux/types.h>#include <linux/moduleparam.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/ioctl.h>#include <linux/cdev.h>#include <linux/string.h>#include <linux/list.h>#include <asm/uaccess.h>#include <asm/atomic.h>#include <asm/unistd.h>#include <linux/device.h>#include <linux/ioport.h>#include <linux/gpio.h>#include <linux/sched.h>#include <linux/wait.h>//#include <asm/arch-s3c2410/irqs.h>//#include <asm/arch-s3c2410/regs-gpio.h>#include "fpga.h"//#define FPGADATA (*(volatile unsigned long *)(fpga_addr + 0x10)) //FPGA data//#define FPGACON (*(volatile unsigned long *)(fpga_addr + 0x08)) //FPGA control //struct cdev cdev;static struct class *fpga_class;static struct device *fpga_dev;static void __iomem *fpga_addr; //FPGA在Linux中映射的虚拟地址//static struct resource *fpga_mem;static dev_t fpga_num;static volatile int ev_fpga = 0;unsigned int temp = 0;unsigned int i;static irqreturn_t fpga_interrupt(int irq, void *dev_id, struct pt_regs *regs){// disable_irq(IRQ_EINT18);// PDEBUG("read %d bytes from FPGA:\n", count);for (i=0; i<FPGAMEM_SIZE/2; i++){temp = ioread16(fpga_addr+FPGA_ADDR_DATA); //从FPGA读取16位数据fpga_devp->readlength = fpga_devp->readlength + 2;//字节数加2// PDEBUG("data %d:%d\t",i,temp);fpga_devp->bus_data[2*i+1] = temp; //将16位数据的低8位转换到字节数组中fpga_devp->bus_data[2*i] = temp >> 8; //将16位数据的高8位转换到字节数组中}temp = 0;ev_fpga = 1;wake_up_interruptible(&(fpga_devp->r_wait));// /* 产生异步读信号*/// if (fpga_devp->async_queue)// kill_fasync(&fpga_devp->async_queue, SIGIO, POLL_IN);return IRQ_HANDLED;}static int fpga_open(struct inode *inode, struct file *file){int ret;struct fpga_dev *fpga_devp;/* Get the per-device structure that contains this cdev */fpga_devp = container_of(inode->i_cdev, struct fpga_dev, cdev);/* Easy access to cmos_devp from rest of the entry points */file->private_data = fpga_devp;/* Initialize some fields */s3c2410_gpio_cfgpin(S3C2410_GPG(10), S3C2410_GPG10_EINT18);//使GPG10为中断EINT18 s3c2410_gpio_pullup(S3C2410_GPG(10), 0);//禁止上拉/* 申请中断*/set_irq_type(IRQ_EINT18,IRQ_TYPE_LEVEL_LOW);//低电平产生中断ret = request_irq(IRQ_EINT18, fpga_interrupt, 0, DEVICE_NAME, (void *)NULL);if(ret){PDEBUG("request interrupt fail\n");return ret;}/* 初始化读等待队列*/init_waitqueue_head(&(fpga_devp->r_wait));PDEBUG("FPGA opened\n");return 0;}static ssize_t fpga_read(struct file *file, char __user *buffer, size_t size, loff_t *ppos){unsigned int count = size;unsigned int ret = 0;struct fpga_dev *fpga_devp = file->private_data;/*获得设备结构体指针*/wait_event_interruptible(fpga_devp->r_wait, ev_fpga);ev_fpga = 0;/* 每次中断从FPGA读取的数据的数量不等于应用程序需要读取的数据时,返回0 */ if (fpga_devp->readlength != count)return 0;/*内核空间->用户空间*/if (copy_to_user(buffer, (void*)(fpga_devp->bus_data), count)){ret = - EFAULT;}else{ret = count;}return ret;}static ssize_t fpga_write(struct file *file,const char __user *buffer, size_t size, loff_t *ppos){unsigned int count = size;unsigned int tempcmd = 0;unsigned int ret = 0;unsigned int i;struct fpga_dev *fpga_devp = file->private_data;/*获得设备结构体指针*//*用户空间->内核空间*/if (copy_from_user((void*)(fpga_devp->cmd_data), buffer, count)){ret = - EFAULT;}else{ret = count;}PDEBUG("write %d bytes to FPGA:\n", count);for (i=0; i<count; i++){tempcmd=fpga_devp->cmd_data[i];// temp=temp<<8;// temp=temp|fpga_devp->cmd_data[2*i+1];iowrite16(tempcmd,fpga_addr+FPGA_ADDR_CMD); //向FPGA写入16位数据PDEBUG("data %d:%d\t",i,tempcmd);}return ret;}//static int fpga_fasync(int fd, struct file *file, int mode)//{// struct fpga_dev *fpga_devp = file->private_data;/*获得设备结构体指针*/// return fasync_helper(fd, file, mode, &fpga_devp->async_queue);//}static int fpga_release(struct inode *inode, struct file *file){// fpga_fasync(-1, file, 0); /* 将文件从异步通知列表中删除*/ free_irq(IRQ_EINT18,NULL);s3c2410_gpio_cfgpin(S3C2410_GPG(10), S3C2410_GPIO_INPUT);PDEBUG("FPGA closed\n");return 0;}////static int fpga_ioctl(// struct inode *inode,// struct file *file,// unsigned int cmd,// unsigned long arg)//{// int i;// int cmddata;//// /* 检测命令的有效性*/// if (_IOC_TYPE(cmd) != FPGA_IOC)//命令是否操作这一类设备// return -EINVAL;// if (_IOC_NR(cmd) > fpga_IOC_MAXNR) //命令序列号是否超出定义// return -EINVAL;//// switch(cmd) {//// case fpga_IOC_ALLON:// for(i=0; i<4; i++) {// s3c2410_gpio_setpin(led_table[i], 0); //设置IO口为0,LED为全亮状态// }// break;//// case fpga_IOC_ALLDOWN:// for(i=0; i<4; i++) {// s3c2410_gpio_setpin(led_table[i], 1); //设置IO口为1,LED为全灭状态// }// break;//// case fpga_IOC_SET:// if (copy_from_user(&cmddata, (int *)arg, sizeof(int)))// return -EFAULT;// s3c2410_gpio_setpin(led_table[cmddata], 0);// break;//// case fpga_IOC_CLEAR:// if (copy_from_user(&cmddata, (int *)arg, sizeof(int)))// return -EFAULT;// s3c2410_gpio_setpin(led_table[cmddata], 1);// break;//// default:// return -EINVAL;// }//// return 0;//}/*文件操作结构体*/static const struct file_operations fpga_fops ={.owner = THIS_MODULE,// .ioctl = fpga_ioctl,// .llseek = fpga_llseek,.read = fpga_read,.write = fpga_write,// .fasync = fpga_fasync,.open = fpga_open,.release = fpga_release,};static int __init fpga_init(void){int ret;struct resource *fpga_res;unsigned int oldval_bwscon;static void *intmsk;static void *eintmask;intmsk = ioremap_nocache(INTMSK,0x0000004);eintmask = ioremap_nocache(EINTMASK,0x0000004);/* 设置S3C2410_BWSCON:数据总线宽度16bits,使用UB/LB,禁止WAIT */ oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON;*((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<5)) | S3C2410_BWSCON_DW1_16 | S3C2410_BWSCON_ST1;/* 设置S3C2410_BANKCON1 */*((volatile unsigned int *)S3C2410_BANKCON1) = 0x0300;/* 设置S3C2410_GPGCON,使GPG10为中断EINT18 */// oldval_gpgcon = *(volatile unsigned int *)S3C2410_GPGCON;// *(volatile unsigned int *)S3C2410_GPGCON = oldval_gpgcon | S3C2410_GPG10_EINT18;/* 设置S3C2410_GPGUP,禁止GPG10上拉*/// oldval_gpgup = *(volatile unsigned int *)S3C2410_GPGUP;// *(volatile unsigned int *)S3C2410_GPGUP = oldval_gpgup | S3C2410_GPG_PUPDIS(10);/* 设置INTMSK,使能中断EINT8_23 */writel((readl(intmsk)) & S3C2410_ENABLE_EINT8_23,intmsk);/* 设置EINTMASK,使能中断EINT18 */writel((readl(eintmask)) & S3C2410_ENABLE_EINT18,eintmask);// val |= S3C2410_BWSCON_DW2_16;//// S3C2410_BWSCON = S3C2410_BWSCON | (0x02<<7);// __raw_writel(val, S3C2410_BWSCON); //设置bank2的数据总线为16位宽度////// val = 0x2a60;//// BANKCON2 = 0x2a60;// __raw_writel(val,S3C2410_BANKCON2); //设置满足S3C2440A的nGCS时序/*动态分配设备号*/ret = alloc_chrdev_region(&fpga_num, 0, FPGA_NR_DEVS, DEVICE_NAME);if (ret < 0){PDEBUG (DEVICE_NAME"can't be registered\n");return ret;}/* 申请设备结构体内存*/fpga_devp = kmalloc(sizeof(struct fpga_dev), GFP_KERNEL);if (!fpga_devp)/*申请失败*/{PDEBUG("request device struct memery fail\n");ret = - ENOMEM;goto fail_kmalloc;}/* 清零设备缓存*/memset(fpga_devp, 0, sizeof(struct fpga_dev));// memset(fpga_devp->cmd_data, 0, FPGACMD_SIZE);// memset(&(fpga_devp->readlength), 0, sizeof(unsigned int));/* 申请I/O内存*/fpga_res = request_mem_region(FPGA_ADDR_START,FPGA_ADDR_SIZE,DEVICE_NAME);if(fpga_res == NULL){PDEBUG("request io memery fail\n");ret = -EINVAL;goto fail_request_mem;}/* 物理地址到虚拟地址映射*/fpga_addr = ioremap(FPGA_ADDR_START,FPGA_ADDR_SIZE);if(fpga_addr == NULL){PDEBUG("remap address fail\n");ret = -ENOMEM;goto fail_ioremap;}/*初始化cdev结构*/cdev_init(&fpga_devp->cdev, &fpga_fops);fpga_devp->cdev.owner = THIS_MODULE;fpga_devp->cdev.ops = &fpga_fops;/* 注册字符设备*/cdev_add(&fpga_devp->cdev, fpga_num, FPGA_NR_DEVS);fpga_class = class_create(THIS_MODULE,DEVICE_NAME);fpga_dev = device_create(fpga_class, NULL, fpga_num, NULL, DEVICE_NAME);PDEBUG (DEVICE_NAME"\tinitialized\n");return 0;fail_kmalloc: unregister_chrdev_region(fpga_num, FPGA_NR_DEVS); /*释放设备号*/return ret;fail_request_mem: kfree(fpga_devp); /*释放设备结构体内存*/unregister_chrdev_region(fpga_num, FPGA_NR_DEVS); /*释放设备号*/return ret;fail_ioremap: release_mem_region(FPGA_ADDR_START,FPGA_ADDR_SIZE); //释放IO内存kfree(fpga_devp); /*释放设备结构体内存*/unregister_chrdev_region(fpga_num, FPGA_NR_DEVS); /*释放设备号*/return ret;}static void __exit fpga_exit(void){iounmap(fpga_addr); //取消地址映射release_mem_region(FPGA_ADDR_START,FPGA_ADDR_SIZE); //释放IO内存kfree(fpga_devp); /*释放设备结构体内存*/unregister_chrdev_region(fpga_num, FPGA_NR_DEVS); /*释放设备号*/device_destroy(fpga_class,fpga_num);class_destroy(fpga_class);cdev_del(&fpga_devp->cdev); /*注销设备*/PDEBUG (DEVICE_NAME"\treleased\n");}module_init(fpga_init);module_exit(fpga_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("David Chen");MODULE_DESCRIPTION("FPGA driver for S3C2440A & XC3S200");。