zoukankan      html  css  js  c++  java
  • ldd3 编写scull尝试

    快速参考:

    #include <linux/types.h>
    dev_t
    dev_t is the type used to represent device numbers within the kernel.
    int MAJOR(dev_t dev); int MINOR(dev_t dev); Macros that extract the major and minor numbers from a device number.
    dev_t MKDEV(unsigned
    int major, unsigned int minor); Macro that builds a dev_t data item from the major and minor numbers.
    #include
    <linux/fs.h> The “filesystem” header is the header required for writing device drivers. Many important functions and data structures are declared in here.
    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 unregister_chrdev_region(dev_t first, unsigned int count);
    Functions that allow a driver to allocate and
    free ranges of device numbers. register_chrdev_region should be used when the desired major number is known in advance; for dynamic allocation, use alloc_chrdev_region instead. int register_chrdev(unsigned int major, const char *name, struct file_operations *fops); The old (pre-2.6) char device registration routine. It is emulated in the 2.6 kernel but should not be used for new code. If the major number is not 0, it is used unchanged; otherwise a dynamic number is assigned for this device.

    int
    unregister_chrdev(unsigned int major, const char *name); Function that undoes a registration made with register_chrdev. Both major and the name string must contain the same values that were used to register the driver.
    struct file_operations; struct file; struct inode; Three important data structures used by most device drivers. The file_operations structure holds a char driver’s methods; struct file represents an open file, and struct inode represents a file on disk.
    #include
    <linux/cdev.h> struct cdev *cdev_alloc(void); void cdev_init(struct cdev *dev, struct file_operations *fops); int cdev_add(struct cdev *dev, dev_t num, unsigned int count); void cdev_del(struct cdev *dev); Functions for the management of cdev structures, which represent char devices within the kernel. #include <linux/kernel.h> container_of(pointer, type, field); A convenience macro that may be used to obtain a pointer to a structure from a pointer to some other structure contained within it.
    #include
    <asm/uaccess.h> This include file declares functions used by kernel code to move data to and from user space. unsigned long copy_from_user (void *to, const void *from, unsigned long count); unsigned long copy_to_user (void *to, const void *from, unsigned long count);
    Copy data between user space and kernel space.

     

    第一节的测试:

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/types.h>         /* dev_t */
    #include <linux/kdev_t.h>        /* MAJOR(dev_t dev); MINOR(dev_t dev); */
    #include <linux/fs.h>            /* chrdev_region */
    
    #include "my_scull.h"
    
    MODULE_AUTHOR("chen");
    MODULE_LICENSE("Dual BSD/GPL");
    
    int my_scull_major = MY_SCULL_MAJOR;
    int my_scull_minor = 0;
    int my_scull_nr_devs = MY_SCULL_NR_DEVS;
    
    static int my_scull_init(void)
    {
        int result;
        dev_t dev;
        printk(KERN_ALERT "my scull init
    ");
    
    /*
     * Get a range of minor numbers to work with, asking for a dynamic
     * major unless directed otherwise at load time.
     */
        if(my_scull_major) {
            dev = MKDEV(my_scull_major, my_scull_minor);
            result = register_chrdev_region(dev, my_scull_nr_devs, "my_scull");
        } else {
            result = alloc_chrdev_region(&dev, my_scull_minor, my_scull_nr_devs, "my_scull");
            my_scull_major = MAJOR(dev);
        }
        if(result < 0) {
            printk(KERN_WARNING "my scull:can't get major %d
    ", my_scull_major);
            return result;
        }
        
        printk(KERN_ALERT "myscull dev:%d, major:%d, minor:%d
    ", dev, my_scull_major, my_scull_minor);
    
    
        return 0;
    }
    
    static void my_scull_cleanup(void)
    {
        dev_t devno = MKDEV(my_scull_major, my_scull_minor);
        
        /* my_scull_cleanup is never called if registering failed */
        unregister_chrdev_region(devno, my_scull_nr_devs);
    
        printk(KERN_ALERT "my scull clean up
    ");
    }
    
    module_init(my_scull_init);
    module_exit(my_scull_cleanup);
    alloc_chrdev_region

    my_scull_load:

    #!/bin/sh
    module="my_scull"
    device="my_scull"
    mode="644"
    
    # invoke insmod with all arguments we got
    # and use a pathname, as newer modutils don't look in. by default
    /sbin/insmod ./$module.ko $* || exit 1
    
    # remove stale nodes
    rm -f /dev/${device}[0-3]
    
    major=$(awk "$2=="$module" {print $1}" /proc/devices)
    echo $major
    #echo "/dev/${device}0 c $major 0"
    mknod /dev/${device}0 c $major 0
    mknod /dev/${device}1 c $major 1
    mknod /dev/${device}2 c $major 2
    mknod /dev/${device}3 c $major 3
    
    # give appropriate group/permissions, and change the group.
    # Not all distributions have staff, some have "wheel" instead.
    group="staff"
    grep -q '^staff:' /etc/group || group="wheel"
    
    chgrp $group /dev/${device}[0-3]
    chmod $mode /dev/${device}[0-3]
    my_scull_load

    my_scull_unload:

    #!/bin/sh
    module="my_scull"
    device="my_scull"
    
    # invoke rmmod with all arguments we got
    /sbin/rmmod $module $* || exit 1
    
    # Remove stale nodes
    rm -f /dev/${device} /dev/${device}[0-3]
    View Code

    看完第三章后和参考例程后的数据

    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/types.h>         /* dev_t */
    #include <linux/kdev_t.h>        /* MAJOR(dev_t dev); MINOR(dev_t dev); */
    #include <linux/fs.h>            /* chrdev_region */
    #include <asm/uaccess.h>
    
    #include "my_scull.h"
    
    MODULE_AUTHOR("chen");
    MODULE_LICENSE("Dual BSD/GPL");
    
    int my_scull_major   = MY_SCULL_MAJOR;
    int my_scull_minor   = 0;
    int my_scull_nr_devs = MY_SCULL_NR_DEVS;
    int my_scull_quantum = MY_SCULL_QUANTUM;
    int my_scull_qset     = MY_SCULL_QSET;
    
    struct my_scull_dev *scull_devices;    /* allocated in my_scull_init */
    
    static struct file_operations my_scull_fops = {
        .owner =   THIS_MODULE,
        .open =    my_scull_open,
        .release = my_scull_release,
        .write =   my_scull_write,
        .read =    my_scull_read,
    //    .llseek =  my_scull_llseek,
    //    .ioctl =   my_scull_ioctl,
    };
    
    /*
     * Empty out the scull device; must be called with the device
     * semaphore held.
     */
    int my_scull_trim(struct my_scull_dev *dev)
    {
        struct scull_qset *next, *dptr;
        int qset = dev->qset;               /* "dev" is not-null */
        int i;
    
        for(dptr = dev->data;dptr;dptr = next) {    /* all the list items */
            if(dptr->data) {
                for(i=0;i<qset;i++)
                    kfree(dptr->data[i]);
                kfree(dptr->data);
                dptr->data = NULL;
            }
            next = dptr->next;
            kfree(dptr);
        }
        dev->size = 0;
        dev->quantum = my_scull_quantum;
        dev->qset = my_scull_qset;
        dev->data = NULL;
        return 0;
    }
    
    /*
     * Set up the char dev structure for this device.
     */ 
    static void my_scull_setup_cdev(struct my_scull_dev *dev, int index)
    {
        int err, devno = MKDEV(my_scull_major, my_scull_minor+index);
    
        cdev_init(&dev->cdev, &my_scull_fops);
        dev->cdev.owner = THIS_MODULE;
        dev->cdev.ops = &my_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);
    }
    
    /*
     * Open and close
     */
    int my_scull_open(struct inode *inode, struct file *filp)
    {
        struct my_scull_dev *dev;   /* device information */
    
        dev = container_of(inode->i_cdev, struct my_scull_dev, cdev);   /* from dev_t get my_scull_dev pointer */
        filp->private_data = dev;   /* for other methods */
    
        /* now trim to 0 the length of the device if open was write-only */
        if((filp->f_flags & O_ACCMODE) == O_WRONLY) {
            my_scull_trim(dev);         /* ignore errors */
        }
        return 0;   /* success */
    }
    
    int my_scull_release(struct inode *inode, struct file *filp)
    {
        return 0;
    }
    
    /*
     * Follow the list
     */
    struct scull_qset *my_scull_follow(struct my_scull_dev *dev, int n)
    {
        struct scull_qset *qs = dev->data;
    
        /* Allocate first qset explicitly if need be */
        if(! qs) {
            qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
            if(qs == NULL)
                return NULL;    /* Nerver mind */
            memset(qs, 0, sizeof(struct scull_qset));
        }
    
        /* Then follow the list */
        while(n--) {
            if(!qs->next) {
                qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
                if(qs->next == NULL)
                    return NULL;    /* Nerver mind */
                memset(qs->next, 0, sizeof(struct scull_qset));
            }
            qs = qs->next;
            continue;
        }
        return qs;
    }
    /*
     * Data management: read and write
     */ 
    ssize_t my_scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
    {
        struct my_scull_dev *dev = filp->private_data;
        struct scull_qset *dptr;        /* the first listitem */
        int quantum = dev->quantum, qset = dev->qset;
        int itemsize = quantum * qset;  /* how many bytes in the listitem */
        int item, s_pos, q_pos, rest;
        ssize_t retval = 0;
    
        if(down_interruptible(&dev->sem))
            return -ERESTARTSYS;
        if(*f_pos >= dev->size)
            goto out;
        if(*f_pos + count > dev->size)
            count = dev->size - *f_pos;
    
        /* find listitem, qset index, and offset in the quantum */
        item = (long)*f_pos / itemsize;
        rest = (long)*f_pos % itemsize;
        s_pos = rest / quantum; 
        q_pos = rest % quantum;
    
        /* follow the list up to the right position (defined elsewhere) */
        dptr = my_scull_follow(dev, item);
    
        if(dptr == NULL || !dptr->data || !dptr->data[s_pos])
            goto out;   /* don't fill holes */
    
        /* read only up to the end of this quantum */
        if(count > quantum - q_pos)
            count = quantum - q_pos;
    
        if(copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) {
            retval = -EFAULT;
            goto out;
        }
        *f_pos += count;
        retval = count;
    
    out:
        up(&dev->sem);
        return retval;
    }
    
    ssize_t my_scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
    {
        struct my_scull_dev *dev = filp->private_data;
        struct scull_qset *dptr;
        int quantum = dev->quantum, qset = dev->qset;
        int itemsize = quantum * qset;
        int item, s_pos, q_pos, rest;
        ssize_t retval = -ENOMEM;       /* value used in "goto out" statements */
        if(down_interruptible(&dev->sem))
            return -ERESTARTSYS;
    
        /* find listitem, qset index and offset in the quantum */
        item = (long)*f_pos / itemsize;
        rest = (long)*f_pos % itemsize;
        s_pos = rest / quantum;
        q_pos = rest % quantum;
        /* follow the list up to the right position */
        dptr = my_scull_follow(dev, item);
        if(dptr == NULL)
            goto out;
        if(!dptr->data) {
            dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
            if(!dptr->data)
                goto out;
            memset(dptr->data, 0, qset * sizeof(char *));
        }
    
        if(!dptr->data[s_pos]) {
            dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
            if(!dptr->data[s_pos])
                goto out;
        }
        /* write only up to the end of this quantum */
        if(count > quantum - q_pos)
            count = quantum - q_pos;
        if(copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {
            retval = -EFAULT;
            goto out;
        }
        *f_pos += count;
        retval = count;
    
        /* update the size */
        if(dev->size < *f_pos)
            dev->size = *f_pos;
    out:
        up(&dev->sem);
        return retval;
    }
    
    static int my_scull_init(void)
    {
        int result, i;
        dev_t dev;
        printk(KERN_ALERT "my scull init
    ");
    
    /*
     * Get a range of minor numbers to work with, asking for a dynamic
     * major unless directed otherwise at load time.
     */
        if(my_scull_major) {
            dev = MKDEV(my_scull_major, my_scull_minor);
            result = register_chrdev_region(dev, my_scull_nr_devs, "my_scull");
        } else {
            result = alloc_chrdev_region(&dev, my_scull_minor, my_scull_nr_devs, "my_scull");
            my_scull_major = MAJOR(dev);
        }
        if(result < 0) {
            printk(KERN_WARNING "my scull:can't get major %d
    ", my_scull_major);
            return result;
        }
        
        printk(KERN_ALERT "myscull dev:%d, major:%d, minor:%d
    ", dev, my_scull_major, my_scull_minor);
        
        /*
         * allocate the device -- we can't have them static, as the number
         * can be specified at load time
         */
        scull_devices = kmalloc(my_scull_nr_devs*sizeof(struct my_scull_dev), GFP_KERNEL);
        if(!scull_devices) {
            result = -ENOMEM;
            goto fail;      /* Make this more graceful */
        }
        memset(scull_devices, 0, my_scull_nr_devs * sizeof(struct my_scull_dev));
    
        /* Initialize each device */
        for(i=0;i<my_scull_nr_devs;i++) {
            scull_devices[i].quantum = my_scull_quantum;
            scull_devices[i].qset = my_scull_qset;
            init_MUTEX(&scull_devices[i].sem);
            my_scull_setup_cdev(&scull_devices[i], i);
        }
        
        dev = MKDEV(my_scull_major, my_scull_minor+my_scull_nr_devs);
    //    dev += my_scull_p_init(dev);
    //    dev += my_scull_access_init(dev);
    
        return 0;           /* succees */
    fail:
        my_scull_cleanup();
    }
    
    static void my_scull_cleanup(void)
    {
        dev_t devno = MKDEV(my_scull_major, my_scull_minor);
        int i;
    
        if(scull_devices) {
            for(i=0;i<my_scull_nr_devs;i++) {
                my_scull_trim(scull_devices + i);
                cdev_del(&scull_devices[i].cdev);
            }
            kfree(scull_devices);
        }
    
        /* my_scull_cleanup is never called if registering failed */
        unregister_chrdev_region(devno, my_scull_nr_devs);
    
        printk(KERN_ALERT "my scull clean up
    ");
    }
    
    module_init(my_scull_init);
    module_exit(my_scull_cleanup);
    my_scull.c

    头文件

    #ifndef __MY_SCULL_H_
    #define __MY_SCULL_H_
    
    #include <linux/ioctl.h>
    #include <linux/cdev.h>
    
    #ifndef MY_SCULL_MAJOR
    #define MY_SCULL_MAJOR 0        /* dynamic major by default */
    #endif
    
    #ifndef MY_SCULL_NR_DEVS
    #define MY_SCULL_NR_DEVS 4      /* scull0 through scull3 */
    #endif
    
    #ifndef MY_SCULL_QUANTUM
    #define MY_SCULL_QUANTUM 4000
    #endif
    
    #ifndef MY_SCULL_QSET
    #define MY_SCULL_QSET    1000
    #endif
    
    
    /*
     *  Representation of scull quantum sets.
     */
    struct scull_qset {
        void **data;
        struct scull_qset *next;
    };
    
    struct my_scull_dev {
        struct scull_qset *data;    /* Pointer to first quantum set */
        int quantum;                /* the current quantum size */
        int qset;                   /* the current arry size */
        unsigned long size;         /* amount of data sotred here */
        unsigned int access_key;    /* used by sculluid and scullpriv */
        struct semaphore sem;       /* mutual exclusion semaphore     */
        struct cdev cdev;           /* Char device structure */
    };
    
    int my_scull_trim(struct my_scull_dev *dev);
    static void my_scull_setup_cdev(struct my_scull_dev *dev, int index);
    int my_scull_open(struct inode *inode, struct file *filp);
    int my_scull_release(struct inode *inode, struct file *filp);
    struct scull_qset *my_scull_follow(struct my_scull_dev *dev, int n);
    ssize_t my_scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
    ssize_t my_scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);
    static int my_scull_init(void);
    static void my_scull_cleanup(void);
    
    #endif
    my_scull.h
    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    图像,script,link 空地址带来的困惑
    localStorage变更事件当前页响应新解-awen
    opencv在ios上的开发教程
    torch-ios框架XCODE使用备忘
    重拾老本行_图像处理
    dialogic d300语音卡驱动重装后启动报错问题解决方法
    Winpcap构建用户级网桥
    winpcap usb山寨网卡识别
    最近这段时间
    银行IT入门深似海
  • 原文地址:https://www.cnblogs.com/ch122633/p/9159921.html
Copyright © 2011-2022 走看看