前面讲过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等待中.
/* 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等待中.