uio的uio_register_device函数

前面讲过uio的kernel part部分最重要的就是调用uio_register_device 在dev下面注册一个字符设备,例如/dev/uio0
/* use a define to avoid include chaining to get THIS_MODULE */
#define uio_register_device(parent, info) \
    __uio_register_device(THIS_MODULE, parent, info)
而uio_register_device是个宏,继续调用__uio_register_device
int __uio_register_device(struct module *owner,
              struct device *parent,
              struct uio_info *info)
{
    struct uio_device *idev;
    int ret = 0;

    if (!parent || !info || !info->name || !info->version)
        return -EINVAL;

    info->uio_dev = NULL;

    idev = devm_kzalloc(parent, sizeof(*idev), GFP_KERNEL);
    if (!idev) {
        return -ENOMEM;
    }

    idev->owner = owner;
    idev->info = info;
    init_waitqueue_head(&idev->wait);
    atomic_set(&idev->event, 0);

    ret = uio_get_minor(idev);
    if (ret)
        return ret;
//新建dev这样就会在dev下面看到dev/uioX等,这里的class是uio_class 这样就能在sys/class下面看到uio这个class
    idev->dev = device_create(&uio_class, parent,
                  MKDEV(uio_major, idev->minor), idev,
                  "uio%d", idev->minor);
    if (IS_ERR(idev->dev)) {
        printk(KERN_ERR "UIO: device register failed\n");
        ret = PTR_ERR(idev->dev);
        goto err_device_create;
    }
//创建attributes,这样user space就可以通过/sys/class/uio/uio0/maps0和/sys/class/uio/uio0/port0来访问这个uio设备
 sys  
 ├───uio  
       ├───uio0  
       │     ├───maps  
       │          ├───mapX  
       ├───uio1  
             ├───maps                           
             │    ├───mapX        
             ├───portio  
                  ├───portX

    ret = uio_dev_add_attributes(idev);
    if (ret)
        goto err_uio_dev_add_attributes;

    info->uio_dev = idev;
// 这里是处理中断
    if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) {
        /*
         * Note that we deliberately don't use devm_request_irq
         * here. The parent module can unregister the UIO device
         * and call pci_disable_msi, which requires that this
         * irq has been freed. However, the device may have open
         * FDs at the time of unregister and therefore may not be
         * freed until they are released.
         */
        ret = request_irq(info->irq, uio_interrupt,
                  info->irq_flags, info->name, idev);
        if (ret)
            goto err_request_irq;
    }

    return 0;

err_request_irq:
    uio_dev_del_attributes(idev);
err_uio_dev_add_attributes:
    device_destroy(&uio_class, MKDEV(uio_major, idev->minor));
err_device_create:
    uio_free_minor(idev);
    return ret;
}
这里可以看到中断的出来函数是uio_interrupt
static irqreturn_t uio_interrupt(int irq, void *dev_id)
{
    struct uio_device *idev = (struct uio_device *)dev_id;
    irqreturn_t ret = idev->info->handler(irq, idev->info);

    if (ret == IRQ_HANDLED)
        uio_event_notify(idev->info);

    return ret;
}
在uio_interrupt 中会调用uio_info 的handle,以uio_dmem_genirq.c为例    uioinfo->irqcontrol = uio_dmem_genirq_irqcontrol;
在uio_dmem_genirq_irqcontrol 中主要是设置相关中断相关的bit,因此在kernel space执行时间很短,如果执行成功后就调用uio_event_notify 来通知user space。可见对于中断,user space一直在polling等待中.
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值