vserver 1.9.5.x5
[linux-2.6.git] / drivers / isdn / tpam / tpam_main.c
1 /* $Id: tpam_main.c,v 1.1.2.3 2001/09/23 22:25:03 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/interrupt.h>
18
19 #include <linux/init.h>
20 #include <asm/io.h>
21
22 #include "tpam.h"
23
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);
30
31 /* List of boards */
32 static tpam_card *cards; /* = NULL; */
33 /* Number of cards */
34 static int cards_num;
35 /* Configurable id of the driver */
36 static char *id = "tpam\0\0\0\0\0\0\0\0\0\0\0\0";
37
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);
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  */
51 tpam_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  */
70 u32 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  */
87 static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) {
88         tpam_card *card, *c;
89         int i, err;
90
91         if ((err = pci_enable_device(dev))) {
92                 printk(KERN_ERR "TurboPAM: can't enable PCI device at %s\n",
93                         pci_name(dev));
94                 return err;
95         }
96
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");
101                 err = -ENOMEM;
102                 goto err_out_disable_dev;
103         }
104
105         memset((char *)card, 0, sizeof(tpam_card));
106
107         card->irq = dev->irq;
108         spin_lock_init(&card->lock);
109         sprintf(card->interface.id, "%s%d", id, cards_num);
110
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);
116                 err = -EIO;
117                 goto err_out_free_card;
118         }
119
120         /* remap board memory */
121         if (!(card->bar0 = ioremap(pci_resource_start(dev, 0),
122                                                    0x800000))) {
123                 printk(KERN_ERR "TurboPAM: tpam_register_card: "
124                        "unable to remap bar0\n");
125                 err = -EIO;
126                 goto err_out_free_irq;
127         }
128
129         /* reset the board */
130         readl(card->bar0 + TPAM_RESETPAM_REGISTER);
131
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);
139
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;
154
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);
159                 err = -EIO;
160                 goto err_out_iounmap;
161         }
162         card->id = card->interface.channels;
163
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);
173         }
174
175         /* initialize the rest of board structure */
176         card->channels_used = 0;
177         card->channels_tested = 0;
178         card->running = 0;
179         card->busy = 0;
180         card->roundrobin = 0;
181         card->loopmode = 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);
186
187         /* add the board at the end of the list of boards */
188         card->next = NULL;
189         if (cards) {
190                 c = cards;
191                 while (c->next)
192                         c = c->next;
193                 c->next = card;
194         }
195         else
196                 cards = card;
197
198         ++cards_num;
199         pci_set_drvdata(dev, card);
200
201         return 0;
202
203 err_out_iounmap:
204         iounmap(card->bar0);
205
206 err_out_free_irq:
207         free_irq(card->irq, card);
208
209 err_out_free_card:
210         kfree(card);
211
212 err_out_disable_dev:
213         pci_disable_device(dev);
214         return err;
215 }
216
217 /*
218  * Unregisters a TurboPAM board by releasing all its ressources (irq, mem etc).
219  *
220  *      card: the board.
221  */
222 static void __devexit tpam_unregister_card(struct pci_dev *pcidev, tpam_card *card) {
223         isdn_ctrl cmd;
224
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);
229
230         /* release interrupt */
231         free_irq(card->irq, card);
232
233         /* release mapped memory */
234         iounmap(card->bar0);
235
236         pci_disable_device(pcidev);
237 }
238
239 /*
240  * Stops the driver.
241  */
242 static void __devexit tpam_remove(struct pci_dev *pcidev) {
243         tpam_card *card = pci_get_drvdata(pcidev);
244         tpam_card *c;
245
246         /* remove from the list of cards */
247         if (card == cards)
248                 cards = cards->next;
249         else {
250                 c = cards;
251                 while (c->next != card) 
252                         c = c->next;
253                 c->next = c->next->next;
254         }
255         
256         /* unregister each board */
257         tpam_unregister_card(pcidev, card);
258         
259         /* and free the board structure itself */
260         kfree(card);
261 }
262
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 },
266         { }
267 };
268
269 MODULE_DEVICE_TABLE(pci, tpam_pci_tbl);
270
271 static struct pci_driver tpam_driver = {
272         .name           = "tpam",
273         .id_table       = tpam_pci_tbl,
274         .probe          = tpam_probe,
275         .remove         = __devexit_p(tpam_remove),
276 };
277
278 static int __init tpam_init(void) {
279         int ret;
280         
281         ret = pci_module_init(&tpam_driver);
282         if (ret)
283                 return ret;
284         printk(KERN_INFO "TurboPAM: %d card%s found, driver loaded.\n", 
285                cards_num, (cards_num > 1) ? "s" : "");
286         return 0;
287 }
288
289 static void __exit tpam_exit(void) {
290         pci_unregister_driver(&tpam_driver);
291         printk(KERN_INFO "TurboPAM: driver unloaded\n");
292 }
293
294 /* Module entry points */
295 module_init(tpam_init);
296 module_exit(tpam_exit);
297