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