Commit 4d80d59437247075029534adec8d69fce2cfb87a
Committed by
Greg Kroah-Hartman
1 parent
328a14e70e
Exists in
master
and in
4 other branches
UIO: add generic UIO platform driver
This patch adds a generic UIO platform driver. It eliminates the need for a dedicated kernel module for simple platform devices. Users only need to implement their irq handler in platform code and fill a struct uio_info there. This helps avoiding code duplication as UIO platform drivers often share a lot of common code. Signed-off-by: Uwe Kleine-König <Uwe.Kleine-Koenig@digi.com> Signed-off-by: Hans J. Koch <hjk@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 3 changed files with 126 additions and 0 deletions Side-by-side Diff
drivers/uio/Kconfig
... | ... | @@ -26,6 +26,13 @@ |
26 | 26 | To compile this driver as a module, choose M here: the module |
27 | 27 | will be called uio_cif. |
28 | 28 | |
29 | +config UIO_PDRV | |
30 | + tristate "Userspace I/O platform driver" | |
31 | + help | |
32 | + Generic platform driver for Userspace I/O devices. | |
33 | + | |
34 | + If you don't know what to do here, say N. | |
35 | + | |
29 | 36 | config UIO_SMX |
30 | 37 | tristate "SMX cryptengine UIO interface" |
31 | 38 | default n |
drivers/uio/Makefile
drivers/uio/uio_pdrv.c
1 | +/* | |
2 | + * drivers/uio/uio_pdrv.c | |
3 | + * | |
4 | + * Copyright (C) 2008 by Digi International Inc. | |
5 | + * All rights reserved. | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or modify it | |
8 | + * under the terms of the GNU General Public License version 2 as published by | |
9 | + * the Free Software Foundation. | |
10 | + */ | |
11 | +#include <linux/platform_device.h> | |
12 | +#include <linux/uio_driver.h> | |
13 | +#include <linux/stringify.h> | |
14 | + | |
15 | +#define DRIVER_NAME "uio" | |
16 | + | |
17 | +struct uio_platdata { | |
18 | + struct uio_info *uioinfo; | |
19 | +}; | |
20 | + | |
21 | +static int uio_pdrv_probe(struct platform_device *pdev) | |
22 | +{ | |
23 | + struct uio_info *uioinfo = pdev->dev.platform_data; | |
24 | + struct uio_platdata *pdata; | |
25 | + struct uio_mem *uiomem; | |
26 | + int ret = -ENODEV; | |
27 | + int i; | |
28 | + | |
29 | + if (!uioinfo || !uioinfo->name || !uioinfo->version) { | |
30 | + dev_dbg(&pdev->dev, "%s: err_uioinfo\n", __func__); | |
31 | + goto err_uioinfo; | |
32 | + } | |
33 | + | |
34 | + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | |
35 | + if (!pdata) { | |
36 | + ret = -ENOMEM; | |
37 | + dev_dbg(&pdev->dev, "%s: err_alloc_pdata\n", __func__); | |
38 | + goto err_alloc_pdata; | |
39 | + } | |
40 | + | |
41 | + pdata->uioinfo = uioinfo; | |
42 | + | |
43 | + uiomem = &uioinfo->mem[0]; | |
44 | + | |
45 | + for (i = 0; i < pdev->num_resources; ++i) { | |
46 | + struct resource *r = &pdev->resource[i]; | |
47 | + | |
48 | + if (r->flags != IORESOURCE_MEM) | |
49 | + continue; | |
50 | + | |
51 | + if (uiomem >= &uioinfo->mem[MAX_UIO_MAPS]) { | |
52 | + dev_warn(&pdev->dev, "device has more than " | |
53 | + __stringify(MAX_UIO_MAPS) | |
54 | + " I/O memory resources.\n"); | |
55 | + break; | |
56 | + } | |
57 | + | |
58 | + uiomem->memtype = UIO_MEM_PHYS; | |
59 | + uiomem->addr = r->start; | |
60 | + uiomem->size = r->end - r->start + 1; | |
61 | + ++uiomem; | |
62 | + } | |
63 | + | |
64 | + while (uiomem < &uioinfo->mem[MAX_UIO_MAPS]) { | |
65 | + uiomem->size = 0; | |
66 | + ++uiomem; | |
67 | + } | |
68 | + | |
69 | + pdata->uioinfo->priv = pdata; | |
70 | + | |
71 | + ret = uio_register_device(&pdev->dev, pdata->uioinfo); | |
72 | + | |
73 | + if (ret) { | |
74 | + kfree(pdata); | |
75 | +err_alloc_pdata: | |
76 | +err_uioinfo: | |
77 | + return ret; | |
78 | + } | |
79 | + | |
80 | + platform_set_drvdata(pdev, pdata); | |
81 | + | |
82 | + return 0; | |
83 | +} | |
84 | + | |
85 | +static int uio_pdrv_remove(struct platform_device *pdev) | |
86 | +{ | |
87 | + struct uio_platdata *pdata = platform_get_drvdata(pdev); | |
88 | + | |
89 | + uio_unregister_device(pdata->uioinfo); | |
90 | + | |
91 | + return 0; | |
92 | +} | |
93 | + | |
94 | +static struct platform_driver uio_pdrv = { | |
95 | + .probe = uio_pdrv_probe, | |
96 | + .remove = uio_pdrv_remove, | |
97 | + .driver = { | |
98 | + .name = DRIVER_NAME, | |
99 | + .owner = THIS_MODULE, | |
100 | + }, | |
101 | +}; | |
102 | + | |
103 | +static int __init uio_pdrv_init(void) | |
104 | +{ | |
105 | + return platform_driver_register(&uio_pdrv); | |
106 | +} | |
107 | + | |
108 | +static void __exit uio_pdrv_exit(void) | |
109 | +{ | |
110 | + platform_driver_unregister(&uio_pdrv); | |
111 | +} | |
112 | +module_init(uio_pdrv_init); | |
113 | +module_exit(uio_pdrv_exit); | |
114 | + | |
115 | +MODULE_AUTHOR("Uwe Kleine-Koenig"); | |
116 | +MODULE_DESCRIPTION("Userspace I/O platform driver"); | |
117 | +MODULE_LICENSE("GPL"); | |
118 | +MODULE_ALIAS("platform:" DRIVER_NAME); |