美文网首页
LDD学习笔记系列之二

LDD学习笔记系列之二

作者: 卐卍扫地僧卐卍 | 来源:发表于2018-11-30 23:47 被阅读0次

    基础知识


    主设备号和次设备号

    #include <linux/types.h>
    
    dev_t /* 主设备号:12bit,次设备号:20bit */
    MAJOR(dev_t dev);/* 获取主设备号 */
    MINOR(dev_t dev);/* 获取次设备号 */
    MKDEV(int major, int minor);/* 组合设备编号 */
    
    #include <linux/fs.h>
    
    int register_chrdev_region(dev_t first, unsigned int count, char *name);
    int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name);
    void unregitster_chrdev_region(dev_t first, unsigned int count);
    
    if (scull_major) {
        dev = MKDEV(scull_major, scull_minor);
        result = register_chrdev_region(dev, scull_nr_devs, "scull");
    } else {
        result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs, "scull");
        scull_major = MAJOR(dev);
    }
    if (result < 0) {
        printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
        return result;
    }
    

    重要数据结构

    #include <linux/fs.h>
    
    inode 
    dev_t i_rdev;
    struct cdev *i_cdev;
    - 内核用inode结构在内部表示文件;
    - 和file结构不同,file结构表示打开的文件描述符;
    - 对单个文件,可能会有许多个表示打开的文件描述符的file结构,但他们都指向单个inode结构
    
    unsigned int iminor(struct inode *inode);
    unsigned int imajor(struct inode *inode);
    
    fops → struct file_operations 
    
    sturct module *owner; /* THIS_MODULE <linux/module.h> */
    int (*open)(struct inode *, struct file *);
    - 检查设备特定错误;
    - 初始化首次打开的设备;
    - 如有必要,更新`f_op`指针;
    - 分配并填写置于`filp->private_data`里的数据结构;
    
    #include <linux/kernel.h>
    container_of(pointer, container_type, container_field);
    
    int (*release)(struct inode *, struct file *);
    ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write)(struct file *, char __user *, size_t, loff_t *);
    
    #include <asm/uaccess.h>
    #include <linux/uaccess.h>
    unsigned long copy_to_user(void __user *to, const void *from, unsigned long count);
    unsigned long copy_from_user(void *to, const void __user *from, unsigned long count);
    
    filp → struct file
    mode_t f_mode;
    lofft_t f_pos;
    unsigned int f_flags;
    struct file_operations *f_op;
    void *private_data;
    struct dentry *f_dentry;
    

    字符设备的注册及移除

    方式一

    #include <linux/cdev.h>
    void cdev_init(struct cdev *cdev, struct file_operation *fops);
    int cdev_add(struct cdev *dev, dev_t num, unsigned int count);
    void cdev_del(struct cdev *dev);
    

    方式二

    int register_chrdev(unsigned int major, const char *name, struct file_operations *fops);
    int unregister_chrdev(unsigned int major, const char *name);
    

    字符设备驱动编写要点


    1. 获取设备编号;
    /*
     * Get a range of minor numbers to work with, asking for a dynamic
     * major unless directed otherwise at load time.
     */
    if (scull_major) {
        dev = MKDEV(scull_major, scull_minor);
        result = register_chrdev_region(dev, scull_nr_devs, "scull");
    } else {
        result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,
                "scull");
        scull_major = MAJOR(dev);
    }
    if (result < 0) {
        printk(KERN_WARNING "scull: can't get major %d\n", scull_major);
        return result;
    }
    
    1. 注册字符设备;
    /*
     * Set up the char_dev structure for this device.
     */
    static void scull_setup_cdev(struct scull_dev *dev, int index)
    {
        int err, devno = MKDEV(scull_major, scull_minor + index);
        
        cdev_init(&dev->cdev, &scull_fops);
        dev->cdev.owner = THIS_MODULE;
        dev->cdev.ops = &scull_fops;
        err = cdev_add (&dev->cdev, devno, 1);
        /* Fail gracefully if need be */
        if (err)
            printk(KERN_NOTICE "Error %d adding scull%d", err, index);
    }
    

    example


    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/init.h>
    #include <linux/kernel.h>    /* printk() */
    #include <linux/fs.h>        /* everything... */
    #include <linux/errno.h>    /* error codes */
    #include <linux/types.h>    /* size_t */
    #include <linux/cdev.h>
    #include <linux/uaccess.h>    /* copy_*_user */
    
    int example_major = 0;
    int example_minor = 0;
    static unsigned int example_nr_devs = 1;
    typedef struct EXAMPLE_CDEV
    {
         struct cdev cdev;            
    }EXAMPLE_CDEV_STRU;
    static EXAMPLE_CDEV_STRU example_cdev;
    
    module_param(example_major, int, S_IRUGO);
    module_param(example_minor, int, S_IRUGO);
    
    MODULE_LICENSE("Dual BSD/GPL");
    
    static int example_open(struct inode *inode, struct file *filp) 
    {
        printk("example: open\n");
        return 0;
    }
    
    static int example_close(struct inode *inode, struct file *filp) 
    {
        printk("example: close\n");
        return 0;
    }
    
    static ssize_t example_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
    {
        size_t count;
        uint8_t byte;
        char data[] = "0123456789\r\n";
        
        printk("example: read (size=%zu)\n", size);
        for(count = 0; (count < size) && (*f_pos) < strlen(data); ++(*f_pos), ++count) {
            byte = data[*f_pos];
            if(copy_to_user(buf + count, &byte, 1) != 0) {
                break;
            }
            printk("example: read (buf[%zu]=%c)\n", count, (unsigned)byte);
        }
    
        return count;
    }
    
    static ssize_t example_write(struct file *filp, const char __user *buf, size_t size, loff_t *f_pos) 
    {
        size_t count;
        uint8_t byte;
    
        printk("example: write (size=%zu)\n", size);
        for(count = 0; count < size; ++count) {
            if(copy_from_user(&byte, buf + count, 1) != 0) {
                break;
            }
            printk("example: write (buf[%zu]=%c)\n", count, (unsigned)byte);
        }
    
        return count;
    }
    
    static struct file_operations example_fops = {
        .open = example_open,
        .release = example_close,
        .read = example_read,
        .write = example_write,
    };
    
    static void example_setup_cdev(EXAMPLE_CDEV_STRU *dev, int index)
    {
        int err, devno = MKDEV(example_major, example_minor + index);
        
        cdev_init(&dev->cdev, &example_fops);
        dev->cdev.owner = THIS_MODULE;
        dev->cdev.ops = &example_fops;
        err = cdev_add (&dev->cdev, devno, 1);
        /* Fail gracefully if need be */
        if (err)
            printk(KERN_NOTICE "Error %d adding example-%d", err, index);
    }
    
    
    static int example_init(void) 
    {
        dev_t dev;
        int result;
    
        printk("example: init\n");
    
        if (example_major) {
            dev = MKDEV(example_major, example_minor);
            result = register_chrdev_region(dev, example_nr_devs, "example");
        } else {
            result = alloc_chrdev_region(&dev, example_minor, example_nr_devs,
                    "example");
            example_major = MAJOR(dev);
        }
        if (result < 0) {
            printk(KERN_WARNING "example: can't get major %d\n", example_major);
            return result;
        }
        example_setup_cdev(&example_cdev, 0);
        printk("example: %s driver(major %d) installed.\n", "example", example_major);
    
        return 0;
    }
    
    static void example_exit(void) 
    {
        dev_t dev = MKDEV(example_major, example_minor);
    
        printk("example: exit\n");
        /* Delete the character device driver from system. */
        cdev_del(&example_cdev.cdev);
        /* Unregister the allocated character device. */
        unregister_chrdev_region(dev, example_nr_devs);
        printk("example: %s driver removed.\n", "example"); 
    }
    
    module_init(example_init);
    module_exit(example_exit);
    
    
    #!/bin/sh
    # $Id: example_load,v 0.1 2018/11/15 $
    
    module="example"
    echo "-------begin--------"
    insmod ./$module.ko
    dmesg | tail -2
    major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)
    #echo $major
    sudo rm -f /dev/$module
    sudo mknod /dev/$module c $major 0
    echo -n "hello world" > /dev/$module
    dmesg | tail -n 14
    cat /dev/$module
    dmesg | tail -n 17
    echo "-------end--------"
    

    其他

    tail

    tail [ -f ] [ -c Number | -n Number | -m Number | -b Number | -k Number ] [ File ]
    参数解释:
    -f 该参数用于监视File文件增长。
    -c Number 从 Number 字节位置读取指定文件
    -n Number 从 Number 行位置读取指定文件。
    -m Number 从 Number 多字节字符位置读取指定文件,比方你的文件假设包括中文字,假设指定-c参数,可能导致截断,但使用-m则会避免该问题。
    -b Number 从 Number 表示的512字节块位置读取指定文件。
    -k Number 从 Number 表示的1KB块位置读取指定文件。
    File 指定操作的目标文件名称
    上述命令中,都涉及到number,假设不指定,默认显示10行。Number前面可使用正负号,表示该偏移从顶部还是从尾部開始计算。
    tail可运行文件一般在/usr/bin/以下。
    

    dmesg

    3.png

    echo

    4.png

    mknode

    mknod [options] name {bc} major minor
    mknod [options] name p
    

    awk

    awk 'Pattern {Action}' filename
    -其中Pattern用来指定判断条件
    -{}中包含的是awk的动作,也就是awk对记录的操作
    major=$(awk "\$2==\"example\" {print \$1}" /proc/devices)
    

    相关文章

      网友评论

          本文标题:LDD学习笔记系列之二

          本文链接:https://www.haomeiwen.com/subject/kwakcqtx.html