Commit | Line | Data |
---|---|---|
35189fad RB |
1 | /* |
2 | * Copyright (C) 2005 by Basler Vision Technologies AG | |
3 | * Author: Thomas Koeller <thomas.koeller@baslerweb.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | */ | |
19 | ||
35189fad RB |
20 | #include <linux/compiler.h> |
21 | #include <linux/init.h> | |
22 | #include <linux/module.h> | |
23 | #include <linux/sched.h> | |
24 | #include <linux/wait.h> | |
25 | #include <linux/poll.h> | |
26 | #include <linux/interrupt.h> | |
27 | #include <linux/platform_device.h> | |
28 | #include <linux/miscdevice.h> | |
52e7c5e0 | 29 | #include <linux/smp_lock.h> |
35189fad RB |
30 | |
31 | #include "excite_iodev.h" | |
32 | ||
33 | ||
34 | ||
35 | static const struct resource *iodev_get_resource(struct platform_device *, const char *, unsigned int); | |
7a192ec3 ML |
36 | static int __init iodev_probe(struct platform_device *); |
37 | static int __exit iodev_remove(struct platform_device *); | |
35189fad RB |
38 | static int iodev_open(struct inode *, struct file *); |
39 | static int iodev_release(struct inode *, struct file *); | |
40 | static ssize_t iodev_read(struct file *, char __user *, size_t s, loff_t *); | |
41 | static unsigned int iodev_poll(struct file *, struct poll_table_struct *); | |
937a8015 | 42 | static irqreturn_t iodev_irqhdl(int, void *); |
35189fad RB |
43 | |
44 | ||
45 | ||
46 | static const char iodev_name[] = "iodev"; | |
47 | static unsigned int iodev_irq; | |
48 | static DECLARE_WAIT_QUEUE_HEAD(wq); | |
49 | ||
50 | ||
51 | ||
12323cac | 52 | static const struct file_operations fops = |
35189fad RB |
53 | { |
54 | .owner = THIS_MODULE, | |
55 | .open = iodev_open, | |
56 | .release = iodev_release, | |
57 | .read = iodev_read, | |
58 | .poll = iodev_poll | |
59 | }; | |
60 | ||
61 | static struct miscdevice miscdev = | |
62 | { | |
63 | .minor = MISC_DYNAMIC_MINOR, | |
64 | .name = iodev_name, | |
65 | .fops = &fops | |
66 | }; | |
67 | ||
7a192ec3 ML |
68 | static struct platform_driver iodev_driver = { |
69 | .driver = { | |
70 | .name = iodev_name, | |
71 | .owner = THIS_MODULE, | |
72 | }, | |
35189fad | 73 | .probe = iodev_probe, |
7a192ec3 | 74 | .remove = __devexit_p(iodev_remove), |
35189fad RB |
75 | }; |
76 | ||
77 | ||
78 | ||
79 | static const struct resource * | |
80 | iodev_get_resource(struct platform_device *pdv, const char *name, | |
81 | unsigned int type) | |
82 | { | |
83 | char buf[80]; | |
84 | if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf) | |
85 | return NULL; | |
86 | return platform_get_resource_byname(pdv, type, buf); | |
87 | } | |
88 | ||
89 | ||
90 | ||
91 | /* No hotplugging on the platform bus - use __init */ | |
7a192ec3 | 92 | static int __init iodev_probe(struct platform_device *dev) |
35189fad | 93 | { |
35189fad | 94 | const struct resource * const ri = |
7a192ec3 | 95 | iodev_get_resource(dev, IODEV_RESOURCE_IRQ, IORESOURCE_IRQ); |
35189fad RB |
96 | |
97 | if (unlikely(!ri)) | |
98 | return -ENXIO; | |
99 | ||
100 | iodev_irq = ri->start; | |
101 | return misc_register(&miscdev); | |
102 | } | |
103 | ||
104 | ||
105 | ||
7a192ec3 | 106 | static int __exit iodev_remove(struct platform_device *dev) |
35189fad RB |
107 | { |
108 | return misc_deregister(&miscdev); | |
109 | } | |
110 | ||
35189fad RB |
111 | static int iodev_open(struct inode *i, struct file *f) |
112 | { | |
52e7c5e0 AB |
113 | int ret; |
114 | ||
115 | lock_kernel(); | |
116 | ret = request_irq(iodev_irq, iodev_irqhdl, IRQF_DISABLED, | |
35189fad | 117 | iodev_name, &miscdev); |
52e7c5e0 AB |
118 | unlock_kernel(); |
119 | ||
120 | return ret; | |
35189fad RB |
121 | } |
122 | ||
35189fad RB |
123 | static int iodev_release(struct inode *i, struct file *f) |
124 | { | |
125 | free_irq(iodev_irq, &miscdev); | |
126 | return 0; | |
127 | } | |
128 | ||
129 | ||
130 | ||
131 | ||
132 | static ssize_t | |
133 | iodev_read(struct file *f, char __user *d, size_t s, loff_t *o) | |
134 | { | |
135 | ssize_t ret; | |
136 | DEFINE_WAIT(w); | |
137 | ||
138 | prepare_to_wait(&wq, &w, TASK_INTERRUPTIBLE); | |
139 | if (!signal_pending(current)) | |
140 | schedule(); | |
141 | ret = signal_pending(current) ? -ERESTARTSYS : 0; | |
142 | finish_wait(&wq, &w); | |
143 | return ret; | |
144 | } | |
145 | ||
146 | ||
147 | static unsigned int iodev_poll(struct file *f, struct poll_table_struct *p) | |
148 | { | |
149 | poll_wait(f, &wq, p); | |
150 | return POLLOUT | POLLWRNORM; | |
151 | } | |
152 | ||
937a8015 | 153 | static irqreturn_t iodev_irqhdl(int irq, void *ctxt) |
35189fad RB |
154 | { |
155 | wake_up(&wq); | |
937a8015 | 156 | |
35189fad RB |
157 | return IRQ_HANDLED; |
158 | } | |
159 | ||
35189fad RB |
160 | static int __init iodev_init_module(void) |
161 | { | |
7a192ec3 | 162 | return platform_driver_register(&iodev_driver); |
35189fad RB |
163 | } |
164 | ||
165 | ||
166 | ||
167 | static void __exit iodev_cleanup_module(void) | |
168 | { | |
7a192ec3 | 169 | platform_driver_unregister(&iodev_driver); |
35189fad RB |
170 | } |
171 | ||
172 | module_init(iodev_init_module); | |
173 | module_exit(iodev_cleanup_module); | |
174 | ||
175 | ||
176 | ||
177 | MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>"); | |
178 | MODULE_DESCRIPTION("Basler eXcite i/o interrupt handler"); | |
179 | MODULE_VERSION("0.0"); | |
180 | MODULE_LICENSE("GPL"); |