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
- Lines: 290
- Date:
Mon Jul 2 14:07:55 2001
- Orig file:
v2.4.5/linux/drivers/isdn/tpam/tpam_main.c
- Orig date:
Wed Dec 31 16:00:00 1969
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)