patch-2.4.6 linux/drivers/isdn/tpam/tpam_main.c

Next file: linux/drivers/isdn/tpam/tpam_memory.c
Previous file: linux/drivers/isdn/tpam/tpam_hdlc.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.5/linux/drivers/isdn/tpam/tpam_main.c linux/drivers/isdn/tpam/tpam_main.c
@@ -0,0 +1,289 @@
+/* $Id: tpam_main.c,v 1.1.2.1 2001/06/05 19:45:37 kai Exp $
+ *
+ * Turbo PAM ISDN driver for Linux. (Kernel Driver - main routines)
+ *
+ * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alcôve
+ *
+ * For all support questions please contact: <support@auvertech.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+#include "tpam.h"
+
+/* Local functions prototypes */
+static int __devinit tpam_probe(struct pci_dev *, const struct pci_device_id *);
+static void __devexit tpam_unregister_card(tpam_card *);
+static void __devexit tpam_remove(struct pci_dev *);
+static int __init tpam_init(void);
+static void __exit tpam_exit(void);
+
+/* List of boards */
+static tpam_card *cards; /* = NULL; */
+/* Number of cards */
+static int cards_num;
+/* Configurable id of the driver */
+static char *id = "tpam\0\0\0\0\0\0\0\0\0\0\0\0";
+
+MODULE_DESCRIPTION("Driver for TurboPAM cards");
+MODULE_AUTHOR("Stelian Pop, Alcove");
+MODULE_SUPPORTED_DEVICE("ISDN subsystem");
+MODULE_PARM_DESC(id,"ID-String of the driver");
+MODULE_PARM(id,"s");
+
+/*
+ * Finds a board by its driver ID.
+ *
+ * 	driverId: driver ID (as referenced by the IDSN link layer)
+ *
+ * Return: the tpam_card structure if found, NULL on error.
+ */
+tpam_card *tpam_findcard(int driverid) {
+	tpam_card *p = cards;
+
+	while (p) {
+		if (p->id == driverid)
+			return p;
+		p = p->next;
+	}
+	return NULL;
+}
+
+/*
+ * Finds a channel number by its ncoid.
+ *
+ * 	card: the board
+ * 	ncoid: the NCO id
+ *
+ * Return: the channel number if found, TPAM_CHANNEL_INVALID if not.
+ */
+u32 tpam_findchannel(tpam_card *card, u32 ncoid) {
+	int i;
+
+	for (i = 0; i < TPAM_NBCHANNEL; ++i)
+		if (card->channels[i].ncoid == ncoid)
+			return card->channels[i].num;
+	return TPAM_CHANNEL_INVALID;
+}
+
+/*
+ * Initializes and registers a new TurboPAM card.
+ *
+ * 	dev: the PCI device
+ * 	num: the board number
+ *
+ * Return: 0 if OK, <0 if error
+ */
+static int __devinit tpam_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) {
+	tpam_card *card, *c;
+	int i;
+
+	/* allocate memory for the board structure */
+	if (!(card = (tpam_card *)kmalloc(sizeof(tpam_card), GFP_KERNEL))) {
+		printk(KERN_ERR "TurboPAM: tpam_register_card: "
+		       "kmalloc failed!\n");
+		return -ENOMEM;
+	}
+
+	memset((char *)card, 0, sizeof(tpam_card));
+
+	card->irq = dev->irq;
+	card->lock = SPIN_LOCK_UNLOCKED;
+	sprintf(card->interface.id, "%s%d", id, cards_num);
+
+	/* request interrupt */
+	if (request_irq(card->irq, &tpam_irq, SA_INTERRUPT | SA_SHIRQ, 
+			card->interface.id, card)) {
+		printk(KERN_ERR "TurboPAM: tpam_register_card: "
+		       "could not request irq %d\n", card->irq);
+		kfree(card);
+		return -EIO;
+	}
+
+	/* remap board memory */
+	if (!(card->bar0 = (unsigned long) ioremap(pci_resource_start(dev, 0),
+						   0x800000))) {
+		printk(KERN_ERR "TurboPAM: tpam_register_card: "
+		       "unable to remap bar0\n");
+		free_irq(card->irq, card);
+		kfree(card);
+		return -EIO;
+	}
+
+	/* reset the board */
+	readl(card->bar0 + TPAM_RESETPAM_REGISTER);
+
+	/* initialisation magic :-( */
+	copy_to_pam_dword(card, (void *)0x01800008, 0x00000030);
+	copy_to_pam_dword(card, (void *)0x01800010, 0x00000030);
+	copy_to_pam_dword(card, (void *)0x01800014, 0x42240822);
+	copy_to_pam_dword(card, (void *)0x01800018, 0x07114000);
+	copy_to_pam_dword(card, (void *)0x0180001c, 0x00000400);
+	copy_to_pam_dword(card, (void *)0x01840070, 0x00000010);
+
+	/* fill the ISDN link layer structure */
+	card->interface.channels = TPAM_NBCHANNEL;
+	card->interface.maxbufsize = TPAM_MAXBUFSIZE;
+	card->interface.features = 
+		ISDN_FEATURE_P_EURO |
+		ISDN_FEATURE_L2_HDLC |
+		ISDN_FEATURE_L2_MODEM;
+	card->interface.hl_hdrlen = 0;
+	card->interface.command = tpam_command;
+	card->interface.writebuf_skb = tpam_writebuf_skb;
+	card->interface.writecmd = NULL;
+	card->interface.readstat = NULL;
+
+	/* register wrt the ISDN link layer */
+	if (!register_isdn(&card->interface)) {
+		printk(KERN_ERR "TurboPAM: tpam_register_card: "
+		       "unable to register %s\n", card->interface.id);
+		free_irq(card->irq, card);
+		iounmap((void *)card->bar0);
+		kfree(card);
+		return -EIO;
+	}
+	card->id = card->interface.channels;
+
+	/* initialize all channels */
+	for (i = 0; i < TPAM_NBCHANNEL; ++i) {
+		card->channels[i].num = i;
+		card->channels[i].card = card;
+		card->channels[i].ncoid = TPAM_NCOID_INVALID;
+		card->channels[i].hdlc = 0;
+		card->channels[i].realhdlc = 0;
+		card->channels[i].hdlcshift = 0;
+		skb_queue_head_init(&card->channels[i].sendq);
+	}
+
+	/* initialize the rest of board structure */
+	card->channels_used = 0;
+	card->channels_tested = 0;
+	card->running = 0;
+	card->busy = 0;
+	card->roundrobin = 0;
+	card->loopmode = 0;
+	skb_queue_head_init(&card->sendq);
+	skb_queue_head_init(&card->recvq);
+	card->recv_tq.routine = (void *) (void *) tpam_recv_tq;
+	card->recv_tq.data = card;
+	card->send_tq.routine = (void *) (void *) tpam_send_tq;
+	card->send_tq.data = card;
+
+	/* add the board at the end of the list of boards */
+	card->next = NULL;
+	if (cards) {
+		c = cards;
+		while (c->next)
+			c = c->next;
+		c->next = card;
+	}
+	else
+		cards = card;
+
+	++cards_num;
+	pci_set_drvdata(dev, card);
+
+	return 0;
+}
+
+/*
+ * Unregisters a TurboPAM board by releasing all its ressources (irq, mem etc).
+ *
+ * 	card: the board.
+ */
+static void __devexit tpam_unregister_card(tpam_card *card) {
+	isdn_ctrl cmd;
+
+	/* prevent the ISDN link layer that the driver will be unloaded */
+	cmd.command = ISDN_STAT_UNLOAD;
+	cmd.driver = card->id;
+	(* card->interface.statcallb)(&cmd);
+
+	/* release interrupt */
+	free_irq(card->irq, card);
+
+	/* release mapped memory */
+	iounmap((void *)card->bar0);
+}
+
+/*
+ * Stops the driver.
+ */
+static void __devexit tpam_remove(struct pci_dev *pcidev) {
+	tpam_card *card = pci_get_drvdata(pcidev);
+	tpam_card *c;
+
+	/* remove from the list of cards */
+	if (card == cards)
+		cards = cards->next;
+	else {
+		c = cards;
+		while (c->next != card) 
+			c = c->next;
+		c->next = c->next->next;
+	}
+	
+	/* unregister each board */
+	tpam_unregister_card(card);
+	
+	/* and free the board structure itself */
+	kfree(card);
+}
+
+static struct pci_device_id tpam_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_TURBOPAM,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, tpam_pci_tbl);
+
+static struct pci_driver tpam_driver = {
+	name:		"tpam",
+	id_table:	tpam_pci_tbl,
+	probe:		tpam_probe,
+	remove:		tpam_remove,
+};
+
+static int __init tpam_init(void) {
+	int ret;
+	
+	ret = pci_module_init(&tpam_driver);
+	if (ret)
+		return ret;
+	printk(KERN_INFO "TurboPAM: %d card%s found, driver loaded.\n", 
+	       cards_num, (cards_num > 1) ? "s" : "");
+	return 0;
+}
+
+static void __exit tpam_exit(void) {
+	pci_unregister_driver(&tpam_driver);
+	printk(KERN_INFO "TurboPAM: driver unloaded\n");
+}
+
+/* Module entry points */
+module_init(tpam_init);
+module_exit(tpam_exit);
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)