Linux 字符設備驅動例子

編寫好驅動,經過掛載的方法將驅動程序掛載到內核裏面,大體步驟以下:node


一:  1>創建以.c爲後綴的c語言程序文件 (裏面包含了設備名及設備號等)
     2>創建Makefile文件(做用是經過make來產生設備文件*.ko文件,裏面能夠創建本身的平臺所需的設備文件如:arm等).make 產生相應的設備文件linux


二: 要在/dev下創建相應的設備結點(設備名),用insomd *.ko命令將相應的驅動設備文件掛載到內核中.shell


三:編寫測試文件(.c文件)用來測試內核是否已近成功掛載到內核.(編寫好相應的測試文件後,用gcc –o Filename Filename.c(測試文件名) 來產生相應的可執行文件).bash


四:若是設備驅動掛載成功,當執行測試文件(./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] [module options…]
7.       rmmod: 刪除內核中的模塊, 用法: rmmod [-f,w,s,v]       [modulename]
8.       dmesg: 顯示內核緩衝區,內核的各類信息,內核啓動時的信息會寫入到/var/log/下.less

六.例子函數

第一步:增長頭文件和宏定義

#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"        //設備名
#define BUF_SIZE       1024
static char tmpbuf[BUF_SIZE];
 
//定義主次設備號
static unsigned int TestMajor=0;                     //主
static unsigned int TestMinor=0;                     //次
 
 
static struct cdev *test_cdev;
static dev_t dev;

第三步:增長open/release函數

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

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

第四步:增長read函數

static ssize_t test_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_t test_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 struct file_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 register led device!\n",result);
 
   return 0;
}

第八步:在模塊的出口函數增長設備設備號釋放及設備註銷函數

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

第九步:編譯並加載該模塊

第十步:根據設備號的設置,在文件系統中創建對應的設備節點

$mknod /dev/test  c  XXX(主設備號)  XX(次設備號)

完整例子

驅動文件

#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>
 
#define DEVICENAME  "ccccc"
 
unsigned int major=221;
unsigned int minor=0;
struct cdev *abc;
dev_t dev;
static char bufrh[1024]="read success!";
 
static int aaaaa_open(struct inode *inodep, struct file *filep)
{
       printk("read success!\n");
      return 0;
}
 
int aaaaa_release(struct inode *inodep, struct file *filep)
{
      return 0;
}
static ssize_t aaaaa_read (struct file *filep, char __user *buf, size_t  count, loff_t *offset)
{
       if(copy_to_user(buf, bufrh, 1))
              {
                     printk("copy_to_user fail!\n");
              }
       return 0;
}
 
ssize_t aaaaa_write (struct file *filep, const char __user *buf,  size_t count, loff_t *offse)
{
       printk("write!\n");
       return 0;
}
 
 
static const struct  file_operations  fops = {
       .owner = THIS_MODULE,
       .open = aaaaa_open,
       .release = aaaaa_release,
       .read = aaaaa_read,
       .write = aaaaa_write,
      
      
};
 
 
 
 
static int __init aaaaa_init(void)
{
       int a;
       dev=MKDEV(major, minor);
       a=register_chrdev_region(dev, 1, DEVICENAME);
        
       abc=cdev_alloc();
       abc->owner=THIS_MODULE;
       cdev_init(abc, &fops);
      
       cdev_add(abc, dev, 1);
 
      
       return 0;
}
 
static void __exit  aaaaa_cleanup(void)
{
       cdev_del(abc);
       unregister_chrdev_region(dev, 1);
}
 
module_init(aaaaa_init);
module_exit(aaaaa_cleanup);
MODULE_LICENSE("GPL ");

Makefile文件測試

obj-m += firstqd.o(相應設備文件名)
 
KERDIR = /usr/src/linux-headers-2.6.32-24-generic   #x86平臺
PWD=$(shell pwd)
 
modules:
       $(MAKE) -C $(KERDIR) M=$(PWD)  modules
 
pc:
       gcc -o fristqd firstqd.c
arm:
       arm-linux-gcc -o fristqd firstqd.c
 
clean:
        rm -rf *.o *~core *.depend *.cmd *.ko *.mod.c *.tmp_versions

用戶空間測試代碼

#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
 
char buf[1024];
char bufw[1024]="write success";
int main()
{
      int fd,m,n;
      fd=open("/dev/aaa",O_RDWR);
      if (fd)
        {
            m=read(fd,buf,100);
            printf("read kernel:%s\n",buf);
 
            n=write(fd,bufw,10);
         }
      //printf("ni hao");
      return  0;
}
相關文章
相關標籤/搜索