linux字符型設備驅動 一.注冊設備並創建設備文件


1.字符設備

字符設備、字符設備驅動與用戶空間訪問該設備的程序三者之間的關系

  Linux內核中:

a -- 使用cdev結構體來描述字符設備;

b -- 通過其成員dev_t來定義設備號(分為主、次設備號)以確定字符設備的唯一性;

c -- 通過其成員file_operations來定義字符設備驅動提供給VFS的接口函數,如常見的open()、read()、write()等;

 

     在Linux字符設備驅動中:

a -- 模塊加載函數通過 register_chrdev_region( ) 或 alloc_chrdev_region( )來靜態或者動態獲取設備號;

b -- 通過 cdev_init( ) 建立cdev與 file_operations之間的連接,通過 cdev_add( ) 向系統添加一個cdev以完成注冊;

c -- 模塊卸載函數通過cdev_del( )來注銷cdev,通過 unregister_chrdev_region( )來釋放設備號;


     用戶空間訪問該設備的程序:

a -- 通過Linux系統調用,如open( )、read( )、write( ),來“調用”file_operations來定義字符設備驅動提供給VFS的接口函數;

2.例子

hello.c

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
static int major = 99; //主設備號(用於區分設備類)
static int minor = 0;  //次設備號(用於區分哪個設備)

static dev_t devno;
static struct cdev cdev1;
struct class *hello_class;

static int hello_open(struct inode *inodep, struct file *filep)
{
    printk(KERN_ALERT "hello are opened \r\n");
    return 0;
}

static struct file_operations hello_ops = {
    .open = hello_open,
};

static int hello_init(void)
{
    int ret;
    printk(KERN_ALERT "hello_init\r\n");
    //第一步:將主設備號、次設備號轉化成dev_t類型
    devno = MKDEV(major, minor);
    ret = register_chrdev_region(devno, 1, "hello");
    if (ret < 0)
    {
        printk(KERN_ERR "my register_chrdev_region fail \r\n");
        return ret;
    }
    printk(KERN_INFO "register_chrdev_region success\n");
    //第二步:注冊字符設備驅動
    cdev_init(&cdev1, &hello_ops);
    ret = cdev_add(&cdev1, devno, 1);
    if (ret < 0)
    {
        printk(KERN_ERR "Uable to add dev\n");
        return ret;
    }
    printk(KERN_INFO "cdev_add success\n");
    //第三步:2.6內核之后要向sys文件系統中添加設備
    hello_class = class_create(THIS_MODULE, "hello");
    device_create(hello_class, NULL, devno, NULL, "hello");
    printk(KERN_INFO "device created success\n");
    return 0;
}
static void hello_exit(void)
{
    cdev_del(&cdev1);
    unregister_chrdev_region(devno, 1);
    printk(KERN_ALERT "hell_exit\r\n");
}
MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);

test.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

main()
{
    int fd;

    fd = open("/dev/hello",O_RDWR);
    if(fd<0)
    {
        perror("open fail \n");
        return ;
    }else
    {
        printf("open /dev/hello success! \n");
    }

    close(fd);
}

makefile

#General Purpose Makefile for cross compile Linux Kernel module
ifneq ($(KERNELRELEASE),)
obj-m := hello.o  #+=是連接字符串
else

ARCH := arm    
CROSS_COMPILE := arm-linux-gnueabihf-
KERN_DIR := /home/zqh/lichee/linux-zero-4.14.y  #選擇內核路徑
PWD :=$(shell pwd)   #當前路徑

all:
        $(info "1st")
        make ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERN_DIR) M=$(PWD) modules    
clean:                                   
        rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order .*.o.ko.cmd .*.ko.cmd .*.mod.o.cmd .*.o.cmd
        
endif
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM