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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [irda/] [irqueue.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*********************************************************************
2
 *
3
 * Filename:      irqueue.c
4
 * Version:       0.3
5
 * Description:   General queue implementation
6
 * Status:        Experimental.
7
 * Author:        Dag Brattli <dagb@cs.uit.no>
8
 * Created at:    Tue Jun  9 13:29:31 1998
9
 * Modified at:   Sun Dec 12 13:48:22 1999
10
 * Modified by:   Dag Brattli <dagb@cs.uit.no>
11
 * Modified at:   Thu Jan  4 14:29:10 CET 2001
12
 * Modified by:   Marc Zyngier <mzyngier@freesurf.fr>
13
 *
14
 *     Copyright (C) 1998-1999, Aage Kvalnes <aage@cs.uit.no>
15
 *     Copyright (C) 1998, Dag Brattli,
16
 *     All Rights Reserved.
17
 *
18
 *     This code is taken from the Vortex Operating System written by Aage
19
 *     Kvalnes. Aage has agreed that this code can use the GPL licence,
20
 *     although he does not use that licence in his own code.
21
 *
22
 *     This copyright does however _not_ include the ELF hash() function
23
 *     which I currently don't know which licence or copyright it
24
 *     has. Please inform me if you know.
25
 *
26
 *     This program is free software; you can redistribute it and/or
27
 *     modify it under the terms of the GNU General Public License as
28
 *     published by the Free Software Foundation; either version 2 of
29
 *     the License, or (at your option) any later version.
30
 *
31
 *     Neither Dag Brattli nor University of Tromsø admit liability nor
32
 *     provide warranty for any of this software. This material is
33
 *     provided "AS-IS" and at no charge.
34
 *
35
 ********************************************************************/
36
 
37
#include <net/irda/irda.h>
38
#include <net/irda/irqueue.h>
39
#include <net/irda/irmod.h>
40
 
41
static irda_queue_t *dequeue_general( irda_queue_t **queue, irda_queue_t* element);
42
static __u32 hash( char* name);
43
 
44
/*
45
 * Function hashbin_create ( type, name )
46
 *
47
 *    Create hashbin!
48
 *
49
 */
50
hashbin_t *hashbin_new(int type)
51
{
52
        hashbin_t* hashbin;
53
        int i;
54
 
55
        /*
56
         * Allocate new hashbin
57
         */
58
        hashbin = kmalloc( sizeof(hashbin_t), GFP_ATOMIC);
59
        if (!hashbin)
60
                return NULL;
61
 
62
        /*
63
         * Initialize structure
64
         */
65
        memset(hashbin, 0, sizeof(hashbin_t));
66
        hashbin->hb_type = type;
67
        hashbin->magic = HB_MAGIC;
68
 
69
        /* Make sure all spinlock's are unlocked */
70
        for (i=0;i<HASHBIN_SIZE;i++)
71
                hashbin->hb_mutex[i] = SPIN_LOCK_UNLOCKED;
72
 
73
        return hashbin;
74
}
75
 
76
/*
77
 * Function hashbin_clear (hashbin, free_func)
78
 *
79
 *    Remove all entries from the hashbin, see also the comments in
80
 *    hashbin_delete() below
81
 */
82
int hashbin_clear( hashbin_t* hashbin, FREE_FUNC free_func)
83
{
84
        irda_queue_t* queue;
85
        int i;
86
 
87
        ASSERT(hashbin != NULL, return -1;);
88
        ASSERT(hashbin->magic == HB_MAGIC, return -1;);
89
 
90
        /*
91
         * Free the entries in the hashbin
92
         */
93
        for (i = 0; i < HASHBIN_SIZE; i ++ ) {
94
                queue = dequeue_first( (irda_queue_t**) &hashbin->hb_queue[i]);
95
                while (queue) {
96
                        if (free_func)
97
                                (*free_func)(queue);
98
                        queue = dequeue_first(
99
                                (irda_queue_t**) &hashbin->hb_queue[i]);
100
                }
101
        }
102
        hashbin->hb_size = 0;
103
 
104
        return 0;
105
}
106
 
107
 
108
/*
109
 * Function hashbin_delete (hashbin, free_func)
110
 *
111
 *    Destroy hashbin, the free_func can be a user supplied special routine
112
 *    for deallocating this structure if it's complex. If not the user can
113
 *    just supply kfree, which should take care of the job.
114
 */
115
int hashbin_delete( hashbin_t* hashbin, FREE_FUNC free_func)
116
{
117
        irda_queue_t* queue;
118
        int i;
119
 
120
        ASSERT(hashbin != NULL, return -1;);
121
        ASSERT(hashbin->magic == HB_MAGIC, return -1;);
122
 
123
        /*
124
         *  Free the entries in the hashbin, TODO: use hashbin_clear when
125
         *  it has been shown to work
126
         */
127
        for (i = 0; i < HASHBIN_SIZE; i ++ ) {
128
                queue = dequeue_first((irda_queue_t**) &hashbin->hb_queue[i]);
129
                while (queue ) {
130
                        if (free_func)
131
                                (*free_func)(queue);
132
                        queue = dequeue_first(
133
                                (irda_queue_t**) &hashbin->hb_queue[i]);
134
                }
135
        }
136
 
137
        /*
138
         *  Free the hashbin structure
139
         */
140
        hashbin->magic = ~HB_MAGIC;
141
        kfree(hashbin);
142
 
143
        return 0;
144
}
145
 
146
/*
147
 * Function hashbin_insert (hashbin, entry, name)
148
 *
149
 *    Insert an entry into the hashbin
150
 *
151
 */
152
void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, __u32 hashv, char* name)
153
{
154
        unsigned long flags = 0;
155
        int bin;
156
 
157
        IRDA_DEBUG( 4,"%s()\n", __FUNCTION__);
158
 
159
        ASSERT( hashbin != NULL, return;);
160
        ASSERT( hashbin->magic == HB_MAGIC, return;);
161
 
162
        /*
163
         * Locate hashbin
164
         */
165
        if ( name )
166
                hashv = hash( name );
167
        bin = GET_HASHBIN( hashv );
168
 
169
        /* Synchronize */
170
        if ( hashbin->hb_type & HB_GLOBAL ) {
171
                spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
172
 
173
        } else if ( hashbin->hb_type & HB_LOCAL ) {
174
                save_flags(flags);
175
                cli();
176
        } /* Default is no-lock  */
177
 
178
        /*
179
         * Store name and key
180
         */
181
        entry->q_hash = hashv;
182
        if ( name )
183
                strncpy( entry->q_name, name, 32);
184
 
185
        /*
186
         * Insert new entry first
187
         * TODO: Perhaps allow sorted lists?
188
         *       -> Merge sort if a sorted list should be created
189
         */
190
        if ( hashbin->hb_type & HB_SORTED) {
191
        } else {
192
                enqueue_first( (irda_queue_t**) &hashbin->hb_queue[ bin ],
193
                               entry);
194
        }
195
        hashbin->hb_size++;
196
 
197
        /* Release lock */
198
        if ( hashbin->hb_type & HB_GLOBAL) {
199
 
200
                spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags);
201
 
202
        } else if ( hashbin->hb_type & HB_LOCAL) {
203
                restore_flags( flags);
204
        }
205
}
206
 
207
/*
208
 * Function hashbin_find (hashbin, hashv, name)
209
 *
210
 *    Find item with the given hashv or name
211
 *
212
 */
213
void* hashbin_find( hashbin_t* hashbin, __u32 hashv, char* name )
214
{
215
        int bin, found = FALSE;
216
        unsigned long flags = 0;
217
        irda_queue_t* entry;
218
 
219
        IRDA_DEBUG( 4, "hashbin_find()\n");
220
 
221
        ASSERT( hashbin != NULL, return NULL;);
222
        ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
223
 
224
        /*
225
         * Locate hashbin
226
         */
227
        if ( name )
228
                hashv = hash( name );
229
        bin = GET_HASHBIN( hashv );
230
 
231
        /* Synchronize */
232
        if ( hashbin->hb_type & HB_GLOBAL ) {
233
                spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
234
 
235
        } else if ( hashbin->hb_type & HB_LOCAL ) {
236
                save_flags(flags);
237
                cli();
238
        } /* Default is no-lock  */
239
 
240
        /*
241
         * Search for entry
242
         */
243
        entry = hashbin->hb_queue[ bin];
244
        if ( entry ) {
245
                do {
246
                        /*
247
                         * Check for key
248
                         */
249
                        if ( entry->q_hash == hashv ) {
250
                                /*
251
                                 * Name compare too?
252
                                 */
253
                                if ( name ) {
254
                                        if ( strcmp( entry->q_name, name ) == 0 ) {
255
                                                found = TRUE;
256
                                                break;
257
                                        }
258
                                } else {
259
                                        found = TRUE;
260
                                        break;
261
                                }
262
                        }
263
                        entry = entry->q_next;
264
                } while ( entry != hashbin->hb_queue[ bin ] );
265
        }
266
 
267
        /* Release lock */
268
        if ( hashbin->hb_type & HB_GLOBAL) {
269
                spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags);
270
 
271
        } else if ( hashbin->hb_type & HB_LOCAL) {
272
                restore_flags( flags);
273
        }
274
 
275
        if ( found )
276
                return entry;
277
        else
278
                return NULL;
279
}
280
 
281
void *hashbin_remove_first( hashbin_t *hashbin)
282
{
283
        unsigned long flags;
284
        irda_queue_t *entry = NULL;
285
 
286
        save_flags(flags);
287
        cli();
288
 
289
        entry = hashbin_get_first( hashbin);
290
        if ( entry != NULL)
291
                hashbin_remove( hashbin, entry->q_hash, NULL);
292
 
293
        restore_flags( flags);
294
 
295
        return entry;
296
}
297
 
298
 
299
/*
300
 *  Function hashbin_remove (hashbin, hashv, name)
301
 *
302
 *    Remove entry with the given name
303
 *
304
 */
305
void* hashbin_remove( hashbin_t* hashbin, __u32 hashv, char* name)
306
{
307
        int bin, found = FALSE;
308
        unsigned long flags = 0;
309
        irda_queue_t* entry;
310
 
311
        IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
312
 
313
        ASSERT( hashbin != NULL, return NULL;);
314
        ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
315
 
316
        /*
317
         * Locate hashbin
318
         */
319
        if ( name )
320
                hashv = hash( name );
321
        bin = GET_HASHBIN( hashv );
322
 
323
        /* Synchronize */
324
        if ( hashbin->hb_type & HB_GLOBAL ) {
325
                spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
326
 
327
        } else if ( hashbin->hb_type & HB_LOCAL ) {
328
                save_flags(flags);
329
                cli();
330
        } /* Default is no-lock  */
331
 
332
        /*
333
         * Search for entry
334
         */
335
        entry = hashbin->hb_queue[ bin ];
336
        if ( entry ) {
337
                do {
338
                        /*
339
                         * Check for key
340
                         */
341
                        if ( entry->q_hash == hashv ) {
342
                                /*
343
                                 * Name compare too?
344
                                 */
345
                                if ( name ) {
346
                                        if ( strcmp( entry->q_name, name) == 0)
347
                                        {
348
                                                found = TRUE;
349
                                                break;
350
                                        }
351
                                } else {
352
                                        found = TRUE;
353
                                        break;
354
                                }
355
                        }
356
                        entry = entry->q_next;
357
                } while ( entry != hashbin->hb_queue[ bin ] );
358
        }
359
 
360
        /*
361
         * If entry was found, dequeue it
362
         */
363
        if ( found ) {
364
                dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
365
                                 (irda_queue_t*) entry );
366
                hashbin->hb_size--;
367
 
368
                /*
369
                 *  Check if this item is the currently selected item, and in
370
                 *  that case we must reset hb_current
371
                 */
372
                if ( entry == hashbin->hb_current)
373
                        hashbin->hb_current = NULL;
374
        }
375
 
376
        /* Release lock */
377
        if ( hashbin->hb_type & HB_GLOBAL) {
378
                spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags);
379
 
380
        } else if ( hashbin->hb_type & HB_LOCAL) {
381
                restore_flags( flags);
382
        }
383
 
384
 
385
        /* Return */
386
        if ( found )
387
                return entry;
388
        else
389
                return NULL;
390
 
391
}
392
 
393
/*
394
 *  Function hashbin_remove (hashbin, hashv, name)
395
 *
396
 *    Remove entry with the given name
397
 *
398
 * In some cases, the user of hashbin can't guarantee the unicity
399
 * of either the hashv or name.
400
 * In those cases, using the above function is guaranteed to cause troubles,
401
 * so we use this one instead...
402
 * And by the way, it's also faster, because we skip the search phase ;-)
403
 */
404
void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry)
405
{
406
        unsigned long flags = 0;
407
        int     bin;
408
        __u32   hashv;
409
 
410
        IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
411
 
412
        ASSERT( hashbin != NULL, return NULL;);
413
        ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
414
        ASSERT( entry != NULL, return NULL;);
415
 
416
        /* Check if valid and not already removed... */
417
        if((entry->q_next == NULL) || (entry->q_prev == NULL))
418
                return NULL;
419
 
420
        /*
421
         * Locate hashbin
422
         */
423
        hashv = entry->q_hash;
424
        bin = GET_HASHBIN( hashv );
425
 
426
        /* Synchronize */
427
        if ( hashbin->hb_type & HB_GLOBAL ) {
428
                spin_lock_irqsave( &hashbin->hb_mutex[ bin ], flags);
429
 
430
        } else if ( hashbin->hb_type & HB_LOCAL ) {
431
                save_flags(flags);
432
                cli();
433
        } /* Default is no-lock  */
434
 
435
        /*
436
         * Dequeue the entry...
437
         */
438
        dequeue_general( (irda_queue_t**) &hashbin->hb_queue[ bin ],
439
                         (irda_queue_t*) entry );
440
        hashbin->hb_size--;
441
        entry->q_next = NULL;
442
        entry->q_prev = NULL;
443
 
444
        /*
445
         *  Check if this item is the currently selected item, and in
446
         *  that case we must reset hb_current
447
         */
448
        if ( entry == hashbin->hb_current)
449
                hashbin->hb_current = NULL;
450
 
451
        /* Release lock */
452
        if ( hashbin->hb_type & HB_GLOBAL) {
453
                spin_unlock_irqrestore( &hashbin->hb_mutex[ bin], flags);
454
 
455
        } else if ( hashbin->hb_type & HB_LOCAL) {
456
                restore_flags( flags);
457
        }
458
 
459
        return entry;
460
}
461
 
462
/*
463
 * Function hashbin_get_first (hashbin)
464
 *
465
 *    Get a pointer to first element in hashbin, this function must be
466
 *    called before any calls to hashbin_get_next()!
467
 *
468
 */
469
irda_queue_t *hashbin_get_first( hashbin_t* hashbin)
470
{
471
        irda_queue_t *entry;
472
        int i;
473
 
474
        ASSERT( hashbin != NULL, return NULL;);
475
        ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
476
 
477
        if ( hashbin == NULL)
478
                return NULL;
479
 
480
        for ( i = 0; i < HASHBIN_SIZE; i ++ ) {
481
                entry = hashbin->hb_queue[ i];
482
                if ( entry) {
483
                        hashbin->hb_current = entry;
484
                        return entry;
485
                }
486
        }
487
        /*
488
         *  Did not find any item in hashbin
489
         */
490
        return NULL;
491
}
492
 
493
/*
494
 * Function hashbin_get_next (hashbin)
495
 *
496
 *    Get next item in hashbin. A series of hashbin_get_next() calls must
497
 *    be started by a call to hashbin_get_first(). The function returns
498
 *    NULL when all items have been traversed
499
 *
500
 */
501
irda_queue_t *hashbin_get_next( hashbin_t *hashbin)
502
{
503
        irda_queue_t* entry;
504
        int bin;
505
        int i;
506
 
507
        ASSERT( hashbin != NULL, return NULL;);
508
        ASSERT( hashbin->magic == HB_MAGIC, return NULL;);
509
 
510
        if ( hashbin->hb_current == NULL) {
511
                ASSERT( hashbin->hb_current != NULL, return NULL;);
512
                return NULL;
513
        }
514
        entry = hashbin->hb_current->q_next;
515
        bin = GET_HASHBIN( entry->q_hash);
516
 
517
        /*
518
         *  Make sure that we are not back at the beginning of the queue
519
         *  again
520
         */
521
        if ( entry != hashbin->hb_queue[ bin ]) {
522
                hashbin->hb_current = entry;
523
 
524
                return entry;
525
        }
526
 
527
        /*
528
         *  Check that this is not the last queue in hashbin
529
         */
530
        if ( bin >= HASHBIN_SIZE)
531
                return NULL;
532
 
533
        /*
534
         *  Move to next queue in hashbin
535
         */
536
        bin++;
537
        for ( i = bin; i < HASHBIN_SIZE; i++ ) {
538
                entry = hashbin->hb_queue[ i];
539
                if ( entry) {
540
                        hashbin->hb_current = entry;
541
 
542
                        return entry;
543
                }
544
        }
545
        return NULL;
546
}
547
 
548
/*
549
 * Function enqueue_last (queue, proc)
550
 *
551
 *    Insert item into end of queue.
552
 *
553
 */
554
static void __enqueue_last( irda_queue_t **queue, irda_queue_t* element)
555
{
556
        IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
557
 
558
        /*
559
         * Check if queue is empty.
560
         */
561
        if ( *queue == NULL ) {
562
                /*
563
                 * Queue is empty.  Insert one element into the queue.
564
                 */
565
                element->q_next = element->q_prev = *queue = element;
566
 
567
        } else {
568
                /*
569
                 * Queue is not empty.  Insert element into end of queue.
570
                 */
571
                element->q_prev         = (*queue)->q_prev;
572
                element->q_prev->q_next = element;
573
                (*queue)->q_prev        = element;
574
                element->q_next         = *queue;
575
        }
576
}
577
 
578
inline void enqueue_last( irda_queue_t **queue, irda_queue_t* element)
579
{
580
        unsigned long flags;
581
 
582
        save_flags(flags);
583
        cli();
584
 
585
        __enqueue_last( queue, element);
586
 
587
        restore_flags(flags);
588
}
589
 
590
/*
591
 * Function enqueue_first (queue, proc)
592
 *
593
 *    Insert item first in queue.
594
 *
595
 */
596
void enqueue_first(irda_queue_t **queue, irda_queue_t* element)
597
{
598
 
599
        IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
600
 
601
        /*
602
         * Check if queue is empty.
603
         */
604
        if ( *queue == NULL ) {
605
                /*
606
                 * Queue is empty.  Insert one element into the queue.
607
                 */
608
                element->q_next = element->q_prev = *queue = element;
609
 
610
        } else {
611
                /*
612
                 * Queue is not empty.  Insert element into front of queue.
613
                 */
614
                element->q_next          = (*queue);
615
                (*queue)->q_prev->q_next = element;
616
                element->q_prev          = (*queue)->q_prev;
617
                (*queue)->q_prev         = element;
618
                (*queue)                 = element;
619
        }
620
}
621
 
622
/*
623
 * Function enqueue_queue (queue, list)
624
 *
625
 *    Insert a queue (list) into the start of the first queue
626
 *
627
 */
628
void enqueue_queue( irda_queue_t** queue, irda_queue_t** list )
629
{
630
        irda_queue_t* tmp;
631
 
632
        /*
633
         * Check if queue is empty
634
         */
635
        if ( *queue ) {
636
                (*list)->q_prev->q_next  = (*queue);
637
                (*queue)->q_prev->q_next = (*list);
638
                tmp                      = (*list)->q_prev;
639
                (*list)->q_prev          = (*queue)->q_prev;
640
                (*queue)->q_prev         = tmp;
641
        } else {
642
                *queue                   = (*list);
643
        }
644
 
645
        (*list) = NULL;
646
}
647
 
648
/*
649
 * Function enqueue_second (queue, proc)
650
 *
651
 *    Insert item behind head of queue.
652
 *
653
 */
654
#if 0
655
static void enqueue_second(irda_queue_t **queue, irda_queue_t* element)
656
{
657
        IRDA_DEBUG( 0, "enqueue_second()\n");
658
 
659
        /*
660
         * Check if queue is empty.
661
         */
662
        if ( *queue == NULL ) {
663
                /*
664
                 * Queue is empty.  Insert one element into the queue.
665
                 */
666
                element->q_next = element->q_prev = *queue = element;
667
 
668
        } else {
669
                /*
670
                 * Queue is not empty.  Insert element into ..
671
                 */
672
                element->q_prev = (*queue);
673
                (*queue)->q_next->q_prev = element;
674
                element->q_next = (*queue)->q_next;
675
                (*queue)->q_next = element;
676
        }
677
}
678
#endif
679
 
680
/*
681
 * Function dequeue (queue)
682
 *
683
 *    Remove first entry in queue
684
 *
685
 */
686
irda_queue_t *dequeue_first(irda_queue_t **queue)
687
{
688
        irda_queue_t *ret;
689
 
690
        IRDA_DEBUG( 4, "dequeue_first()\n");
691
 
692
        /*
693
         * Set return value
694
         */
695
        ret =  *queue;
696
 
697
        if ( *queue == NULL ) {
698
                /*
699
                 * Queue was empty.
700
                 */
701
        } else if ( (*queue)->q_next == *queue ) {
702
                /*
703
                 *  Queue only contained a single element. It will now be
704
                 *  empty.
705
                 */
706
                *queue = NULL;
707
        } else {
708
                /*
709
                 * Queue contained several element.  Remove the first one.
710
                 */
711
                (*queue)->q_prev->q_next = (*queue)->q_next;
712
                (*queue)->q_next->q_prev = (*queue)->q_prev;
713
                *queue = (*queue)->q_next;
714
        }
715
 
716
        /*
717
         * Return the removed entry (or NULL of queue was empty).
718
         */
719
        return ret;
720
}
721
 
722
/*
723
 * Function dequeue_general (queue, element)
724
 *
725
 *
726
 */
727
static irda_queue_t *dequeue_general(irda_queue_t **queue, irda_queue_t* element)
728
{
729
        irda_queue_t *ret;
730
 
731
        IRDA_DEBUG( 4, "dequeue_general()\n");
732
 
733
        /*
734
         * Set return value
735
         */
736
        ret =  *queue;
737
 
738
        if ( *queue == NULL ) {
739
                /*
740
                 * Queue was empty.
741
                 */
742
        } else if ( (*queue)->q_next == *queue ) {
743
                /*
744
                 *  Queue only contained a single element. It will now be
745
                 *  empty.
746
                 */
747
                *queue = NULL;
748
 
749
        } else {
750
                /*
751
                 *  Remove specific element.
752
                 */
753
                element->q_prev->q_next = element->q_next;
754
                element->q_next->q_prev = element->q_prev;
755
                if ( (*queue) == element)
756
                        (*queue) = element->q_next;
757
        }
758
 
759
        /*
760
         * Return the removed entry (or NULL of queue was empty).
761
         */
762
        return ret;
763
}
764
 
765
/*
766
 * Function hash (name)
767
 *
768
 *    This function hash the input string 'name' using the ELF hash
769
 *    function for strings.
770
 */
771
static __u32 hash( char* name)
772
{
773
        __u32 h = 0;
774
        __u32 g;
775
 
776
        while(*name) {
777
                h = (h<<4) + *name++;
778
                if ((g = (h & 0xf0000000)))
779
                        h ^=g>>24;
780
                h &=~g;
781
        }
782
        return h;
783
}

powered by: WebSVN 2.1.0

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