linux-old/drivers/isdn/tpam/tpam_main.c
<<
>>
Prefs
   1/* $Id: tpam_main.c,v 1.1.2.2 2001/12/09 18:45:14 kai Exp $
   2 *
   3 * Turbo PAM ISDN driver for Linux. (Kernel Driver - main routines)
   4 *
   5 * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, AlcĂ´ve
   6 *
   7 * This software may be used and distributed according to the terms
   8 * of the GNU General Public License, incorporated herein by reference.
   9 *
  10 * For all support questions please contact: <support@auvertech.fr>
  11 *
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/pci.h>
  16#include <linux/sched.h>
  17#include <linux/tqueue.h>
  18#include <linux/interrupt.h>
  19#include <linux/init.h>
  20#include <asm/io.h>
  21
  22#include "tpam.h"
  23
  24/* Local functions prototypes */
  25static int __devinit tpam_probe(struct pci_dev *, const struct pci_device_id *);
  26static void __devexit tpam_unregister_card(tpam_card *);
  27static void __devexit tpam_remove(struct pci_dev *);
  28static int __init tpam_init(void);
  29static void __exit tpam_exit(void);
  30
  31/* List of boards */
  32static tpam_card *cards; /* = NULL; */
  33/* Number of cards */
  34static int cards_num;
  35/* Configurable id of the driver */
  36static char *id = "tpam\0\0\0\0\0\0\0\0\0\0\0\0";
  37
  38MODULE_DESCRIPTION("ISDN4Linux: Driver for TurboPAM ISDN cards");
  39MODULE_AUTHOR("Stelian Pop");
  40MODULE_LICENSE("GPL");
  41MODULE_PARM_DESC(id,"ID-String of the driver");
  42MODULE_PARM(id,"s");
  43
  44/*
  45 * Finds a board by its driver ID.
  46 *
  47 *      driverId: driver ID (as referenced by the IDSN link layer)
  48 *
  49 * Return: the tpam_card structure if found, NULL on error.
  50 */
  51tpam_card *tpam_findcard(int driverid) {
  52        tpam_card *p = cards;
  53
  54        while (p) {
  55                if (p->id == driverid)
  56                        return p;
  57                p = p->next;
  58        }
  59        return NULL;
  60}
  61
  62/*
  63 * Finds a channel number by its ncoid.
  64 *
  65 *      card: the board
  66 *      ncoid: the NCO id
  67 *
  68 * Return: the channel number if found, TPAM_CHANNEL_INVALID if not.
  69 */
  70u32 tpam_findchannel(tpam_card *card, u32 ncoid) {
  71        int i;
  72
  73        for (i = 0; i < TPAM_NBCHANNEL; ++i)
  74                if (card->channels[i].ncoid == ncoid)
  75                        return card->channels[i].num;
  76        return TPAM_CHANNEL_INVALID;
  77}
  78
  79/*
  80 * Initializes and registers a new TurboPAM card.
  81 *
  82 *      dev: the PCI device
  83 *      num: the board number
  84 *
  85 * Return: 0 if OK, <0 if error
  86 */
  87static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) {
  88        tpam_card *card, *c;
  89        int i;
  90
  91        /* allocate memory for the board structure */
  92        if (!(card = (tpam_card *)kmalloc(sizeof(tpam_card), GFP_KERNEL))) {
  93                printk(KERN_ERR "TurboPAM: tpam_register_card: "
  94                       "kmalloc failed!\n");
  95                return -ENOMEM;
  96        }
  97
  98        memset((char *)card, 0, sizeof(tpam_card));
  99
 100        card->irq = dev->irq;
 101        card->lock = SPIN_LOCK_UNLOCKED;
 102        sprintf(card->interface.id, "%s%d", id, cards_num);
 103
 104        /* request interrupt */
 105        if (request_irq(card->irq, &tpam_irq, SA_INTERRUPT | SA_SHIRQ, 
 106                        card->interface.id, card)) {
 107                printk(KERN_ERR "TurboPAM: tpam_register_card: "
 108                       "could not request irq %d\n", card->irq);
 109                kfree(card);
 110                return -EIO;
 111        }
 112
 113        /* remap board memory */
 114        if (!(card->bar0 = (unsigned long) ioremap(pci_resource_start(dev, 0),
 115                                                   0x800000))) {
 116                printk(KERN_ERR "TurboPAM: tpam_register_card: "
 117                       "unable to remap bar0\n");
 118                free_irq(card->irq, card);
 119                kfree(card);
 120                return -EIO;
 121        }
 122
 123        /* reset the board */
 124        readl(card->bar0 + TPAM_RESETPAM_REGISTER);
 125
 126        /* initialisation magic :-( */
 127        copy_to_pam_dword(card, (void *)0x01800008, 0x00000030);
 128        copy_to_pam_dword(card, (void *)0x01800010, 0x00000030);
 129        copy_to_pam_dword(card, (void *)0x01800014, 0x42240822);
 130        copy_to_pam_dword(card, (void *)0x01800018, 0x07114000);
 131        copy_to_pam_dword(card, (void *)0x0180001c, 0x00000400);
 132        copy_to_pam_dword(card, (void *)0x01840070, 0x00000010);
 133
 134        /* fill the ISDN link layer structure */
 135        card->interface.channels = TPAM_NBCHANNEL;
 136        card->interface.maxbufsize = TPAM_MAXBUFSIZE;
 137        card->interface.features = 
 138                ISDN_FEATURE_P_EURO |
 139                ISDN_FEATURE_L2_HDLC |
 140                ISDN_FEATURE_L2_MODEM |
 141                ISDN_FEATURE_L3_TRANS;
 142        card->interface.hl_hdrlen = 0;
 143        card->interface.command = tpam_command;
 144        card->interface.writebuf_skb = tpam_writebuf_skb;
 145        card->interface.writecmd = NULL;
 146        card->interface.readstat = NULL;
 147
 148        /* register wrt the ISDN link layer */
 149        if (!register_isdn(&card->interface)) {
 150                printk(KERN_ERR "TurboPAM: tpam_register_card: "
 151                       "unable to register %s\n", card->interface.id);
 152                free_irq(card->irq, card);
 153                iounmap((void *)card->bar0);
 154                kfree(card);
 155                return -EIO;
 156        }
 157        card->id = card->interface.channels;
 158
 159        /* initialize all channels */
 160        for (i = 0; i < TPAM_NBCHANNEL; ++i) {
 161                card->channels[i].num = i;
 162                card->channels[i].card = card;
 163                card->channels[i].ncoid = TPAM_NCOID_INVALID;
 164                card->channels[i].hdlc = 0;
 165                card->channels[i].realhdlc = 0;
 166                card->channels[i].hdlcshift = 0;
 167                skb_queue_head_init(&card->channels[i].sendq);
 168        }
 169
 170        /* initialize the rest of board structure */
 171        card->channels_used = 0;
 172        card->channels_tested = 0;
 173        card->running = 0;
 174        card->busy = 0;
 175        card->roundrobin = 0;
 176        card->loopmode = 0;
 177        skb_queue_head_init(&card->sendq);
 178        skb_queue_head_init(&card->recvq);
 179        card->recv_tq.routine = (void *) (void *) tpam_recv_tq;
 180        card->recv_tq.data = card;
 181        card->send_tq.routine = (void *) (void *) tpam_send_tq;
 182        card->send_tq.data = card;
 183
 184        /* add the board at the end of the list of boards */
 185        card->next = NULL;
 186        if (cards) {
 187                c = cards;
 188                while (c->next)
 189                        c = c->next;
 190                c->next = card;
 191        }
 192        else
 193                cards = card;
 194
 195        ++cards_num;
 196        pci_set_drvdata(dev, card);
 197
 198        return 0;
 199}
 200
 201/*
 202 * Unregisters a TurboPAM board by releasing all its ressources (irq, mem etc).
 203 *
 204 *      card: the board.
 205 */
 206static void __devexit tpam_unregister_card(tpam_card *card) {
 207        isdn_ctrl cmd;
 208
 209        /* prevent the ISDN link layer that the driver will be unloaded */
 210        cmd.command = ISDN_STAT_UNLOAD;
 211        cmd.driver = card->id;
 212        (* card->interface.statcallb)(&cmd);
 213
 214        /* release interrupt */
 215        free_irq(card->irq, card);
 216
 217        /* release mapped memory */
 218        iounmap((void *)card->bar0);
 219}
 220
 221/*
 222 * Stops the driver.
 223 */
 224static void __devexit tpam_remove(struct pci_dev *pcidev) {
 225        tpam_card *card = pci_get_drvdata(pcidev);
 226        tpam_card *c;
 227
 228        /* remove from the list of cards */
 229        if (card == cards)
 230                cards = cards->next;
 231        else {
 232                c = cards;
 233                while (c->next != card) 
 234                        c = c->next;
 235                c->next = c->next->next;
 236        }
 237        
 238        /* unregister each board */
 239        tpam_unregister_card(card);
 240        
 241        /* and free the board structure itself */
 242        kfree(card);
 243}
 244
 245static struct pci_device_id tpam_pci_tbl[] __devinitdata = {
 246        { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_TURBOPAM,
 247          PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
 248        { }
 249};
 250
 251MODULE_DEVICE_TABLE(pci, tpam_pci_tbl);
 252
 253static struct pci_driver tpam_driver = {
 254        name:           "tpam",
 255        id_table:       tpam_pci_tbl,
 256        probe:          tpam_probe,
 257        remove:         __devexit_p(tpam_remove),
 258};
 259
 260static int __init tpam_init(void) {
 261        int ret;
 262        
 263        ret = pci_module_init(&tpam_driver);
 264        if (ret)
 265                return ret;
 266        printk(KERN_INFO "TurboPAM: %d card%s found, driver loaded.\n", 
 267               cards_num, (cards_num > 1) ? "s" : "");
 268        return 0;
 269}
 270
 271static void __exit tpam_exit(void) {
 272        pci_unregister_driver(&tpam_driver);
 273        printk(KERN_INFO "TurboPAM: driver unloaded\n");
 274}
 275
 276/* Module entry points */
 277module_init(tpam_init);
 278module_exit(tpam_exit);
 279
 280
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.