Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/irda/irda_device.c
15111 views
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 <[email protected]>
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 <[email protected]>
11
*
12
* Copyright (c) 1999-2000 Dag Brattli, All Rights Reserved.
13
* Copyright (c) 2000-2001 Jean Tourrilhes <[email protected]>
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
56
static void __irda_task_delete(struct irda_task *task);
57
58
static hashbin_t *dongles = NULL;
59
static hashbin_t *tasks = NULL;
60
61
static void irda_task_timer_expired(void *data);
62
63
int __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
85
static 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
92
void 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
*/
107
void 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
}
137
EXPORT_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
*/
146
int 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
167
static void __irda_task_delete(struct irda_task *task)
168
{
169
del_timer(&task->timer);
170
171
kfree(task);
172
}
173
174
static 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
*/
190
static 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
*/
259
static 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
*/
276
static 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
*/
295
struct net_device *alloc_irdadev(int sizeof_priv)
296
{
297
return alloc_netdev(sizeof_priv, "irda%d", irda_device_setup);
298
}
299
EXPORT_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
*/
308
void 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
}
323
EXPORT_SYMBOL(irda_setup_dma);
324
#endif
325
326