diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/hisax/config.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/hisax/config.c')
-rw-r--r-- | drivers/isdn/hisax/config.c | 1958 |
1 files changed, 1958 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c new file mode 100644 index 00000000000..1663ee69d41 --- /dev/null +++ b/drivers/isdn/hisax/config.c @@ -0,0 +1,1958 @@ +/* $Id: config.c,v 2.84.2.5 2004/02/11 13:21:33 keil Exp $ + * + * Author Karsten Keil + * Copyright by Karsten Keil <keil@isdn4linux.de> + * by Kai Germaschewski <kai.germaschewski@gmx.de> + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + * + * For changes and modifications please read + * Documentation/isdn/HiSax.cert + * + * based on the teles driver from Jan den Ouden + * + */ + +#include <linux/types.h> +#include <linux/stddef.h> +#include <linux/timer.h> +#include <linux/config.h> +#include <linux/init.h> +#include "hisax.h" +#include <linux/module.h> +#include <linux/kernel_stat.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> +#define HISAX_STATUS_BUFSIZE 4096 +#define INCLUDE_INLINE_FUNCS + +/* + * This structure array contains one entry per card. An entry looks + * like this: + * + * { type, protocol, p0, p1, p2, NULL } + * + * type + * 1 Teles 16.0 p0=irq p1=membase p2=iobase + * 2 Teles 8.0 p0=irq p1=membase + * 3 Teles 16.3 p0=irq p1=iobase + * 4 Creatix PNP p0=irq p1=IO0 (ISAC) p2=IO1 (HSCX) + * 5 AVM A1 (Fritz) p0=irq p1=iobase + * 6 ELSA PC [p0=iobase] or nothing (autodetect) + * 7 ELSA Quickstep p0=irq p1=iobase + * 8 Teles PCMCIA p0=irq p1=iobase + * 9 ITK ix1-micro p0=irq p1=iobase + * 10 ELSA PCMCIA p0=irq p1=iobase + * 11 Eicon.Diehl Diva p0=irq p1=iobase + * 12 Asuscom ISDNLink p0=irq p1=iobase + * 13 Teleint p0=irq p1=iobase + * 14 Teles 16.3c p0=irq p1=iobase + * 15 Sedlbauer speed p0=irq p1=iobase + * 15 Sedlbauer PC/104 p0=irq p1=iobase + * 15 Sedlbauer speed pci no parameter + * 16 USR Sportster internal p0=irq p1=iobase + * 17 MIC card p0=irq p1=iobase + * 18 ELSA Quickstep 1000PCI no parameter + * 19 Compaq ISDN S0 ISA card p0=irq p1=IO0 (HSCX) p2=IO1 (ISAC) p3=IO2 + * 20 Travers Technologies NETjet-S PCI card + * 21 TELES PCI no parameter + * 22 Sedlbauer Speed Star p0=irq p1=iobase + * 23 reserved + * 24 Dr Neuhaus Niccy PnP/PCI card p0=irq p1=IO0 p2=IO1 (PnP only) + * 25 Teles S0Box p0=irq p1=iobase (from isapnp setup) + * 26 AVM A1 PCMCIA (Fritz) p0=irq p1=iobase + * 27 AVM PnP/PCI p0=irq p1=iobase (PCI no parameter) + * 28 Sedlbauer Speed Fax+ p0=irq p1=iobase (from isapnp setup) + * 29 Siemens I-Surf p0=irq p1=iobase p2=memory (from isapnp setup) + * 30 ACER P10 p0=irq p1=iobase (from isapnp setup) + * 31 HST Saphir p0=irq p1=iobase + * 32 Telekom A4T none + * 33 Scitel Quadro p0=subcontroller (4*S0, subctrl 1...4) + * 34 Gazel ISDN cards + * 35 HFC 2BDS0 PCI none + * 36 Winbond 6692 PCI none + * 37 HFC 2BDS0 S+/SP p0=irq p1=iobase + * 38 Travers Technologies NETspider-U PCI card + * 39 HFC 2BDS0-SP PCMCIA p0=irq p1=iobase + * 40 hotplug interface + * 41 Formula-n enter:now ISDN PCI a/b none + * + * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1 + * + * + */ + +const char *CardType[] = { + "No Card", "Teles 16.0", "Teles 8.0", "Teles 16.3", + "Creatix/Teles PnP", "AVM A1", "Elsa ML", "Elsa Quickstep", + "Teles PCMCIA", "ITK ix1-micro Rev.2", "Elsa PCMCIA", + "Eicon.Diehl Diva", "ISDNLink", "TeleInt", "Teles 16.3c", + "Sedlbauer Speed Card", "USR Sportster", "ith mic Linux", + "Elsa PCI", "Compaq ISA", "NETjet-S", "Teles PCI", + "Sedlbauer Speed Star (PCMCIA)", "AMD 7930", "NICCY", "S0Box", + "AVM A1 (PCMCIA)", "AVM Fritz PnP/PCI", "Sedlbauer Speed Fax +", + "Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T", + "Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692", + "HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA", + "Hotplug", "Formula-n enter:now PCI a/b", +}; + +#ifdef CONFIG_HISAX_ELSA +#define DEFAULT_CARD ISDN_CTYPE_ELSA +#define DEFAULT_CFG {0,0,0,0} +#endif + +#ifdef CONFIG_HISAX_AVM_A1 +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_A1 +#define DEFAULT_CFG {10,0x340,0,0} +#endif + +#ifdef CONFIG_HISAX_AVM_A1_PCMCIA +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_A1_PCMCIA +#define DEFAULT_CFG {11,0x170,0,0} +#endif + +#ifdef CONFIG_HISAX_FRITZPCI +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_FRITZPCI +#define DEFAULT_CFG {0,0,0,0} +#endif + +#ifdef CONFIG_HISAX_16_3 +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_16_3 +#define DEFAULT_CFG {15,0x180,0,0} +#endif + +#ifdef CONFIG_HISAX_S0BOX +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_S0BOX +#define DEFAULT_CFG {7,0x378,0,0} +#endif + +#ifdef CONFIG_HISAX_16_0 +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_16_0 +#define DEFAULT_CFG {15,0xd0000,0xd80,0} +#endif + +#ifdef CONFIG_HISAX_TELESPCI +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_TELESPCI +#define DEFAULT_CFG {0,0,0,0} +#endif + +#ifdef CONFIG_HISAX_IX1MICROR2 +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_IX1MICROR2 +#define DEFAULT_CFG {5,0x390,0,0} +#endif + +#ifdef CONFIG_HISAX_DIEHLDIVA +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_DIEHLDIVA +#define DEFAULT_CFG {0,0x0,0,0} +#endif + +#ifdef CONFIG_HISAX_ASUSCOM +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_ASUSCOM +#define DEFAULT_CFG {5,0x200,0,0} +#endif + +#ifdef CONFIG_HISAX_TELEINT +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_TELEINT +#define DEFAULT_CFG {5,0x300,0,0} +#endif + +#ifdef CONFIG_HISAX_SEDLBAUER +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_SEDLBAUER +#define DEFAULT_CFG {11,0x270,0,0} +#endif + +#ifdef CONFIG_HISAX_SPORTSTER +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_SPORTSTER +#define DEFAULT_CFG {7,0x268,0,0} +#endif + +#ifdef CONFIG_HISAX_MIC +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_MIC +#define DEFAULT_CFG {12,0x3e0,0,0} +#endif + +#ifdef CONFIG_HISAX_NETJET +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_NETJET_S +#define DEFAULT_CFG {0,0,0,0} +#endif + +#ifdef CONFIG_HISAX_HFCS +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_TELES3C +#define DEFAULT_CFG {5,0x500,0,0} +#endif + +#ifdef CONFIG_HISAX_HFC_PCI +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_HFC_PCI +#define DEFAULT_CFG {0,0,0,0} +#endif + +#ifdef CONFIG_HISAX_HFC_SX +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_HFC_SX +#define DEFAULT_CFG {5,0x2E0,0,0} +#endif + + +#ifdef CONFIG_HISAX_AMD7930 +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_AMD7930 +#define DEFAULT_CFG {12,0x3e0,0,0} +#endif + +#ifdef CONFIG_HISAX_NICCY +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_NICCY +#define DEFAULT_CFG {0,0x0,0,0} +#endif + +#ifdef CONFIG_HISAX_ISURF +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_ISURF +#define DEFAULT_CFG {5,0x100,0xc8000,0} +#endif + +#ifdef CONFIG_HISAX_HSTSAPHIR +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_HSTSAPHIR +#define DEFAULT_CFG {5,0x250,0,0} +#endif + +#ifdef CONFIG_HISAX_BKM_A4T +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_BKM_A4T +#define DEFAULT_CFG {0,0x0,0,0} +#endif + +#ifdef CONFIG_HISAX_SCT_QUADRO +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_SCT_QUADRO +#define DEFAULT_CFG {1,0x0,0,0} +#endif + +#ifdef CONFIG_HISAX_GAZEL +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_GAZEL +#define DEFAULT_CFG {15,0x180,0,0} +#endif + +#ifdef CONFIG_HISAX_W6692 +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_W6692 +#define DEFAULT_CFG {0,0,0,0} +#endif + +#ifdef CONFIG_HISAX_NETJET_U +#undef DEFAULT_CARD +#undef DEFAULT_CFG +#define DEFAULT_CARD ISDN_CTYPE_NETJET_U +#define DEFAULT_CFG {0,0,0,0} +#endif + +#ifdef CONFIG_HISAX_1TR6 +#define DEFAULT_PROTO ISDN_PTYPE_1TR6 +#define DEFAULT_PROTO_NAME "1TR6" +#endif +#ifdef CONFIG_HISAX_NI1 +#undef DEFAULT_PROTO +#define DEFAULT_PROTO ISDN_PTYPE_NI1 +#undef DEFAULT_PROTO_NAME +#define DEFAULT_PROTO_NAME "NI1" +#endif +#ifdef CONFIG_HISAX_EURO +#undef DEFAULT_PROTO +#define DEFAULT_PROTO ISDN_PTYPE_EURO +#undef DEFAULT_PROTO_NAME +#define DEFAULT_PROTO_NAME "EURO" +#endif +#ifndef DEFAULT_PROTO +#define DEFAULT_PROTO ISDN_PTYPE_UNKNOWN +#define DEFAULT_PROTO_NAME "UNKNOWN" +#endif +#ifndef DEFAULT_CARD +#define DEFAULT_CARD 0 +#define DEFAULT_CFG {0,0,0,0} +#endif + +#define FIRST_CARD { \ + DEFAULT_CARD, \ + DEFAULT_PROTO, \ + DEFAULT_CFG, \ + NULL, \ +} + +struct IsdnCard cards[HISAX_MAX_CARDS] = { + FIRST_CARD, +}; + +#define HISAX_IDSIZE (HISAX_MAX_CARDS*8) +static char HiSaxID[HISAX_IDSIZE] = { 0, }; + +char *HiSax_id = HiSaxID; +#ifdef MODULE +/* Variables for insmod */ +static int type[HISAX_MAX_CARDS] = { 0, }; +static int protocol[HISAX_MAX_CARDS] = { 0, }; +static int io[HISAX_MAX_CARDS] = { 0, }; +#undef IO0_IO1 +#ifdef CONFIG_HISAX_16_3 +#define IO0_IO1 +#endif +#ifdef CONFIG_HISAX_NICCY +#undef IO0_IO1 +#define IO0_IO1 +#endif +#ifdef IO0_IO1 +static int io0[HISAX_MAX_CARDS] __devinitdata = { 0, }; +static int io1[HISAX_MAX_CARDS] __devinitdata = { 0, }; +#endif +static int irq[HISAX_MAX_CARDS] __devinitdata = { 0, }; +static int mem[HISAX_MAX_CARDS] __devinitdata = { 0, }; +static char *id = HiSaxID; + +MODULE_DESCRIPTION("ISDN4Linux: Driver for passive ISDN cards"); +MODULE_AUTHOR("Karsten Keil"); +MODULE_LICENSE("GPL"); +module_param_array(type, int, NULL, 0); +module_param_array(protocol, int, NULL, 0); +module_param_array(io, int, NULL, 0); +module_param_array(irq, int, NULL, 0); +module_param_array(mem, int, NULL, 0); +module_param(id, charp, 0); +#ifdef IO0_IO1 +module_param_array(io0, int, NULL, 0); +module_param_array(io1, int, NULL, 0); +#endif +#endif /* MODULE */ + +int nrcards; + +extern char *l1_revision; +extern char *l2_revision; +extern char *l3_revision; +extern char *lli_revision; +extern char *tei_revision; + +char *HiSax_getrev(const char *revision) +{ + char *rev; + char *p; + + if ((p = strchr(revision, ':'))) { + rev = p + 2; + p = strchr(rev, '$'); + *--p = 0; + } else + rev = "???"; + return rev; +} + +void __init HiSaxVersion(void) +{ + char tmp[64]; + + printk(KERN_INFO "HiSax: Linux Driver for passive ISDN cards\n"); +#ifdef MODULE + printk(KERN_INFO "HiSax: Version 3.5 (module)\n"); +#else + printk(KERN_INFO "HiSax: Version 3.5 (kernel)\n"); +#endif + strcpy(tmp, l1_revision); + printk(KERN_INFO "HiSax: Layer1 Revision %s\n", HiSax_getrev(tmp)); + strcpy(tmp, l2_revision); + printk(KERN_INFO "HiSax: Layer2 Revision %s\n", HiSax_getrev(tmp)); + strcpy(tmp, tei_revision); + printk(KERN_INFO "HiSax: TeiMgr Revision %s\n", HiSax_getrev(tmp)); + strcpy(tmp, l3_revision); + printk(KERN_INFO "HiSax: Layer3 Revision %s\n", HiSax_getrev(tmp)); + strcpy(tmp, lli_revision); + printk(KERN_INFO "HiSax: LinkLayer Revision %s\n", + HiSax_getrev(tmp)); +} + +#ifndef MODULE +#define MAX_ARG (HISAX_MAX_CARDS*5) +static int __init HiSax_setup(char *line) +{ + int i, j, argc; + int ints[MAX_ARG + 1]; + char *str; + + str = get_options(line, MAX_ARG, ints); + argc = ints[0]; + printk(KERN_DEBUG "HiSax_setup: argc(%d) str(%s)\n", argc, str); + i = 0; + j = 1; + while (argc && (i < HISAX_MAX_CARDS)) { + cards[i].protocol = DEFAULT_PROTO; + if (argc) { + cards[i].typ = ints[j]; + j++; + argc--; + } + if (argc) { + cards[i].protocol = ints[j]; + j++; + argc--; + } + if (argc) { + cards[i].para[0] = ints[j]; + j++; + argc--; + } + if (argc) { + cards[i].para[1] = ints[j]; + j++; + argc--; + } + if (argc) { + cards[i].para[2] = ints[j]; + j++; + argc--; + } + i++; + } + if (str && *str) { + if (strlen(str) < HISAX_IDSIZE) + strcpy(HiSaxID, str); + else + printk(KERN_WARNING "HiSax: ID too long!"); + } else + strcpy(HiSaxID, "HiSax"); + + HiSax_id = HiSaxID; + return 1; +} + +__setup("hisax=", HiSax_setup); +#endif /* MODULES */ + +#if CARD_TELES0 +extern int setup_teles0(struct IsdnCard *card); +#endif + +#if CARD_TELES3 +extern int setup_teles3(struct IsdnCard *card); +#endif + +#if CARD_S0BOX +extern int setup_s0box(struct IsdnCard *card); +#endif + +#if CARD_TELESPCI +extern int setup_telespci(struct IsdnCard *card); +#endif + +#if CARD_AVM_A1 +extern int setup_avm_a1(struct IsdnCard *card); +#endif + +#if CARD_AVM_A1_PCMCIA +extern int setup_avm_a1_pcmcia(struct IsdnCard *card); +#endif + +#if CARD_FRITZPCI +extern int setup_avm_pcipnp(struct IsdnCard *card); +#endif + +#if CARD_ELSA +extern int setup_elsa(struct IsdnCard *card); +#endif + +#if CARD_IX1MICROR2 +extern int setup_ix1micro(struct IsdnCard *card); +#endif + +#if CARD_DIEHLDIVA +extern int setup_diva(struct IsdnCard *card); +#endif + +#if CARD_ASUSCOM +extern int setup_asuscom(struct IsdnCard *card); +#endif + +#if CARD_TELEINT +extern int setup_TeleInt(struct IsdnCard *card); +#endif + +#if CARD_SEDLBAUER +extern int setup_sedlbauer(struct IsdnCard *card); +#endif + +#if CARD_SPORTSTER +extern int setup_sportster(struct IsdnCard *card); +#endif + +#if CARD_MIC +extern int setup_mic(struct IsdnCard *card); +#endif + +#if CARD_NETJET_S +extern int setup_netjet_s(struct IsdnCard *card); +#endif + +#if CARD_HFCS +extern int setup_hfcs(struct IsdnCard *card); +#endif + +#if CARD_HFC_PCI +extern int setup_hfcpci(struct IsdnCard *card); +#endif + +#if CARD_HFC_SX +extern int setup_hfcsx(struct IsdnCard *card); +#endif + +#if CARD_AMD7930 +extern int setup_amd7930(struct IsdnCard *card); +#endif + +#if CARD_NICCY +extern int setup_niccy(struct IsdnCard *card); +#endif + +#if CARD_ISURF +extern int setup_isurf(struct IsdnCard *card); +#endif + +#if CARD_HSTSAPHIR +extern int setup_saphir(struct IsdnCard *card); +#endif + +#if CARD_TESTEMU +extern int setup_testemu(struct IsdnCard *card); +#endif + +#if CARD_BKM_A4T +extern int setup_bkm_a4t(struct IsdnCard *card); +#endif + +#if CARD_SCT_QUADRO +extern int setup_sct_quadro(struct IsdnCard *card); +#endif + +#if CARD_GAZEL +extern int setup_gazel(struct IsdnCard *card); +#endif + +#if CARD_W6692 +extern int setup_w6692(struct IsdnCard *card); +#endif + +#if CARD_NETJET_U +extern int setup_netjet_u(struct IsdnCard *card); +#endif + +#if CARD_FN_ENTERNOW_PCI +extern int setup_enternow_pci(struct IsdnCard *card); +#endif + +/* + * Find card with given driverId + */ +static inline struct IsdnCardState *hisax_findcard(int driverid) +{ + int i; + + for (i = 0; i < nrcards; i++) + if (cards[i].cs) + if (cards[i].cs->myid == driverid) + return cards[i].cs; + return NULL; +} + +/* + * Find card with given card number + */ +struct IsdnCardState *hisax_get_card(int cardnr) +{ + if ((cardnr <= nrcards) && (cardnr > 0)) + if (cards[cardnr - 1].cs) + return cards[cardnr - 1].cs; + return NULL; +} + +int HiSax_readstatus(u_char __user *buf, int len, int id, int channel) +{ + int count, cnt; + u_char __user *p = buf; + struct IsdnCardState *cs = hisax_findcard(id); + + if (cs) { + if (len > HISAX_STATUS_BUFSIZE) { + printk(KERN_WARNING + "HiSax: status overflow readstat %d/%d\n", + len, HISAX_STATUS_BUFSIZE); + } + count = cs->status_end - cs->status_read + 1; + if (count >= len) + count = len; + copy_to_user(p, cs->status_read, count); + cs->status_read += count; + if (cs->status_read > cs->status_end) + cs->status_read = cs->status_buf; + p += count; + count = len - count; + while (count) { + if (count > HISAX_STATUS_BUFSIZE) + cnt = HISAX_STATUS_BUFSIZE; + else + cnt = count; + copy_to_user(p, cs->status_read, cnt); + p += cnt; + cs->status_read += cnt % HISAX_STATUS_BUFSIZE; + count -= cnt; + } + return len; + } else { + printk(KERN_ERR + "HiSax: if_readstatus called with invalid driverId!\n"); + return -ENODEV; + } +} + +int jiftime(char *s, long mark) +{ + s += 8; + + *s-- = '\0'; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = '.'; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = mark % 6 + '0'; + mark /= 6; + *s-- = ':'; + *s-- = mark % 10 + '0'; + mark /= 10; + *s-- = mark % 10 + '0'; + return 8; +} + +static u_char tmpbuf[HISAX_STATUS_BUFSIZE]; + +void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, + va_list args) +{ + /* if head == NULL the fmt contains the full info */ + + u_long flags; + int count, i; + u_char *p; + isdn_ctrl ic; + int len; + + if (!cs) { + printk(KERN_WARNING "HiSax: No CardStatus for message"); + return; + } + spin_lock_irqsave(&cs->statlock, flags); + p = tmpbuf; + if (head) { + p += jiftime(p, jiffies); + p += sprintf(p, " %s", head); + p += vsprintf(p, fmt, args); + *p++ = '\n'; + *p = 0; + len = p - tmpbuf; + p = tmpbuf; + } else { + p = fmt; + len = strlen(fmt); + } + if (len > HISAX_STATUS_BUFSIZE) { + spin_unlock_irqrestore(&cs->statlock, flags); + printk(KERN_WARNING "HiSax: status overflow %d/%d\n", + len, HISAX_STATUS_BUFSIZE); + return; + } + count = len; + i = cs->status_end - cs->status_write + 1; + if (i >= len) + i = len; + len -= i; + memcpy(cs->status_write, p, i); + cs->status_write += i; + if (cs->status_write > cs->status_end) + cs->status_write = cs->status_buf; + p += i; + if (len) { + memcpy(cs->status_write, p, len); + cs->status_write += len; + } +#ifdef KERNELSTACK_DEBUG + i = (ulong) & len - current->kernel_stack_page; + sprintf(tmpbuf, "kstack %s %lx use %ld\n", current->comm, + current->kernel_stack_page, i); + len = strlen(tmpbuf); + for (p = tmpbuf, i = len; i > 0; i--, p++) { + *cs->status_write++ = *p; + if (cs->status_write > cs->status_end) + cs->status_write = cs->status_buf; + count++; + } +#endif + spin_unlock_irqrestore(&cs->statlock, flags); + if (count) { + ic.command = ISDN_STAT_STAVAIL; + ic.driver = cs->myid; + ic.arg = count; + cs->iif.statcallb(&ic); + } +} + +void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + VHiSax_putstatus(cs, head, fmt, args); + va_end(args); +} + +int ll_run(struct IsdnCardState *cs, int addfeatures) +{ + isdn_ctrl ic; + + ic.driver = cs->myid; + ic.command = ISDN_STAT_RUN; + cs->iif.features |= addfeatures; + cs->iif.statcallb(&ic); + return 0; +} + +void ll_stop(struct IsdnCardState *cs) +{ + isdn_ctrl ic; + + ic.command = ISDN_STAT_STOP; + ic.driver = cs->myid; + cs->iif.statcallb(&ic); + // CallcFreeChan(cs); +} + +static void ll_unload(struct IsdnCardState *cs) +{ + isdn_ctrl ic; + + ic.command = ISDN_STAT_UNLOAD; + ic.driver = cs->myid; + cs->iif.statcallb(&ic); + if (cs->status_buf) + kfree(cs->status_buf); + cs->status_read = NULL; + cs->status_write = NULL; + cs->status_end = NULL; + kfree(cs->dlog); + cs->dlog = NULL; +} + +static void closecard(int cardnr) +{ + struct IsdnCardState *csta = cards[cardnr].cs; + + if (csta->bcs->BC_Close != NULL) { + csta->bcs->BC_Close(csta->bcs + 1); + csta->bcs->BC_Close(csta->bcs); + } + + skb_queue_purge(&csta->rq); + skb_queue_purge(&csta->sq); + if (csta->rcvbuf) { + kfree(csta->rcvbuf); + csta->rcvbuf = NULL; + } + if (csta->tx_skb) { + dev_kfree_skb(csta->tx_skb); + csta->tx_skb = NULL; + } + if (csta->DC_Close != NULL) { + csta->DC_Close(csta); + } + if (csta->cardmsg) + csta->cardmsg(csta, CARD_RELEASE, NULL); + if (csta->dbusytimer.function != NULL) // FIXME? + del_timer(&csta->dbusytimer); + ll_unload(csta); +} + +static int init_card(struct IsdnCardState *cs) +{ + int irq_cnt, cnt = 3, ret; + + if (!cs->irq) { + ret = cs->cardmsg(cs, CARD_INIT, NULL); + return(ret); + } + irq_cnt = kstat_irqs(cs->irq); + printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], + cs->irq, irq_cnt); + if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) { + printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n", + cs->irq); + return 1; + } + while (cnt) { + cs->cardmsg(cs, CARD_INIT, NULL); + /* Timeout 10ms */ + msleep(10); + printk(KERN_INFO "%s: IRQ %d count %d\n", + CardType[cs->typ], cs->irq, kstat_irqs(cs->irq)); + if (kstat_irqs(cs->irq) == irq_cnt) { + printk(KERN_WARNING + "%s: IRQ(%d) getting no interrupts during init %d\n", + CardType[cs->typ], cs->irq, 4 - cnt); + if (cnt == 1) { + free_irq(cs->irq, cs); + return 2; + } else { + cs->cardmsg(cs, CARD_RESET, NULL); + cnt--; + } + } else { + cs->cardmsg(cs, CARD_TEST, NULL); + return 0; + } + } + return 3; +} + +static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner) +{ + int ret = 0; + struct IsdnCard *card = cards + cardnr; + struct IsdnCardState *cs; + + cs = kmalloc(sizeof(struct IsdnCardState), GFP_ATOMIC); + if (!cs) { + printk(KERN_WARNING + "HiSax: No memory for IsdnCardState(card %d)\n", + cardnr + 1); + goto out; + } + memset(cs, 0, sizeof(struct IsdnCardState)); + card->cs = cs; + spin_lock_init(&cs->statlock); + spin_lock_init(&cs->lock); + cs->chanlimit = 2; /* maximum B-channel number */ + cs->logecho = 0; /* No echo logging */ + cs->cardnr = cardnr; + cs->debug = L1_DEB_WARN; + cs->HW_Flags = 0; + cs->busy_flag = busy_flag; + cs->irq_flags = I4L_IRQ_FLAG; +#if TEI_PER_CARD + if (card->protocol == ISDN_PTYPE_NI1) + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); +#else + test_and_set_bit(FLG_TWO_DCHAN, &cs->HW_Flags); +#endif + cs->protocol = card->protocol; + + if (card->typ <= 0 || card->typ > ISDN_CTYPE_COUNT) { + printk(KERN_WARNING + "HiSax: Card Type %d out of range\n", card->typ); + goto outf_cs; + } + if (!(cs->dlog = kmalloc(MAX_DLOG_SPACE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for dlog(card %d)\n", cardnr + 1); + goto outf_cs; + } + if (!(cs->status_buf = kmalloc(HISAX_STATUS_BUFSIZE, GFP_ATOMIC))) { + printk(KERN_WARNING + "HiSax: No memory for status_buf(card %d)\n", + cardnr + 1); + goto outf_dlog; + } + cs->stlist = NULL; + cs->status_read = cs->status_buf; + cs->status_write = cs->status_buf; + cs->status_end = cs->status_buf + HISAX_STATUS_BUFSIZE - 1; + cs->typ = card->typ; +#ifdef MODULE + cs->iif.owner = lockowner; +#endif + strcpy(cs->iif.id, id); + cs->iif.channels = 2; + cs->iif.maxbufsize = MAX_DATA_SIZE; + cs->iif.hl_hdrlen = MAX_HEADER_LEN; + cs->iif.features = + ISDN_FEATURE_L2_X75I | + ISDN_FEATURE_L2_HDLC | + ISDN_FEATURE_L2_HDLC_56K | + ISDN_FEATURE_L2_TRANS | + ISDN_FEATURE_L3_TRANS | +#ifdef CONFIG_HISAX_1TR6 + ISDN_FEATURE_P_1TR6 | +#endif +#ifdef CONFIG_HISAX_EURO + ISDN_FEATURE_P_EURO | +#endif +#ifdef CONFIG_HISAX_NI1 + ISDN_FEATURE_P_NI1 | +#endif + 0; + + cs->iif.command = HiSax_command; + cs->iif.writecmd = NULL; + cs->iif.writebuf_skb = HiSax_writebuf_skb; + cs->iif.readstat = HiSax_readstatus; + register_isdn(&cs->iif); + cs->myid = cs->iif.channels; + printk(KERN_INFO + "HiSax: Card %d Protocol %s Id=%s (%d)\n", cardnr + 1, + (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : + (card->protocol == ISDN_PTYPE_EURO) ? "EDSS1" : + (card->protocol == ISDN_PTYPE_LEASED) ? "LEASED" : + (card->protocol == ISDN_PTYPE_NI1) ? "NI1" : + "NONE", cs->iif.id, cs->myid); + switch (card->typ) { +#if CARD_TELES0 + case ISDN_CTYPE_16_0: + case ISDN_CTYPE_8_0: + ret = setup_teles0(card); + break; +#endif +#if CARD_TELES3 + case ISDN_CTYPE_16_3: + case ISDN_CTYPE_PNP: + case ISDN_CTYPE_TELESPCMCIA: + case ISDN_CTYPE_COMPAQ_ISA: + ret = setup_teles3(card); + break; +#endif +#if CARD_S0BOX + case ISDN_CTYPE_S0BOX: + ret = setup_s0box(card); + break; +#endif +#if CARD_TELESPCI + case ISDN_CTYPE_TELESPCI: + ret = setup_telespci(card); + break; +#endif +#if CARD_AVM_A1 + case ISDN_CTYPE_A1: + ret = setup_avm_a1(card); + break; +#endif +#if CARD_AVM_A1_PCMCIA + case ISDN_CTYPE_A1_PCMCIA: + ret = setup_avm_a1_pcmcia(card); + break; +#endif +#if CARD_FRITZPCI + case ISDN_CTYPE_FRITZPCI: + ret = setup_avm_pcipnp(card); + break; +#endif +#if CARD_ELSA + case ISDN_CTYPE_ELSA: + case ISDN_CTYPE_ELSA_PNP: + case ISDN_CTYPE_ELSA_PCMCIA: + case ISDN_CTYPE_ELSA_PCI: + ret = setup_elsa(card); + break; +#endif +#if CARD_IX1MICROR2 + case ISDN_CTYPE_IX1MICROR2: + ret = setup_ix1micro(card); + break; +#endif +#if CARD_DIEHLDIVA + case ISDN_CTYPE_DIEHLDIVA: + ret = setup_diva(card); + break; +#endif +#if CARD_ASUSCOM + case ISDN_CTYPE_ASUSCOM: + ret = setup_asuscom(card); + break; +#endif +#if CARD_TELEINT + case ISDN_CTYPE_TELEINT: + ret = setup_TeleInt(card); + break; +#endif +#if CARD_SEDLBAUER + case ISDN_CTYPE_SEDLBAUER: + case ISDN_CTYPE_SEDLBAUER_PCMCIA: + case ISDN_CTYPE_SEDLBAUER_FAX: + ret = setup_sedlbauer(card); + break; +#endif +#if CARD_SPORTSTER + case ISDN_CTYPE_SPORTSTER: + ret = setup_sportster(card); + break; +#endif +#if CARD_MIC + case ISDN_CTYPE_MIC: + ret = setup_mic(card); + break; +#endif +#if CARD_NETJET_S + case ISDN_CTYPE_NETJET_S: + ret = setup_netjet_s(card); + break; +#endif +#if CARD_HFCS + case ISDN_CTYPE_TELES3C: + case ISDN_CTYPE_ACERP10: + ret = setup_hfcs(card); + break; +#endif +#if CARD_HFC_PCI + case ISDN_CTYPE_HFC_PCI: + ret = setup_hfcpci(card); + break; +#endif +#if CARD_HFC_SX + case ISDN_CTYPE_HFC_SX: + ret = setup_hfcsx(card); + break; +#endif +#if CARD_NICCY + case ISDN_CTYPE_NICCY: + ret = setup_niccy(card); + break; +#endif +#if CARD_AMD7930 + case ISDN_CTYPE_AMD7930: + ret = setup_amd7930(card); + break; +#endif +#if CARD_ISURF + case ISDN_CTYPE_ISURF: + ret = setup_isurf(card); + break; +#endif +#if CARD_HSTSAPHIR + case ISDN_CTYPE_HSTSAPHIR: + ret = setup_saphir(card); + break; +#endif +#if CARD_TESTEMU + case ISDN_CTYPE_TESTEMU: + ret = setup_testemu(card); + break; +#endif +#if CARD_BKM_A4T + case ISDN_CTYPE_BKM_A4T: + ret = setup_bkm_a4t(card); + break; +#endif +#if CARD_SCT_QUADRO + case ISDN_CTYPE_SCT_QUADRO: + ret = setup_sct_quadro(card); + break; +#endif +#if CARD_GAZEL + case ISDN_CTYPE_GAZEL: + ret = setup_gazel(card); + break; +#endif +#if CARD_W6692 + case ISDN_CTYPE_W6692: + ret = setup_w6692(card); + break; +#endif +#if CARD_NETJET_U + case ISDN_CTYPE_NETJET_U: + ret = setup_netjet_u(card); + break; +#endif +#if CARD_FN_ENTERNOW_PCI + case ISDN_CTYPE_ENTERNOW: + ret = setup_enternow_pci(card); + break; +#endif + case ISDN_CTYPE_DYNAMIC: + ret = 2; + break; + default: + printk(KERN_WARNING + "HiSax: Support for %s Card not selected\n", + CardType[card->typ]); + ll_unload(cs); + goto outf_cs; + } + if (!ret) { + ll_unload(cs); + goto outf_cs; + } + if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_ATOMIC))) { + printk(KERN_WARNING "HiSax: No memory for isac rcvbuf\n"); + ll_unload(cs); + goto outf_cs; + } + cs->rcvidx = 0; + cs->tx_skb = NULL; + cs->tx_cnt = 0; + cs->event = 0; + cs->tqueue.data = cs; + + skb_queue_head_init(&cs->rq); + skb_queue_head_init(&cs->sq); + + init_bcstate(cs, 0); + init_bcstate(cs, 1); + + /* init_card only handles interrupts which are not */ + /* used here for the loadable driver */ + switch (card->typ) { + case ISDN_CTYPE_DYNAMIC: + ret = 0; + break; + default: + ret = init_card(cs); + break; + } + if (ret) { + closecard(cardnr); + ret = 0; + goto outf_cs; + } + init_tei(cs, cs->protocol); + ret = CallcNewChan(cs); + if (ret) { + closecard(cardnr); + ret = 0; + goto outf_cs; + } + /* ISAR needs firmware download first */ + if (!test_bit(HW_ISAR, &cs->HW_Flags)) + ll_run(cs, 0); + + ret = 1; + goto out; + + outf_dlog: + kfree(cs->dlog); + outf_cs: + kfree(cs); + card->cs = NULL; + out: + return ret; +} + +void HiSax_shiftcards(int idx) +{ + int i; + + for (i = idx; i < (HISAX_MAX_CARDS - 1); i++) + memcpy(&cards[i], &cards[i + 1], sizeof(cards[i])); +} + +int HiSax_inithardware(int *busy_flag) +{ + int foundcards = 0; + int i = 0; + int t = ','; + int flg = 0; + char *id; + char *next_id = HiSax_id; + char ids[20]; + + if (strchr(HiSax_id, ',')) + t = ','; + else if (strchr(HiSax_id, '%')) + t = '%'; + + while (i < nrcards) { + if (cards[i].typ < 1) + break; + id = next_id; + if ((next_id = strchr(id, t))) { + *next_id++ = 0; + strcpy(ids, id); + flg = i + 1; + } else { + next_id = id; + if (flg >= i) + strcpy(ids, id); + else + sprintf(ids, "%s%d", id, i); + } + if (checkcard(i, ids, busy_flag, THIS_MODULE)) { + foundcards++; + i++; + } else { + /* make sure we don't oops the module */ + if (cards[i].typ > 0 && cards[i].typ <= ISDN_CTYPE_COUNT) { + printk(KERN_WARNING + "HiSax: Card %s not installed !\n", + CardType[cards[i].typ]); + } + HiSax_shiftcards(i); + nrcards--; + } + } + return foundcards; +} + +void HiSax_closecard(int cardnr) +{ + int i, last = nrcards - 1; + + if (cardnr > last || cardnr < 0) + return; + if (cards[cardnr].cs) { + ll_stop(cards[cardnr].cs); + release_tei(cards[cardnr].cs); + CallcFreeChan(cards[cardnr].cs); + + closecard(cardnr); + if (cards[cardnr].cs->irq) + free_irq(cards[cardnr].cs->irq, cards[cardnr].cs); + kfree((void *) cards[cardnr].cs); + cards[cardnr].cs = NULL; + } + i = cardnr; + while (i <= last) { + cards[i] = cards[i + 1]; + i++; + } + nrcards--; +} + +void HiSax_reportcard(int cardnr, int sel) +{ + struct IsdnCardState *cs = cards[cardnr].cs; + |