• 字符设备驱动开发


    本驱动笔记,都是记录宋宝华的驱动书籍,代码也是参考他的,撰写文章,主要记录学习心得

    1.字符驱动,作者用globalmem这样的例子来讲解驱动。
    问题1.insmod globalmem.ko驱动。如何和mknod 创建的设备绑定的。
    答:通过主设备号来绑定。
    问题2.insmod globalmem.ko,会失败,提示Device or resource busy
    答:这是主设备号冲突导致的,默认sample里面是固定主设备号,需要修改为动态分配设备号。
    问题3:动态分配主设备号,如何知道分配主设备是多少
    答:cat /proc/devices 可以看到主设备号的分配

    附录,单一设备的驱动代码和makefile

    `#include <linux/module.h>

    include <linux/types.h>

    include <linux/fs.h>

    include <linux/errno.h>

    include <linux/mm.h>

    include <linux/sched.h>

    include <linux/init.h>

    include <linux/cdev.h>

    include <linux/uaccess.h>

    include<linux/slab.h>

    define GLOBAMEM_SIZE 0x1000

    define MEM_CLEAR 0X1

    define GLOBALMEM_MAJOR 0

    static int globalmem_major = GLOBALMEM_MAJOR;
    /* globalmem设备结构体 */
    struct globalmem_dev {
    struct cdev cdev;
    unsigned char mem[GLOBAMEM_SIZE];
    };

    struct globalmem_dev globalmem_devp;
    /
    文件打开函数 */
    int globalmem_open(struct inode *inode, struct file filp)
    {
    /
    /
    filp->private_data = globalmem_devp;
    return 0;
    }
    /
    文件释放函数 */
    int globalmem_release(struct inode *inode, struct file *filp)
    {
    return 0;
    }

    /* ioctl 设备控制函数 */
    static long globalmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
    {
    //
    struct globalmem_dev dev = filp->private_data;/ 获得设备结构体指针 */

    switch (cmd){
    case MEM_CLEAR:
    	memset(dev->mem, 0, GLOBAMEM_SIZE);
    	printk(KERN_INFO "globalmem is set to zero\n");
    	break;
    
    default:
    	return - EINVAL;
    }
    
    return 0;
    

    }

    /* 读函数 */
    static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
    {

    unsigned long p = *ppos;
    unsigned int count = size;
    int ret = 0;
    struct globalmem_dev *dev = filp->private_data;/* 获得设备结构体指针 */ 
    
    
    if (p >= GLOBAMEM_SIZE)
    	return 0;
    if (count > GLOBAMEM_SIZE - p)
    	count = GLOBAMEM_SIZE - p;
    
    /* 内核空间--> 用户空间 */
    if (copy_to_user(buf, (void *)(dev->mem + p), count)) {
    	ret = EFAULT;
    }else {
    	*ppos += count;
    	ret = count;
    
    	printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
    }
    
    return ret;
    

    }
    static ssize_t globalmem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
    {

    unsigned long p = *ppos;
    unsigned int count = size;
    int ret = 0;
    struct globalmem_dev *dev = filp->private_data;/* 获得设备结构体指针 */ 
    
    
    if (p >= GLOBAMEM_SIZE)
    	return 0;
    if (count > GLOBAMEM_SIZE - p)
    	count = GLOBAMEM_SIZE - p;
    
    /* 用户空间--> 内核空间 */
    if (copy_from_user((void *)(dev->mem + p), buf,count)) {
    	ret = EFAULT;
    }else {
    	*ppos += count;
    	ret = count;
    
    	printk(KERN_INFO "write %u bytes(s) from %lu\n", count, p);
    }
    
    return ret;
    

    }
    static loff_t globalmem_llseek(struct file *filp, loff_t offset,int orig)
    {

    int ret = 0;
    struct globalmem_dev *dev = filp->private_data;/* 获得设备结构体指针 */ 
    
    
    
    return ret;
    

    }
    /* 文件操作结构体 */
    static const struct file_operations globalmem_fops = {
    .owner = THIS_MODULE,
    .llseek = globalmem_llseek,
    .read = globalmem_read,
    .write = globalmem_write,
    .unlocked_ioctl = globalmem_ioctl,
    .open = globalmem_open,
    .release = globalmem_release,
    };

    /* 初始化并注册cdev */
    static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
    {
    int err, devno = MKDEV(globalmem_major, index);

    cdev_init(&dev->cdev, &globalmem_fops);
    dev->cdev.owner = THIS_MODULE;
    err = cdev_add(&dev->cdev, devno, 1);
    if (err)
    	printk(KERN_NOTICE "Error %d adding globalmem %d", err, index);
    

    }

    /* 设备驱动模块加载函数 /
    int globalmem_init(void)
    {
    int result;
    dev_t devno = MKDEV(globalmem_major, 0); /
    devno = (250<<20) | 0 */

    /* 申请设备号 */
    if (globalmem_major)
    	result = register_chrdev_region(devno, 1, "globalmem");
    else { /* 动态申请设备号 */
    	result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
    	globalmem_major = MAJOR(devno);
    }
    if (result < 0)
    	return result;
    
    /* 动态申请设备结构体的内存 */
    globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
    if (!globalmem_devp) { /* 申请失败 */
    	result = - ENOMEM;
    	goto fail_malloc;
    }
    
    memset (globalmem_devp, 0, sizeof(struct globalmem_dev));
    
    globalmem_setup_cdev(globalmem_devp, 0);
    return 0;
    

    fail_malloc:
    unregister_chrdev_region(devno, 1);
    return result;
    }

    /* 模块卸载函数 /
    void globalmem_exit(void)
    {
    cdev_del(&globalmem_devp->cdev); /
    注销CDEV /
    kfree(globalmem_devp); /
    释放设备结构体内存 /
    unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /
    释放设备号 */
    }

    MODULE_AUTHOR("Fourier");
    MODULE_LICENSE("Dual BSD/GPL");

    module_param(globalmem_major, int, S_IRUGO);

    module_init(globalmem_init);
    module_exit(globalmem_exit);

    makefile如下:KVERS = $(shell uname -r)
    obj-m += dev.o
    build: kernel_modules
    kernel_modules:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
    clean:
    make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean`

  • 相关阅读:
    Django(十五)模板详解:模板标签、过滤器、模板注释、模板继承、html转义
    Python @函数装饰器及用法
    NPM概述及使用简介
    MVC、MVT简介
    十、Vue:Vuex实现data(){}内数据多个组件间共享
    九、响应式发:rem和less(适配移动端)
    八、Vue-lazyload
    Vue点到子路由,父级,无法高亮问题解决
    七、Vue组件库:Element、Swiper(轮播专用组件)
    六、Vue-Router:基础路由处理、路由提取成单独文件、路由嵌套、路由传参数、路由高亮、html5的history使用
  • 原文地址:https://www.cnblogs.com/gaoshanxiaolu/p/16288240.html
Copyright © 2020-2023  润新知