• linux 驱动入门1


    世事艰难,人生不易。 夜深人静时候,回顾过去,往事历历在目。创南京,混苏州,下上海。都付出了巨大的努力。多少个不眠的夜晚,在冥思苦想。天生愚钝。又不是学计算机的。一直没较为深刻的理解

    编程什么东西,一直没有入门。

    感谢Qisda, 让我在08年就开始接触android. 都不容易。

    编程是什么?

    编程是数据处理。如何处理? cpu通过指令指针的跳转,实现了读下一条指令,cpu实现了读指令,编译指令。

    感谢marvell. 哎marvell技术 不可谓不强。认识一大批牛人。jialin, jiaguo, xinjiang wenzhao fuqiang ruikuang xia . 哎,我们一个team。我是最菜的。一个上海交大,一个武大,一个哈工大。一个南大。
    一个中国科大少年班。南航和他们比太菜了。哎。 就不断的琢磨。

    还是老套路把。先从简单字符驱动开始。

    驱动是为了沟通os和硬件。起到了承上启下的作用。哪就说明这个模块就能让os认识它。有能操作硬件。

    那如何让os认识它呢?

    就一句话int cdev_add(struct cdev *p, dev_t dev, unsigned count).
    那这些参数哪来的呢?

    struct cdev就需要自己创建结构体内存。 dev_t是分配的设备号。

    struct globalmem_dev{
    struct cdev cdev;
    unsigned char mem[GLOBALMEM_SIZE];
    };

    这样就创建了这个结构体。初始化时候分配内存就好了。为什么要弄个结构体。弄个静态全局变量可以吗? 也可以的 。但是不太方便。为什么不方便呢? 下面说

    还要分配设备号
    if (globalmem_major){
    result = register_chrdev_region(devno, 2, "globalmem");
    }else {
    result = alloc_chrdev_region(&devno,0, 2, "globalmem");
    globalmem_major = MAJOR(devno);
    }
    有了cdev dev_t. 就可以添加到os了。

    为什么参数要有个设备号呢? 系统有很多的驱动,应用程序只看到设备节点。当应用open的时候,系统会看大这个设备的设备号。根据设备号找对应的驱动。所以add的时候需要跟上设备号。

    cdev初始化还要加上fop。
    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,
    };

    当应用call open的时候,操作系统会先做一些通用的处理。做什么通用的处理我也不清楚,正在学习,不知道就不知道。千万别像书上写的。这里一般用不到。不必了解。不了解中国人怎么写出操作系统来?

    做通用处理的时候会产生inode file两个结构体。 同时把file的fop的控件用驱动的add的cdev里的fop初始化。哪肯定的,不然以后read write时候参数都有file指针,那系统如何找到我们驱动的真正的read write
    实现呢?

    static int globalmem_open(struct inode *inode, struct file *filp){
    struct globalmem_dev *dev;
    dev = container_of(inode->i_cdev, struct globalmem_dev, cdev);
    filp->private_data = dev;
    printk(KERN_ALERT "globalmem_open!");
    return 0;
    }
    dev = container_of(inode->i_cdev, struct globalmem_dev, cdev);
    filp->private_data = dev;
    这两句话看清楚了吗? 使劲理解。

    下面把我的测试代码发出来把
    #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 <asm/io.h>
    //#include <asm/system.h>
    #include <asm/uaccess.h>
    #include <linux/slab.h>

    MODULE_AUTHOR("qcom.shanghai@gmail.com");
    MODULE_LICENSE("Dual BSD/GPL");

    #define GLOBALMEM_SIZE 0X1000
    #define MEM_CLEAR 0x1

    static int globalmem_major = 0;

    struct globalmem_dev{
    struct cdev cdev;
    unsigned char mem[GLOBALMEM_SIZE];
    };

    struct globalmem_dev *globalmem_devp;

    static int globalmem_open(struct inode *inode, struct file *filp){
    struct globalmem_dev *dev;
    dev = container_of(inode->i_cdev, struct globalmem_dev, cdev);
    filp->private_data = dev;
    printk(KERN_ALERT "globalmem_open!");
    //marvell 臧春杰
    return 0;
    }

    static int globalmem_release(struct inode *inode, struct file *filp){
    printk(KERN_ALERT "globalmem_release!");
    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 >= GLOBALMEM_SIZE){
    return 0;
    }
    if (count > GLOBALMEM_SIZE - p){
    count = GLOBALMEM_SIZE - p;
    }

    if (copy_to_user(buf, (void *)(dev->mem + p), count)){
    ret = - EFAULT;
    }else {
    *ppos += count;
    ret = count;
    printk(KERN_ALERT "read %u bytes from %lu ", 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;
    //marvell 臧春杰
    int ret = 0;
    struct globalmem_dev *dev = filp->private_data;

    if (p >= GLOBALMEM_SIZE){
    return 0;
    }

    if (count > GLOBALMEM_SIZE - p){
    count = GLOBALMEM_SIZE - p;
    }
    if (copy_from_user(dev->mem + p, buf, count)){
    ret = - EFAULT;
    }else {
    *ppos += count;
    ret = count;
    printk(KERN_ALERT "write %u bytes from %lu ", count, p);
    }

    return ret;
    }

    static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig){
    loff_t ret = 0;
    switch(orig){
    case 0:
    if (offset < 0){
    ret = - EFAULT;
    break;
    }
    if ((unsigned int)offset > GLOBALMEM_SIZE){
    ret = - EFAULT;
    break;
    }
    filp->f_pos = (unsigned int) offset;
    ret = filp->f_pos;
    break;

    case 1:

    if ((filp->f_pos + offset) > GLOBALMEM_SIZE){
    ret = - EFAULT;
    //marvell 臧春杰
    break;
    }

    if ((filp->f_pos + offset) < 0){
    ret = - EFAULT;
    break;
    }
    filp->f_pos += offset;
    ret = filp->f_pos;
    break;

    default:
    ret = - EFAULT;
    break;
    }

    return ret;

    }

    static long globalmem_ioctl(struct file *flip, unsigned int cmd, unsigned long arg){
    printk(KERN_ALERT "globalmem_ioctl");
    return 10L;
    }

    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,
    };

    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; //marvell 臧春杰
    err = cdev_add(&dev->cdev, devno, 1);
    if (err){
    printk(KERN_ALERT"cdev_add failed!");
    }
    }

     

    static int __init globalmem_init(void){
    int result;
    dev_t devno = MKDEV(globalmem_major, 0);
    if (globalmem_major){
    result = register_chrdev_region(devno, 2, "globalmem");
    }else {
    result = alloc_chrdev_region(&devno,0, 2, "globalmem");
    globalmem_major = MAJOR(devno);
    }
    printk(KERN_ALERT "major-------------->%d ", globalmem_major);
    if (result < 0){
    return result;
    }

    globalmem_devp = kmalloc(2 * sizeof(struct globalmem_dev), GFP_KERNEL);
    if (! globalmem_devp){
    result = -ENOMEM;
    goto fail_malloc;
    }
    memset(globalmem_devp, 0, 2 * sizeof(struct globalmem_dev));
    globalmem_setup_cdev(&globalmem_devp[0], 0);
    //marvell 臧春杰
    globalmem_setup_cdev(&globalmem_devp[1], 1);

    return 0;

    fail_malloc:
    //marvell 臧春杰
    unregister_chrdev_region(devno, 1);
    return result;
    }

    static void __exit globalmem_exit(void){
    cdev_del(&globalmem_devp[0].cdev);

    cdev_del(&globalmem_devp[1].cdev);
    kfree(globalmem_devp);
    unregister_chrdev_region(MKDEV(globalmem_major, 0), 2);
    }


    module_param(globalmem_major, int, S_IRUGO);
    module_init(globalmem_init);
    module_exit(globalmem_exit);


    这个代码我在ubuntu16.04上编译测试过。

    结果如下

    [ 443.797578] major-------------->247
    [ 593.833449] globalmem_open!
    [ 593.833486] write 13 bytes from 0
    [ 593.833499] globalmem_release!
    [ 620.507565] globalmem_open!
    [ 620.507659] read 4096 bytes from 0
    [ 620.509053] globalmem_release!
    [ 647.025424] globalmem_open!
    [ 647.025465] write 16 bytes from 0
    [ 647.025475] globalmem_release!
    [ 650.531294] globalmem_open!
    [ 650.531327] read 4096 bytes from 0

    可以直接拷贝,写个makefile编译,后续我再加点自动创建设备节点。就不用自己mknod了。

    不吃苦中苦,难为人上人。千万别成王宝强。

  • 相关阅读:
    使用Loadrunner监控Windows资源
    Tomcat使用线程池配置高并发连接
    性能测试中遇到的坑
    本地eclipse启动tomcat后无法访问
    Linux常用命令汇总
    Dubbo底层采用Socket进行通信详解
    今天遇到了一个Spring出现的一个未知错误,分享下
    maven pom.xml 详细
    Oracle 数据库中在使用中文模糊查询时输入中文查询不到结果的解决方法
    mybatis属性详解
  • 原文地址:https://www.cnblogs.com/nan-jing/p/5775038.html
Copyright © 2020-2023  润新知