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 */
25 static int __devinit tpam_probe(struct pci_dev *, const struct pci_device_id *);
26 static void __devexit tpam_unregister_card(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_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  */
tpam_findcard(int driverid)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  */
tpam_findchannel(tpam_card * card,u32 ncoid)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  */
tpam_probe(struct pci_dev * dev,const struct pci_device_id * pci_id)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;
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  */
tpam_unregister_card(tpam_card * card)206 static 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  */
tpam_remove(struct pci_dev * pcidev)224 static 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 
245 static 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 
251 MODULE_DEVICE_TABLE(pci, tpam_pci_tbl);
252 
253 static 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 
tpam_init(void)260 static 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 
tpam_exit(void)271 static 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 */
277 module_init(tpam_init);
278 module_exit(tpam_exit);
279 
280