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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [bluetooth/] [dtl1_cs.c] - Blame information for rev 67

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *
3
 *  A driver for Nokia Connectivity Card DTL-1 devices
4
 *
5
 *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
6
 *
7
 *
8
 *  This program is free software; you can redistribute it and/or modify
9
 *  it under the terms of the GNU General Public License version 2 as
10
 *  published by the Free Software Foundation;
11
 *
12
 *  Software distributed under the License is distributed on an "AS
13
 *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14
 *  implied. See the License for the specific language governing
15
 *  rights and limitations under the License.
16
 *
17
 *  The initial developer of the original code is David A. Hinds
18
 *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
19
 *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
20
 *
21
 */
22
 
23
#include <linux/module.h>
24
 
25
#include <linux/kernel.h>
26
#include <linux/init.h>
27
#include <linux/slab.h>
28
#include <linux/types.h>
29
#include <linux/delay.h>
30
#include <linux/errno.h>
31
#include <linux/ptrace.h>
32
#include <linux/ioport.h>
33
#include <linux/spinlock.h>
34
#include <linux/moduleparam.h>
35
 
36
#include <linux/skbuff.h>
37
#include <linux/string.h>
38
#include <linux/serial.h>
39
#include <linux/serial_reg.h>
40
#include <linux/bitops.h>
41
#include <asm/system.h>
42
#include <asm/io.h>
43
 
44
#include <pcmcia/cs_types.h>
45
#include <pcmcia/cs.h>
46
#include <pcmcia/cistpl.h>
47
#include <pcmcia/ciscode.h>
48
#include <pcmcia/ds.h>
49
#include <pcmcia/cisreg.h>
50
 
51
#include <net/bluetooth/bluetooth.h>
52
#include <net/bluetooth/hci_core.h>
53
 
54
 
55
 
56
/* ======================== Module parameters ======================== */
57
 
58
 
59
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
60
MODULE_DESCRIPTION("Bluetooth driver for Nokia Connectivity Card DTL-1");
61
MODULE_LICENSE("GPL");
62
 
63
 
64
 
65
/* ======================== Local structures ======================== */
66
 
67
 
68
typedef struct dtl1_info_t {
69
        struct pcmcia_device *p_dev;
70
        dev_node_t node;
71
 
72
        struct hci_dev *hdev;
73
 
74
        spinlock_t lock;                /* For serializing operations */
75
 
76
        unsigned long flowmask;         /* HCI flow mask */
77
        int ri_latch;
78
 
79
        struct sk_buff_head txq;
80
        unsigned long tx_state;
81
 
82
        unsigned long rx_state;
83
        unsigned long rx_count;
84
        struct sk_buff *rx_skb;
85
} dtl1_info_t;
86
 
87
 
88
static int dtl1_config(struct pcmcia_device *link);
89
static void dtl1_release(struct pcmcia_device *link);
90
 
91
static void dtl1_detach(struct pcmcia_device *p_dev);
92
 
93
 
94
/* Transmit states  */
95
#define XMIT_SENDING  1
96
#define XMIT_WAKEUP   2
97
#define XMIT_WAITING  8
98
 
99
/* Receiver States */
100
#define RECV_WAIT_NSH   0
101
#define RECV_WAIT_DATA  1
102
 
103
 
104
typedef struct {
105
        u8 type;
106
        u8 zero;
107
        u16 len;
108
} __attribute__ ((packed)) nsh_t;       /* Nokia Specific Header */
109
 
110
#define NSHL  4                         /* Nokia Specific Header Length */
111
 
112
 
113
 
114
/* ======================== Interrupt handling ======================== */
115
 
116
 
117
static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
118
{
119
        int actual = 0;
120
 
121
        /* Tx FIFO should be empty */
122
        if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
123
                return 0;
124
 
125
        /* Fill FIFO with current frame */
126
        while ((fifo_size-- > 0) && (actual < len)) {
127
                /* Transmit next byte */
128
                outb(buf[actual], iobase + UART_TX);
129
                actual++;
130
        }
131
 
132
        return actual;
133
}
134
 
135
 
136
static void dtl1_write_wakeup(dtl1_info_t *info)
137
{
138
        if (!info) {
139
                BT_ERR("Unknown device");
140
                return;
141
        }
142
 
143
        if (test_bit(XMIT_WAITING, &(info->tx_state))) {
144
                set_bit(XMIT_WAKEUP, &(info->tx_state));
145
                return;
146
        }
147
 
148
        if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
149
                set_bit(XMIT_WAKEUP, &(info->tx_state));
150
                return;
151
        }
152
 
153
        do {
154
                register unsigned int iobase = info->p_dev->io.BasePort1;
155
                register struct sk_buff *skb;
156
                register int len;
157
 
158
                clear_bit(XMIT_WAKEUP, &(info->tx_state));
159
 
160
                if (!pcmcia_dev_present(info->p_dev))
161
                        return;
162
 
163
                if (!(skb = skb_dequeue(&(info->txq))))
164
                        break;
165
 
166
                /* Send frame */
167
                len = dtl1_write(iobase, 32, skb->data, skb->len);
168
 
169
                if (len == skb->len) {
170
                        set_bit(XMIT_WAITING, &(info->tx_state));
171
                        kfree_skb(skb);
172
                } else {
173
                        skb_pull(skb, len);
174
                        skb_queue_head(&(info->txq), skb);
175
                }
176
 
177
                info->hdev->stat.byte_tx += len;
178
 
179
        } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
180
 
181
        clear_bit(XMIT_SENDING, &(info->tx_state));
182
}
183
 
184
 
185
static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
186
{
187
        u8 flowmask = *(u8 *)skb->data;
188
        int i;
189
 
190
        printk(KERN_INFO "Bluetooth: Nokia control data =");
191
        for (i = 0; i < skb->len; i++) {
192
                printk(" %02x", skb->data[i]);
193
        }
194
        printk("\n");
195
 
196
        /* transition to active state */
197
        if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
198
                clear_bit(XMIT_WAITING, &(info->tx_state));
199
                dtl1_write_wakeup(info);
200
        }
201
 
202
        info->flowmask = flowmask;
203
 
204
        kfree_skb(skb);
205
}
206
 
207
 
208
static void dtl1_receive(dtl1_info_t *info)
209
{
210
        unsigned int iobase;
211
        nsh_t *nsh;
212
        int boguscount = 0;
213
 
214
        if (!info) {
215
                BT_ERR("Unknown device");
216
                return;
217
        }
218
 
219
        iobase = info->p_dev->io.BasePort1;
220
 
221
        do {
222
                info->hdev->stat.byte_rx++;
223
 
224
                /* Allocate packet */
225
                if (info->rx_skb == NULL)
226
                        if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
227
                                BT_ERR("Can't allocate mem for new packet");
228
                                info->rx_state = RECV_WAIT_NSH;
229
                                info->rx_count = NSHL;
230
                                return;
231
                        }
232
 
233
                *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
234
                nsh = (nsh_t *)info->rx_skb->data;
235
 
236
                info->rx_count--;
237
 
238
                if (info->rx_count == 0) {
239
 
240
                        switch (info->rx_state) {
241
                        case RECV_WAIT_NSH:
242
                                info->rx_state = RECV_WAIT_DATA;
243
                                info->rx_count = nsh->len + (nsh->len & 0x0001);
244
                                break;
245
                        case RECV_WAIT_DATA:
246
                                bt_cb(info->rx_skb)->pkt_type = nsh->type;
247
 
248
                                /* remove PAD byte if it exists */
249
                                if (nsh->len & 0x0001) {
250
                                        info->rx_skb->tail--;
251
                                        info->rx_skb->len--;
252
                                }
253
 
254
                                /* remove NSH */
255
                                skb_pull(info->rx_skb, NSHL);
256
 
257
                                switch (bt_cb(info->rx_skb)->pkt_type) {
258
                                case 0x80:
259
                                        /* control data for the Nokia Card */
260
                                        dtl1_control(info, info->rx_skb);
261
                                        break;
262
                                case 0x82:
263
                                case 0x83:
264
                                case 0x84:
265
                                        /* send frame to the HCI layer */
266
                                        info->rx_skb->dev = (void *) info->hdev;
267
                                        bt_cb(info->rx_skb)->pkt_type &= 0x0f;
268
                                        hci_recv_frame(info->rx_skb);
269
                                        break;
270
                                default:
271
                                        /* unknown packet */
272
                                        BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
273
                                        kfree_skb(info->rx_skb);
274
                                        break;
275
                                }
276
 
277
                                info->rx_state = RECV_WAIT_NSH;
278
                                info->rx_count = NSHL;
279
                                info->rx_skb = NULL;
280
                                break;
281
                        }
282
 
283
                }
284
 
285
                /* Make sure we don't stay here too long */
286
                if (boguscount++ > 32)
287
                        break;
288
 
289
        } while (inb(iobase + UART_LSR) & UART_LSR_DR);
290
}
291
 
292
 
293
static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
294
{
295
        dtl1_info_t *info = dev_inst;
296
        unsigned int iobase;
297
        unsigned char msr;
298
        int boguscount = 0;
299
        int iir, lsr;
300
 
301
        BUG_ON(!info->hdev);
302
 
303
        iobase = info->p_dev->io.BasePort1;
304
 
305
        spin_lock(&(info->lock));
306
 
307
        iir = inb(iobase + UART_IIR) & UART_IIR_ID;
308
        while (iir) {
309
 
310
                /* Clear interrupt */
311
                lsr = inb(iobase + UART_LSR);
312
 
313
                switch (iir) {
314
                case UART_IIR_RLSI:
315
                        BT_ERR("RLSI");
316
                        break;
317
                case UART_IIR_RDI:
318
                        /* Receive interrupt */
319
                        dtl1_receive(info);
320
                        break;
321
                case UART_IIR_THRI:
322
                        if (lsr & UART_LSR_THRE) {
323
                                /* Transmitter ready for data */
324
                                dtl1_write_wakeup(info);
325
                        }
326
                        break;
327
                default:
328
                        BT_ERR("Unhandled IIR=%#x", iir);
329
                        break;
330
                }
331
 
332
                /* Make sure we don't stay here too long */
333
                if (boguscount++ > 100)
334
                        break;
335
 
336
                iir = inb(iobase + UART_IIR) & UART_IIR_ID;
337
 
338
        }
339
 
340
        msr = inb(iobase + UART_MSR);
341
 
342
        if (info->ri_latch ^ (msr & UART_MSR_RI)) {
343
                info->ri_latch = msr & UART_MSR_RI;
344
                clear_bit(XMIT_WAITING, &(info->tx_state));
345
                dtl1_write_wakeup(info);
346
        }
347
 
348
        spin_unlock(&(info->lock));
349
 
350
        return IRQ_HANDLED;
351
}
352
 
353
 
354
 
355
/* ======================== HCI interface ======================== */
356
 
357
 
358
static int dtl1_hci_open(struct hci_dev *hdev)
359
{
360
        set_bit(HCI_RUNNING, &(hdev->flags));
361
 
362
        return 0;
363
}
364
 
365
 
366
static int dtl1_hci_flush(struct hci_dev *hdev)
367
{
368
        dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
369
 
370
        /* Drop TX queue */
371
        skb_queue_purge(&(info->txq));
372
 
373
        return 0;
374
}
375
 
376
 
377
static int dtl1_hci_close(struct hci_dev *hdev)
378
{
379
        if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
380
                return 0;
381
 
382
        dtl1_hci_flush(hdev);
383
 
384
        return 0;
385
}
386
 
387
 
388
static int dtl1_hci_send_frame(struct sk_buff *skb)
389
{
390
        dtl1_info_t *info;
391
        struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
392
        struct sk_buff *s;
393
        nsh_t nsh;
394
 
395
        if (!hdev) {
396
                BT_ERR("Frame for unknown HCI device (hdev=NULL)");
397
                return -ENODEV;
398
        }
399
 
400
        info = (dtl1_info_t *)(hdev->driver_data);
401
 
402
        switch (bt_cb(skb)->pkt_type) {
403
        case HCI_COMMAND_PKT:
404
                hdev->stat.cmd_tx++;
405
                nsh.type = 0x81;
406
                break;
407
        case HCI_ACLDATA_PKT:
408
                hdev->stat.acl_tx++;
409
                nsh.type = 0x82;
410
                break;
411
        case HCI_SCODATA_PKT:
412
                hdev->stat.sco_tx++;
413
                nsh.type = 0x83;
414
                break;
415
        };
416
 
417
        nsh.zero = 0;
418
        nsh.len = skb->len;
419
 
420
        s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
421
        if (!s)
422
                return -ENOMEM;
423
 
424
        skb_reserve(s, NSHL);
425
        skb_copy_from_linear_data(skb, skb_put(s, skb->len), skb->len);
426
        if (skb->len & 0x0001)
427
                *skb_put(s, 1) = 0;      /* PAD */
428
 
429
        /* Prepend skb with Nokia frame header and queue */
430
        memcpy(skb_push(s, NSHL), &nsh, NSHL);
431
        skb_queue_tail(&(info->txq), s);
432
 
433
        dtl1_write_wakeup(info);
434
 
435
        kfree_skb(skb);
436
 
437
        return 0;
438
}
439
 
440
 
441
static void dtl1_hci_destruct(struct hci_dev *hdev)
442
{
443
}
444
 
445
 
446
static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,  unsigned long arg)
447
{
448
        return -ENOIOCTLCMD;
449
}
450
 
451
 
452
 
453
/* ======================== Card services HCI interaction ======================== */
454
 
455
 
456
static int dtl1_open(dtl1_info_t *info)
457
{
458
        unsigned long flags;
459
        unsigned int iobase = info->p_dev->io.BasePort1;
460
        struct hci_dev *hdev;
461
 
462
        spin_lock_init(&(info->lock));
463
 
464
        skb_queue_head_init(&(info->txq));
465
 
466
        info->rx_state = RECV_WAIT_NSH;
467
        info->rx_count = NSHL;
468
        info->rx_skb = NULL;
469
 
470
        set_bit(XMIT_WAITING, &(info->tx_state));
471
 
472
        /* Initialize HCI device */
473
        hdev = hci_alloc_dev();
474
        if (!hdev) {
475
                BT_ERR("Can't allocate HCI device");
476
                return -ENOMEM;
477
        }
478
 
479
        info->hdev = hdev;
480
 
481
        hdev->type = HCI_PCCARD;
482
        hdev->driver_data = info;
483
        SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
484
 
485
        hdev->open     = dtl1_hci_open;
486
        hdev->close    = dtl1_hci_close;
487
        hdev->flush    = dtl1_hci_flush;
488
        hdev->send     = dtl1_hci_send_frame;
489
        hdev->destruct = dtl1_hci_destruct;
490
        hdev->ioctl    = dtl1_hci_ioctl;
491
 
492
        hdev->owner = THIS_MODULE;
493
 
494
        spin_lock_irqsave(&(info->lock), flags);
495
 
496
        /* Reset UART */
497
        outb(0, iobase + UART_MCR);
498
 
499
        /* Turn off interrupts */
500
        outb(0, iobase + UART_IER);
501
 
502
        /* Initialize UART */
503
        outb(UART_LCR_WLEN8, iobase + UART_LCR);        /* Reset DLAB */
504
        outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
505
 
506
        info->ri_latch = inb(info->p_dev->io.BasePort1 + UART_MSR) & UART_MSR_RI;
507
 
508
        /* Turn on interrupts */
509
        outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
510
 
511
        spin_unlock_irqrestore(&(info->lock), flags);
512
 
513
        /* Timeout before it is safe to send the first HCI packet */
514
        msleep(2000);
515
 
516
        /* Register HCI device */
517
        if (hci_register_dev(hdev) < 0) {
518
                BT_ERR("Can't register HCI device");
519
                info->hdev = NULL;
520
                hci_free_dev(hdev);
521
                return -ENODEV;
522
        }
523
 
524
        return 0;
525
}
526
 
527
 
528
static int dtl1_close(dtl1_info_t *info)
529
{
530
        unsigned long flags;
531
        unsigned int iobase = info->p_dev->io.BasePort1;
532
        struct hci_dev *hdev = info->hdev;
533
 
534
        if (!hdev)
535
                return -ENODEV;
536
 
537
        dtl1_hci_close(hdev);
538
 
539
        spin_lock_irqsave(&(info->lock), flags);
540
 
541
        /* Reset UART */
542
        outb(0, iobase + UART_MCR);
543
 
544
        /* Turn off interrupts */
545
        outb(0, iobase + UART_IER);
546
 
547
        spin_unlock_irqrestore(&(info->lock), flags);
548
 
549
        if (hci_unregister_dev(hdev) < 0)
550
                BT_ERR("Can't unregister HCI device %s", hdev->name);
551
 
552
        hci_free_dev(hdev);
553
 
554
        return 0;
555
}
556
 
557
static int dtl1_probe(struct pcmcia_device *link)
558
{
559
        dtl1_info_t *info;
560
 
561
        /* Create new info device */
562
        info = kzalloc(sizeof(*info), GFP_KERNEL);
563
        if (!info)
564
                return -ENOMEM;
565
 
566
        info->p_dev = link;
567
        link->priv = info;
568
 
569
        link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
570
        link->io.NumPorts1 = 8;
571
        link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
572
        link->irq.IRQInfo1 = IRQ_LEVEL_ID;
573
 
574
        link->irq.Handler = dtl1_interrupt;
575
        link->irq.Instance = info;
576
 
577
        link->conf.Attributes = CONF_ENABLE_IRQ;
578
        link->conf.IntType = INT_MEMORY_AND_IO;
579
 
580
        return dtl1_config(link);
581
}
582
 
583
 
584
static void dtl1_detach(struct pcmcia_device *link)
585
{
586
        dtl1_info_t *info = link->priv;
587
 
588
        dtl1_release(link);
589
 
590
        kfree(info);
591
}
592
 
593
static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
594
{
595
        int i;
596
 
597
        i = pcmcia_get_tuple_data(handle, tuple);
598
        if (i != CS_SUCCESS)
599
                return i;
600
 
601
        return pcmcia_parse_tuple(handle, tuple, parse);
602
}
603
 
604
static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
605
{
606
        if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS)
607
                return CS_NO_MORE_ITEMS;
608
        return get_tuple(handle, tuple, parse);
609
}
610
 
611
static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse)
612
{
613
        if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS)
614
                return CS_NO_MORE_ITEMS;
615
        return get_tuple(handle, tuple, parse);
616
}
617
 
618
static int dtl1_config(struct pcmcia_device *link)
619
{
620
        dtl1_info_t *info = link->priv;
621
        tuple_t tuple;
622
        u_short buf[256];
623
        cisparse_t parse;
624
        cistpl_cftable_entry_t *cf = &parse.cftable_entry;
625
        int i;
626
 
627
        tuple.TupleData = (cisdata_t *)buf;
628
        tuple.TupleOffset = 0;
629
        tuple.TupleDataMax = 255;
630
        tuple.Attributes = 0;
631
        tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
632
 
633
        /* Look for a generic full-sized window */
634
        link->io.NumPorts1 = 8;
635
        i = first_tuple(link, &tuple, &parse);
636
        while (i != CS_NO_MORE_ITEMS) {
637
                if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
638
                        link->conf.ConfigIndex = cf->index;
639
                        link->io.BasePort1 = cf->io.win[0].base;
640
                        link->io.NumPorts1 = cf->io.win[0].len;  /*yo */
641
                        link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
642
                        i = pcmcia_request_io(link, &link->io);
643
                        if (i == CS_SUCCESS)
644
                                break;
645
                }
646
                i = next_tuple(link, &tuple, &parse);
647
        }
648
 
649
        if (i != CS_SUCCESS) {
650
                cs_error(link, RequestIO, i);
651
                goto failed;
652
        }
653
 
654
        i = pcmcia_request_irq(link, &link->irq);
655
        if (i != CS_SUCCESS) {
656
                cs_error(link, RequestIRQ, i);
657
                link->irq.AssignedIRQ = 0;
658
        }
659
 
660
        i = pcmcia_request_configuration(link, &link->conf);
661
        if (i != CS_SUCCESS) {
662
                cs_error(link, RequestConfiguration, i);
663
                goto failed;
664
        }
665
 
666
        if (dtl1_open(info) != 0)
667
                goto failed;
668
 
669
        strcpy(info->node.dev_name, info->hdev->name);
670
        link->dev_node = &info->node;
671
 
672
        return 0;
673
 
674
failed:
675
        dtl1_release(link);
676
        return -ENODEV;
677
}
678
 
679
 
680
static void dtl1_release(struct pcmcia_device *link)
681
{
682
        dtl1_info_t *info = link->priv;
683
 
684
        dtl1_close(info);
685
 
686
        pcmcia_disable_device(link);
687
}
688
 
689
 
690
static struct pcmcia_device_id dtl1_ids[] = {
691
        PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
692
        PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
693
        PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
694
        PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3),
695
        PCMCIA_DEVICE_NULL
696
};
697
MODULE_DEVICE_TABLE(pcmcia, dtl1_ids);
698
 
699
static struct pcmcia_driver dtl1_driver = {
700
        .owner          = THIS_MODULE,
701
        .drv            = {
702
                .name   = "dtl1_cs",
703
        },
704
        .probe          = dtl1_probe,
705
        .remove         = dtl1_detach,
706
        .id_table       = dtl1_ids,
707
};
708
 
709
static int __init init_dtl1_cs(void)
710
{
711
        return pcmcia_register_driver(&dtl1_driver);
712
}
713
 
714
 
715
static void __exit exit_dtl1_cs(void)
716
{
717
        pcmcia_unregister_driver(&dtl1_driver);
718
}
719
 
720
module_init(init_dtl1_cs);
721
module_exit(exit_dtl1_cs);

powered by: WebSVN 2.1.0

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