zoukankan      html  css  js  c++  java
  • 【原】获取物理地址空间驱动

    获取物理地址空间驱动,支持多个子驱动,Example: insmod gphyaddr.ko varm=1:4M,2:5K。

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/slab.h>
    
    #define    MAX_DEV_NUM             32
    #define    GET_PYH_SPACE_SIZE      0
    #define    GET_PYHSICAL_ADDR       1
    
    struct gphyaddr_dev
    {
        int dev_num;
        dev_t dev;
        struct class *cls;
        struct cdev cdev;
        
        int index[MAX_DEV_NUM];
        unsigned long space_size[MAX_DEV_NUM];
        
        unsigned int p_addr[MAX_DEV_NUM];
        unsigned int order[MAX_DEV_NUM];
        unsigned long v_addr[MAX_DEV_NUM];
    };
    
    static struct gphyaddr_dev * g_dev = NULL;
    static char * vram="1:4M";
    
    module_param(vram, charp, 0644);
    MODULE_PARM_DESC(vram,"A string variable");
    
    static int gphyaddr_open(struct inode *inode, struct file *file)
    {
        struct gphyaddr_dev * dev;
        dev = container_of(inode->i_cdev, struct gphyaddr_dev, cdev);
        
        file->private_data = dev;
        
        return 0;
    }
    
    static long gphyaddr_ioctl(struct file *file,
                            unsigned int cmd,
                            unsigned long arg)
    {
        struct gphyaddr_dev * dev = file->private_data;
        struct inode *inode = file->f_path.dentry->d_inode;
        
        int minor = MINOR(inode->i_rdev);
        //printk("%s:minor: %d.
    ", __func__, minor);
        //printk("p_addr: 0x%x.
    ", dev->p_addr[minor]);
        //printk("v_addr: 0x%lx, order: %d.
    ", dev->v_addr[minor], dev->order[minor]);
    
        switch (cmd)
        {
            case GET_PYH_SPACE_SIZE:
                return (long)(dev->order[minor] * PAGE_SIZE);
            case GET_PYHSICAL_ADDR:
                return (long)dev->v_addr[minor];
            default:
                printk("Parameter error!!
    ");
                return -1;
        }
        return 0;
    
    }
    
    struct file_operations gphyaddr_fops = {
        .owner =    THIS_MODULE,
        .open =     gphyaddr_open,
        .unlocked_ioctl = gphyaddr_ioctl,
    };
    
    static void gphyaddr_exit(void)
    {
        int index, i;
        
        printk("gphyaddr_exit.
    ");
        if (g_dev)
        {
            for(i = 0; i < g_dev->dev_num; i++)
            {
                index = g_dev->index[i];
                device_destroy(g_dev->cls, MKDEV(MAJOR(g_dev->dev), index));
    
                if(g_dev->v_addr[index] > 0)
                {
                    free_pages(g_dev->v_addr[index], g_dev->order[index]);
                }
            }
            if(NULL != g_dev->cls)
            {
                class_destroy(g_dev->cls);
            }
            
            if(g_dev->cdev.count > 0)
            {
                cdev_del(&g_dev->cdev);
            }
    
            if(g_dev->dev_num > 0)
            {
                unregister_chrdev_region(g_dev->dev, g_dev->dev_num);
            }
            
            kfree(g_dev);
        }
    }
    
    static int get_phy_addr(struct gphyaddr_dev * g_dev, unsigned int space_size, int index)
    {
        char *v_addr;
        unsigned int p_addr,order;
        
        order = get_order(space_size);
        if(order >= MAX_ORDER)
        {
            printk("ERROR: order(%u) >= MAX_ORDER(%u)!!!
    ", order, MAX_ORDER);
            order = MAX_ORDER - 1;
        }
        v_addr = (char *)__get_free_pages(GFP_KERNEL, order);
        if(v_addr == NULL)
        {
            printk("ERROR: get_free_pages err!!!
    ");
            return -EFAULT;
        }
        
        p_addr = virt_to_phys(v_addr);
        
        printk("index= %d, order= %d, space_size= 0x%lx, p_addr: 0x%x
    ", index, order, order * PAGE_SIZE, p_addr);
    
        g_dev->p_addr[index] = p_addr;
        g_dev->order[index] = order;
        g_dev->v_addr[index] = (unsigned long)v_addr;
    
        return 0;
    }
    
    static int parse_vram_param(struct gphyaddr_dev * g_dev, const char *param, int max_dev_num)
    {
        int i = 0;
        unsigned long size;
        char *p, *start;
    
        start = (char *)param;
        g_dev->dev_num = 0;
        
        while (1)
        {
            p = start;
    
            g_dev->index[i] = simple_strtoul(p, &p, 10);
    
            if (p == param)
                goto err;
    
            if (*p != ':')
                goto err;
    
            if (g_dev->index[i] > max_dev_num)
                goto err;
    
            size = memparse(p + 1, &p);
    
            if (!size)
                goto err;
            
            printk("i: %d index: %d size: 0x%x
    ",i, g_dev->index[i], (u32)size);
            g_dev->space_size[g_dev->index[i]] = size;
            g_dev->dev_num++;
            i++;
    
            if (*p == 0)
                break;
    
            if (*p != ',')
                goto err;
    
            ++p;
    
            start = p;
        }
        
        return 0;
    err:
        printk("Input format error!!
       Example: insmod gphyaddr.ko varm=1:4M,2:5K
    ");
        return -EINVAL;
    }
    
    static int gphyaddr_init(void)
    {
        int ret, index, i;
        
        g_dev = kmalloc(sizeof(struct gphyaddr_dev), GFP_KERNEL);
        if (!g_dev)
        {
            printk("Error: kmalloc ERR.
    ");
            ret = -ENOMEM;
            goto fail;
        }
        memset(g_dev, 0, sizeof(struct gphyaddr_dev));
    
        if (parse_vram_param(g_dev, vram, MAX_DEV_NUM))
         {
             printk("Error: failed to parse vram parameters: %s
    ", vram);
             ret = -ENOMEM;
             goto fail;
         }
        
        alloc_chrdev_region(&g_dev->dev, 0, g_dev->dev_num, "gphyaddr");
        
        cdev_init(&g_dev->cdev, &gphyaddr_fops);
        g_dev->cdev.owner = THIS_MODULE;
        g_dev->cdev.ops = &gphyaddr_fops;
        ret = cdev_add (&g_dev->cdev, g_dev->dev, g_dev->dev_num);//添加字符设备
        if(ret)
        {
            printk("Error: %d adding gphyaddr.
    ", ret);
            goto fail;
        }
        
        g_dev->cls = class_create(THIS_MODULE, "gphyaddr");
    
        for(i = 0; i < g_dev->dev_num; i++)
        {
            index = g_dev->index[i];
            ret = get_phy_addr(g_dev, g_dev->space_size[index], index);
            if(ret)
            {
                printk("Error: %d get_phy_addr!!
    ", ret);
                goto fail;
            }
            
            device_create(g_dev->cls, NULL, MKDEV(MAJOR(g_dev->dev), index), NULL, "gphyaddr%d", index);
        }
        
        return 0;
        
    fail:
        gphyaddr_exit();
        return ret;
    }  
    
    module_init(gphyaddr_init);
    module_exit(gphyaddr_exit);
    MODULE_LICENSE("GPL");
  • 相关阅读:
    go第二天
    go第一天
    engish
    english
    git 生成公钥
    tp5 验证码
    css处理文本折行截断
    数组对象总结(牢记)
    全局css样式
    Flexbox 弹性盒子布局
  • 原文地址:https://www.cnblogs.com/eleclsc/p/11547244.html
Copyright © 2011-2022 走看看