2 * drivers/uio/uio_ubicom32ring.c
4 * Userspace I/O platform driver for Ubicom32 ring buffers
6 * (C) Copyright 2009, Ubicom, Inc.
8 * This file is part of the Ubicom32 Linux Kernel Port.
10 * Based on uio_ubicom32ring.c by Magnus Damm
12 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
13 * it and/or modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, either version 2 of the
15 * License, or (at your option) any later version.
17 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
18 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
19 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
20 * the GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with the Ubicom32 Linux Kernel Port. If not,
24 * see <http://www.gnu.org/licenses/>.
27 #include <linux/platform_device.h>
28 #include <linux/uio_driver.h>
29 #include <linux/spinlock.h>
30 #include <linux/bitops.h>
31 #include <linux/interrupt.h>
32 #include <linux/stringify.h>
34 #include <asm/ip5000.h>
35 #include <asm/ubicom32ring.h>
37 #define DRIVER_NAME "uio_ubicom32ring"
39 struct uio_ubicom32ring_data
{
40 struct uio_info
*uioinfo
;
42 struct uio_ubicom32ring_regs
*regs
;
45 * IRQ used to kick the ring buffer
57 static irqreturn_t
uio_ubicom32ring_handler(int irq
, struct uio_info
*dev_info
)
59 struct uio_ubicom32ring_data
*priv
= dev_info
->priv
;
61 /* Just disable the interrupt in the interrupt controller, and
62 * remember the state so we can allow user space to enable it later.
65 if (!test_and_set_bit(0, &priv
->flags
))
66 disable_irq_nosync(irq
);
71 static int uio_ubicom32ring_irqcontrol(struct uio_info
*dev_info
, s32 irq_on
)
73 struct uio_ubicom32ring_data
*priv
= dev_info
->priv
;
76 /* Allow user space to enable and disable the interrupt
77 * in the interrupt controller, but keep track of the
78 * state to prevent per-irq depth damage.
80 * Serialize this operation to support multiple tasks.
83 spin_lock_irqsave(&priv
->lock
, flags
);
87 * Kick the ring buffer (if we can)
89 if (priv
->irq_tx
!= 0xFF) {
90 ubicom32_set_interrupt(priv
->irq_tx
);
94 if (priv
->irq_rx
!= 0xFF) {
96 if (test_and_clear_bit(0, &priv
->flags
))
97 enable_irq(dev_info
->irq
);
99 if (!test_and_set_bit(0, &priv
->flags
))
100 disable_irq(dev_info
->irq
);
104 spin_unlock_irqrestore(&priv
->lock
, flags
);
109 static int uio_ubicom32ring_probe(struct platform_device
*pdev
)
111 struct uio_info
*uioinfo
;
112 struct uio_mem
*uiomem
;
113 struct uio_ubicom32ring_data
*priv
;
114 struct uio_ubicom32ring_regs
*regs
;
115 struct resource
*mem_resource
;
116 struct resource
*irqtx_resource
;
117 struct resource
*irqrx_resource
;
121 uioinfo
= kzalloc(sizeof(struct uio_info
), GFP_KERNEL
);
123 dev_err(&pdev
->dev
, "unable to kmalloc\n");
128 * Allocate private data with some string space after
130 i
= sizeof(DRIVER_NAME
) + 1;
131 i
+= pdev
->dev
.platform_data
? strlen(pdev
->dev
.platform_data
) : 0;
132 priv
= kzalloc(sizeof(struct uio_ubicom32ring_data
) + i
, GFP_KERNEL
);
134 dev_err(&pdev
->dev
, "unable to kmalloc\n");
139 strcpy(priv
->name
, DRIVER_NAME
":");
140 if (pdev
->dev
.platform_data
) {
141 strcat(priv
->name
, pdev
->dev
.platform_data
);
143 uioinfo
->priv
= priv
;
144 uioinfo
->name
= priv
->name
;
145 uioinfo
->version
= "0.1";
147 priv
->uioinfo
= uioinfo
;
148 spin_lock_init(&priv
->lock
);
149 priv
->flags
= 0; /* interrupt is enabled to begin with */
152 * Get our resources, the IRQ_TX and IRQ_RX are optional.
155 irqtx_resource
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 0);
156 if (irqtx_resource
) {
157 priv
->irq_tx
= irqtx_resource
->start
;
162 irqrx_resource
= platform_get_resource(pdev
, IORESOURCE_IRQ
, 1);
163 if (irqrx_resource
) {
164 priv
->irq_rx
= irqrx_resource
->start
;
165 uioinfo
->irq
= priv
->irq_rx
;
166 uioinfo
->handler
= uio_ubicom32ring_handler
;
169 mem_resource
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
170 if (!mem_resource
|| !mem_resource
->start
) {
171 dev_err(&pdev
->dev
, "No valid memory resource found\n");
175 regs
= (struct uio_ubicom32ring_regs
*)mem_resource
->start
;
178 if (regs
->version
!= UIO_UBICOM32RING_REG_VERSION
) {
179 dev_err(&pdev
->dev
, "version %d not supported\n", regs
->version
);
185 * First range is the shared register space, if we have any
187 uiomem
= &uioinfo
->mem
[0];
188 if (regs
->regs_size
) {
189 uiomem
->memtype
= UIO_MEM_PHYS
;
190 uiomem
->addr
= (u32_t
)regs
->regs
;
191 uiomem
->size
= regs
->regs_size
;
193 dev_info(&pdev
->dev
, "regs:%p (%u) / rings: %d found\n", regs
->regs
, regs
->regs_size
, regs
->num_rings
);
195 dev_info(&pdev
->dev
, "rings: %d found\n", regs
->num_rings
);
199 * The rest of the range correspond to the rings
201 for (i
= 0; i
< regs
->num_rings
; i
++) {
202 dev_info(&pdev
->dev
, "\t%d: entries:%d ring:%p\n",
203 i
, regs
->rings
[i
]->entries
, &(regs
->rings
[i
]->ring
));
204 if (uiomem
>= &uioinfo
->mem
[MAX_UIO_MAPS
]) {
205 dev_warn(&pdev
->dev
, "device has more than "
206 __stringify(MAX_UIO_MAPS
)
207 " I/O memory resources.\n");
211 uiomem
->memtype
= UIO_MEM_PHYS
;
212 uiomem
->addr
= (u32_t
)&(regs
->rings
[i
]->head
);
213 uiomem
->size
= (regs
->rings
[i
]->entries
* sizeof(u32_t
)) +
214 sizeof(struct uio_ubicom32ring_desc
);
218 while (uiomem
< &uioinfo
->mem
[MAX_UIO_MAPS
]) {
223 /* This driver requires no hardware specific kernel code to handle
224 * interrupts. Instead, the interrupt handler simply disables the
225 * interrupt in the interrupt controller. User space is responsible
226 * for performing hardware specific acknowledge and re-enabling of
227 * the interrupt in the interrupt controller.
229 * Interrupt sharing is not supported.
231 uioinfo
->irq_flags
= IRQF_DISABLED
;
232 uioinfo
->irqcontrol
= uio_ubicom32ring_irqcontrol
;
234 ret
= uio_register_device(&pdev
->dev
, priv
->uioinfo
);
236 dev_err(&pdev
->dev
, "unable to register uio device\n");
240 platform_set_drvdata(pdev
, priv
);
242 dev_info(&pdev
->dev
, "'%s' using irq: rx %d tx %d, regs %p\n",
243 priv
->name
, priv
->irq_rx
, priv
->irq_tx
, priv
->regs
);
253 static int uio_ubicom32ring_remove(struct platform_device
*pdev
)
255 struct uio_ubicom32ring_data
*priv
= platform_get_drvdata(pdev
);
257 uio_unregister_device(priv
->uioinfo
);
258 kfree(priv
->uioinfo
);
263 static struct platform_driver uio_ubicom32ring
= {
264 .probe
= uio_ubicom32ring_probe
,
265 .remove
= uio_ubicom32ring_remove
,
268 .owner
= THIS_MODULE
,
272 static int __init
uio_ubicom32ring_init(void)
274 return platform_driver_register(&uio_ubicom32ring
);
277 static void __exit
uio_ubicom32ring_exit(void)
279 platform_driver_unregister(&uio_ubicom32ring
);
282 module_init(uio_ubicom32ring_init
);
283 module_exit(uio_ubicom32ring_exit
);
285 MODULE_AUTHOR("Patrick Tjin");
286 MODULE_DESCRIPTION("Userspace I/O driver for Ubicom32 ring buffers");
287 MODULE_LICENSE("GPL v2");
288 MODULE_ALIAS("platform:" DRIVER_NAME
);