[go: nahoru, domu]

11b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil/*
21b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
31b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * general timer device for using in ISDN stacks
41b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
51b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * Author	Karsten Keil <kkeil@novell.com>
61b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
71b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * Copyright 2008  by Karsten Keil <kkeil@novell.com>
81b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
91b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * This program is free software; you can redistribute it and/or modify
101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * it under the terms of the GNU General Public License version 2 as
111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * published by the Free Software Foundation.
121b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
131b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * This program is distributed in the hope that it will be useful,
141b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * but WITHOUT ANY WARRANTY; without even the implied warranty of
151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
161b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil * GNU General Public License for more details.
171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil *
181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil */
191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
201b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include <linux/poll.h>
211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include <linux/vmalloc.h>
225a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
231b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include <linux/timer.h>
241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include <linux/miscdevice.h>
251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include <linux/module.h>
261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil#include <linux/mISDNif.h>
2776a64921dad9acd76270dc74249f0dfe11c84bb8Arnd Bergmann#include <linux/mutex.h>
285b8343540a3d27f87a4d9d72bb39b7d4cc3dd95eHannes Eder#include "core.h"
291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
3076a64921dad9acd76270dc74249f0dfe11c84bb8Arnd Bergmannstatic DEFINE_MUTEX(mISDN_mutex);
31dfa96ec1bb83641242c48883c2bae8f1f30483b2Hannes Ederstatic u_int	*debug;
321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstruct mISDNtimerdev {
351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int			next_id;
361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct list_head	pending;
371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct list_head	expired;
381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	wait_queue_head_t	wait;
391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	u_int			work;
401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	spinlock_t		lock; /* protect lists */
411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil};
421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
431b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstruct mISDNtimer {
441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct list_head	list;
451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct  mISDNtimerdev	*dev;
461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct timer_list	tl;
471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int			id;
481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil};
491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
511b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_open(struct inode *ino, struct file *filep)
521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNtimerdev	*dev;
541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_TIMER)
561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);
571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	dev = kmalloc(sizeof(struct mISDNtimerdev) , GFP_KERNEL);
581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!dev)
591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		return -ENOMEM;
601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	dev->next_id = 1;
611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	INIT_LIST_HEAD(&dev->pending);
621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	INIT_LIST_HEAD(&dev->expired);
631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	spin_lock_init(&dev->lock);
641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	dev->work = 0;
651b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	init_waitqueue_head(&dev->wait);
661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	filep->private_data = dev;
676bff338bb60cb97f4ad06aa20f5c8e547eb1bc7aAndrew Morton	return nonseekable_open(ino, filep);
681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
691b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
701b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
711b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_close(struct inode *ino, struct file *filep)
721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNtimerdev	*dev = filep->private_data;
74c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro	struct list_head	*list = &dev->pending;
751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNtimer	*timer, *next;
761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_TIMER)
781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s(%p,%p)\n", __func__, ino, filep);
79c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro
80c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro	spin_lock_irq(&dev->lock);
81c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro	while (!list_empty(list)) {
82c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro		timer = list_first_entry(list, struct mISDNtimer, list);
83c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro		spin_unlock_irq(&dev->lock);
84c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro		del_timer_sync(&timer->tl);
85c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro		spin_lock_irq(&dev->lock);
86c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro		/* it might have been moved to ->expired */
87c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro		list_del(&timer->list);
881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		kfree(timer);
891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
90c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro	spin_unlock_irq(&dev->lock);
91c08c464d6f4136d9e48ffa23c0bcd93442343b2aAl Viro
921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	list_for_each_entry_safe(timer, next, &dev->expired, list) {
931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		kfree(timer);
941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	kfree(dev);
961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return 0;
971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic ssize_t
100c46f0a2d40f7ceb5fb696309bcd088ac75d0fe20Hannes EdermISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off)
1011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
1021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNtimerdev	*dev = filep->private_data;
103ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro	struct list_head *list = &dev->expired;
1041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNtimer	*timer;
1051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int	ret = 0;
1061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_TIMER)
1081b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s(%p, %p, %d, %p)\n", __func__,
109475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       filep, buf, (int)count, off);
1101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
111ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro	if (count < sizeof(int))
112ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro		return -ENOSPC;
113ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro
114ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro	spin_lock_irq(&dev->lock);
115ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro	while (list_empty(list) && (dev->work == 0)) {
116ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro		spin_unlock_irq(&dev->lock);
1171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (filep->f_flags & O_NONBLOCK)
1181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return -EAGAIN;
1191b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		wait_event_interruptible(dev->wait, (dev->work ||
120ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro						     !list_empty(list)));
1211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (signal_pending(current))
1221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return -ERESTARTSYS;
123ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro		spin_lock_irq(&dev->lock);
1241b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
1251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (dev->work)
1261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		dev->work = 0;
127ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro	if (!list_empty(list)) {
128ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro		timer = list_first_entry(list, struct mISDNtimer, list);
1291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		list_del(&timer->list);
130ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro		spin_unlock_irq(&dev->lock);
131c46f0a2d40f7ceb5fb696309bcd088ac75d0fe20Hannes Eder		if (put_user(timer->id, (int __user *)buf))
1321b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			ret = -EFAULT;
1331b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		else
1341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			ret = sizeof(int);
1351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		kfree(timer);
136ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro	} else {
137ebb06be16bc9a1e66a010ca50c75c5128bafb4b1Al Viro		spin_unlock_irq(&dev->lock);
1381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
1391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return ret;
1401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
1411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic unsigned int
1431b2b03f8e514e4f68e293846ba511a948b80243cKarsten KeilmISDN_poll(struct file *filep, poll_table *wait)
1441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
1451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNtimerdev	*dev = filep->private_data;
1461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	unsigned int		mask = POLLERR;
1471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_TIMER)
1491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s(%p, %p)\n", __func__, filep, wait);
1501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (dev) {
1511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		poll_wait(filep, &dev->wait, wait);
1521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		mask = 0;
1531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (dev->work || !list_empty(&dev->expired))
1541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			mask |= (POLLIN | POLLRDNORM);
1551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (*debug & DEBUG_TIMER)
1561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_DEBUG "%s work(%d) empty(%d)\n", __func__,
157475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       dev->work, list_empty(&dev->expired));
1581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
1591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return mask;
1601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
1611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic void
163ce425a9f2c0182e9a9e49c7dc18699f2db4c3f48Andi Kleendev_expire_timer(unsigned long data)
1641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
165ce425a9f2c0182e9a9e49c7dc18699f2db4c3f48Andi Kleen	struct mISDNtimer *timer = (void *)data;
1661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	u_long			flags;
1671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	spin_lock_irqsave(&timer->dev->lock, flags);
1691b1089561ce596a4032ba1039365090304db1cfdAl Viro	if (timer->id >= 0)
1701b1089561ce596a4032ba1039365090304db1cfdAl Viro		list_move_tail(&timer->list, &timer->dev->expired);
1711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	spin_unlock_irqrestore(&timer->dev->lock, flags);
1721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	wake_up_interruptible(&timer->dev->wait);
1731b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
1741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
1761b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilmisdn_add_timer(struct mISDNtimerdev *dev, int timeout)
1771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
178475be4d85a274d0961593db41cf85689db1d583cJoe Perches	int			id;
1791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNtimer	*timer;
1801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
1811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (!timeout) {
1821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		dev->work = 1;
1831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		wake_up_interruptible(&dev->wait);
1841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		id = 0;
1851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	} else {
1861b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		timer = kzalloc(sizeof(struct mISDNtimer), GFP_KERNEL);
1871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (!timer)
1881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			return -ENOMEM;
1891678ec00a632f8b9204e28e5c506128881171604Al Viro		timer->dev = dev;
1901678ec00a632f8b9204e28e5c506128881171604Al Viro		setup_timer(&timer->tl, dev_expire_timer, (long)timer);
1911678ec00a632f8b9204e28e5c506128881171604Al Viro		spin_lock_irq(&dev->lock);
1921678ec00a632f8b9204e28e5c506128881171604Al Viro		id = timer->id = dev->next_id++;
1931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (dev->next_id < 0)
1941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			dev->next_id = 1;
1951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		list_add_tail(&timer->list, &dev->pending);
1961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		timer->tl.expires = jiffies + ((HZ * (u_long)timeout) / 1000);
1971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		add_timer(&timer->tl);
1981678ec00a632f8b9204e28e5c506128881171604Al Viro		spin_unlock_irq(&dev->lock);
1991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
2001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return id;
2011b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
2021b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2031b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic int
2041b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilmisdn_del_timer(struct mISDNtimerdev *dev, int id)
2051b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
2061b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNtimer	*timer;
2071b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2081b1089561ce596a4032ba1039365090304db1cfdAl Viro	spin_lock_irq(&dev->lock);
2091b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	list_for_each_entry(timer, &dev->pending, list) {
2101b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (timer->id == id) {
2111b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			list_del_init(&timer->list);
2121b1089561ce596a4032ba1039365090304db1cfdAl Viro			timer->id = -1;
2131b1089561ce596a4032ba1039365090304db1cfdAl Viro			spin_unlock_irq(&dev->lock);
2141b1089561ce596a4032ba1039365090304db1cfdAl Viro			del_timer_sync(&timer->tl);
2151b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			kfree(timer);
2161b1089561ce596a4032ba1039365090304db1cfdAl Viro			return id;
2171b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
2181b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
2191b1089561ce596a4032ba1039365090304db1cfdAl Viro	spin_unlock_irq(&dev->lock);
2201b1089561ce596a4032ba1039365090304db1cfdAl Viro	return 0;
2211b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
2221b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
223703c631ebbcadcfd861d01e697fdda7c388fec9aArnd Bergmannstatic long
224703c631ebbcadcfd861d01e697fdda7c388fec9aArnd BergmannmISDN_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
2251b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
2261b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	struct mISDNtimerdev	*dev = filep->private_data;
2271b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int			id, tout, ret = 0;
2281b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2291b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2301b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (*debug & DEBUG_TIMER)
2311b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_DEBUG "%s(%p, %x, %lx)\n", __func__,
232475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       filep, cmd, arg);
23376a64921dad9acd76270dc74249f0dfe11c84bb8Arnd Bergmann	mutex_lock(&mISDN_mutex);
2341b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	switch (cmd) {
2351b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case IMADDTIMER:
2361b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (get_user(tout, (int __user *)arg)) {
2371b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			ret = -EFAULT;
2381b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
2391b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
2401b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		id = misdn_add_timer(dev, tout);
2411b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (*debug & DEBUG_TIMER)
2421b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_DEBUG "%s add %d id %d\n", __func__,
243475be4d85a274d0961593db41cf85689db1d583cJoe Perches			       tout, id);
2441b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (id < 0) {
2451b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			ret = id;
2461b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
2471b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
2481b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (put_user(id, (int __user *)arg))
2491b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			ret = -EFAULT;
2501b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
2511b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	case IMDELTIMER:
2521b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (get_user(id, (int __user *)arg)) {
2531b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			ret = -EFAULT;
2541b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			break;
2551b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		}
2561b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (*debug & DEBUG_TIMER)
2571b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			printk(KERN_DEBUG "%s del id %d\n", __func__, id);
2581b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		id = misdn_del_timer(dev, id);
2591b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		if (put_user(id, (int __user *)arg))
2601b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil			ret = -EFAULT;
2611b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		break;
2621b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	default:
2631b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		ret = -EINVAL;
2641b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	}
26576a64921dad9acd76270dc74249f0dfe11c84bb8Arnd Bergmann	mutex_unlock(&mISDN_mutex);
2661b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return ret;
2671b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
2681b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
269eac74af9b547e29c9634ed5eff4d514349e73310Karsten Keilstatic const struct file_operations mISDN_fops = {
27089b107adce32a52920b36787b60c8f24c986c526Al Viro	.owner		= THIS_MODULE,
2711b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.read		= mISDN_read,
2721b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.poll		= mISDN_poll,
273703c631ebbcadcfd861d01e697fdda7c388fec9aArnd Bergmann	.unlocked_ioctl	= mISDN_ioctl,
2741b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.open		= mISDN_open,
2751b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.release	= mISDN_close,
2766038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann	.llseek		= no_llseek,
2771b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil};
2781b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2791b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilstatic struct miscdevice mISDNtimer = {
2801b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.minor	= MISC_DYNAMIC_MINOR,
2811b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.name	= "mISDNtimer",
2821b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	.fops	= &mISDN_fops,
2831b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil};
2841b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2851b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilint
286dfa96ec1bb83641242c48883c2bae8f1f30483b2Hannes EdermISDN_inittimer(u_int *deb)
2871b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
2881b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	int	err;
2891b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2901b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	debug = deb;
2911b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	err = misc_register(&mISDNtimer);
2921b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	if (err)
2931b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil		printk(KERN_WARNING "mISDN: Could not register timer device\n");
2941b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	return err;
2951b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
2961b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil
2971b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keilvoid mISDN_timer_cleanup(void)
2981b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil{
2991b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil	misc_deregister(&mISDNtimer);
3001b2b03f8e514e4f68e293846ba511a948b80243cKarsten Keil}
301