【原】获取物理地址空间驱动

获取物理地址空间驱动,支持多个子驱动,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.\n", __func__, minor);
    //printk("p_addr: 0x%x.\n", dev->p_addr[minor]);
    //printk("v_addr: 0x%lx, order: %d.\n", 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!!\n");
            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.\n");
    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)!!!\n", 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!!!\n");
        return -EFAULT;
    }
    
    p_addr = virt_to_phys(v_addr);
    
    printk("index= %d, order= %d, space_size= 0x%lx, p_addr: 0x%x\n", 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\n",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!!\n   Example: insmod gphyaddr.ko varm=1:4M,2:5K\n");
    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.\n");
        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\n", 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.\n", 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!!\n", 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");

转载于:https://www.cnblogs.com/eleclsc/p/11547244.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值