将现有Linux设备结构与设备文件相关联

时间:2013-05-30 22:00:43

标签: linux-kernel linux-device-driver device-tree

我正在使用嵌入在具有Linux内核2.6.33的Virtex4 FPGA中的PowerPC 405进行开发。

到目前为止,我一直在以内核可加载模块的形式编写FPGA中实现的平台设备的驱动程序。使用平面Open Firmware Device Tree文件注册设备。要创建设备文件,我使用OF函数获取设备节点,然后注册一个新的miscdevice,然后自动注册一个次设备号并为我创建设备文件。这也会创建一个device嵌入miscdevice(即miscdevice.this_device

问题是我现在需要执行DMA操作。我尝试使用dma_alloc_coherent()调用miscdevice.this_device函数,但此设备未与任何总线关联,并且始终返回错误。我做了一些挖掘,结果发现struct of_device也嵌入了struct device(即of_device.dev)。当我尝试使用dma_alloc_coherent()时,它工作正常。

所以现在我有两个不同的struct device结构,一个用于管理我的角色设备文件,另一个用于管理底层的Open Firmware系统调用,总线和DMA事务。当然,这些设备在sysfs中并不相互关联。

我的问题是,是否有可能以某种方式请求为我从OF层获得的device结构创建设备文件而不是使用Misc设备API创建新设备?这样一切都将与单个device结构相关联。

2 个答案:

答案 0 :(得分:3)

我认为您对dma_alloc_coherent()的修正是正确的。

但我不认为使用嵌入在结构of_device中的设备结构来替换您创建的miscdevice是不对的。 of_device是Open Firmware数据库中对象的描述。并且根据Linux设备驱动程序模型,设备结构嵌入在Linux内核中的各种设备对象中。而且我认为你将miscdevice注册为一个字符设备,应该有file_operations结构相关联。

总之,他们是不同的观点,他们不能互相替换。

答案 1 :(得分:0)

我使用 miscdevice.this_device 为 raspberry pi 编写了一些实验性的 dma 驱动程序

#include <linux/module.h>   /* Needed by all modules */
#include <linux/kernel.h>   /* Needed for KERN_INFO */
#include <linux/miscdevice.h>
#include "gpio.h"
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include "DMA.h"
#include <linux/of_irq.h>

static int my_open(struct inode *i, struct file *f)
{
    printk(KERN_INFO "Driver: open() %d\n", current->pid);
    return 0;
}
static int my_close(struct inode *i, struct file *f)
{
    printk(KERN_INFO "Driver: close()\n");
    return 0;
}

static ssize_t my_read(struct file *f, char __user *buf, size_t len, loff_t *off)
{
    printk(KERN_INFO "Driver: read()\n");
    return 0;
}

char databuf[100];
static ssize_t my_write(struct file *f, const char __user *buf, size_t len, loff_t *off)
{
    if(copy_from_user(databuf, buf, 100) != 0) return 0;
    printk("Data from the user: %s\n", databuf);
    return len;
}

  static struct file_operations sample_fops =
{
    .owner = THIS_MODULE,
    .open = my_open,
    .release = my_close,
    .read = my_read,
    .write = my_write
};

struct miscdevice sample_device = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "ledButton",
    .fops = &sample_fops,
    .mode = 0666,
};

//static struct dmadata_s *cpu_addr;
//dma_addr_t dma_addr;

struct dma_cb *virt_cb;
dma_addr_t phys_cb;

uint32_t *virt_src;
dma_addr_t phys_src;

uint32_t *virt_dst;
dma_addr_t phys_dst;

static irqreturn_t dma_irq_fn(int irq, void *dev_id)
{
    printk("destAddr %u\n", *virt_dst);
    dma_regs->CS.INT = 1;
    return IRQ_HANDLED;
}

static struct device *dev;

int IRQ_DMA0;
static int __init ofcd_init(void) /* Constructor */
{
    int error, mret;
    struct device_node * np = NULL;
    
    error = misc_register(&sample_device);
    if (error) {
        pr_err("can't misc_register :(\n");
        return error;
    }

    dev = sample_device.this_device;
    dev->coherent_dma_mask = ~0;
    dev->dma_mask = &dev->coherent_dma_mask;

//  dev_set_name(dev, "mydmadev");
    
//  cpu_addr = (struct dmadata_s*)kmalloc(sizeof(struct dmadata_s), GFP_KERNEL | GFP_DMA);
    //dma_addr = dma_map_single(dev, cpu_addr, sizeof(struct dmadata_s), DMA_BIDIRECTIONAL);
    virt_cb = dma_alloc_coherent(dev, 32, &phys_cb, GFP_KERNEL | GFP_DMA);
    if(virt_cb == 0 || phys_cb == 0){
        printk("DMA cb error\n");
    }

    virt_src = dma_alloc_coherent(dev, 4, &phys_src, GFP_KERNEL | GFP_DMA);
    if(virt_src == 0 || phys_src == 0){
        printk("DMA src error\n");
    }

    virt_dst = dma_alloc_coherent(dev, 4, &phys_dst, GFP_KERNEL | GFP_DMA);
    if(virt_dst == 0 || phys_dst == 0){
        printk("DMA dst error\n");
    }

    memset(virt_cb, 0, sizeof(*virt_cb));
    dma_regs = (struct dma_ch *)ioremap(DMA_BASE, sizeof(struct dma_ch));
    
    
//  strcpy(cpu_addr->srcAddr, "DMA0");
    *virt_src = 200;
    virt_cb->TI.SRC_INC = 1;
    virt_cb->TI.DEST_INC = 1;
    virt_cb->TI.INTEN = 1;
    virt_cb->SOURCE_AD = (uint32_t)phys_src;
    virt_cb->DEST_AD = (uint32_t)phys_dst;
    virt_cb->TXFR_LEN = 4;
    virt_cb->reserved[0] = 0;
    virt_cb->reserved[1] = 0;
    
    printk("srcAddr %u\n", *virt_src);
    printk("destAddr %u\n", *virt_dst);
    
    //dma_regs->CS = (DMA_CS_t){.RESET = 1, .END = 1};
    dma_regs->CS.RESET = 1;
    udelay(10);
//  dma_regs->CS = (DMA_CS_t){.END = 1, .INT = 1};
    dma_regs->CS.INT = 1;
    dma_regs->CS.END = 1;
    dma_regs->CONBLK_AD = (uint32_t)phys_cb;
    //dma_regs->DEBUG = (DMA_DEBUG_t){.READ_LAST_NOT_SET_ERROR = 1, .FIFO_ERROR = 1, .READ_ERROR = 1};
    dma_regs->DEBUG.READ_LAST_NOT_SET_ERROR = 1;
    dma_regs->DEBUG.FIFO_ERROR = 1;
    dma_regs->DEBUG.READ_ERROR =1;
    udelay(10);
//  dma_regs->CS = (DMA_CS_t){.RESET = 1, .PRIORITY = 8, .PANIC_PRIORITY = 8, .ACTIVE = 1};
    dma_regs->CS.RESET = 1;
    udelay(10);
    dma_regs->CS.PRIORITY = 8;
    dma_regs->CS.PANIC_PRIORITY = 8;
    dma_regs->CS.ACTIVE = 1;
    if(dma_regs->CS.ERROR) printk("ERROR %d %d\n", dma_regs->CS.ACTIVE, dma_regs->CS.PANIC_PRIORITY);



    //np = of_find_compatible_node(NULL,NULL,"brcm,bcm2835-system-timer");
    np = of_find_node_by_path("/soc/dma@7e007000");
    if (np == NULL){
        printk("Error node not found\n");
    }
//  printk("node name %s\n", np->name);
    
    IRQ_DMA0 = irq_of_parse_and_map(np, 0);
    if (IRQ_DMA0 <= 0) {
        printk("Can't parse IRQ\n");
    }

    mret = request_irq(IRQ_DMA0, dma_irq_fn, IRQF_SHARED, "dma", &dma_irq_fn);
    if (mret < 0) printk(KERN_ALERT "%s: dma request_irg failed with %d\n", __func__, mret);

    return 0;
}
 
static void __exit ofcd_exit(void) /* Destructor */
{
    free_irq( IRQ_DMA0, &dma_irq_fn );
    //dma_unmap_single(dev, dma_addr, sizeof(struct dmadata_s), DMA_BIDIRECTIONAL);
    //kfree(cpu_addr);
    dma_free_coherent(dev, 32, virt_cb, phys_cb);
    dma_free_coherent(dev, 4, virt_src, phys_src);
    dma_free_coherent(dev, 4, virt_dst, phys_dst);
    iounmap(dma_regs);
//  device_unregister(dev);
    misc_deregister(&sample_device);
    printk(KERN_INFO "Module unregistered\n");
}

module_init(ofcd_init);
module_exit(ofcd_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("MBajor>");
MODULE_DESCRIPTION("PiCNC driver");
MODULE_VERSION("0.1");

我希望这会有所帮助。