当前位置:操作系统 > 安卓/Android >>

我对android理解之pmem

在android中,pmem是特地从内存中划出来的一块,给android的用户空间需要物理上连续的进程使用。
我们首先分析pmem驱动。
pmem使用的是platform bus注册的。
1,device部分:
struct platform_device mxc_android_pmem_device = {
    .name = "android_pmem",
    .id = 0,
};
其data部分:
static struct android_pmem_platform_data android_pmem_pdata = {
    .name = "pmem_adsp",
    .start = 0,
    .size = SZ_32M,
    .no_allocator = 0,
    .cached = PMEM_NONCACHE_NORMAL,
};
android_pmem_pdata.start在fixup_mxc_board中重新计算了:
        size = t->u.mem.size;

        android_pmem_pdata.start =
                PHYS_OFFSET + size - android_pmem_pdata.size;

2,driver部分:
在drivers/misc/pmem.c定义:
static struct platform_driver pmem_driver = {
    .probe = pmem_probe,
    .remove = pmem_remove,
    .driver = { .name = "android_pmem" }
};
device和driver匹配后将执行pmem_probe:
static int pmem_probe(struct platform_device *pdev)
{
    struct android_pmem_platform_data *pdata;

    if (!pdev || !pdev->dev.platform_data) {
        printk(KERN_ALERT "Unable to probe pmem!\n");
        return -1;
    }
    pdata = pdev->dev.platform_data;
    return pmem_setup(pdata, NULL, NULL);//2-1
}
2-1:pmem_setup(pdata, NULL, NULL):
int pmem_setup(struct android_pmem_platform_data *pdata,
           long (*ioctl)(struct file *, unsigned int, unsigned long),
           int (*release)(struct inode *, struct file *))
{
    int err = 0;
    int i, index = 0;
    int id = id_count;
    id_count++;

    pmem[id].no_allocator = pdata->no_allocator; //为0
    pmem[id].cached = pdata->cached; //PMEM_NONCACHE_NORMAL
    pmem[id].buffered = pdata->buffered;
    pmem[id].base = pdata->start;//开始位置
    pmem[id].size = pdata->size;//大小
    pmem[id].ioctl = ioctl;
    pmem[id].release = release;
    init_rwsem(&pmem[id].bitmap_sem);
    init_MUTEX(&pmem[id].data_list_sem);
    INIT_LIST_HEAD(&pmem[id].data_list);
    pmem[id].dev.name = pdata->name;
    pmem[id].dev.minor = id;//次设备好
    pmem[id].dev.fops = &pmem_fops;//fops
    printk(KERN_INFO "%s: %d init\n", pdata->name, pdata->cached);

    err = misc_register(&pmem[id].dev);//注册pmem设备
    if (err) {
        printk(KERN_ALERT "Unable to register pmem driver!\n");
        goto err_cant_register_device;
    }
    pmem[id].num_entries = pmem[id].size / PMEM_MIN_ALLOC;//有多少页

    pmem[id].bitmap = kmalloc(pmem[id].num_entries * //申请这么多个pmem_bits
                  sizeof(struct pmem_bits), GFP_KERNEL);
    if (!pmem[id].bitmap)
        goto err_no_mem_for_metadata;

    memset(pmem[id].bitmap, 0, sizeof(struct pmem_bits) *
                      pmem[id].num_entries);

    for (i = sizeof(pmem[id].num_entries) * 8 - 1; i >= 0; i--) {
        if ((pmem[id].num_entries) &  1<<i) {
            PMEM_ORDER(id, index) = i;
            index = PMEM_NEXT_INDEX(id, index);
        }
    }

    if (pmem[id].cached)
        pmem[id].vbase = ioremap_cached(pmem[id].base,
                        pmem[id].size);
#ifdef ioremap_ext_buffered
    else if (pmem[id].buffered)
        pmem[id].vbase = ioremap_ext_buffered(pmem[id].base,
                              pmem[id].size);
#endif
    else
        pmem[id].vbase = ioremap(pmem[id].base, pmem[id].size);//映射pmem的基地址

    if (pmem[id].vbase == 0)
        goto error_cant_remap;

    pmem[id].garbage_pfn = page_to_pfn(alloc_page(GFP_KERNEL));
    if (pmem[id].no_allocator)
        pmem[id].allocated = 0;

#if PMEM_DEBUG
    debugfs_create_file(pdata->name, S_IFREG | S_IRUGO, NULL, (void *)id,
                &debug_fops);
#endif
    return 0;
error_cant_remap:
    kfree(pmem[id].bitmap);
err_no_mem_for_metadata:
    misc_deregister(&pmem[id].dev);
err_cant_register_device:
    return -1;
}
我们发现pmem_setup将pmem初始化后注册为misc设备。我们后面上层对pmem访问就是对该misc设备的操作,所以fops非常重要:
struct file_operations pmem_fops = {
    .release = pmem_release,
    .mmap = pmem_mmap,
    .open = pmem_open,
    .unlocked_ioctl = pmem_ioctl,
};
我们首先看下pmem_open:
static int pmem_open(struct inode *inode, struct file *file)
{
    struct pmem_data *data;//pmem_data结构,每打开一次新建一个pmem_data
    int id = get_id(file);
    int ret = 0;

    DLOG("current %u file %p(%d)\n", current->pid, file, file_count(file));
    /* setup file->private_data to indicate its unmapped */
    /*  you can only open a pmem device one time */
    if (file->private_data != NULL)
        return -1;
    data = kmalloc(sizeof(struct pmem_data), GFP_KERNEL);
    if (!data) {
        printk("pmem: unable to allocate memory for pmem metadata.");
        return -1;
    }
    data->flags = 0;<

补充:移动开发 , Android ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,