#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#ifdef LINUX26
#include <linux/moduleparam.h>
#endif
#include "plx.h"
#define DEVICE_NAME "plxDriver"
#define PLX_8311
//static int iMajor;
static int plx_major = 0;
struct cdev cdev;
dev_t devno;
struct class *plx_class;
static struct Plx *cards[PLX_MAX_IFACES];
bool Found_card_flag = 0;

static void plx_release(struct Plx *plx)
{
    unsigned short val;
    val = 0x0;
    if (plx->freeregion_plx)
        release_mem_region(plx->region, plx->len);

if (plx->addr)
        iounmap(plx->addr);

if (plx)
        kfree(plx);
    printk("Freed a plx card\n");

}

static int shrec_open(struct inode *inode, struct file *file)
{
    try_module_get( THIS_MODULE );

printk("open driver\n");
    return 0;
}

static int shrec_release( struct inode *inode, struct file *file )
{
    module_put( THIS_MODULE );
    if (wc->freeregion_plx)
        release_mem_region(wc->plx_region, wc->plx_len);
    if (wc->freeregion_dsp)
        release_mem_region(wc->dsp_region, wc->dsp_len);
    if (wc->plx)
        iounmap(wc->plx);
    if (wc->dsp)
        iounmap(wc->dsp);
    if (wc)
        vfree(wc);
    return 0;
}

static struct file_operations shrec_fops = {
    owner:        THIS_MODULE,
    open:            shrec_open,
    read:            shrec_read,
    write:        shrec_write,
    release:    shrec_release,
};

static int __devinit plx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
    int x;
    int ret;
    int res;
    struct Plx *plx;

for (x=0;x<PLX_MAX_IFACES;x++)
    {
        if (!cards[x])   
            break;
    }
    if (x >= PLX_MAX_IFACES)
    {
        printk("Too many interfaces\n");
        return -EIO;
    }
    if (pci_enable_device(pdev))
    {
        res = -EIO;
    }
    else
    {
        plx = kmalloc(sizeof(struct Plx), GFP_KERNEL);
        if (!plx) return -ENOMEM;
        memset(plx, 0x0, sizeof(struct Plx));
        if (pdev->irq < 1)
        {
            if (plx)
                kfree(plx);
            printk(KERN_ERR "No IRQ allocated for device\n");
            return -ENODEV;
        }

cards[x] = plx;
        plx->dev = pdev;
        plx->region = pci_resource_start(pdev,0);  //1、获取plx地址空间基地址0的首地址,该地址为物理地址,由系统启动是保存在pdev结构体中
        plx->len = pci_resource_len(pdev,0);   //获取基地址0的空间大小

if (check_mem_region(plx->region, plx->len))  //2、检查该区域是否可用
        {
            printk("plx region %lx-%lx already in use\n", plx->region, plx->region + plx->len);
            if (plx)
                kfree(plx);
            return -EIO;
        }

if (request_mem_region(plx->region, plx->len, "plx"))  //3、申请使用该区域
        {
            plx->freeregion_plx = 1;
        }
        plx->addr = ioremap(plx->region, plx->len);  //4、将该区域的物理地址映射为虚拟地址,程序对只能对虚拟地址进行读写
        if (!plx->addr)
        {
            printk("Cannot ioremap memory space at 0x%lx\n", plx->region);
            goto err_out_free_plx;
        }
        pci_set_drvdata(pdev, plx);

printk("Found  plx card %d\n",x);
        Found_card_flag = 1;
        res = 0;
    }
    return res;

err_out_free_plx:
    if (plx->freeregion_plx)
        release_mem_region(plx->region, plx->len);
    if (plx->addr)
        iounmap(plx->addr);
    if (plx)
        kfree(plx);
    return -EIO;

}

static void __devexit plx_remove_one(struct pci_dev *pdev)
{
    struct Plx *plx = pci_get_drvdata(pdev);
    unsigned short reg;

if (plx)
    {
        reg = 0x0;
        wait_ms(5000);
        if (!plx->usecount)
            plx_release(plx);
        else
            plx->dead = 1;
    }
}

static struct pci_device_id plx_pci_tbl[] =
{
    /*probe pcie cards*/
    { 0x10b5, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
    /*probe pci cards*/
    /*tejxapci*/
    { 0x10b5, 0x00fa, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
    { 0x10b5, 0x00fb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
    { 0x10b5, 0x00fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
};

MODULE_DEVICE_TABLE(pci, plx_pci_tbl);

static struct pci_driver plx_driver =
{
    name:     "plx_driver",
    probe:     plx_init_one,
    remove:    plx_remove_one,
    suspend: NULL,
    resume:    NULL,
    id_table: plx_pci_tbl, /*加载驱动时,会探测pci链表中的节点,如果有pci设备中有与
                          plx_pci_tbl信息匹配的,则调用plx_init_one,对该设备进行配置及初始化*/
};

static int __init plx_driver_init(void)
{
    int res;
    res = pci_register_driver(&plx_driver);/*注册pci驱动*/
    if (res)
        return -ENODEV;
    if(plx_major)
    {
        devno = MKDEV(plx_major,0);/*获取主设备号*/

res = register_chrdev_region(devno,1,DEVICE_NAME);
    }
    else
    {
        res = alloc_chrdev_region(&devno,0,1,DEVICE_NAME);
        plx_major = MAJOR(devno);
        printk("major = %d\n",plx_major);
    }

if(Found_card_flag)
  {
    /*注册设备*/
    cdev_init(&cdev,&shrec_fops);
    cdev.owner = THIS_MODULE;
    res = cdev_add(&cdev,devno,1);
    if (res)
        printk("Error %d adding plx",res);

/*创建设备文件节点*/
    plx_class = class_create(THIS_MODULE, DEVICE_NAME);
   if(IS_ERR(plx_class))
        { printk("Err: failed in creating class.\n");
             return -1;
         }
    device_create( plx_class, NULL, devno, DEVICE_NAME);
  }
  else
      printk("Not found Synway card!\n");

return 0;

}

static void __exit plx_driver_cleanup(void)
{
    unregister_chrdev_region(devno,1);/*注销设备号*/

pci_unregister_driver(&plx_driver);/*注销pci驱动,会调用plx_remove_one函数*/

/*注销文件节点*/
     if(Found_card_flag)
     {
        device_destroy(plx_class, devno);
        class_destroy(plx_class);

cdev_del(&cdev);/*注销字符设备*/

}  
}
module_init(plx_driver_init);
module_exit(plx_driver_cleanup);

Linux pci驱动源码的更多相关文章

  1. Davinci DM6446开发攻略——LINUX GPIO驱动源码移植

    一.             DM6446 GPIO的介绍      说到LINUX 驱动移植,没有移植过的朋友,或刚刚进入LINUX领域的朋友,最好去看看<LINUX 设备驱动程序>第三 ...

  2. (转)Linux设备驱动之HID驱动 源码分析

    //Linux设备驱动之HID驱动 源码分析 http://blog.chinaunix.net/uid-20543183-id-1930836.html HID是Human Interface De ...

  3. linux调度器源码分析 - 运行(四)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 之前的文章已经将调度器的数据结构.初始化.加入进程都进行了分析,这篇文章将主要说明调度器是如何在程序稳定运 ...

  4. Linux环境PostgreSQL源码编译安装

    Linux环境PostgreSQL源码编译安装 Linux版本: Red Hat 6.4 PostgreSQL版本: postgresql-9.3.2.tar.gz 数据存放目录: /var/post ...

  5. 编译 wl18xx驱动源码

    在做beagleboneblack移植的时候,wl18xx的驱动源码是自动编译的.但是移植到其他平台优越平台不一样,所以就不能自动编译 所以用其他方式编译.http://e2e.ti.com/supp ...

  6. Android源码浅析(四)——我在Android开发中常用到的adb命令,Linux命令,源码编译命令

    Android源码浅析(四)--我在Android开发中常用到的adb命令,Linux命令,源码编译命令 我自己平时开发的时候积累的一些命令,希望对你有所帮助 adb是什么?: adb的全称为Andr ...

  7. Linux学习之源码包安装与脚本安装(十八)

    Linux学习之源码包安装与脚本安装 目录 源码包与RPM包的区别 源码包安装 脚本安装 源码包与RPM包的区别 1.区别 安装之前的区别:概念上的区别 安装之后的区别:安装位置不同 源码包: 开源的 ...

  8. linux调度器源码分析 - 初始化(二)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 引言 上期文章linux调度器源码分析 - 概述(一)已经把调度器相关的数据结构介绍了一遍,本篇着重通过代码说明 ...

  9. MySQL的JDBC驱动源码解析

    原文:   MySQL的JDBC驱动源码解析 大家都知道JDBC是Java访问数据库的一套规范,具体访问数据库的细节有各个数据库厂商自己实现 Java数据库连接(JDBC)由一组用 Java 编程语言 ...

随机推荐

  1. HDU-5273

    Dylans loves sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/ ...

  2. Java Web学习脑图

    Java Web学习脑图,从知乎上摘录,感谢知乎网友的分享.

  3. Android点击图标重新启动问题

    原文:http://blog.csdn.net/jianiuqi/article/details/54091181 项目中的小问题:发现应用打包安装后按home键切换到后台后,点击应用图标又重新打开了 ...

  4. 图片乱码问题 解决方法 php

    两个开发者都是下载同一个项目的git代码,但到本地环境,一个可以正常显示图片验证码,一个不行,找个半天开始以为环境问题 找了半天 不是 很多没说到重点 其实不只是当前文件格式问题 也要考虑其他调用文件 ...

  5. Django CRM查询 XXX.object.filter() 常用用法总结

    __gt 大于 __gte 大于等于 User.objects.filter(age__gt=10) // 查询年龄大于10岁的用户 User.objects.filter(age__gte=10) ...

  6. java逆向相关

    1.将war文件导入到Eclipse 在导入war文件之前,新建项目,比如:webPorject 在Myeclipse中:在File===>import==>General中选择Archi ...

  7. codis 的dashboard服务无法启动 提示pid已经运行

    ps -rf|grep pid号 ,一直查询不到,进程并没有运行, 后来在Zookeeper中发现get /zk/codis/db_gdata/dashboard 这个中存在着pid,连接到zooke ...

  8. 0821Servlet基础

    什么是servlet    jsp页面的前身是servlet, 但是servlet和jsp是两个不同概念    servlet是运行在服务器端的一段程序, 是可以直接运行一段java后台代码      ...

  9. 从Linux下载文件到Windows没有换行问题

    这是一个小问题,一般用txt打开文件才会遇到,word打开也是正常(估计其他编程软件打开也正常). 顺便提一下pscp从Linux上下载文件到Windows. C:\Users\xuefei>p ...

  10. Hive 默认分区

    在hive里面表可以创建成分区表,但是当分区字段的值是'' 或者 null时 hive会自动将分区命名为默认分区名称. 默认情况下,默认分区的名称为__HIVE_DEFAULT_PARTITION__ ...