0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/poll.h>
0012 #include <linux/vmalloc.h>
0013 #include <linux/slab.h>
0014 #include <linux/timer.h>
0015 #include <linux/miscdevice.h>
0016 #include <linux/module.h>
0017 #include <linux/mISDNif.h>
0018 #include <linux/mutex.h>
0019 #include <linux/sched/signal.h>
0020
0021 #include "core.h"
0022
0023 static DEFINE_MUTEX(mISDN_mutex);
0024 static u_int *debug;
0025
0026
0027 struct mISDNtimerdev {
0028 int next_id;
0029 struct list_head pending;
0030 struct list_head expired;
0031 wait_queue_head_t wait;
0032 u_int work;
0033 spinlock_t lock;
0034 };
0035
0036 struct mISDNtimer {
0037 struct list_head list;
0038 struct mISDNtimerdev *dev;
0039 struct timer_list tl;
0040 int id;
0041 };
0042
0043 static int
0044 mISDN_open(struct inode *ino, struct file *filep)
0045 {
0046 struct mISDNtimerdev *dev;
0047
0048 if (*debug & DEBUG_TIMER)
0049 printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);
0050 dev = kmalloc(sizeof(struct mISDNtimerdev) , GFP_KERNEL);
0051 if (!dev)
0052 return -ENOMEM;
0053 dev->next_id = 1;
0054 INIT_LIST_HEAD(&dev->pending);
0055 INIT_LIST_HEAD(&dev->expired);
0056 spin_lock_init(&dev->lock);
0057 dev->work = 0;
0058 init_waitqueue_head(&dev->wait);
0059 filep->private_data = dev;
0060 return nonseekable_open(ino, filep);
0061 }
0062
0063 static int
0064 mISDN_close(struct inode *ino, struct file *filep)
0065 {
0066 struct mISDNtimerdev *dev = filep->private_data;
0067 struct list_head *list = &dev->pending;
0068 struct mISDNtimer *timer, *next;
0069
0070 if (*debug & DEBUG_TIMER)
0071 printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);
0072
0073 spin_lock_irq(&dev->lock);
0074 while (!list_empty(list)) {
0075 timer = list_first_entry(list, struct mISDNtimer, list);
0076 spin_unlock_irq(&dev->lock);
0077 del_timer_sync(&timer->tl);
0078 spin_lock_irq(&dev->lock);
0079
0080 list_del(&timer->list);
0081 kfree(timer);
0082 }
0083 spin_unlock_irq(&dev->lock);
0084
0085 list_for_each_entry_safe(timer, next, &dev->expired, list) {
0086 kfree(timer);
0087 }
0088 kfree(dev);
0089 return 0;
0090 }
0091
0092 static ssize_t
0093 mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off)
0094 {
0095 struct mISDNtimerdev *dev = filep->private_data;
0096 struct list_head *list = &dev->expired;
0097 struct mISDNtimer *timer;
0098 int ret = 0;
0099
0100 if (*debug & DEBUG_TIMER)
0101 printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__,
0102 filep, buf, (int)count, off);
0103
0104 if (count < sizeof(int))
0105 return -ENOSPC;
0106
0107 spin_lock_irq(&dev->lock);
0108 while (list_empty(list) && (dev->work == 0)) {
0109 spin_unlock_irq(&dev->lock);
0110 if (filep->f_flags & O_NONBLOCK)
0111 return -EAGAIN;
0112 wait_event_interruptible(dev->wait, (dev->work ||
0113 !list_empty(list)));
0114 if (signal_pending(current))
0115 return -ERESTARTSYS;
0116 spin_lock_irq(&dev->lock);
0117 }
0118 if (dev->work)
0119 dev->work = 0;
0120 if (!list_empty(list)) {
0121 timer = list_first_entry(list, struct mISDNtimer, list);
0122 list_del(&timer->list);
0123 spin_unlock_irq(&dev->lock);
0124 if (put_user(timer->id, (int __user *)buf))
0125 ret = -EFAULT;
0126 else
0127 ret = sizeof(int);
0128 kfree(timer);
0129 } else {
0130 spin_unlock_irq(&dev->lock);
0131 }
0132 return ret;
0133 }
0134
0135 static __poll_t
0136 mISDN_poll(struct file *filep, poll_table *wait)
0137 {
0138 struct mISDNtimerdev *dev = filep->private_data;
0139 __poll_t mask = EPOLLERR;
0140
0141 if (*debug & DEBUG_TIMER)
0142 printk(KERN_DEBUG "%s(%p, %p)\n", __func__, filep, wait);
0143 if (dev) {
0144 poll_wait(filep, &dev->wait, wait);
0145 mask = 0;
0146 if (dev->work || !list_empty(&dev->expired))
0147 mask |= (EPOLLIN | EPOLLRDNORM);
0148 if (*debug & DEBUG_TIMER)
0149 printk(KERN_DEBUG "%s work(%d) empty(%d)\n", __func__,
0150 dev->work, list_empty(&dev->expired));
0151 }
0152 return mask;
0153 }
0154
0155 static void
0156 dev_expire_timer(struct timer_list *t)
0157 {
0158 struct mISDNtimer *timer = from_timer(timer, t, tl);
0159 u_long flags;
0160
0161 spin_lock_irqsave(&timer->dev->lock, flags);
0162 if (timer->id >= 0)
0163 list_move_tail(&timer->list, &timer->dev->expired);
0164 wake_up_interruptible(&timer->dev->wait);
0165 spin_unlock_irqrestore(&timer->dev->lock, flags);
0166 }
0167
0168 static int
0169 misdn_add_timer(struct mISDNtimerdev *dev, int timeout)
0170 {
0171 int id;
0172 struct mISDNtimer *timer;
0173
0174 if (!timeout) {
0175 dev->work = 1;
0176 wake_up_interruptible(&dev->wait);
0177 id = 0;
0178 } else {
0179 timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL);
0180 if (!timer)
0181 return -ENOMEM;
0182 timer->dev = dev;
0183 timer_setup(&timer->tl, dev_expire_timer, 0);
0184 spin_lock_irq(&dev->lock);
0185 id = timer->id = dev->next_id++;
0186 if (dev->next_id < 0)
0187 dev->next_id = 1;
0188 list_add_tail(&timer->list, &dev->pending);
0189 timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000);
0190 add_timer(&timer->tl);
0191 spin_unlock_irq(&dev->lock);
0192 }
0193 return id;
0194 }
0195
0196 static int
0197 misdn_del_timer(struct mISDNtimerdev *dev, int id)
0198 {
0199 struct mISDNtimer *timer;
0200
0201 spin_lock_irq(&dev->lock);
0202 list_for_each_entry(timer, &dev->pending, list) {
0203 if (timer->id == id) {
0204 list_del_init(&timer->list);
0205 timer->id = -1;
0206 spin_unlock_irq(&dev->lock);
0207 del_timer_sync(&timer->tl);
0208 kfree(timer);
0209 return id;
0210 }
0211 }
0212 spin_unlock_irq(&dev->lock);
0213 return 0;
0214 }
0215
0216 static long
0217 mISDN_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
0218 {
0219 struct mISDNtimerdev *dev = filep->private_data;
0220 int id, tout, ret = 0;
0221
0222
0223 if (*debug & DEBUG_TIMER)
0224 printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__,
0225 filep, cmd, arg);
0226 mutex_lock(&mISDN_mutex);
0227 switch (cmd) {
0228 case IMADDTIMER:
0229 if (get_user(tout, (int __user *)arg)) {
0230 ret = -EFAULT;
0231 break;
0232 }
0233 id = misdn_add_timer(dev, tout);
0234 if (*debug & DEBUG_TIMER)
0235 printk(KERN_DEBUG "%s add %d id %d\n", __func__,
0236 tout, id);
0237 if (id < 0) {
0238 ret = id;
0239 break;
0240 }
0241 if (put_user(id, (int __user *)arg))
0242 ret = -EFAULT;
0243 break;
0244 case IMDELTIMER:
0245 if (get_user(id, (int __user *)arg)) {
0246 ret = -EFAULT;
0247 break;
0248 }
0249 if (*debug & DEBUG_TIMER)
0250 printk(KERN_DEBUG "%s del id %d\n", __func__, id);
0251 id = misdn_del_timer(dev, id);
0252 if (put_user(id, (int __user *)arg))
0253 ret = -EFAULT;
0254 break;
0255 default:
0256 ret = -EINVAL;
0257 }
0258 mutex_unlock(&mISDN_mutex);
0259 return ret;
0260 }
0261
0262 static const struct file_operations mISDN_fops = {
0263 .owner = THIS_MODULE,
0264 .read = mISDN_read,
0265 .poll = mISDN_poll,
0266 .unlocked_ioctl = mISDN_ioctl,
0267 .open = mISDN_open,
0268 .release = mISDN_close,
0269 .llseek = no_llseek,
0270 };
0271
0272 static struct miscdevice mISDNtimer = {
0273 .minor = MISC_DYNAMIC_MINOR,
0274 .name = "mISDNtimer",
0275 .fops = &mISDN_fops,
0276 };
0277
0278 int
0279 mISDN_inittimer(u_int *deb)
0280 {
0281 int err;
0282
0283 debug = deb;
0284 err = misc_register(&mISDNtimer);
0285 if (err)
0286 printk(KERN_WARNING "mISDN: Could not register timer device\n");
0287 return err;
0288 }
0289
0290 void mISDN_timer_cleanup(void)
0291 {
0292 misc_deregister(&mISDNtimer);
0293 }