1/* $Id: tpam_main.c,v 1.1.1.1 2008/10/15 03:26:34 james26_jang 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