首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux 驱动程序开发步骤(X86平台)

Linux 驱动程序开发步骤(X86平台)

编写好驱动,通过挂载的方法将驱动程序挂载到内核里面,大致步骤如下:
: 1>建立以.c为后缀的c语言程序文件(里面包含了设备名及设备号等)
2>建立Makefile文件(作用是通过make来产生设备文件*.ko文件,里面可以建立自己的平台所需的设备文件如:arm).make 产生相应的设备文件
: 要在/dev下建立相应的设备结点(设备名),insomd *.ko命令将相应的驱动设备文件挂载到内核中.
:编写测试文件(.c文件)用来测试内核是否已近成功挂载到内核.(编写好相应的测试文件后,gcc –o Filename Filename.c(测试文件名) 来产生相应的可执行文件).
:如果设备驱动挂载成功,当执行测试文件(./Filename)时会产生相应的结果.

:可能用到的相关命令:
1.      lsmod:列出内核已经载入模块的专题.
输出:
Module(模块名)           size(大小)          used by (..使用)
2.      demop:分析可加载模块的依赖性,生成modules.dep文件和映射文件
3.      uname–r   显示内核版本(在编写Makefile时使用到)
4.      modprobe : linux内核添加和删除模块(相关参数请查看man帮助文档)
5.      modinfo:显示内核模块的信息.
6.      insmod: linux内核中加载一个模块,用法:insmod  [filename] [moduleoptions…]
7.      rmmod: 删除内核中的模块,用法: rmmod [-f,w,s,v]     [modulename]
8.      dmesg: 显示内核缓冲区,内核的各种信息,内核启动时的信息会写入到/var/log/.

.例子1:
第一步:增加头文件和宏定义
#include<linux/fs.h>
#include<linux/types.h>
#include<linux/cdev.h>
#include<linux/uaccess.h>
#include<linux/module>
#include<linux/kernel>

第二步:添加与字符设备定义及注册有关的数据成员
//定义设备名称
#define DEVICE_NAME"test"       //设备名
#defineBUF_SIZE      1024
static chartmpbuf[BUF_SIZE];

//定义主次设备号
static unsigned intTestMajor=0;                    //
static unsigned intTestMinor=0;                    //


static struct cdev*test_cdev;
static dev_tdev;

第三步:增加open/release函数

static inttest_chardev_open(struct inode *inode,struct file*file)
{
   printk("open major=%d, minor=%d\n", imajor(inode),
                                    iminor(inode));
      return 0;
}

static inttest_chardev_release(struct inode *inode,struct file*file)
{
     printk("closemajor=%d,minor=%d\n",imajor(inode),
                                     iminor(inode));
      return 0;
}

第四步:增加read函数
static ssize_ttest_chardev_read(struct file *file,char __user*buf,
                           size_t const count,loff_t *offset)
{
      if(count < BUF_SIZE)
      {
             if(copy_to_user(buf,tmpbuf,count))
             {
               printk("copy to user fail \n");
             return -EFAULT;
             }
      }else{
             printk("read size must be less than %d\n",BUF_SIZE);
             return -EINVAL;
}
      *offset += count;
             return count;
}


第五步:增加write函数
static ssize_ttest_chardev_write(struct file *file, const char__user  *buf,size_t const count,loff_t*offset)
{
      if(count < BUF_SIZE)
      {
             if(copy_from_user(tmpbuf,buf,count))
             {
               printk("copy from user fail \n");
             return -EFAULT;
              }
      }else{
      
             printk("size must be less than %d\n", BUF_SIZE);
             return -EINVAL;
}           
      *offset += count;
      return count;
}

第六步:添加增加file_operations 成员

static structfile_operations chardev_fops={
      .owner = THIS_MODULE,
      .read = test_chardev_read,
      .write = test_chardev_write,
      .open = test_chardev_open,
      .release = test_chardev_release,
};

第七步:在模块的入口添加设备的设备号获取及设备注册
static int __init chrdev_init(void)
{      
int result;

if(TestMajor)
{
       dev=MKDEV(TestMajor,TestMinor);//创建设备编号
       result=register_chrdev_region(dev,1,DEVICE_NAME);
} else {
       result=alloc_chrdev_region(&dev,TestMinor,1,DEVICE_NAME);
       TestMajor=MAJOR(dev);
}
if(result<0)
{
       printk(KERN_WARNING"LED: cannot get major %d\n",TestMajor);
       return result;
}

test_cdev=cdev_alloc();
cdev_init(test_cdev,&chardev_fops);
//test_cdev->ops=&chardev_fops;
test_cdev->owner=THIS_MODULE;
result=cdev_add(test_cdev,dev,1);
if(result)
       printk("<1>Error %d while registerled device!\n",result);

return 0;
}

第八步:在模块的出口函数增加设备设备号释放及设备注销函数

      unregister_chrdev_region(MKDEV(TestMajor,TestMinor),1);
      cdev_del(test_cdev);

第九步:编译并加载该模块
返回列表