Linux字符设备驱动

来源:互联网 发布:java事务的隔离级别 编辑:程序博客网 时间:2024/06/15 19:15
  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 1024int 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 0
原创粉丝点击