OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [irda/] [irda_device.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*********************************************************************
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
 
45
#include <asm/ioctls.h>
46
#include <asm/uaccess.h>
47
#include <asm/dma.h>
48
#include <asm/io.h>
49
 
50
#include <net/irda/irda_device.h>
51
#include <net/irda/irlap.h>
52
#include <net/irda/timer.h>
53
#include <net/irda/wrapper.h>
54
 
55
static void __irda_task_delete(struct irda_task *task);
56
 
57
static hashbin_t *dongles = NULL;
58
static hashbin_t *tasks = NULL;
59
 
60
#ifdef CONFIG_IRDA_DEBUG
61
static const char *task_state[] = {
62
        "IRDA_TASK_INIT",
63
        "IRDA_TASK_DONE",
64
        "IRDA_TASK_WAIT",
65
        "IRDA_TASK_WAIT1",
66
        "IRDA_TASK_WAIT2",
67
        "IRDA_TASK_WAIT3",
68
        "IRDA_TASK_CHILD_INIT",
69
        "IRDA_TASK_CHILD_WAIT",
70
        "IRDA_TASK_CHILD_DONE",
71
};
72
#endif  /* CONFIG_IRDA_DEBUG */
73
 
74
static void irda_task_timer_expired(void *data);
75
 
76
int __init irda_device_init( void)
77
{
78
        dongles = hashbin_new(HB_NOLOCK);
79
        if (dongles == NULL) {
80
                IRDA_WARNING("IrDA: Can't allocate dongles hashbin!\n");
81
                return -ENOMEM;
82
        }
83
        spin_lock_init(&dongles->hb_spinlock);
84
 
85
        tasks = hashbin_new(HB_LOCK);
86
        if (tasks == NULL) {
87
                IRDA_WARNING("IrDA: Can't allocate tasks hashbin!\n");
88
                hashbin_delete(dongles, NULL);
89
                return -ENOMEM;
90
        }
91
 
92
        /* We no longer initialise the driver ourselves here, we let
93
         * the system do it for us... - Jean II */
94
 
95
        return 0;
96
}
97
 
98
static void leftover_dongle(void *arg)
99
{
100
        struct dongle_reg *reg = arg;
101
        IRDA_WARNING("IrDA: Dongle type %x not unregistered\n",
102
                     reg->type);
103
}
104
 
105
void irda_device_cleanup(void)
106
{
107
        IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
108
 
109
        hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete);
110
 
111
        hashbin_delete(dongles, leftover_dongle);
112
}
113
 
114
/*
115
 * Function irda_device_set_media_busy (self, status)
116
 *
117
 *    Called when we have detected that another station is transmitting
118
 *    in contention mode.
119
 */
120
void irda_device_set_media_busy(struct net_device *dev, int status)
121
{
122
        struct irlap_cb *self;
123
 
124
        IRDA_DEBUG(4, "%s(%s)\n", __FUNCTION__, status ? "TRUE" : "FALSE");
125
 
126
        self = (struct irlap_cb *) dev->atalk_ptr;
127
 
128
        /* Some drivers may enable the receive interrupt before calling
129
         * irlap_open(), or they may disable the receive interrupt
130
         * after calling irlap_close().
131
         * The IrDA stack is protected from this in irlap_driver_rcv().
132
         * However, the driver calls directly the wrapper, that calls
133
         * us directly. Make sure we protect ourselves.
134
         * Jean II */
135
        if (!self || self->magic != LAP_MAGIC)
136
                return;
137
 
138
        if (status) {
139
                self->media_busy = TRUE;
140
                if (status == SMALL)
141
                        irlap_start_mbusy_timer(self, SMALLBUSY_TIMEOUT);
142
                else
143
                        irlap_start_mbusy_timer(self, MEDIABUSY_TIMEOUT);
144
                IRDA_DEBUG( 4, "Media busy!\n");
145
        } else {
146
                self->media_busy = FALSE;
147
                irlap_stop_mbusy_timer(self);
148
        }
149
}
150
EXPORT_SYMBOL(irda_device_set_media_busy);
151
 
152
 
153
/*
154
 * Function irda_device_is_receiving (dev)
155
 *
156
 *    Check if the device driver is currently receiving data
157
 *
158
 */
159
int irda_device_is_receiving(struct net_device *dev)
160
{
161
        struct if_irda_req req;
162
        int ret;
163
 
164
        IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
165
 
166
        if (!dev->do_ioctl) {
167
                IRDA_ERROR("%s: do_ioctl not impl. by device driver\n",
168
                           __FUNCTION__);
169
                return -1;
170
        }
171
 
172
        ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCGRECEIVING);
173
        if (ret < 0)
174
                return ret;
175
 
176
        return req.ifr_receiving;
177
}
178
 
179
void irda_task_next_state(struct irda_task *task, IRDA_TASK_STATE state)
180
{
181
        IRDA_DEBUG(2, "%s(), state = %s\n", __FUNCTION__, task_state[state]);
182
 
183
        task->state = state;
184
}
185
EXPORT_SYMBOL(irda_task_next_state);
186
 
187
static void __irda_task_delete(struct irda_task *task)
188
{
189
        del_timer(&task->timer);
190
 
191
        kfree(task);
192
}
193
 
194
void irda_task_delete(struct irda_task *task)
195
{
196
        /* Unregister task */
197
        hashbin_remove(tasks, (long) task, NULL);
198
 
199
        __irda_task_delete(task);
200
}
201
EXPORT_SYMBOL(irda_task_delete);
202
 
203
/*
204
 * Function irda_task_kick (task)
205
 *
206
 *    Tries to execute a task possible multiple times until the task is either
207
 *    finished, or askes for a timeout. When a task is finished, we do post
208
 *    processing, and notify the parent task, that is waiting for this task
209
 *    to complete.
210
 */
211
static int irda_task_kick(struct irda_task *task)
212
{
213
        int finished = TRUE;
214
        int count = 0;
215
        int timeout;
216
 
217
        IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
218
 
219
        IRDA_ASSERT(task != NULL, return -1;);
220
        IRDA_ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;);
221
 
222
        /* Execute task until it's finished, or askes for a timeout */
223
        do {
224
                timeout = task->function(task);
225
                if (count++ > 100) {
226
                        IRDA_ERROR("%s: error in task handler!\n",
227
                                   __FUNCTION__);
228
                        irda_task_delete(task);
229
                        return TRUE;
230
                }
231
        } while ((timeout == 0) && (task->state != IRDA_TASK_DONE));
232
 
233
        if (timeout < 0) {
234
                IRDA_ERROR("%s: Error executing task!\n", __FUNCTION__);
235
                irda_task_delete(task);
236
                return TRUE;
237
        }
238
 
239
        /* Check if we are finished */
240
        if (task->state == IRDA_TASK_DONE) {
241
                del_timer(&task->timer);
242
 
243
                /* Do post processing */
244
                if (task->finished)
245
                        task->finished(task);
246
 
247
                /* Notify parent */
248
                if (task->parent) {
249
                        /* Check if parent is waiting for us to complete */
250
                        if (task->parent->state == IRDA_TASK_CHILD_WAIT) {
251
                                task->parent->state = IRDA_TASK_CHILD_DONE;
252
 
253
                                /* Stop timer now that we are here */
254
                                del_timer(&task->parent->timer);
255
 
256
                                /* Kick parent task */
257
                                irda_task_kick(task->parent);
258
                        }
259
                }
260
                irda_task_delete(task);
261
        } else if (timeout > 0) {
262
                irda_start_timer(&task->timer, timeout, (void *) task,
263
                                 irda_task_timer_expired);
264
                finished = FALSE;
265
        } else {
266
                IRDA_DEBUG(0, "%s(), not finished, and no timeout!\n",
267
                           __FUNCTION__);
268
                finished = FALSE;
269
        }
270
 
271
        return finished;
272
}
273
 
274
/*
275
 * Function irda_task_execute (instance, function, finished)
276
 *
277
 *    This function registers and tries to execute tasks that may take some
278
 *    time to complete. We do it this hairy way since we may have been
279
 *    called from interrupt context, so it's not possible to use
280
 *    schedule_timeout()
281
 * Two important notes :
282
 *      o Make sure you irda_task_delete(task); in case you delete the
283
 *        calling instance.
284
 *      o No real need to lock when calling this function, but you may
285
 *        want to lock within the task handler.
286
 * Jean II
287
 */
288
struct irda_task *irda_task_execute(void *instance,
289
                                    IRDA_TASK_CALLBACK function,
290
                                    IRDA_TASK_CALLBACK finished,
291
                                    struct irda_task *parent, void *param)
292
{
293
        struct irda_task *task;
294
 
295
        IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
296
 
297
        task = kmalloc(sizeof(struct irda_task), GFP_ATOMIC);
298
        if (!task)
299
                return NULL;
300
 
301
        task->state    = IRDA_TASK_INIT;
302
        task->instance = instance;
303
        task->function = function;
304
        task->finished = finished;
305
        task->parent   = parent;
306
        task->param    = param;
307
        task->magic    = IRDA_TASK_MAGIC;
308
 
309
        init_timer(&task->timer);
310
 
311
        /* Register task */
312
        hashbin_insert(tasks, (irda_queue_t *) task, (long) task, NULL);
313
 
314
        /* No time to waste, so lets get going! */
315
        return irda_task_kick(task) ? NULL : task;
316
}
317
EXPORT_SYMBOL(irda_task_execute);
318
 
319
/*
320
 * Function irda_task_timer_expired (data)
321
 *
322
 *    Task time has expired. We now try to execute task (again), and restart
323
 *    the timer if the task has not finished yet
324
 */
325
static void irda_task_timer_expired(void *data)
326
{
327
        struct irda_task *task;
328
 
329
        IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
330
 
331
        task = (struct irda_task *) data;
332
 
333
        irda_task_kick(task);
334
}
335
 
336
/*
337
 * Function irda_device_setup (dev)
338
 *
339
 *    This function should be used by low level device drivers in a similar way
340
 *    as ether_setup() is used by normal network device drivers
341
 */
342
static void irda_device_setup(struct net_device *dev)
343
{
344
        dev->hard_header_len = 0;
345
        dev->addr_len        = LAP_ALEN;
346
 
347
        dev->type            = ARPHRD_IRDA;
348
        dev->tx_queue_len    = 8; /* Window size + 1 s-frame */
349
 
350
        memset(dev->broadcast, 0xff, LAP_ALEN);
351
 
352
        dev->mtu = 2048;
353
        dev->flags = IFF_NOARP;
354
}
355
 
356
/*
357
 * Funciton  alloc_irdadev
358
 *      Allocates and sets up an IRDA device in a manner similar to
359
 *      alloc_etherdev.
360
 */
361
struct net_device *alloc_irdadev(int sizeof_priv)
362
{
363
        return alloc_netdev(sizeof_priv, "irda%d", irda_device_setup);
364
}
365
EXPORT_SYMBOL(alloc_irdadev);
366
 
367
/*
368
 * Function irda_device_init_dongle (self, type, qos)
369
 *
370
 *    Initialize attached dongle.
371
 *
372
 * Important : request_module require us to call this function with
373
 * a process context and irq enabled. - Jean II
374
 */
375
dongle_t *irda_device_dongle_init(struct net_device *dev, int type)
376
{
377
        struct dongle_reg *reg;
378
        dongle_t *dongle = kzalloc(sizeof(dongle_t), GFP_KERNEL);
379
 
380
        might_sleep();
381
 
382
        spin_lock(&dongles->hb_spinlock);
383
        reg = hashbin_find(dongles, type, NULL);
384
 
385
#ifdef CONFIG_KMOD
386
        /* Try to load the module needed */
387
        if (!reg && capable(CAP_SYS_MODULE)) {
388
                spin_unlock(&dongles->hb_spinlock);
389
 
390
                request_module("irda-dongle-%d", type);
391
 
392
                spin_lock(&dongles->hb_spinlock);
393
                reg = hashbin_find(dongles, type, NULL);
394
        }
395
#endif
396
 
397
        if (!reg || !try_module_get(reg->owner) ) {
398
                IRDA_ERROR("IrDA: Unable to find requested dongle type %x\n",
399
                           type);
400
                kfree(dongle);
401
                dongle = NULL;
402
        }
403
        if (dongle) {
404
                /* Bind the registration info to this particular instance */
405
                dongle->issue = reg;
406
                dongle->dev = dev;
407
        }
408
        spin_unlock(&dongles->hb_spinlock);
409
        return dongle;
410
}
411
EXPORT_SYMBOL(irda_device_dongle_init);
412
 
413
/*
414
 * Function irda_device_dongle_cleanup (dongle)
415
 */
416
int irda_device_dongle_cleanup(dongle_t *dongle)
417
{
418
        IRDA_ASSERT(dongle != NULL, return -1;);
419
 
420
        dongle->issue->close(dongle);
421
        module_put(dongle->issue->owner);
422
        kfree(dongle);
423
 
424
        return 0;
425
}
426
EXPORT_SYMBOL(irda_device_dongle_cleanup);
427
 
428
/*
429
 * Function irda_device_register_dongle (dongle)
430
 */
431
int irda_device_register_dongle(struct dongle_reg *new)
432
{
433
        spin_lock(&dongles->hb_spinlock);
434
        /* Check if this dongle has been registered before */
435
        if (hashbin_find(dongles, new->type, NULL)) {
436
                IRDA_MESSAGE("%s: Dongle type %x already registered\n",
437
                             __FUNCTION__, new->type);
438
        } else {
439
                /* Insert IrDA dongle into hashbin */
440
                hashbin_insert(dongles, (irda_queue_t *) new, new->type, NULL);
441
        }
442
        spin_unlock(&dongles->hb_spinlock);
443
 
444
        return 0;
445
}
446
EXPORT_SYMBOL(irda_device_register_dongle);
447
 
448
/*
449
 * Function irda_device_unregister_dongle (dongle)
450
 *
451
 *    Unregister dongle, and remove dongle from list of registered dongles
452
 *
453
 */
454
void irda_device_unregister_dongle(struct dongle_reg *dongle)
455
{
456
        struct dongle *node;
457
 
458
        spin_lock(&dongles->hb_spinlock);
459
        node = hashbin_remove(dongles, dongle->type, NULL);
460
        if (!node)
461
                IRDA_ERROR("%s: dongle not found!\n", __FUNCTION__);
462
        spin_unlock(&dongles->hb_spinlock);
463
}
464
EXPORT_SYMBOL(irda_device_unregister_dongle);
465
 
466
#ifdef CONFIG_ISA_DMA_API
467
/*
468
 * Function setup_dma (idev, buffer, count, mode)
469
 *
470
 *    Setup the DMA channel. Commonly used by LPC FIR drivers
471
 *
472
 */
473
void irda_setup_dma(int channel, dma_addr_t buffer, int count, int mode)
474
{
475
        unsigned long flags;
476
 
477
        flags = claim_dma_lock();
478
 
479
        disable_dma(channel);
480
        clear_dma_ff(channel);
481
        set_dma_mode(channel, mode);
482
        set_dma_addr(channel, buffer);
483
        set_dma_count(channel, count);
484
        enable_dma(channel);
485
 
486
        release_dma_lock(flags);
487
}
488
EXPORT_SYMBOL(irda_setup_dma);
489
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.