字符设备驱动学习

字符设备驱动学习_第1张图片

#include
#include
#include
#include

#define HELLO_MAJOR 0
#define HELLO_NR_DEVS 2

int hello_major = HELLO_MAJOR;
int hello_minor = 0;

//高12位是主设备号,低20位是次设备号
dev_t devt;

int hello_nr_devs = HELLO_NR_DEVS;

module_param(hello_major, int, S_IRUGO);
module_param(hello_minor, int, S_IRUGO);
module_param(hello_nr_devs, int, S_IRUGO);

/*实际的字符设备结构*/
struct hello_char_dev {
    struct cdev cdev; /*类似于面向对象的继承*/
    char c; 
};

struct hello_char_dev *hc_devp;

int hc_open(struct inode *inode, struct file *filp) {
    printk(KERN_INFO "open hc_dev%d %d\n",iminor(inode),MINOR(inode->i_cdev->dev));
    return 0;
}

ssize_t hc_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos) {
    printk(KERN_INFO "read hc_dev\n");
    return 0;
}

ssize_t hc_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos) {
    printk(KERN_INFO "write hc_dev\n");
    /*不能返回0,否则会不停的写*/
    return count;
}

int hc_release(struct inode *inode, struct file *filp) {
    printk(KERN_INFO "release hc_dev\n");
    return 0;
}

/*字符设备的操作函数*/
struct file_operations hc_fops = {
    .owner =    THIS_MODULE,
    .read =     hc_read,
    .write =    hc_write,
    .open =     hc_open,
    .release =  hc_release,
};


static int __init hello_init(void) {
    int ret,i;
    if(hello_major) {
        devt = MKDEV(hello_major,hello_minor);
        ret = register_chrdev_region(devt,hello_nr_devs,"hello_chr");
    }
    else {
        ret = alloc_chrdev_region(&devt,hello_minor,hello_nr_devs,"hello_chr");
        hello_major = MAJOR(devt);
    }
    if (ret < 0) {
        printk(KERN_WARNING "hello: can't get major %d\n", hello_major);
        goto fail;
    }
    
    hc_devp = kzalloc(sizeof(struct hello_char_dev)*hello_nr_devs,GFP_KERNEL);
    if(!hc_devp) {
        printk(KERN_WARNING "alloc mem failed");
        ret = -ENOMEM;
        goto failure_kzalloc;
    }
    for(i = 0; i < hello_nr_devs; i++) {
        cdev_init(&hc_devp[i].cdev,&hc_fops);
        hc_devp[i].cdev.owner = THIS_MODULE;
        ret = cdev_add(&hc_devp[i].cdev,MKDEV(hello_major,hello_minor+i),1);
        if(ret) {
            printk(KERN_WARNING"fail add hc_dev%d",i);
        }
    }
    return 0;

failure_kzalloc:
    unregister_chrdev_region(devt,hello_nr_devs);
fail:
    return ret;
}

static void __exit hello_exit(void) {
    int i;
    for(i=0;i<hello_nr_devs;i++)
        cdev_del(&hc_devp[i].cdev);
    kfree(hc_devp);
    unregister_chrdev_region(devt,hello_nr_devs);
    printk(KERN_INFO "GOODBYE LINUX\n");
}

module_init(hello_init);
module_exit(hello_exit);

//描述性定义
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("KGZ");
MODULE_VERSION("V1.0");

KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)

obj-m	:=hello_chr.o

all:
	make -C $(KERNELDIR) M=$(PWD) modules

clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod *.order *.symvers


模块只有一些打印,省略了具体的操作,一些读写函数里面和初始化函数里面的操作比较固定。

程序当中没有使用相关的api来创建设备文件,这里的话,可以使用命令进行创建,
在这里插入图片描述
后续可以使用cat命令和echo进行读和写,然后观察驱动程序的输出。

你可能感兴趣的:(#,深入理解linux内核,c++,linux,哈希算法)