[Xenomai] Q: UDD sample code ?

Philippe Gerum rpm at xenomai.org
Tue Feb 7 10:25:09 CET 2017


On 02/07/2017 08:31 AM, Ran Shalit wrote:
> Hello,
> 
> I would like to write a UDD driver.
> The API are documented very well, yet a simple example can help here.
> 
> Does anyone have an example to share ?
> 

A trivial driver for a random PCI device having two BARs we want to
expose to user-space via the mmap() interface, along with a way for some
application thread to wait for IRQ events received from that device (see
udd_notify_event(), automatically called by UDD upon interrupt receipt
since udd_device.irq contains a valid IRQ number).

#include <linux/kernel.h>
#include <linux/module.h>
#include <rtdm/driver.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <rtdm/udd.h>

static int foo_open(struct rtdm_fd *fd, int oflags)
{
	return 0;
}

static void foo_close(struct rtdm_fd *fd)
{
}

static int foo_mmap(struct rtdm_fd *fd, struct vm_area_struct *vma)
{
	struct udd_memregion *rn;
	struct udd_device *udd;
	int ret;

	udd = udd_get_device(fd);
	rn = udd->mem_regions + rtdm_fd_minor(fd);

	switch (rn->type) {
	case UDD_MEM_PHYS:
		ret = rtdm_mmap_iomem(vma, rn->addr);
		break;
	case UDD_MEM_LOGICAL:
		ret = rtdm_mmap_kmem(vma, (void *)rn->addr);
		break;
	case UDD_MEM_VIRTUAL:
		ret = rtdm_mmap_vmem(vma, (void *)rn->addr);
		break;
	default:
		ret = -EINVAL;
	}

	return ret;
}

int foo_interrupt(struct udd_device *udd)
{
	/* ack device interrupt, UDD will call udd_notify_event() next */

	return RTDM_IRQ_HANDLED;
}

static struct udd_device udd = {
	.device_flags = RTDM_NAMED_DEVICE,
	.device_name = "foo",
	.ops = {
		.interrupt = foo_interrupt,
		.close = foo_close,
		.open = foo_open,
		.mmap = foo_mmap,
	}
};

#define PCI_VENDOR_ID_WHATEVER 	0x????
#define PCI_DEVICE_ID_FOO  	0x????

static struct pci_device_id foo_pci_ids[] = {
	{ PCI_DEVICE(PCI_VENDOR_ID_WHATEVER, PCI_DEVICE_ID_FOO) },
	{0,}
};

static int foo_pci_probe(struct pci_dev *dev, const struct pci_device_id
*id)
{
	unsigned int regs_len, mem_len;
	unsigned long regs, mem;
	int ret;

	ret = pci_enable_device(dev);
	if (ret < 0)
		return ret;

	regs = pci_resource_start(dev, 0);
	regs_len  = pci_resource_end(dev, 0) - regs;

	mem = pci_resource_start(dev, 1);
	mem_len  = pci_resource_end(dev, 1) - mem;

	/* exposed as /dev/rtdm/foo,mapper0 */
	udd.mem_regions[0].name = "foo-regs";
	udd.mem_regions[0].addr = regs;
	udd.mem_regions[0].len = regs_len;
	udd.mem_regions[0].type = UDD_MEM_PHYS;

	/* exposed as /dev/rtdm/foo,mapper1 */
	udd.mem_regions[1].name = "foo-mem";
	udd.mem_regions[1].addr = mem;
	udd.mem_regions[1].len = mem_len;
	udd.mem_regions[1].type = UDD_MEM_PHYS;

	/* Enable automatic notification. */
	udd.irq = dev->irq;

	ret = udd_register_device(&udd);
	if (ret)
		printk(KERN_ERR "failed to register FOO driver (%d)\n",
		       ret);

	return ret;
}

static void foo_pci_remove(struct pci_dev *dev)
{
	udd_unregister_device(&udd);
	pci_disable_device(dev);
}

static struct pci_driver foo_pci_driver = {
	.name = "foo",
	.remove = foo_pci_remove,
	.id_table = foo_pci_ids,
	.probe = foo_pci_probe,
};

static int __init foo_init(void)
{
	return pci_register_driver(&foo_pci_driver);
}
static void __exit foo_exit(void)
{
	pci_unregister_driver(&foo_pci_driver);
}

MODULE_LICENSE("GPL");
module_init(foo_init);
module_exit(foo_exit);

-- 
Philippe.



More information about the Xenomai mailing list