linux/drivers/bluetooth/bt3c_cs.c
<<
>>
Prefs
   1/*
   2 *
   3 *  Driver for the 3Com Bluetooth PCMCIA card
   4 *
   5 *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
   6 *                           Jose Orlando Pereira <jop@di.uminho.pt>
   7 *
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License version 2 as
  11 *  published by the Free Software Foundation;
  12 *
  13 *  Software distributed under the License is distributed on an "AS
  14 *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  15 *  implied. See the License for the specific language governing
  16 *  rights and limitations under the License.
  17 *
  18 *  The initial developer of the original code is David A. Hinds
  19 *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  20 *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  21 *
  22 */
  23
  24#include <linux/module.h>
  25
  26#include <linux/kernel.h>
  27#include <linux/init.h>
  28#include <linux/slab.h>
  29#include <linux/types.h>
  30#include <linux/delay.h>
  31#include <linux/errno.h>
  32#include <linux/ptrace.h>
  33#include <linux/ioport.h>
  34#include <linux/spinlock.h>
  35#include <linux/moduleparam.h>
  36
  37#include <linux/skbuff.h>
  38#include <linux/string.h>
  39#include <linux/serial.h>
  40#include <linux/serial_reg.h>
  41#include <linux/bitops.h>
  42#include <asm/io.h>
  43
  44#include <linux/device.h>
  45#include <linux/firmware.h>
  46
  47#include <pcmcia/cistpl.h>
  48#include <pcmcia/ciscode.h>
  49#include <pcmcia/ds.h>
  50#include <pcmcia/cisreg.h>
  51
  52#include <net/bluetooth/bluetooth.h>
  53#include <net/bluetooth/hci_core.h>
  54
  55
  56
  57/* ======================== Module parameters ======================== */
  58
  59
  60MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
  61MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
  62MODULE_LICENSE("GPL");
  63MODULE_FIRMWARE("BT3CPCC.bin");
  64
  65
  66
  67/* ======================== Local structures ======================== */
  68
  69
  70typedef struct bt3c_info_t {
  71        struct pcmcia_device *p_dev;
  72
  73        struct hci_dev *hdev;
  74
  75        spinlock_t lock;                /* For serializing operations */
  76
  77        struct sk_buff_head txq;
  78        unsigned long tx_state;
  79
  80        unsigned long rx_state;
  81        unsigned long rx_count;
  82        struct sk_buff *rx_skb;
  83} bt3c_info_t;
  84
  85
  86static int bt3c_config(struct pcmcia_device *link);
  87static void bt3c_release(struct pcmcia_device *link);
  88
  89static void bt3c_detach(struct pcmcia_device *p_dev);
  90
  91
  92/* Transmit states  */
  93#define XMIT_SENDING  1
  94#define XMIT_WAKEUP   2
  95#define XMIT_WAITING  8
  96
  97/* Receiver states */
  98#define RECV_WAIT_PACKET_TYPE   0
  99#define RECV_WAIT_EVENT_HEADER  1
 100#define RECV_WAIT_ACL_HEADER    2
 101#define RECV_WAIT_SCO_HEADER    3
 102#define RECV_WAIT_DATA          4
 103
 104
 105
 106/* ======================== Special I/O functions ======================== */
 107
 108
 109#define DATA_L   0
 110#define DATA_H   1
 111#define ADDR_L   2
 112#define ADDR_H   3
 113#define CONTROL  4
 114
 115
 116static inline void bt3c_address(unsigned int iobase, unsigned short addr)
 117{
 118        outb(addr & 0xff, iobase + ADDR_L);
 119        outb((addr >> 8) & 0xff, iobase + ADDR_H);
 120}
 121
 122
 123static inline void bt3c_put(unsigned int iobase, unsigned short value)
 124{
 125        outb(value & 0xff, iobase + DATA_L);
 126        outb((value >> 8) & 0xff, iobase + DATA_H);
 127}
 128
 129
 130static inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value)
 131{
 132        bt3c_address(iobase, addr);
 133        bt3c_put(iobase, value);
 134}
 135
 136
 137static inline unsigned short bt3c_get(unsigned int iobase)
 138{
 139        unsigned short value = inb(iobase + DATA_L);
 140
 141        value |= inb(iobase + DATA_H) << 8;
 142
 143        return value;
 144}
 145
 146
 147static inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr)
 148{
 149        bt3c_address(iobase, addr);
 150
 151        return bt3c_get(iobase);
 152}
 153
 154
 155
 156/* ======================== Interrupt handling ======================== */
 157
 158
 159static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
 160{
 161        int actual = 0;
 162
 163        bt3c_address(iobase, 0x7080);
 164
 165        /* Fill FIFO with current frame */
 166        while (actual < len) {
 167                /* Transmit next byte */
 168                bt3c_put(iobase, buf[actual]);
 169                actual++;
 170        }
 171
 172        bt3c_io_write(iobase, 0x7005, actual);
 173
 174        return actual;
 175}
 176
 177
 178static void bt3c_write_wakeup(bt3c_info_t *info)
 179{
 180        if (!info) {
 181                BT_ERR("Unknown device");
 182                return;
 183        }
 184
 185        if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
 186                return;
 187
 188        do {
 189                unsigned int iobase = info->p_dev->resource[0]->start;
 190                register struct sk_buff *skb;
 191                int len;
 192
 193                if (!pcmcia_dev_present(info->p_dev))
 194                        break;
 195
 196
 197                if (!(skb = skb_dequeue(&(info->txq)))) {
 198                        clear_bit(XMIT_SENDING, &(info->tx_state));
 199                        break;
 200                }
 201
 202                /* Send frame */
 203                len = bt3c_write(iobase, 256, skb->data, skb->len);
 204
 205                if (len != skb->len) {
 206                        BT_ERR("Very strange");
 207                }
 208
 209                kfree_skb(skb);
 210
 211                info->hdev->stat.byte_tx += len;
 212
 213        } while (0);
 214}
 215
 216
 217static void bt3c_receive(bt3c_info_t *info)
 218{
 219        unsigned int iobase;
 220        int size = 0, avail;
 221
 222        if (!info) {
 223                BT_ERR("Unknown device");
 224                return;
 225        }
 226
 227        iobase = info->p_dev->resource[0]->start;
 228
 229        avail = bt3c_read(iobase, 0x7006);
 230        //printk("bt3c_cs: receiving %d bytes\n", avail);
 231
 232        bt3c_address(iobase, 0x7480);
 233        while (size < avail) {
 234                size++;
 235                info->hdev->stat.byte_rx++;
 236
 237                /* Allocate packet */
 238                if (info->rx_skb == NULL) {
 239                        info->rx_state = RECV_WAIT_PACKET_TYPE;
 240                        info->rx_count = 0;
 241                        if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
 242                                BT_ERR("Can't allocate mem for new packet");
 243                                return;
 244                        }
 245                }
 246
 247
 248                if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
 249
 250                        info->rx_skb->dev = (void *) info->hdev;
 251                        bt_cb(info->rx_skb)->pkt_type = inb(iobase + DATA_L);
 252                        inb(iobase + DATA_H);
 253                        //printk("bt3c: PACKET_TYPE=%02x\n", bt_cb(info->rx_skb)->pkt_type);
 254
 255                        switch (bt_cb(info->rx_skb)->pkt_type) {
 256
 257                        case HCI_EVENT_PKT:
 258                                info->rx_state = RECV_WAIT_EVENT_HEADER;
 259                                info->rx_count = HCI_EVENT_HDR_SIZE;
 260                                break;
 261
 262                        case HCI_ACLDATA_PKT:
 263                                info->rx_state = RECV_WAIT_ACL_HEADER;
 264                                info->rx_count = HCI_ACL_HDR_SIZE;
 265                                break;
 266
 267                        case HCI_SCODATA_PKT:
 268                                info->rx_state = RECV_WAIT_SCO_HEADER;
 269                                info->rx_count = HCI_SCO_HDR_SIZE;
 270                                break;
 271
 272                        default:
 273                                /* Unknown packet */
 274                                BT_ERR("Unknown HCI packet with type 0x%02x received", bt_cb(info->rx_skb)->pkt_type);
 275                                info->hdev->stat.err_rx++;
 276                                clear_bit(HCI_RUNNING, &(info->hdev->flags));
 277
 278                                kfree_skb(info->rx_skb);
 279                                info->rx_skb = NULL;
 280                                break;
 281
 282                        }
 283
 284                } else {
 285
 286                        __u8 x = inb(iobase + DATA_L);
 287
 288                        *skb_put(info->rx_skb, 1) = x;
 289                        inb(iobase + DATA_H);
 290                        info->rx_count--;
 291
 292                        if (info->rx_count == 0) {
 293
 294                                int dlen;
 295                                struct hci_event_hdr *eh;
 296                                struct hci_acl_hdr *ah;
 297                                struct hci_sco_hdr *sh;
 298
 299                                switch (info->rx_state) {
 300
 301                                case RECV_WAIT_EVENT_HEADER:
 302                                        eh = hci_event_hdr(info->rx_skb);
 303                                        info->rx_state = RECV_WAIT_DATA;
 304                                        info->rx_count = eh->plen;
 305                                        break;
 306
 307                                case RECV_WAIT_ACL_HEADER:
 308                                        ah = hci_acl_hdr(info->rx_skb);
 309                                        dlen = __le16_to_cpu(ah->dlen);
 310                                        info->rx_state = RECV_WAIT_DATA;
 311                                        info->rx_count = dlen;
 312                                        break;
 313
 314                                case RECV_WAIT_SCO_HEADER:
 315                                        sh = hci_sco_hdr(info->rx_skb);
 316                                        info->rx_state = RECV_WAIT_DATA;
 317                                        info->rx_count = sh->dlen;
 318                                        break;
 319
 320                                case RECV_WAIT_DATA:
 321                                        hci_recv_frame(info->rx_skb);
 322                                        info->rx_skb = NULL;
 323                                        break;
 324
 325                                }
 326
 327                        }
 328
 329                }
 330
 331        }
 332
 333        bt3c_io_write(iobase, 0x7006, 0x0000);
 334}
 335
 336
 337static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
 338{
 339        bt3c_info_t *info = dev_inst;
 340        unsigned int iobase;
 341        int iir;
 342        irqreturn_t r = IRQ_NONE;
 343
 344        if (!info || !info->hdev)
 345                /* our irq handler is shared */
 346                return IRQ_NONE;
 347
 348        iobase = info->p_dev->resource[0]->start;
 349
 350        spin_lock(&(info->lock));
 351
 352        iir = inb(iobase + CONTROL);
 353        if (iir & 0x80) {
 354                int stat = bt3c_read(iobase, 0x7001);
 355
 356                if ((stat & 0xff) == 0x7f) {
 357                        BT_ERR("Very strange (stat=0x%04x)", stat);
 358                } else if ((stat & 0xff) != 0xff) {
 359                        if (stat & 0x0020) {
 360                                int status = bt3c_read(iobase, 0x7002) & 0x10;
 361                                BT_INFO("%s: Antenna %s", info->hdev->name,
 362                                                        status ? "out" : "in");
 363                        }
 364                        if (stat & 0x0001)
 365                                bt3c_receive(info);
 366                        if (stat & 0x0002) {
 367                                //BT_ERR("Ack (stat=0x%04x)", stat);
 368                                clear_bit(XMIT_SENDING, &(info->tx_state));
 369                                bt3c_write_wakeup(info);
 370                        }
 371
 372                        bt3c_io_write(iobase, 0x7001, 0x0000);
 373
 374                        outb(iir, iobase + CONTROL);
 375                }
 376                r = IRQ_HANDLED;
 377        }
 378
 379        spin_unlock(&(info->lock));
 380
 381        return r;
 382}
 383
 384
 385
 386/* ======================== HCI interface ======================== */
 387
 388
 389static int bt3c_hci_flush(struct hci_dev *hdev)
 390{
 391        bt3c_info_t *info = hci_get_drvdata(hdev);
 392
 393        /* Drop TX queue */
 394        skb_queue_purge(&(info->txq));
 395
 396        return 0;
 397}
 398
 399
 400static int bt3c_hci_open(struct hci_dev *hdev)
 401{
 402        set_bit(HCI_RUNNING, &(hdev->flags));
 403
 404        return 0;
 405}
 406
 407
 408static int bt3c_hci_close(struct hci_dev *hdev)
 409{
 410        if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
 411                return 0;
 412
 413        bt3c_hci_flush(hdev);
 414
 415        return 0;
 416}
 417
 418
 419static int bt3c_hci_send_frame(struct sk_buff *skb)
 420{
 421        bt3c_info_t *info;
 422        struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
 423        unsigned long flags;
 424
 425        if (!hdev) {
 426                BT_ERR("Frame for unknown HCI device (hdev=NULL)");
 427                return -ENODEV;
 428        }
 429
 430        info = hci_get_drvdata(hdev);
 431
 432        switch (bt_cb(skb)->pkt_type) {
 433        case HCI_COMMAND_PKT:
 434                hdev->stat.cmd_tx++;
 435                break;
 436        case HCI_ACLDATA_PKT:
 437                hdev->stat.acl_tx++;
 438                break;
 439        case HCI_SCODATA_PKT:
 440                hdev->stat.sco_tx++;
 441                break;
 442        };
 443
 444        /* Prepend skb with frame type */
 445        memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
 446        skb_queue_tail(&(info->txq), skb);
 447
 448        spin_lock_irqsave(&(info->lock), flags);
 449
 450        bt3c_write_wakeup(info);
 451
 452        spin_unlock_irqrestore(&(info->lock), flags);
 453
 454        return 0;
 455}
 456
 457
 458static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
 459{
 460        return -ENOIOCTLCMD;
 461}
 462
 463
 464
 465/* ======================== Card services HCI interaction ======================== */
 466
 467
 468static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware,
 469                              int count)
 470{
 471        char *ptr = (char *) firmware;
 472        char b[9];
 473        unsigned int iobase, size, addr, fcs, tmp;
 474        int i, err = 0;
 475
 476        iobase = info->p_dev->resource[0]->start;
 477
 478        /* Reset */
 479        bt3c_io_write(iobase, 0x8040, 0x0404);
 480        bt3c_io_write(iobase, 0x8040, 0x0400);
 481
 482        udelay(1);
 483
 484        bt3c_io_write(iobase, 0x8040, 0x0404);
 485
 486        udelay(17);
 487
 488        /* Load */
 489        while (count) {
 490                if (ptr[0] != 'S') {
 491                        BT_ERR("Bad address in firmware");
 492                        err = -EFAULT;
 493                        goto error;
 494                }
 495
 496                memset(b, 0, sizeof(b));
 497                memcpy(b, ptr + 2, 2);
 498                size = simple_strtoul(b, NULL, 16);
 499
 500                memset(b, 0, sizeof(b));
 501                memcpy(b, ptr + 4, 8);
 502                addr = simple_strtoul(b, NULL, 16);
 503
 504                memset(b, 0, sizeof(b));
 505                memcpy(b, ptr + (size * 2) + 2, 2);
 506                fcs = simple_strtoul(b, NULL, 16);
 507
 508                memset(b, 0, sizeof(b));
 509                for (tmp = 0, i = 0; i < size; i++) {
 510                        memcpy(b, ptr + (i * 2) + 2, 2);
 511                        tmp += simple_strtol(b, NULL, 16);
 512                }
 513
 514                if (((tmp + fcs) & 0xff) != 0xff) {
 515                        BT_ERR("Checksum error in firmware");
 516                        err = -EILSEQ;
 517                        goto error;
 518                }
 519
 520                if (ptr[1] == '3') {
 521                        bt3c_address(iobase, addr);
 522
 523                        memset(b, 0, sizeof(b));
 524                        for (i = 0; i < (size - 4) / 2; i++) {
 525                                memcpy(b, ptr + (i * 4) + 12, 4);
 526                                tmp = simple_strtoul(b, NULL, 16);
 527                                bt3c_put(iobase, tmp);
 528                        }
 529                }
 530
 531                ptr   += (size * 2) + 6;
 532                count -= (size * 2) + 6;
 533        }
 534
 535        udelay(17);
 536
 537        /* Boot */
 538        bt3c_address(iobase, 0x3000);
 539        outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL);
 540
 541error:
 542        udelay(17);
 543
 544        /* Clear */
 545        bt3c_io_write(iobase, 0x7006, 0x0000);
 546        bt3c_io_write(iobase, 0x7005, 0x0000);
 547        bt3c_io_write(iobase, 0x7001, 0x0000);
 548
 549        return err;
 550}
 551
 552
 553static int bt3c_open(bt3c_info_t *info)
 554{
 555        const struct firmware *firmware;
 556        struct hci_dev *hdev;
 557        int err;
 558
 559        spin_lock_init(&(info->lock));
 560
 561        skb_queue_head_init(&(info->txq));
 562
 563        info->rx_state = RECV_WAIT_PACKET_TYPE;
 564        info->rx_count = 0;
 565        info->rx_skb = NULL;
 566
 567        /* Initialize HCI device */
 568        hdev = hci_alloc_dev();
 569        if (!hdev) {
 570                BT_ERR("Can't allocate HCI device");
 571                return -ENOMEM;
 572        }
 573
 574        info->hdev = hdev;
 575
 576        hdev->bus = HCI_PCCARD;
 577        hci_set_drvdata(hdev, info);
 578        SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
 579
 580        hdev->open     = bt3c_hci_open;
 581        hdev->close    = bt3c_hci_close;
 582        hdev->flush    = bt3c_hci_flush;
 583        hdev->send     = bt3c_hci_send_frame;
 584        hdev->ioctl    = bt3c_hci_ioctl;
 585
 586        /* Load firmware */
 587        err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev);
 588        if (err < 0) {
 589                BT_ERR("Firmware request failed");
 590                goto error;
 591        }
 592
 593        err = bt3c_load_firmware(info, firmware->data, firmware->size);
 594
 595        release_firmware(firmware);
 596
 597        if (err < 0) {
 598                BT_ERR("Firmware loading failed");
 599                goto error;
 600        }
 601
 602        /* Timeout before it is safe to send the first HCI packet */
 603        msleep(1000);
 604
 605        /* Register HCI device */
 606        err = hci_register_dev(hdev);
 607        if (err < 0) {
 608                BT_ERR("Can't register HCI device");
 609                goto error;
 610        }
 611
 612        return 0;
 613
 614error:
 615        info->hdev = NULL;
 616        hci_free_dev(hdev);
 617        return err;
 618}
 619
 620
 621static int bt3c_close(bt3c_info_t *info)
 622{
 623        struct hci_dev *hdev = info->hdev;
 624
 625        if (!hdev)
 626                return -ENODEV;
 627
 628        bt3c_hci_close(hdev);
 629
 630        hci_unregister_dev(hdev);
 631        hci_free_dev(hdev);
 632
 633        return 0;
 634}
 635
 636static int bt3c_probe(struct pcmcia_device *link)
 637{
 638        bt3c_info_t *info;
 639
 640        /* Create new info device */
 641        info = kzalloc(sizeof(*info), GFP_KERNEL);
 642        if (!info)
 643                return -ENOMEM;
 644
 645        info->p_dev = link;
 646        link->priv = info;
 647
 648        link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
 649                CONF_AUTO_SET_IO;
 650
 651        return bt3c_config(link);
 652}
 653
 654
 655static void bt3c_detach(struct pcmcia_device *link)
 656{
 657        bt3c_info_t *info = link->priv;
 658
 659        bt3c_release(link);
 660        kfree(info);
 661}
 662
 663static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data)
 664{
 665        int *try = priv_data;
 666
 667        if (!try)
 668                p_dev->io_lines = 16;
 669
 670        if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0))
 671                return -EINVAL;
 672
 673        p_dev->resource[0]->end = 8;
 674        p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
 675        p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
 676
 677        return pcmcia_request_io(p_dev);
 678}
 679
 680static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
 681                                      void *priv_data)
 682{
 683        static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
 684        int j;
 685
 686        if (p_dev->io_lines > 3)
 687                return -ENODEV;
 688
 689        p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
 690        p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
 691        p_dev->resource[0]->end = 8;
 692
 693        for (j = 0; j < 5; j++) {
 694                p_dev->resource[0]->start = base[j];
 695                p_dev->io_lines = base[j] ? 16 : 3;
 696                if (!pcmcia_request_io(p_dev))
 697                        return 0;
 698        }
 699        return -ENODEV;
 700}
 701
 702static int bt3c_config(struct pcmcia_device *link)
 703{
 704        bt3c_info_t *info = link->priv;
 705        int i;
 706        unsigned long try;
 707
 708        /* First pass: look for a config entry that looks normal.
 709           Two tries: without IO aliases, then with aliases */
 710        for (try = 0; try < 2; try++)
 711                if (!pcmcia_loop_config(link, bt3c_check_config, (void *) try))
 712                        goto found_port;
 713
 714        /* Second pass: try to find an entry that isn't picky about
 715           its base address, then try to grab any standard serial port
 716           address, and finally try to get any free port. */
 717        if (!pcmcia_loop_config(link, bt3c_check_config_notpicky, NULL))
 718                goto found_port;
 719
 720        BT_ERR("No usable port range found");
 721        goto failed;
 722
 723found_port:
 724        i = pcmcia_request_irq(link, &bt3c_interrupt);
 725        if (i != 0)
 726                goto failed;
 727
 728        i = pcmcia_enable_device(link);
 729        if (i != 0)
 730                goto failed;
 731
 732        if (bt3c_open(info) != 0)
 733                goto failed;
 734
 735        return 0;
 736
 737failed:
 738        bt3c_release(link);
 739        return -ENODEV;
 740}
 741
 742
 743static void bt3c_release(struct pcmcia_device *link)
 744{
 745        bt3c_info_t *info = link->priv;
 746
 747        bt3c_close(info);
 748
 749        pcmcia_disable_device(link);
 750}
 751
 752
 753static const struct pcmcia_device_id bt3c_ids[] = {
 754        PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
 755        PCMCIA_DEVICE_NULL
 756};
 757MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);
 758
 759static struct pcmcia_driver bt3c_driver = {
 760        .owner          = THIS_MODULE,
 761        .name           = "bt3c_cs",
 762        .probe          = bt3c_probe,
 763        .remove         = bt3c_detach,
 764        .id_table       = bt3c_ids,
 765};
 766
 767static int __init init_bt3c_cs(void)
 768{
 769        return pcmcia_register_driver(&bt3c_driver);
 770}
 771
 772
 773static void __exit exit_bt3c_cs(void)
 774{
 775        pcmcia_unregister_driver(&bt3c_driver);
 776}
 777
 778module_init(init_bt3c_cs);
 779module_exit(exit_bt3c_cs);
 780
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.