linux/drivers/ipack/carriers/tpci200.c
<<
>>
Prefs
   1/**
   2 * tpci200.c
   3 *
   4 * driver for the TEWS TPCI-200 device
   5 *
   6 * Copyright (C) 2009-2012 CERN (www.cern.ch)
   7 * Author: Nicolas Serafini, EIC2 SA
   8 * Author: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License as published by the Free
  12 * Software Foundation; version 2 of the License.
  13 */
  14
  15#include <linux/module.h>
  16#include <linux/slab.h>
  17#include "tpci200.h"
  18
  19static const u16 tpci200_status_timeout[] = {
  20        TPCI200_A_TIMEOUT,
  21        TPCI200_B_TIMEOUT,
  22        TPCI200_C_TIMEOUT,
  23        TPCI200_D_TIMEOUT,
  24};
  25
  26static const u16 tpci200_status_error[] = {
  27        TPCI200_A_ERROR,
  28        TPCI200_B_ERROR,
  29        TPCI200_C_ERROR,
  30        TPCI200_D_ERROR,
  31};
  32
  33static const size_t tpci200_space_size[IPACK_SPACE_COUNT] = {
  34        [IPACK_IO_SPACE]    = TPCI200_IO_SPACE_SIZE,
  35        [IPACK_ID_SPACE]    = TPCI200_ID_SPACE_SIZE,
  36        [IPACK_INT_SPACE]   = TPCI200_INT_SPACE_SIZE,
  37        [IPACK_MEM8_SPACE]  = TPCI200_MEM8_SPACE_SIZE,
  38        [IPACK_MEM16_SPACE] = TPCI200_MEM16_SPACE_SIZE,
  39};
  40
  41static const size_t tpci200_space_interval[IPACK_SPACE_COUNT] = {
  42        [IPACK_IO_SPACE]    = TPCI200_IO_SPACE_INTERVAL,
  43        [IPACK_ID_SPACE]    = TPCI200_ID_SPACE_INTERVAL,
  44        [IPACK_INT_SPACE]   = TPCI200_INT_SPACE_INTERVAL,
  45        [IPACK_MEM8_SPACE]  = TPCI200_MEM8_SPACE_INTERVAL,
  46        [IPACK_MEM16_SPACE] = TPCI200_MEM16_SPACE_INTERVAL,
  47};
  48
  49static struct tpci200_board *check_slot(struct ipack_device *dev)
  50{
  51        struct tpci200_board *tpci200;
  52
  53        if (dev == NULL)
  54                return NULL;
  55
  56
  57        tpci200 = dev_get_drvdata(dev->bus->parent);
  58
  59        if (tpci200 == NULL) {
  60                dev_info(&dev->dev, "carrier board not found\n");
  61                return NULL;
  62        }
  63
  64        if (dev->slot >= TPCI200_NB_SLOT) {
  65                dev_info(&dev->dev,
  66                         "Slot [%d:%d] doesn't exist! Last tpci200 slot is %d.\n",
  67                         dev->bus->bus_nr, dev->slot, TPCI200_NB_SLOT-1);
  68                return NULL;
  69        }
  70
  71        return tpci200;
  72}
  73
  74static void tpci200_clear_mask(struct tpci200_board *tpci200,
  75                               __le16 __iomem *addr, u16 mask)
  76{
  77        unsigned long flags;
  78        spin_lock_irqsave(&tpci200->regs_lock, flags);
  79        iowrite16(ioread16(addr) & (~mask), addr);
  80        spin_unlock_irqrestore(&tpci200->regs_lock, flags);
  81}
  82
  83static void tpci200_set_mask(struct tpci200_board *tpci200,
  84                             __le16 __iomem *addr, u16 mask)
  85{
  86        unsigned long flags;
  87        spin_lock_irqsave(&tpci200->regs_lock, flags);
  88        iowrite16(ioread16(addr) | mask, addr);
  89        spin_unlock_irqrestore(&tpci200->regs_lock, flags);
  90}
  91
  92static void tpci200_unregister(struct tpci200_board *tpci200)
  93{
  94        free_irq(tpci200->info->pdev->irq, (void *) tpci200);
  95
  96        pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs);
  97        pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs);
  98
  99        pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
 100        pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
 101        pci_release_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR);
 102        pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
 103        pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR);
 104
 105        pci_disable_device(tpci200->info->pdev);
 106        pci_dev_put(tpci200->info->pdev);
 107}
 108
 109static void tpci200_enable_irq(struct tpci200_board *tpci200,
 110                               int islot)
 111{
 112        tpci200_set_mask(tpci200,
 113                        &tpci200->info->interface_regs->control[islot],
 114                        TPCI200_INT0_EN | TPCI200_INT1_EN);
 115}
 116
 117static void tpci200_disable_irq(struct tpci200_board *tpci200,
 118                                int islot)
 119{
 120        tpci200_clear_mask(tpci200,
 121                        &tpci200->info->interface_regs->control[islot],
 122                        TPCI200_INT0_EN | TPCI200_INT1_EN);
 123}
 124
 125static irqreturn_t tpci200_slot_irq(struct slot_irq *slot_irq)
 126{
 127        irqreturn_t ret;
 128
 129        if (!slot_irq)
 130                return -ENODEV;
 131        ret = slot_irq->handler(slot_irq->arg);
 132
 133        return ret;
 134}
 135
 136static irqreturn_t tpci200_interrupt(int irq, void *dev_id)
 137{
 138        struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id;
 139        struct slot_irq *slot_irq;
 140        irqreturn_t ret;
 141        u16 status_reg;
 142        int i;
 143
 144        /* Read status register */
 145        status_reg = ioread16(&tpci200->info->interface_regs->status);
 146
 147        /* Did we cause the interrupt? */
 148        if (!(status_reg & TPCI200_SLOT_INT_MASK))
 149                return IRQ_NONE;
 150
 151        /* callback to the IRQ handler for the corresponding slot */
 152        rcu_read_lock();
 153        for (i = 0; i < TPCI200_NB_SLOT; i++) {
 154                if (!(status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2 * i))))
 155                        continue;
 156                slot_irq = rcu_dereference(tpci200->slots[i].irq);
 157                ret = tpci200_slot_irq(slot_irq);
 158                if (ret == -ENODEV) {
 159                        dev_info(&tpci200->info->pdev->dev,
 160                                 "No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n",
 161                                 tpci200->number, i);
 162                        tpci200_disable_irq(tpci200, i);
 163                }
 164        }
 165        rcu_read_unlock();
 166
 167        return IRQ_HANDLED;
 168}
 169
 170static int tpci200_free_irq(struct ipack_device *dev)
 171{
 172        struct slot_irq *slot_irq;
 173        struct tpci200_board *tpci200;
 174
 175        tpci200 = check_slot(dev);
 176        if (tpci200 == NULL)
 177                return -EINVAL;
 178
 179        if (mutex_lock_interruptible(&tpci200->mutex))
 180                return -ERESTARTSYS;
 181
 182        if (tpci200->slots[dev->slot].irq == NULL) {
 183                mutex_unlock(&tpci200->mutex);
 184                return -EINVAL;
 185        }
 186
 187        tpci200_disable_irq(tpci200, dev->slot);
 188        slot_irq = tpci200->slots[dev->slot].irq;
 189        /* uninstall handler */
 190        RCU_INIT_POINTER(tpci200->slots[dev->slot].irq, NULL);
 191        synchronize_rcu();
 192        kfree(slot_irq);
 193        mutex_unlock(&tpci200->mutex);
 194        return 0;
 195}
 196
 197static int tpci200_request_irq(struct ipack_device *dev,
 198                               irqreturn_t (*handler)(void *), void *arg)
 199{
 200        int res = 0;
 201        struct slot_irq *slot_irq;
 202        struct tpci200_board *tpci200;
 203
 204        tpci200 = check_slot(dev);
 205        if (tpci200 == NULL)
 206                return -EINVAL;
 207
 208        if (mutex_lock_interruptible(&tpci200->mutex))
 209                return -ERESTARTSYS;
 210
 211        if (tpci200->slots[dev->slot].irq != NULL) {
 212                dev_err(&dev->dev,
 213                        "Slot [%d:%d] IRQ already registered !\n",
 214                        dev->bus->bus_nr,
 215                        dev->slot);
 216                res = -EINVAL;
 217                goto out_unlock;
 218        }
 219
 220        slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL);
 221        if (slot_irq == NULL) {
 222                dev_err(&dev->dev,
 223                        "Slot [%d:%d] unable to allocate memory for IRQ !\n",
 224                        dev->bus->bus_nr, dev->slot);
 225                res = -ENOMEM;
 226                goto out_unlock;
 227        }
 228
 229        /*
 230         * WARNING: Setup Interrupt Vector in the IndustryPack device
 231         * before an IRQ request.
 232         * Read the User Manual of your IndustryPack device to know
 233         * where to write the vector in memory.
 234         */
 235        slot_irq->handler = handler;
 236        slot_irq->arg = arg;
 237        slot_irq->holder = dev;
 238
 239        rcu_assign_pointer(tpci200->slots[dev->slot].irq, slot_irq);
 240        tpci200_enable_irq(tpci200, dev->slot);
 241
 242out_unlock:
 243        mutex_unlock(&tpci200->mutex);
 244        return res;
 245}
 246
 247static int tpci200_register(struct tpci200_board *tpci200)
 248{
 249        int i;
 250        int res;
 251        phys_addr_t ioidint_base;
 252        unsigned short slot_ctrl;
 253
 254        if (pci_enable_device(tpci200->info->pdev) < 0)
 255                return -ENODEV;
 256
 257        /* Request IP interface register (Bar 2) */
 258        res = pci_request_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR,
 259                                 "Carrier IP interface registers");
 260        if (res) {
 261                dev_err(&tpci200->info->pdev->dev,
 262                        "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !",
 263                        tpci200->info->pdev->bus->number,
 264                        tpci200->info->pdev->devfn);
 265                goto out_disable_pci;
 266        }
 267
 268        /* Request IO ID INT space (Bar 3) */
 269        res = pci_request_region(tpci200->info->pdev,
 270                                 TPCI200_IO_ID_INT_SPACES_BAR,
 271                                 "Carrier IO ID INT space");
 272        if (res) {
 273                dev_err(&tpci200->info->pdev->dev,
 274                        "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !",
 275                        tpci200->info->pdev->bus->number,
 276                        tpci200->info->pdev->devfn);
 277                goto out_release_ip_space;
 278        }
 279
 280        /* Request MEM8 space (Bar 5) */
 281        res = pci_request_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR,
 282                                 "Carrier MEM8 space");
 283        if (res) {
 284                dev_err(&tpci200->info->pdev->dev,
 285                        "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 5!",
 286                        tpci200->info->pdev->bus->number,
 287                        tpci200->info->pdev->devfn);
 288                goto out_release_ioid_int_space;
 289        }
 290
 291        /* Request MEM16 space (Bar 4) */
 292        res = pci_request_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR,
 293                                 "Carrier MEM16 space");
 294        if (res) {
 295                dev_err(&tpci200->info->pdev->dev,
 296                        "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!",
 297                        tpci200->info->pdev->bus->number,
 298                        tpci200->info->pdev->devfn);
 299                goto out_release_mem8_space;
 300        }
 301
 302        /* Map internal tpci200 driver user space */
 303        tpci200->info->interface_regs =
 304                ioremap_nocache(pci_resource_start(tpci200->info->pdev,
 305                                           TPCI200_IP_INTERFACE_BAR),
 306                        TPCI200_IFACE_SIZE);
 307
 308        /* Initialize lock that protects interface_regs */
 309        spin_lock_init(&tpci200->regs_lock);
 310
 311        ioidint_base = pci_resource_start(tpci200->info->pdev,
 312                                          TPCI200_IO_ID_INT_SPACES_BAR);
 313        tpci200->mod_mem[IPACK_IO_SPACE] = ioidint_base + TPCI200_IO_SPACE_OFF;
 314        tpci200->mod_mem[IPACK_ID_SPACE] = ioidint_base + TPCI200_ID_SPACE_OFF;
 315        tpci200->mod_mem[IPACK_INT_SPACE] =
 316                ioidint_base + TPCI200_INT_SPACE_OFF;
 317        tpci200->mod_mem[IPACK_MEM8_SPACE] =
 318                pci_resource_start(tpci200->info->pdev,
 319                                   TPCI200_MEM8_SPACE_BAR);
 320        tpci200->mod_mem[IPACK_MEM16_SPACE] =
 321                pci_resource_start(tpci200->info->pdev,
 322                                   TPCI200_MEM16_SPACE_BAR);
 323
 324        /* Set the default parameters of the slot
 325         * INT0 disabled, level sensitive
 326         * INT1 disabled, level sensitive
 327         * error interrupt disabled
 328         * timeout interrupt disabled
 329         * recover time disabled
 330         * clock rate 8 MHz
 331         */
 332        slot_ctrl = 0;
 333        for (i = 0; i < TPCI200_NB_SLOT; i++)
 334                writew(slot_ctrl, &tpci200->info->interface_regs->control[i]);
 335
 336        res = request_irq(tpci200->info->pdev->irq,
 337                          tpci200_interrupt, IRQF_SHARED,
 338                          KBUILD_MODNAME, (void *) tpci200);
 339        if (res) {
 340                dev_err(&tpci200->info->pdev->dev,
 341                        "(bn 0x%X, sn 0x%X) unable to register IRQ !",
 342                        tpci200->info->pdev->bus->number,
 343                        tpci200->info->pdev->devfn);
 344                goto out_release_ioid_int_space;
 345        }
 346
 347        return 0;
 348
 349out_release_mem8_space:
 350        pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR);
 351out_release_ioid_int_space:
 352        pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR);
 353out_release_ip_space:
 354        pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR);
 355out_disable_pci:
 356        pci_disable_device(tpci200->info->pdev);
 357        return res;
 358}
 359
 360static int tpci200_get_clockrate(struct ipack_device *dev)
 361{
 362        struct tpci200_board *tpci200 = check_slot(dev);
 363        __le16 __iomem *addr;
 364
 365        if (!tpci200)
 366                return -ENODEV;
 367
 368        addr = &tpci200->info->interface_regs->control[dev->slot];
 369        return (ioread16(addr) & TPCI200_CLK32) ? 32 : 8;
 370}
 371
 372static int tpci200_set_clockrate(struct ipack_device *dev, int mherz)
 373{
 374        struct tpci200_board *tpci200 = check_slot(dev);
 375        __le16 __iomem *addr;
 376
 377        if (!tpci200)
 378                return -ENODEV;
 379
 380        addr = &tpci200->info->interface_regs->control[dev->slot];
 381
 382        switch (mherz) {
 383        case 8:
 384                tpci200_clear_mask(tpci200, addr, TPCI200_CLK32);
 385                break;
 386        case 32:
 387                tpci200_set_mask(tpci200, addr, TPCI200_CLK32);
 388                break;
 389        default:
 390                return -EINVAL;
 391        }
 392        return 0;
 393}
 394
 395static int tpci200_get_error(struct ipack_device *dev)
 396{
 397        struct tpci200_board *tpci200 = check_slot(dev);
 398        __le16 __iomem *addr;
 399        u16 mask;
 400
 401        if (!tpci200)
 402                return -ENODEV;
 403
 404        addr = &tpci200->info->interface_regs->status;
 405        mask = tpci200_status_error[dev->slot];
 406        return (ioread16(addr) & mask) ? 1 : 0;
 407}
 408
 409static int tpci200_get_timeout(struct ipack_device *dev)
 410{
 411        struct tpci200_board *tpci200 = check_slot(dev);
 412        __le16 __iomem *addr;
 413        u16 mask;
 414
 415        if (!tpci200)
 416                return -ENODEV;
 417
 418        addr = &tpci200->info->interface_regs->status;
 419        mask = tpci200_status_timeout[dev->slot];
 420
 421        return (ioread16(addr) & mask) ? 1 : 0;
 422}
 423
 424static int tpci200_reset_timeout(struct ipack_device *dev)
 425{
 426        struct tpci200_board *tpci200 = check_slot(dev);
 427        __le16 __iomem *addr;
 428        u16 mask;
 429
 430        if (!tpci200)
 431                return -ENODEV;
 432
 433        addr = &tpci200->info->interface_regs->status;
 434        mask = tpci200_status_timeout[dev->slot];
 435
 436        iowrite16(mask, addr);
 437        return 0;
 438}
 439
 440static void tpci200_uninstall(struct tpci200_board *tpci200)
 441{
 442        tpci200_unregister(tpci200);
 443        kfree(tpci200->slots);
 444}
 445
 446static const struct ipack_bus_ops tpci200_bus_ops = {
 447        .request_irq = tpci200_request_irq,
 448        .free_irq = tpci200_free_irq,
 449        .get_clockrate = tpci200_get_clockrate,
 450        .set_clockrate = tpci200_set_clockrate,
 451        .get_error     = tpci200_get_error,
 452        .get_timeout   = tpci200_get_timeout,
 453        .reset_timeout = tpci200_reset_timeout,
 454};
 455
 456static int tpci200_install(struct tpci200_board *tpci200)
 457{
 458        int res;
 459
 460        tpci200->slots = kzalloc(
 461                TPCI200_NB_SLOT * sizeof(struct tpci200_slot), GFP_KERNEL);
 462        if (tpci200->slots == NULL)
 463                return -ENOMEM;
 464
 465        res = tpci200_register(tpci200);
 466        if (res) {
 467                kfree(tpci200->slots);
 468                tpci200->slots = NULL;
 469                return res;
 470        }
 471
 472        mutex_init(&tpci200->mutex);
 473        return 0;
 474}
 475
 476static void tpci200_release_device(struct ipack_device *dev)
 477{
 478        kfree(dev);
 479}
 480
 481static int tpci200_create_device(struct tpci200_board *tpci200, int i)
 482{
 483        int ret;
 484        enum ipack_space space;
 485        struct ipack_device *dev =
 486                kzalloc(sizeof(struct ipack_device), GFP_KERNEL);
 487        if (!dev)
 488                return -ENOMEM;
 489        dev->slot = i;
 490        dev->bus = tpci200->info->ipack_bus;
 491        dev->release = tpci200_release_device;
 492
 493        for (space = 0; space < IPACK_SPACE_COUNT; space++) {
 494                dev->region[space].start =
 495                        tpci200->mod_mem[space]
 496                        + tpci200_space_interval[space] * i;
 497                dev->region[space].size = tpci200_space_size[space];
 498        }
 499
 500        ret = ipack_device_init(dev);
 501        if (ret < 0) {
 502                ipack_put_device(dev);
 503                return ret;
 504        }
 505
 506        ret = ipack_device_add(dev);
 507        if (ret < 0)
 508                ipack_put_device(dev);
 509
 510        return ret;
 511}
 512
 513static int tpci200_pci_probe(struct pci_dev *pdev,
 514                             const struct pci_device_id *id)
 515{
 516        int ret, i;
 517        struct tpci200_board *tpci200;
 518        u32 reg32;
 519
 520        tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL);
 521        if (!tpci200)
 522                return -ENOMEM;
 523
 524        tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL);
 525        if (!tpci200->info) {
 526                ret = -ENOMEM;
 527                goto out_err_info;
 528        }
 529
 530        pci_dev_get(pdev);
 531
 532        /* Obtain a mapping of the carrier's PCI configuration registers */
 533        ret = pci_request_region(pdev, TPCI200_CFG_MEM_BAR,
 534                                 KBUILD_MODNAME " Configuration Memory");
 535        if (ret) {
 536                dev_err(&pdev->dev, "Failed to allocate PCI Configuration Memory");
 537                ret = -EBUSY;
 538                goto out_err_pci_request;
 539        }
 540        tpci200->info->cfg_regs = ioremap_nocache(
 541                        pci_resource_start(pdev, TPCI200_CFG_MEM_BAR),
 542                        pci_resource_len(pdev, TPCI200_CFG_MEM_BAR));
 543        if (!tpci200->info->cfg_regs) {
 544                dev_err(&pdev->dev, "Failed to map PCI Configuration Memory");
 545                ret = -EFAULT;
 546                goto out_err_ioremap;
 547        }
 548
 549        /* Disable byte swapping for 16 bit IP module access. This will ensure
 550         * that the Industrypack big endian byte order is preserved by the
 551         * carrier. */
 552        reg32 = ioread32(tpci200->info->cfg_regs + LAS1_DESC);
 553        reg32 |= 1 << LAS_BIT_BIGENDIAN;
 554        iowrite32(reg32, tpci200->info->cfg_regs + LAS1_DESC);
 555
 556        reg32 = ioread32(tpci200->info->cfg_regs + LAS2_DESC);
 557        reg32 |= 1 << LAS_BIT_BIGENDIAN;
 558        iowrite32(reg32, tpci200->info->cfg_regs + LAS2_DESC);
 559
 560        /* Save struct pci_dev pointer */
 561        tpci200->info->pdev = pdev;
 562        tpci200->info->id_table = (struct pci_device_id *)id;
 563
 564        /* register the device and initialize it */
 565        ret = tpci200_install(tpci200);
 566        if (ret) {
 567                dev_err(&pdev->dev, "error during tpci200 install\n");
 568                ret = -ENODEV;
 569                goto out_err_install;
 570        }
 571
 572        /* Register the carrier in the industry pack bus driver */
 573        tpci200->info->ipack_bus = ipack_bus_register(&pdev->dev,
 574                                                      TPCI200_NB_SLOT,
 575                                                      &tpci200_bus_ops,
 576                                                      THIS_MODULE);
 577        if (!tpci200->info->ipack_bus) {
 578                dev_err(&pdev->dev,
 579                        "error registering the carrier on ipack driver\n");
 580                ret = -EFAULT;
 581                goto out_err_bus_register;
 582        }
 583
 584        /* save the bus number given by ipack to logging purpose */
 585        tpci200->number = tpci200->info->ipack_bus->bus_nr;
 586        dev_set_drvdata(&pdev->dev, tpci200);
 587
 588        for (i = 0; i < TPCI200_NB_SLOT; i++)
 589                tpci200_create_device(tpci200, i);
 590        return 0;
 591
 592out_err_bus_register:
 593        tpci200_uninstall(tpci200);
 594out_err_install:
 595        iounmap(tpci200->info->cfg_regs);
 596out_err_ioremap:
 597        pci_release_region(pdev, TPCI200_CFG_MEM_BAR);
 598out_err_pci_request:
 599        pci_dev_put(pdev);
 600        kfree(tpci200->info);
 601out_err_info:
 602        kfree(tpci200);
 603        return ret;
 604}
 605
 606static void __tpci200_pci_remove(struct tpci200_board *tpci200)
 607{
 608        ipack_bus_unregister(tpci200->info->ipack_bus);
 609        tpci200_uninstall(tpci200);
 610
 611        kfree(tpci200->info);
 612        kfree(tpci200);
 613}
 614
 615static void tpci200_pci_remove(struct pci_dev *dev)
 616{
 617        struct tpci200_board *tpci200 = pci_get_drvdata(dev);
 618
 619        __tpci200_pci_remove(tpci200);
 620}
 621
 622static const struct pci_device_id tpci200_idtable[] = {
 623        { TPCI200_VENDOR_ID, TPCI200_DEVICE_ID, TPCI200_SUBVENDOR_ID,
 624          TPCI200_SUBDEVICE_ID },
 625        { 0, },
 626};
 627
 628MODULE_DEVICE_TABLE(pci, tpci200_idtable);
 629
 630static struct pci_driver tpci200_pci_drv = {
 631        .name = "tpci200",
 632        .id_table = tpci200_idtable,
 633        .probe = tpci200_pci_probe,
 634        .remove = tpci200_pci_remove,
 635};
 636
 637module_pci_driver(tpci200_pci_drv);
 638
 639MODULE_DESCRIPTION("TEWS TPCI-200 device driver");
 640MODULE_LICENSE("GPL");
 641