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