1/*********************************************************************
2 *
3 * Filename:      irda_device.c
4 * Version:       0.9
5 * Description:   Utility functions used by the device drivers
6 * Status:        Experimental.
7 * Author:        Dag Brattli <dagb@cs.uit.no>
8 * Created at:    Sat Oct  9 09:22:27 1999
9 * Modified at:   Sun Jan 23 17:41:24 2000
10 * Modified by:   Dag Brattli <dagb@cs.uit.no>
11 *
12 *     Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
13 *     Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
14 *
15 *     This program is free software; you can redistribute it and/or
16 *     modify it under the terms of the GNU General Public License as
17 *     published by the Free Software Foundation; either version 2 of
18 *     the License, or (at your option) any later version.
19 *
20 *     This program is distributed in the hope that it will be useful,
21 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
22 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 *     GNU General Public License for more details.
24 *
25 *     You should have received a copy of the GNU General Public License
26 *     along with this program; if not, write to the Free Software
27 *     Foundation, Inc., 59 Temple Place, Suite 330, Boston,
28 *     MA 02111-1307 USA
29 *
30 ********************************************************************/
31
32#include <linux/string.h>
33#include <linux/proc_fs.h>
34#include <linux/skbuff.h>
35#include <linux/capability.h>
36#include <linux/if.h>
37#include <linux/if_ether.h>
38#include <linux/if_arp.h>
39#include <linux/netdevice.h>
40#include <linux/init.h>
41#include <linux/tty.h>
42#include <linux/kmod.h>
43#include <linux/spinlock.h>
44#include <linux/slab.h>
45
46#include <asm/ioctls.h>
47#include <asm/uaccess.h>
48#include <asm/dma.h>
49#include <asm/io.h>
50
51#include <net/irda/irda_device.h>
52#include <net/irda/irlap.h>
53#include <net/irda/timer.h>
54#include <net/irda/wrapper.h>
55
56static void __irda_task_delete(struct irda_task *task);
57
58static hashbin_t *dongles = NULL;
59static hashbin_t *tasks = NULL;
60
61static void irda_task_timer_expired(void *data);
62
63int __init irda_device_init( void)
64{
65	dongles = hashbin_new(HB_NOLOCK);
66	if (dongles == NULL) {
67		IRDA_WARNING("IrDA: Can't allocate dongles hashbin!\n");
68		return -ENOMEM;
69	}
70	spin_lock_init(&dongles->hb_spinlock);
71
72	tasks = hashbin_new(HB_LOCK);
73	if (tasks == NULL) {
74		IRDA_WARNING("IrDA: Can't allocate tasks hashbin!\n");
75		hashbin_delete(dongles, NULL);
76		return -ENOMEM;
77	}
78
79	/* We no longer initialise the driver ourselves here, we let
80	 * the system do it for us... - Jean II */
81
82	return 0;
83}
84
85static void leftover_dongle(void *arg)
86{
87	struct dongle_reg *reg = arg;
88	IRDA_WARNING("IrDA: Dongle type %x not unregistered\n",
89		     reg->type);
90}
91
92void irda_device_cleanup(void)
93{
94	IRDA_DEBUG(4, "%s()\n", __func__);
95
96	hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
97
98	hashbin_delete(dongles, leftover_dongle);
99}
100
101/*
102 * Function irda_device_set_media_busy (self, status)
103 *
104 *    Called when we have detected that another station is transmitting
105 *    in contention mode.
106 */
107void irda_device_set_media_busy(struct net_device *dev, int status)
108{
109	struct irlap_cb *self;
110
111	IRDA_DEBUG(4, "%s(%s)\n", __func__, status ? "TRUE" : "FALSE");
112
113	self = (struct irlap_cb *) dev->atalk_ptr;
114
115	/* Some drivers may enable the receive interrupt before calling
116	 * irlap_open(), or they may disable the receive interrupt
117	 * after calling irlap_close().
118	 * The IrDA stack is protected from this in irlap_driver_rcv().
119	 * However, the driver calls directly the wrapper, that calls
120	 * us directly. Make sure we protect ourselves.
121	 * Jean II */
122	if (!self || self->magic != LAP_MAGIC)
123		return;
124
125	if (status) {
126		self->media_busy = TRUE;
127		if (status == SMALL)
128			irlap_start_mbusy_timer(self, SMALLBUSY_TIMEOUT);
129		else
130			irlap_start_mbusy_timer(self, MEDIABUSY_TIMEOUT);
131		IRDA_DEBUG( 4, "Media busy!\n");
132	} else {
133		self->media_busy = FALSE;
134		irlap_stop_mbusy_timer(self);
135	}
136}
137EXPORT_SYMBOL(irda_device_set_media_busy);
138
139
140/*
141 * Function irda_device_is_receiving (dev)
142 *
143 *    Check if the device driver is currently receiving data
144 *
145 */
146int irda_device_is_receiving(struct net_device *dev)
147{
148	struct if_irda_req req;
149	int ret;
150
151	IRDA_DEBUG(2, "%s()\n", __func__);
152
153	if (!dev->netdev_ops->ndo_do_ioctl) {
154		IRDA_ERROR("%s: do_ioctl not impl. by device driver\n",
155			   __func__);
156		return -1;
157	}
158
159	ret = (dev->netdev_ops->ndo_do_ioctl)(dev, (struct ifreq *) &req,
160					      SIOCGRECEIVING);
161	if (ret < 0)
162		return ret;
163
164	return req.ifr_receiving;
165}
166
167static void __irda_task_delete(struct irda_task *task)
168{
169	del_timer(&task->timer);
170
171	kfree(task);
172}
173
174static void irda_task_delete(struct irda_task *task)
175{
176	/* Unregister task */
177	hashbin_remove(tasks, (long) task, NULL);
178
179	__irda_task_delete(task);
180}
181
182/*
183 * Function irda_task_kick (task)
184 *
185 *    Tries to execute a task possible multiple times until the task is either
186 *    finished, or askes for a timeout. When a task is finished, we do post
187 *    processing, and notify the parent task, that is waiting for this task
188 *    to complete.
189 */
190static int irda_task_kick(struct irda_task *task)
191{
192	int finished = TRUE;
193	int count = 0;
194	int timeout;
195
196	IRDA_DEBUG(2, "%s()\n", __func__);
197
198	IRDA_ASSERT(task != NULL, return -1;);
199	IRDA_ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;);
200
201	/* Execute task until it's finished, or askes for a timeout */
202	do {
203		timeout = task->function(task);
204		if (count++ > 100) {
205			IRDA_ERROR("%s: error in task handler!\n",
206				   __func__);
207			irda_task_delete(task);
208			return TRUE;
209		}
210	} while ((timeout == 0) && (task->state != IRDA_TASK_DONE));
211
212	if (timeout < 0) {
213		IRDA_ERROR("%s: Error executing task!\n", __func__);
214		irda_task_delete(task);
215		return TRUE;
216	}
217
218	/* Check if we are finished */
219	if (task->state == IRDA_TASK_DONE) {
220		del_timer(&task->timer);
221
222		/* Do post processing */
223		if (task->finished)
224			task->finished(task);
225
226		/* Notify parent */
227		if (task->parent) {
228			/* Check if parent is waiting for us to complete */
229			if (task->parent->state == IRDA_TASK_CHILD_WAIT) {
230				task->parent->state = IRDA_TASK_CHILD_DONE;
231
232				/* Stop timer now that we are here */
233				del_timer(&task->parent->timer);
234
235				/* Kick parent task */
236				irda_task_kick(task->parent);
237			}
238		}
239		irda_task_delete(task);
240	} else if (timeout > 0) {
241		irda_start_timer(&task->timer, timeout, (void *) task,
242				 irda_task_timer_expired);
243		finished = FALSE;
244	} else {
245		IRDA_DEBUG(0, "%s(), not finished, and no timeout!\n",
246			   __func__);
247		finished = FALSE;
248	}
249
250	return finished;
251}
252
253/*
254 * Function irda_task_timer_expired (data)
255 *
256 *    Task time has expired. We now try to execute task (again), and restart
257 *    the timer if the task has not finished yet
258 */
259static void irda_task_timer_expired(void *data)
260{
261	struct irda_task *task;
262
263	IRDA_DEBUG(2, "%s()\n", __func__);
264
265	task = (struct irda_task *) data;
266
267	irda_task_kick(task);
268}
269
270/*
271 * Function irda_device_setup (dev)
272 *
273 *    This function should be used by low level device drivers in a similar way
274 *    as ether_setup() is used by normal network device drivers
275 */
276static void irda_device_setup(struct net_device *dev)
277{
278	dev->hard_header_len = 0;
279	dev->addr_len        = LAP_ALEN;
280
281	dev->type            = ARPHRD_IRDA;
282	dev->tx_queue_len    = 8; /* Window size + 1 s-frame */
283
284	memset(dev->broadcast, 0xff, LAP_ALEN);
285
286	dev->mtu = 2048;
287	dev->flags = IFF_NOARP;
288}
289
290/*
291 * Funciton  alloc_irdadev
292 * 	Allocates and sets up an IRDA device in a manner similar to
293 * 	alloc_etherdev.
294 */
295struct net_device *alloc_irdadev(int sizeof_priv)
296{
297	return alloc_netdev(sizeof_priv, "irda%d", irda_device_setup);
298}
299EXPORT_SYMBOL(alloc_irdadev);
300
301#ifdef CONFIG_ISA_DMA_API
302/*
303 * Function setup_dma (idev, buffer, count, mode)
304 *
305 *    Setup the DMA channel. Commonly used by LPC FIR drivers
306 *
307 */
308void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode)
309{
310	unsigned long flags;
311
312	flags = claim_dma_lock();
313
314	disable_dma(channel);
315	clear_dma_ff(channel);
316	set_dma_mode(channel, mode);
317	set_dma_addr(channel, buffer);
318	set_dma_count(channel, count);
319	enable_dma(channel);
320
321	release_dma_lock(flags);
322}
323EXPORT_SYMBOL(irda_setup_dma);
324#endif
325