1 /* $Id: tpam_main.c,v 1.1.2.3 2001/09/23 22:25:03 kai Exp $
3 * Turbo PAM ISDN driver for Linux. (Kernel Driver - main routines)
5 * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, AlcĂ´ve
7 * This software may be used and distributed according to the terms
8 * of the GNU General Public License, incorporated herein by reference.
10 * For all support questions please contact: <support@auvertech.fr>
14 #include <linux/module.h>
15 #include <linux/pci.h>
16 #include <linux/sched.h>
17 #include <linux/interrupt.h>
19 #include <linux/init.h>
24 /* Local functions prototypes */
25 static int __devinit tpam_probe(struct pci_dev *, const struct pci_device_id *);
26 static void __devexit tpam_unregister_card(struct pci_dev *, tpam_card *);
27 static void __devexit tpam_remove(struct pci_dev *);
28 static int __init tpam_init(void);
29 static void __exit tpam_exit(void);
32 static tpam_card *cards; /* = NULL; */
35 /* Configurable id of the driver */
36 static char *id = "tpam\0\0\0\0\0\0\0\0\0\0\0\0";
38 MODULE_DESCRIPTION("ISDN4Linux: Driver for TurboPAM ISDN cards");
39 MODULE_AUTHOR("Stelian Pop");
40 MODULE_LICENSE("GPL");
41 MODULE_PARM_DESC(id,"ID-String of the driver");
42 module_param(id, charp, 0);
45 * Finds a board by its driver ID.
47 * driverId: driver ID (as referenced by the IDSN link layer)
49 * Return: the tpam_card structure if found, NULL on error.
51 tpam_card *tpam_findcard(int driverid) {
55 if (p->id == driverid)
63 * Finds a channel number by its ncoid.
68 * Return: the channel number if found, TPAM_CHANNEL_INVALID if not.
70 u32 tpam_findchannel(tpam_card *card, u32 ncoid) {
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;
80 * Initializes and registers a new TurboPAM card.
83 * num: the board number
85 * Return: 0 if OK, <0 if error
87 static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) {
91 if ((err = pci_enable_device(dev))) {
92 printk(KERN_ERR "TurboPAM: can't enable PCI device at %s\n",
97 /* allocate memory for the board structure */
98 if (!(card = (tpam_card *)kmalloc(sizeof(tpam_card), GFP_KERNEL))) {
99 printk(KERN_ERR "TurboPAM: tpam_register_card: "
100 "kmalloc failed!\n");
102 goto err_out_disable_dev;
105 memset((char *)card, 0, sizeof(tpam_card));
107 card->irq = dev->irq;
108 spin_lock_init(&card->lock);
109 sprintf(card->interface.id, "%s%d", id, cards_num);
111 /* request interrupt */
112 if (request_irq(card->irq, &tpam_irq, SA_INTERRUPT | SA_SHIRQ,
113 card->interface.id, card)) {
114 printk(KERN_ERR "TurboPAM: tpam_register_card: "
115 "could not request irq %d\n", card->irq);
117 goto err_out_free_card;
120 /* remap board memory */
121 if (!(card->bar0 = ioremap(pci_resource_start(dev, 0),
123 printk(KERN_ERR "TurboPAM: tpam_register_card: "
124 "unable to remap bar0\n");
126 goto err_out_free_irq;
129 /* reset the board */
130 readl(card->bar0 + TPAM_RESETPAM_REGISTER);
132 /* initialisation magic :-( */
133 copy_to_pam_dword(card, 0x01800008, 0x00000030);
134 copy_to_pam_dword(card, 0x01800010, 0x00000030);
135 copy_to_pam_dword(card, 0x01800014, 0x42240822);
136 copy_to_pam_dword(card, 0x01800018, 0x07114000);
137 copy_to_pam_dword(card, 0x0180001c, 0x00000400);
138 copy_to_pam_dword(card, 0x01840070, 0x00000010);
140 /* fill the ISDN link layer structure */
141 card->interface.owner = THIS_MODULE;
142 card->interface.channels = TPAM_NBCHANNEL;
143 card->interface.maxbufsize = TPAM_MAXBUFSIZE;
144 card->interface.features =
145 ISDN_FEATURE_P_EURO |
146 ISDN_FEATURE_L2_HDLC |
147 ISDN_FEATURE_L2_MODEM |
148 ISDN_FEATURE_L3_TRANS;
149 card->interface.hl_hdrlen = 0;
150 card->interface.command = tpam_command;
151 card->interface.writebuf_skb = tpam_writebuf_skb;
152 card->interface.writecmd = NULL;
153 card->interface.readstat = NULL;
155 /* register wrt the ISDN link layer */
156 if (!register_isdn(&card->interface)) {
157 printk(KERN_ERR "TurboPAM: tpam_register_card: "
158 "unable to register %s\n", card->interface.id);
160 goto err_out_iounmap;
162 card->id = card->interface.channels;
164 /* initialize all channels */
165 for (i = 0; i < TPAM_NBCHANNEL; ++i) {
166 card->channels[i].num = i;
167 card->channels[i].card = card;
168 card->channels[i].ncoid = TPAM_NCOID_INVALID;
169 card->channels[i].hdlc = 0;
170 card->channels[i].realhdlc = 0;
171 card->channels[i].hdlcshift = 0;
172 skb_queue_head_init(&card->channels[i].sendq);
175 /* initialize the rest of board structure */
176 card->channels_used = 0;
177 card->channels_tested = 0;
180 card->roundrobin = 0;
182 skb_queue_head_init(&card->sendq);
183 skb_queue_head_init(&card->recvq);
184 INIT_WORK(&card->recv_tq, (void *) (void *) tpam_recv_tq, card);
185 INIT_WORK(&card->send_tq, (void *) (void *) tpam_send_tq, card);
187 /* add the board at the end of the list of boards */
199 pci_set_drvdata(dev, card);
207 free_irq(card->irq, card);
213 pci_disable_device(dev);
218 * Unregisters a TurboPAM board by releasing all its ressources (irq, mem etc).
222 static void __devexit tpam_unregister_card(struct pci_dev *pcidev, tpam_card *card) {
225 /* prevent the ISDN link layer that the driver will be unloaded */
226 cmd.command = ISDN_STAT_UNLOAD;
227 cmd.driver = card->id;
228 (* card->interface.statcallb)(&cmd);
230 /* release interrupt */
231 free_irq(card->irq, card);
233 /* release mapped memory */
236 pci_disable_device(pcidev);
242 static void __devexit tpam_remove(struct pci_dev *pcidev) {
243 tpam_card *card = pci_get_drvdata(pcidev);
246 /* remove from the list of cards */
251 while (c->next != card)
253 c->next = c->next->next;
256 /* unregister each board */
257 tpam_unregister_card(pcidev, card);
259 /* and free the board structure itself */
263 static struct pci_device_id tpam_pci_tbl[] = {
264 { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_TURBOPAM,
265 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
269 MODULE_DEVICE_TABLE(pci, tpam_pci_tbl);
271 static struct pci_driver tpam_driver = {
273 .id_table = tpam_pci_tbl,
275 .remove = __devexit_p(tpam_remove),
278 static int __init tpam_init(void) {
281 ret = pci_module_init(&tpam_driver);
284 printk(KERN_INFO "TurboPAM: %d card%s found, driver loaded.\n",
285 cards_num, (cards_num > 1) ? "s" : "");
289 static void __exit tpam_exit(void) {
290 pci_unregister_driver(&tpam_driver);
291 printk(KERN_INFO "TurboPAM: driver unloaded\n");
294 /* Module entry points */
295 module_init(tpam_init);
296 module_exit(tpam_exit);