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 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> 29 30#include "excite_iodev.h" 31 32 33 34static const struct resource *iodev_get_resource(struct platform_device *, const char *, unsigned int); 35static int __init iodev_probe(struct device *); 36static int __exit iodev_remove(struct device *); 37static int iodev_open(struct inode *, struct file *); 38static int iodev_release(struct inode *, struct file *); 39static ssize_t iodev_read(struct file *, char __user *, size_t s, loff_t *); 40static unsigned int iodev_poll(struct file *, struct poll_table_struct *); 41static irqreturn_t iodev_irqhdl(int, void *); 42 43 44 45static const char iodev_name[] = "iodev"; 46static unsigned int iodev_irq; 47static DECLARE_WAIT_QUEUE_HEAD(wq); 48 49 50 51static struct file_operations fops = 52{ 53 .owner = THIS_MODULE, 54 .open = iodev_open, 55 .release = iodev_release, 56 .read = iodev_read, 57 .poll = iodev_poll 58}; 59 60static struct miscdevice miscdev = 61{ 62 .minor = MISC_DYNAMIC_MINOR, 63 .name = iodev_name, 64 .fops = &fops 65}; 66 67static struct device_driver iodev_driver = 68{ 69 .name = (char *) iodev_name, 70 .bus = &platform_bus_type, 71 .owner = THIS_MODULE, 72 .probe = iodev_probe, 73 .remove = __exit_p(iodev_remove) 74}; 75 76 77 78static const struct resource * 79iodev_get_resource(struct platform_device *pdv, const char *name, 80 unsigned int type) 81{ 82 char buf[80]; 83 if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf) 84 return NULL; 85 return platform_get_resource_byname(pdv, type, buf); 86} 87 88 89 90/* No hotplugging on the platform bus - use __init */ 91static int __init iodev_probe(struct device *dev) 92{ 93 struct platform_device * const pdv = to_platform_device(dev); 94 const struct resource * const ri = 95 iodev_get_resource(pdv, IODEV_RESOURCE_IRQ, IORESOURCE_IRQ); 96 97 if (unlikely(!ri)) 98 return -ENXIO; 99 100 iodev_irq = ri->start; 101 return misc_register(&miscdev); 102} 103 104 105 106static int __exit iodev_remove(struct device *dev) 107{ 108 return misc_deregister(&miscdev); 109} 110 111static int iodev_open(struct inode *i, struct file *f) 112{ 113 return request_irq(iodev_irq, iodev_irqhdl, IRQF_DISABLED, 114 iodev_name, &miscdev); 115} 116 117static int iodev_release(struct inode *i, struct file *f) 118{ 119 free_irq(iodev_irq, &miscdev); 120 return 0; 121} 122 123 124 125 126static ssize_t 127iodev_read(struct file *f, char __user *d, size_t s, loff_t *o) 128{ 129 ssize_t ret; 130 DEFINE_WAIT(w); 131 132 prepare_to_wait(&wq, &w, TASK_INTERRUPTIBLE); 133 if (!signal_pending(current)) 134 schedule(); 135 ret = signal_pending(current) ? -ERESTARTSYS : 0; 136 finish_wait(&wq, &w); 137 return ret; 138} 139 140 141static unsigned int iodev_poll(struct file *f, struct poll_table_struct *p) 142{ 143 poll_wait(f, &wq, p); 144 return POLLOUT | POLLWRNORM; 145} 146 147static irqreturn_t iodev_irqhdl(int irq, void *ctxt) 148{ 149 wake_up(&wq); 150 151 return IRQ_HANDLED; 152} 153 154static int __init iodev_init_module(void) 155{ 156 return driver_register(&iodev_driver); 157} 158 159 160 161static void __exit iodev_cleanup_module(void) 162{ 163 driver_unregister(&iodev_driver); 164} 165 166module_init(iodev_init_module); 167module_exit(iodev_cleanup_module); 168 169 170 171MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>"); 172MODULE_DESCRIPTION("Basler eXcite i/o interrupt handler"); 173MODULE_VERSION("0.0"); 174MODULE_LICENSE("GPL"); 175