Linux字符设备驱动

  1. 实现一组对外的访问接口, open、release、read、write将这些函数的实现赋值给file_operations这个结构体中。
  2. 实现对字符设备驱动程序的创建和初始化。
  3. 按照内核模块的编写方法去制定对应的入口函数和出口函数。入口函数实现对驱动程序的注册功能,需要调用驱动程序的初始化函数进行初始化操作。出口函数就是完成对程序的卸载;
  4. 编译对应的驱动程序源码,从而得到.ko文件,查看/proc/devices文件,从而判断对应的驱动程序是否注册成功,若成功,在/dev目录下将会看到创建对应的设备文件以及设备号,通过mknod命令实现

art.c

//art.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define TEST_DEVICE_FILENAME "/dev/art_dev"  //设备文件名
#define BUFF_SIZE 1024
int main()
{
    int fd,nwrite,nread;
    char buff[BUFF_SIZE];  //缓冲区
     /* 打开文件 */
    fd=open("/dev/art_dev",O_RDWR);
    if(fd<0){
        perror("open");  
        exit(1);
     }  
    do{
        printf("向内核输入字符内容为('q'退出):");
        memset(buff,0,BUFF_SIZE);
        if(fgets(buff,BUFF_SIZE,stdin)==NULL){
            perror("error fgets");  
            break;
        }
        buff[strlen(buff)-1]='\0';
        if(write(fd,buff,strlen(buff))<0)  //向内核设备写入数据
        {
            perror("error write");  
            break;
        }
        if(read(fd,buff,BUFF_SIZE)<0)  //从内核设备读取数据
        {
            perror("error write");  
            break;
        }
        else{
            printf("从内核中读出字符内容为:%s\n\n",buff);
        }
    }while(strncmp(buff,"q",1));
    close(fd);
    exit(0);
}

art_dev.c

//art_dev.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/cdev.h> 
#include <asm/uaccess.h>
#define TEST_DEVICE_NAME "art_dev" 
#define BUFF_SIZE 1024
// 全局变量 
static struct cdev art_dev;
unsigned int major = 0;//主设备号
static char *data = NULL;//内核空间大小
dev_t dev;//起始的设备编号

/* 写函数 */
static ssize_t art_write(struct file *file, const char *buffer, size_t count, loff_t *f_pos)
{
     if(count<0)
    {       
         return -EINVAL;        
    }
    memset(data,0,BUFF_SIZE);
    count=(BUFF_SIZE>count) ?count:BUFF_SIZE;
    if(copy_from_user(data,buffer,count)) //将用户缓冲的数据复制到内核空间
    {   
         return -EFAULT;
    }
        return count;
}

/* 读函数 */ 
static ssize_t art_read( struct file *file, char *buf, size_t count, loff_t *f_pos)
{
     int len;   
     if(count<0)
     {      
         return -EINVAL;            
     }  
     len=strlen(data);  
     count=(len>count)?count:len;
     if(copy_to_user(buf,data,count)) //将内核缓冲的数据复制到用户空间 
     {      
        return -EFAULT; 
     }  
     return count;
}

/* 打开函数 */
static int art_open(struct inode *inode,struct file *file)
{
      printk("This is open operation.\n");
        /* 分配并初始化缓冲区 */
        data=(char*)kmalloc(sizeof(char)*BUFF_SIZE,GFP_KERNEL);
         if(!data)
        {
             printk("malloc error!");
              return -ENOMEM;
        }

         memset(data,0,BUFF_SIZE);  
        return 0;
}
/* 关闭函数 */
static int art_release(struct inode *inode,struct file *file)
{   
      printk("This is release operation.\n");   
      if(data)
      { 
           kfree(data);  //释放缓冲区
           data=NULL;    //防止出现野指针
       }
       return 0;
}

/* 虚拟设备的file——operation结构 */
static struct file_operations art_fops=
{
    .owner=THIS_MODULE,
    .read=art_read,
        .write=art_write,
    .open=art_open,
        .release=art_release, 
};
/* 创建、初始化字符设备,并且注册到系统 */
static void art_setup_cdev( struct cdev *cdev, int minor, struct file_operations *fops)
{       
         int error;
         cdev_init(cdev,fops);
         cdev->owner=THIS_MODULE;
         cdev->ops=fops;
         error=cdev_add(cdev,dev,1);
         if(error)
        {
             printk(KERN_NOTICE"Error %d adding test %d",error,minor);
        }
}
//模块注册入口 
static int __init _init_artmodule(void)
{

       int result;
       dev=MKDEV(major,0);
       if(major)
       { 
           //静态注册一个设备,设备号事先指定好,用cat/proc/devices来查看
          result=register_chrdev_region(dev,1,TEST_DEVICE_NAME);
       }
       else
       {    //动态分配一个设备号 
          result=alloc_chrdev_region(&dev,0,1,TEST_DEVICE_NAME);
       }    
      if(result<0)
      {     
           printk(KERN_WARNING"Test device:unable to get major %d\n",major);
           return result;
       }
       art_setup_cdev(&art_dev,0,&art_fops);
       printk("The major of the test device is %d\n",dev);
       return 0;
}


/* 卸载模块 */
static void __exit _cleanup_artmodule(void)
{

         cdev_del(&art_dev);
         unregister_chrdev_region(MKDEV(major,0),1);
         printk("Test device uninstalled.\n");

}

module_init(_init_artmodule);
module_exit(_cleanup_artmodule);



MaKefile

ifeq ($(KERNELRELEASE),)
    KERNELDIR ?= /lib/modules/$(shell uname -r)/build  

    PWD := $(shell pwd)     
    modules:
         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    modules_install:
         $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
    clean:   
         rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions 
    .PHONE: 
         modules modules_install clean
     else
         obj-m := art_dev.o  
     endif

字符设备调试步骤

字符设备调试步骤

字符设备调试步骤

linux字符设备驱动设计与实现详细文档下载

360云盘下载,点击前复制密码 访问密码 4e86

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值