diff options
Diffstat (limited to 'drivers/isdn')
184 files changed, 100 insertions, 101479 deletions
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 1ca4d70d198a..be8387c0eeef 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig @@ -21,59 +21,8 @@ menuconfig ISDN if ISDN -menuconfig ISDN_I4L - tristate "Old ISDN4Linux (deprecated)" - depends on TTY - ---help--- - This driver allows you to use an ISDN adapter for networking - connections and as dialin/out device. The isdn-tty's have a built - in AT-compatible modem emulator. Network devices support autodial, - channel-bundling, callback and caller-authentication without having - a daemon running. A reduced T.70 protocol is supported with tty's - suitable for German BTX. On D-Channel, the protocols EDSS1 - (Euro-ISDN) and 1TR6 (German style) are supported. See - <file:Documentation/isdn/README> for more information. - - ISDN support in the linux kernel is moving towards a new API, - called CAPI (Common ISDN Application Programming Interface). - Therefore the old ISDN4Linux layer will eventually become obsolete. - It is still available, though, for use with adapters that are not - supported by the new CAPI subsystem yet. - -source "drivers/isdn/i4l/Kconfig" - -menuconfig ISDN_CAPI - tristate "CAPI 2.0 subsystem" - help - This provides CAPI (the Common ISDN Application Programming - Interface) Version 2.0, a standard making it easy for programs to - access ISDN hardware in a device independent way. (For details see - <http://www.capi.org/>.) CAPI supports making and accepting voice - and data connections, controlling call options and protocols, - as well as ISDN supplementary services like call forwarding or - three-party conferences (if supported by the specific hardware - driver). - - Select this option and the appropriate hardware driver below if - you have an ISDN adapter supported by the CAPI subsystem. - -if ISDN_CAPI - source "drivers/isdn/capi/Kconfig" -source "drivers/isdn/hardware/Kconfig" - -endif # ISDN_CAPI - -source "drivers/isdn/gigaset/Kconfig" - -source "drivers/isdn/hysdn/Kconfig" - source "drivers/isdn/mISDN/Kconfig" -config ISDN_HDLC - tristate - select CRC_CCITT - select BITREVERSE - endif # ISDN diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index e7d3d8f2ad5a..63baf27a2c79 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -3,12 +3,6 @@ # Object files in subdirectories -obj-$(CONFIG_ISDN_I4L) += i4l/ obj-$(CONFIG_ISDN_CAPI) += capi/ obj-$(CONFIG_MISDN) += mISDN/ obj-$(CONFIG_ISDN) += hardware/ -obj-$(CONFIG_ISDN_DIVERSION) += divert/ -obj-$(CONFIG_ISDN_DRV_HISAX) += hisax/ -obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop/ -obj-$(CONFIG_HYSDN) += hysdn/ -obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/ diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig index abaadce376c5..573fea5500ce 100644 --- a/drivers/isdn/capi/Kconfig +++ b/drivers/isdn/capi/Kconfig @@ -1,4 +1,22 @@ # SPDX-License-Identifier: GPL-2.0-only +menuconfig ISDN_CAPI + tristate "CAPI 2.0 subsystem" + help + This provides CAPI (the Common ISDN Application Programming + Interface) Version 2.0, a standard making it easy for programs to + access ISDN hardware in a device independent way. (For details see + <http://www.capi.org/>.) CAPI supports making and accepting voice + and data connections, controlling call options and protocols, + as well as ISDN supplementary services like call forwarding or + three-party conferences (if supported by the specific hardware + driver). + + This subsystem requires a hardware specific driver. + See CONFIG_BT_CMTP for the last remaining regular driver + in the kernel that uses the CAPI subsystem. + +if ISDN_CAPI + config CAPI_TRACE bool "CAPI trace support" default y @@ -27,15 +45,6 @@ config ISDN_CAPI_MIDDLEWARE device. If you want to use pppd with pppdcapiplugin to dial up to your ISP, say Y here. -config ISDN_CAPI_CAPIDRV - tristate "CAPI2.0 capidrv interface support" - depends on ISDN_I4L - help - This option provides the glue code to hook up CAPI driven cards to - the legacy isdn4linux link layer. If you have a card which is - supported by a CAPI driver, but still want to use old features like - ippp interfaces or ttyI emulation, say Y/M here. - config ISDN_CAPI_CAPIDRV_VERBOSE bool "Verbose reason code reporting" depends on ISDN_CAPI_CAPIDRV @@ -43,3 +52,5 @@ config ISDN_CAPI_CAPIDRV_VERBOSE If you say Y here, the capidrv interface will give verbose reasons for disconnecting. This will increase the size of the kernel by 7 KB. If unsure, say N. + +endif diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile index 06da3ed2c40a..d299f3e75f89 100644 --- a/drivers/isdn/capi/Makefile +++ b/drivers/isdn/capi/Makefile @@ -13,3 +13,5 @@ obj-$(CONFIG_ISDN_CAPI_CAPIDRV) += capidrv.o kernelcapi-y := kcapi.o capiutil.o capilib.o kernelcapi-$(CONFIG_PROC_FS) += kcapi_proc.o + +ccflags-y += -I$(srctree)/$(src)/../include -I$(srctree)/$(src)/../include/uapi diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c deleted file mode 100644 index e8949f3dcae1..000000000000 --- a/drivers/isdn/capi/capidrv.c +++ /dev/null @@ -1,2525 +0,0 @@ -/* $Id: capidrv.c,v 1.1.2.2 2004/01/12 23:17:24 keil Exp $ - * - * ISDN4Linux Driver, using capi20 interface (kernelcapi) - * - * Copyright 1997 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/compiler.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/slab.h> -#include <linux/fcntl.h> -#include <linux/fs.h> -#include <linux/signal.h> -#include <linux/mm.h> -#include <linux/timer.h> -#include <linux/wait.h> -#include <linux/skbuff.h> -#include <linux/isdn.h> -#include <linux/isdnif.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/capi.h> -#include <linux/kernelcapi.h> -#include <linux/ctype.h> -#include <linux/init.h> -#include <linux/moduleparam.h> - -#include <linux/isdn/capiutil.h> -#include <linux/isdn/capicmd.h> -#include "capidrv.h" - -static int debugmode = 0; - -MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); -module_param(debugmode, uint, S_IRUGO | S_IWUSR); - -/* -------- type definitions ----------------------------------------- */ - - -struct capidrv_contr { - - struct capidrv_contr *next; - struct module *owner; - u32 contrnr; - char name[20]; - - /* - * for isdn4linux - */ - isdn_if interface; - int myid; - - /* - * LISTEN state - */ - int state; - u32 cipmask; - u32 cipmask2; - struct timer_list listentimer; - - /* - * ID of capi message sent - */ - u16 msgid; - - /* - * B-Channels - */ - int nbchan; - struct capidrv_bchan { - struct capidrv_contr *contr; - u8 msn[ISDN_MSNLEN]; - int l2; - int l3; - u8 num[ISDN_MSNLEN]; - u8 mynum[ISDN_MSNLEN]; - int si1; - int si2; - int incoming; - int disconnecting; - struct capidrv_plci { - struct capidrv_plci *next; - u32 plci; - u32 ncci; /* ncci for CONNECT_ACTIVE_IND */ - u16 msgid; /* to identfy CONNECT_CONF */ - int chan; - int state; - int leasedline; - struct capidrv_ncci { - struct capidrv_ncci *next; - struct capidrv_plci *plcip; - u32 ncci; - u16 msgid; /* to identfy CONNECT_B3_CONF */ - int chan; - int state; - int oldstate; - /* */ - u16 datahandle; - struct ncci_datahandle_queue { - struct ncci_datahandle_queue *next; - u16 datahandle; - int len; - } *ackqueue; - } *ncci_list; - } *plcip; - struct capidrv_ncci *nccip; - } *bchans; - - struct capidrv_plci *plci_list; - - /* for q931 data */ - u8 q931_buf[4096]; - u8 *q931_read; - u8 *q931_write; - u8 *q931_end; -}; - - -struct capidrv_data { - struct capi20_appl ap; - int ncontr; - struct capidrv_contr *contr_list; -}; - -typedef struct capidrv_plci capidrv_plci; -typedef struct capidrv_ncci capidrv_ncci; -typedef struct capidrv_contr capidrv_contr; -typedef struct capidrv_data capidrv_data; -typedef struct capidrv_bchan capidrv_bchan; - -/* -------- data definitions ----------------------------------------- */ - -static capidrv_data global; -static DEFINE_SPINLOCK(global_lock); - -static void handle_dtrace_data(capidrv_contr *card, - int send, int level2, u8 *data, u16 len); - -/* -------- convert functions ---------------------------------------- */ - -static inline u32 b1prot(int l2, int l3) -{ - switch (l2) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - return 0; - case ISDN_PROTO_L2_HDLC: - default: - return 0; - case ISDN_PROTO_L2_TRANS: - return 1; - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - return 2; - case ISDN_PROTO_L2_FAX: - return 4; - case ISDN_PROTO_L2_MODEM: - return 8; - } -} - -static inline u32 b2prot(int l2, int l3) -{ - switch (l2) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - default: - return 0; - case ISDN_PROTO_L2_HDLC: - case ISDN_PROTO_L2_TRANS: - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - case ISDN_PROTO_L2_MODEM: - return 1; - case ISDN_PROTO_L2_FAX: - return 4; - } -} - -static inline u32 b3prot(int l2, int l3) -{ - switch (l2) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - case ISDN_PROTO_L2_HDLC: - case ISDN_PROTO_L2_TRANS: - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - case ISDN_PROTO_L2_MODEM: - default: - return 0; - case ISDN_PROTO_L2_FAX: - return 4; - } -} - -static _cstruct b1config_async_v110(u16 rate) -{ - /* CAPI-Spec "B1 Configuration" */ - static unsigned char buf[9]; - buf[0] = 8; /* len */ - /* maximum bitrate */ - buf[1] = rate & 0xff; buf[2] = (rate >> 8) & 0xff; - buf[3] = 8; buf[4] = 0; /* 8 bits per character */ - buf[5] = 0; buf[6] = 0; /* parity none */ - buf[7] = 0; buf[8] = 0; /* 1 stop bit */ - return buf; -} - -static _cstruct b1config(int l2, int l3) -{ - switch (l2) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - case ISDN_PROTO_L2_HDLC: - case ISDN_PROTO_L2_TRANS: - default: - return NULL; - case ISDN_PROTO_L2_V11096: - return b1config_async_v110(9600); - case ISDN_PROTO_L2_V11019: - return b1config_async_v110(19200); - case ISDN_PROTO_L2_V11038: - return b1config_async_v110(38400); - } -} - -static inline u16 si2cip(u8 si1, u8 si2) -{ - static const u8 cip[17][5] = - { - /* 0 1 2 3 4 */ - {0, 0, 0, 0, 0}, /*0 */ - {16, 16, 4, 26, 16}, /*1 */ - {17, 17, 17, 4, 4}, /*2 */ - {2, 2, 2, 2, 2}, /*3 */ - {18, 18, 18, 18, 18}, /*4 */ - {2, 2, 2, 2, 2}, /*5 */ - {0, 0, 0, 0, 0}, /*6 */ - {2, 2, 2, 2, 2}, /*7 */ - {2, 2, 2, 2, 2}, /*8 */ - {21, 21, 21, 21, 21}, /*9 */ - {19, 19, 19, 19, 19}, /*10 */ - {0, 0, 0, 0, 0}, /*11 */ - {0, 0, 0, 0, 0}, /*12 */ - {0, 0, 0, 0, 0}, /*13 */ - {0, 0, 0, 0, 0}, /*14 */ - {22, 22, 22, 22, 22}, /*15 */ - {27, 27, 27, 28, 27} /*16 */ - }; - if (si1 > 16) - si1 = 0; - if (si2 > 4) - si2 = 0; - - return (u16) cip[si1][si2]; -} - -static inline u8 cip2si1(u16 cipval) -{ - static const u8 si[32] = - {7, 1, 7, 7, 1, 1, 7, 7, /*0-7 */ - 7, 1, 0, 0, 0, 0, 0, 0, /*8-15 */ - 1, 2, 4, 10, 9, 9, 15, 7, /*16-23 */ - 7, 7, 1, 16, 16, 0, 0, 0}; /*24-31 */ - - if (cipval > 31) - cipval = 0; /* .... */ - return si[cipval]; -} - -static inline u8 cip2si2(u16 cipval) -{ - static const u8 si[32] = - {0, 0, 0, 0, 2, 3, 0, 0, /*0-7 */ - 0, 3, 0, 0, 0, 0, 0, 0, /*8-15 */ - 1, 2, 0, 0, 9, 0, 0, 0, /*16-23 */ - 0, 0, 3, 2, 3, 0, 0, 0}; /*24-31 */ - - if (cipval > 31) - cipval = 0; /* .... */ - return si[cipval]; -} - - -/* -------- controller management ------------------------------------- */ - -static inline capidrv_contr *findcontrbydriverid(int driverid) -{ - unsigned long flags; - capidrv_contr *p; - - spin_lock_irqsave(&global_lock, flags); - for (p = global.contr_list; p; p = p->next) - if (p->myid == driverid) - break; - spin_unlock_irqrestore(&global_lock, flags); - return p; -} - -static capidrv_contr *findcontrbynumber(u32 contr) -{ - unsigned long flags; - capidrv_contr *p = global.contr_list; - - spin_lock_irqsave(&global_lock, flags); - for (p = global.contr_list; p; p = p->next) - if (p->contrnr == contr) - break; - spin_unlock_irqrestore(&global_lock, flags); - return p; -} - - -/* -------- plci management ------------------------------------------ */ - -static capidrv_plci *new_plci(capidrv_contr *card, int chan) -{ - capidrv_plci *plcip; - - plcip = kzalloc(sizeof(capidrv_plci), GFP_ATOMIC); - - if (plcip == NULL) - return NULL; - - plcip->state = ST_PLCI_NONE; - plcip->plci = 0; - plcip->msgid = 0; - plcip->chan = chan; - plcip->next = card->plci_list; - card->plci_list = plcip; - card->bchans[chan].plcip = plcip; - - return plcip; -} - -static capidrv_plci *find_plci_by_plci(capidrv_contr *card, u32 plci) -{ - capidrv_plci *p; - for (p = card->plci_list; p; p = p->next) - if (p->plci == plci) - return p; - return NULL; -} - -static capidrv_plci *find_plci_by_msgid(capidrv_contr *card, u16 msgid) -{ - capidrv_plci *p; - for (p = card->plci_list; p; p = p->next) - if (p->msgid == msgid) - return p; - return NULL; -} - -static capidrv_plci *find_plci_by_ncci(capidrv_contr *card, u32 ncci) -{ - capidrv_plci *p; - for (p = card->plci_list; p; p = p->next) - if (p->plci == (ncci & 0xffff)) - return p; - return NULL; -} - -static void free_plci(capidrv_contr *card, capidrv_plci *plcip) -{ - capidrv_plci **pp; - - for (pp = &card->plci_list; *pp; pp = &(*pp)->next) { - if (*pp == plcip) { - *pp = (*pp)->next; - card->bchans[plcip->chan].plcip = NULL; - card->bchans[plcip->chan].disconnecting = 0; - card->bchans[plcip->chan].incoming = 0; - kfree(plcip); - return; - } - } - printk(KERN_ERR "capidrv-%d: free_plci %p (0x%x) not found, Huh?\n", - card->contrnr, plcip, plcip->plci); -} - -/* -------- ncci management ------------------------------------------ */ - -static inline capidrv_ncci *new_ncci(capidrv_contr *card, - capidrv_plci *plcip, - u32 ncci) -{ - capidrv_ncci *nccip; - - nccip = kzalloc(sizeof(capidrv_ncci), GFP_ATOMIC); - - if (nccip == NULL) - return NULL; - - nccip->ncci = ncci; - nccip->state = ST_NCCI_NONE; - nccip->plcip = plcip; - nccip->chan = plcip->chan; - nccip->datahandle = 0; - - nccip->next = plcip->ncci_list; - plcip->ncci_list = nccip; - - card->bchans[plcip->chan].nccip = nccip; - - return nccip; -} - -static inline capidrv_ncci *find_ncci(capidrv_contr *card, u32 ncci) -{ - capidrv_plci *plcip; - capidrv_ncci *p; - - if ((plcip = find_plci_by_ncci(card, ncci)) == NULL) - return NULL; - - for (p = plcip->ncci_list; p; p = p->next) - if (p->ncci == ncci) - return p; - return NULL; -} - -static inline capidrv_ncci *find_ncci_by_msgid(capidrv_contr *card, - u32 ncci, u16 msgid) -{ - capidrv_plci *plcip; - capidrv_ncci *p; - - if ((plcip = find_plci_by_ncci(card, ncci)) == NULL) - return NULL; - - for (p = plcip->ncci_list; p; p = p->next) - if (p->msgid == msgid) - return p; - return NULL; -} - -static void free_ncci(capidrv_contr *card, struct capidrv_ncci *nccip) -{ - struct capidrv_ncci **pp; - - for (pp = &(nccip->plcip->ncci_list); *pp; pp = &(*pp)->next) { - if (*pp == nccip) { - *pp = (*pp)->next; - break; - } - } - card->bchans[nccip->chan].nccip = NULL; - kfree(nccip); -} - -static int capidrv_add_ack(struct capidrv_ncci *nccip, - u16 datahandle, int len) -{ - struct ncci_datahandle_queue *n, **pp; - - n = kmalloc(sizeof(struct ncci_datahandle_queue), GFP_ATOMIC); - if (!n) { - printk(KERN_ERR "capidrv: kmalloc ncci_datahandle failed\n"); - return -1; - } - n->next = NULL; - n->datahandle = datahandle; - n->len = len; - for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next); - *pp = n; - return 0; -} - -static int capidrv_del_ack(struct capidrv_ncci *nccip, u16 datahandle) -{ - struct ncci_datahandle_queue **pp, *p; - int len; - - for (pp = &nccip->ackqueue; *pp; pp = &(*pp)->next) { - if ((*pp)->datahandle == datahandle) { - p = *pp; - len = p->len; - *pp = (*pp)->next; - kfree(p); - return len; - } - } - return -1; -} - -/* -------- convert and send capi message ---------------------------- */ - -static void send_message(capidrv_contr *card, _cmsg *cmsg) -{ - struct sk_buff *skb; - size_t len; - - if (capi_cmsg2message(cmsg, cmsg->buf)) { - printk(KERN_ERR "capidrv::send_message: parser failure\n"); - return; - } - len = CAPIMSG_LEN(cmsg->buf); - skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) { - printk(KERN_ERR "capidrv::send_message: can't allocate mem\n"); - return; - } - skb_put_data(skb, cmsg->buf, len); - if (capi20_put_message(&global.ap, skb) != CAPI_NOERROR) - kfree_skb(skb); -} - -/* -------- state machine -------------------------------------------- */ - -struct listenstatechange { - int actstate; - int nextstate; - int event; -}; - -static struct listenstatechange listentable[] = -{ - {ST_LISTEN_NONE, ST_LISTEN_WAIT_CONF, EV_LISTEN_REQ}, - {ST_LISTEN_ACTIVE, ST_LISTEN_ACTIVE_WAIT_CONF, EV_LISTEN_REQ}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_ERROR}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_ERROR}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_NONE, EV_LISTEN_CONF_EMPTY}, - {ST_LISTEN_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, - {ST_LISTEN_ACTIVE_WAIT_CONF, ST_LISTEN_ACTIVE, EV_LISTEN_CONF_OK}, - {}, -}; - -static void listen_change_state(capidrv_contr *card, int event) -{ - struct listenstatechange *p = listentable; - while (p->event) { - if (card->state == p->actstate && p->event == event) { - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: listen_change_state %d -> %d\n", - card->contrnr, card->state, p->nextstate); - card->state = p->nextstate; - return; - } - p++; - } - printk(KERN_ERR "capidrv-%d: listen_change_state state=%d event=%d ????\n", - card->contrnr, card->state, event); - -} - -/* ------------------------------------------------------------------ */ - -static void p0(capidrv_contr *card, capidrv_plci *plci) -{ - isdn_ctrl cmd; - - card->bchans[plci->chan].contr = NULL; - cmd.command = ISDN_STAT_DHUP; - cmd.driver = card->myid; - cmd.arg = plci->chan; - card->interface.statcallb(&cmd); - free_plci(card, plci); -} - -/* ------------------------------------------------------------------ */ - -struct plcistatechange { - int actstate; - int nextstate; - int event; - void (*changefunc)(capidrv_contr *card, capidrv_plci *plci); -}; - -static struct plcistatechange plcitable[] = -{ - /* P-0 */ - {ST_PLCI_NONE, ST_PLCI_OUTGOING, EV_PLCI_CONNECT_REQ, NULL}, - {ST_PLCI_NONE, ST_PLCI_ALLOCATED, EV_PLCI_FACILITY_IND_UP, NULL}, - {ST_PLCI_NONE, ST_PLCI_INCOMING, EV_PLCI_CONNECT_IND, NULL}, - {ST_PLCI_NONE, ST_PLCI_RESUMEING, EV_PLCI_RESUME_REQ, NULL}, - /* P-0.1 */ - {ST_PLCI_OUTGOING, ST_PLCI_NONE, EV_PLCI_CONNECT_CONF_ERROR, p0}, - {ST_PLCI_OUTGOING, ST_PLCI_ALLOCATED, EV_PLCI_CONNECT_CONF_OK, NULL}, - /* P-1 */ - {ST_PLCI_ALLOCATED, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_ALLOCATED, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-ACT */ - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_HELD, EV_PLCI_HOLD_IND, NULL}, - {ST_PLCI_ACTIVE, ST_PLCI_DISCONNECTING, EV_PLCI_SUSPEND_IND, NULL}, - /* P-2 */ - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_FACILITY_IND, EV_PLCI_FACILITY_IND_UP, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_RESP, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - {ST_PLCI_INCOMING, ST_PLCI_DISCONNECTING, EV_PLCI_CD_IND, NULL}, - /* P-3 */ - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_CONNECT_REJECT, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_ACCEPTING, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_FACILITY_IND, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-4 */ - {ST_PLCI_ACCEPTING, ST_PLCI_ACTIVE, EV_PLCI_CONNECT_ACTIVE_IND, NULL}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_DISCONNECT_REQ, NULL}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTING, EV_PLCI_FACILITY_IND_DOWN, NULL}, - {ST_PLCI_ACCEPTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-5 */ - {ST_PLCI_DISCONNECTING, ST_PLCI_DISCONNECTED, EV_PLCI_DISCONNECT_IND, NULL}, - /* P-6 */ - {ST_PLCI_DISCONNECTED, ST_PLCI_NONE, EV_PLCI_DISCONNECT_RESP, p0}, - /* P-0.Res */ - {ST_PLCI_RESUMEING, ST_PLCI_NONE, EV_PLCI_RESUME_CONF_ERROR, p0}, - {ST_PLCI_RESUMEING, ST_PLCI_RESUME, EV_PLCI_RESUME_CONF_OK, NULL}, - /* P-RES */ - {ST_PLCI_RESUME, ST_PLCI_ACTIVE, EV_PLCI_RESUME_IND, NULL}, - /* P-HELD */ - {ST_PLCI_HELD, ST_PLCI_ACTIVE, EV_PLCI_RETRIEVE_IND, NULL}, - {}, -}; - -static void plci_change_state(capidrv_contr *card, capidrv_plci *plci, int event) -{ - struct plcistatechange *p = plcitable; - while (p->event) { - if (plci->state == p->actstate && p->event == event) { - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: plci_change_state:0x%x %d -> %d\n", - card->contrnr, plci->plci, plci->state, p->nextstate); - plci->state = p->nextstate; - if (p->changefunc) - p->changefunc(card, plci); - return; - } - p++; - } - printk(KERN_ERR "capidrv-%d: plci_change_state:0x%x state=%d event=%d ????\n", - card->contrnr, plci->plci, plci->state, event); -} - -/* ------------------------------------------------------------------ */ - -static _cmsg cmsg; - -static void n0(capidrv_contr *card, capidrv_ncci *ncci) -{ - isdn_ctrl cmd; - - capi_fill_DISCONNECT_REQ(&cmsg, - global.ap.applid, - card->msgid++, - ncci->plcip->plci, - NULL, /* BChannelinformation */ - NULL, /* Keypadfacility */ - NULL, /* Useruserdata */ /* $$$$ */ - NULL /* Facilitydataarray */ - ); - plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ); - send_message(card, &cmsg); - - cmd.command = ISDN_STAT_BHUP; - cmd.driver = card->myid; - cmd.arg = ncci->chan; - card->interface.statcallb(&cmd); - free_ncci(card, ncci); -} - -/* ------------------------------------------------------------------ */ - -struct nccistatechange { - int actstate; - int nextstate; - int event; - void (*changefunc)(capidrv_contr *card, capidrv_ncci *ncci); -}; - -static struct nccistatechange nccitable[] = -{ - /* N-0 */ - {ST_NCCI_NONE, ST_NCCI_OUTGOING, EV_NCCI_CONNECT_B3_REQ, NULL}, - {ST_NCCI_NONE, ST_NCCI_INCOMING, EV_NCCI_CONNECT_B3_IND, NULL}, - /* N-0.1 */ - {ST_NCCI_OUTGOING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_CONF_OK, NULL}, - {ST_NCCI_OUTGOING, ST_NCCI_NONE, EV_NCCI_CONNECT_B3_CONF_ERROR, n0}, - /* N-1 */ - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_CONNECT_B3_REJECT, NULL}, - {ST_NCCI_INCOMING, ST_NCCI_ALLOCATED, EV_NCCI_CONNECT_B3_RESP, NULL}, - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_INCOMING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-2 */ - {ST_NCCI_ALLOCATED, ST_NCCI_ACTIVE, EV_NCCI_CONNECT_B3_ACTIVE_IND, NULL}, - {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_ALLOCATED, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-ACT */ - {ST_NCCI_ACTIVE, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL}, - {ST_NCCI_ACTIVE, ST_NCCI_RESETING, EV_NCCI_RESET_B3_REQ, NULL}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_ACTIVE, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-3 */ - {ST_NCCI_RESETING, ST_NCCI_ACTIVE, EV_NCCI_RESET_B3_IND, NULL}, - {ST_NCCI_RESETING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_RESETING, ST_NCCI_DISCONNECTING, EV_NCCI_DISCONNECT_B3_REQ, NULL}, - /* N-4 */ - {ST_NCCI_DISCONNECTING, ST_NCCI_DISCONNECTED, EV_NCCI_DISCONNECT_B3_IND, NULL}, - {ST_NCCI_DISCONNECTING, ST_NCCI_PREVIOUS, EV_NCCI_DISCONNECT_B3_CONF_ERROR, NULL}, - /* N-5 */ - {ST_NCCI_DISCONNECTED, ST_NCCI_NONE, EV_NCCI_DISCONNECT_B3_RESP, n0}, - {}, -}; - -static void ncci_change_state(capidrv_contr *card, capidrv_ncci *ncci, int event) -{ - struct nccistatechange *p = nccitable; - while (p->event) { - if (ncci->state == p->actstate && p->event == event) { - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ncci_change_state:0x%x %d -> %d\n", - card->contrnr, ncci->ncci, ncci->state, p->nextstate); - if (p->nextstate == ST_NCCI_PREVIOUS) { - ncci->state = ncci->oldstate; - ncci->oldstate = p->actstate; - } else { - ncci->oldstate = p->actstate; - ncci->state = p->nextstate; - } - if (p->changefunc) - p->changefunc(card, ncci); - return; - } - p++; - } - printk(KERN_ERR "capidrv-%d: ncci_change_state:0x%x state=%d event=%d ????\n", - card->contrnr, ncci->ncci, ncci->state, event); -} - -/* ------------------------------------------------------------------- */ - -static inline int new_bchan(capidrv_contr *card) -{ - int i; - for (i = 0; i < card->nbchan; i++) { - if (card->bchans[i].plcip == NULL) { - card->bchans[i].disconnecting = 0; - return i; - } - } - return -1; -} - -/* ------------------------------------------------------------------- */ -static char *capi_info2str(u16 reason) -{ -#ifndef CONFIG_ISDN_CAPI_CAPIDRV_VERBOSE - return ".."; -#else - switch (reason) { - -/*-- informative values (corresponding message was processed) -----*/ - case 0x0001: - return "NCPI not supported by current protocol, NCPI ignored"; - case 0x0002: - return "Flags not supported by current protocol, flags ignored"; - case 0x0003: - return "Alert already sent by another application"; - -/*-- error information concerning CAPI_REGISTER -----*/ - case 0x1001: - return "Too many applications"; - case 0x1002: - return "Logical block size too small, must be at least 128 Bytes"; - case 0x1003: - return "Buffer exceeds 64 kByte"; - case 0x1004: - return "Message buffer size too small, must be at least 1024 Bytes"; - case 0x1005: - return "Max. number of logical connections not supported"; - case 0x1006: - return "Reserved"; - case 0x1007: - return "The message could not be accepted because of an internal busy condition"; - case 0x1008: - return "OS resource error (no memory ?)"; - case 0x1009: - return "CAPI not installed"; - case 0x100A: - return "Controller does not support external equipment"; - case 0x100B: - return "Controller does only support external equipment"; - -/*-- error information concerning message exchange functions -----*/ - case 0x1101: - return "Illegal application number"; - case 0x1102: - return "Illegal command or subcommand or message length less than 12 bytes"; - case 0x1103: - return "The message could not be accepted because of a queue full condition !! The error code does not imply that CAPI cannot receive messages directed to another controller, PLCI or NCCI"; - case 0x1104: - return "Queue is empty"; - case 0x1105: - return "Queue overflow, a message was lost !! This indicates a configuration error. The only recovery from this error is to perform a CAPI_RELEASE"; - case 0x1106: - return "Unknown notification parameter"; - case 0x1107: - return "The Message could not be accepted because of an internal busy condition"; - case 0x1108: - return "OS Resource error (no memory ?)"; - case 0x1109: - return "CAPI not installed"; - case 0x110A: - return "Controller does not support external equipment"; - case 0x110B: - return "Controller does only support external equipment"; - -/*-- error information concerning resource / coding problems -----*/ - case 0x2001: - return "Message not supported in current state"; - case 0x2002: - return "Illegal Controller / PLCI / NCCI"; - case 0x2003: - return "Out of PLCI"; - case 0x2004: - return "Out of NCCI"; - case 0x2005: - return "Out of LISTEN"; - case 0x2006: - return "Out of FAX resources (protocol T.30)"; - case 0x2007: - return "Illegal message parameter coding"; - -/*-- error information concerning requested services -----*/ - case 0x3001: - return "B1 protocol not supported"; - case 0x3002: - return "B2 protocol not supported"; - case 0x3003: - return "B3 protocol not supported"; - case 0x3004: - return "B1 protocol parameter not supported"; - case 0x3005: - return "B2 protocol parameter not supported"; - case 0x3006: - return "B3 protocol parameter not supported"; - case 0x3007: - return "B protocol combination not supported"; - case 0x3008: - return "NCPI not supported"; - case 0x3009: - return "CIP Value unknown"; - case 0x300A: - return "Flags not supported (reserved bits)"; - case 0x300B: - return "Facility not supported"; - case 0x300C: - return "Data length not supported by current protocol"; - case 0x300D: - return "Reset procedure not supported by current protocol"; - -/*-- informations about the clearing of a physical connection -----*/ - case 0x3301: - return "Protocol error layer 1 (broken line or B-channel removed by signalling protocol)"; - case 0x3302: - return "Protocol error layer 2"; - case 0x3303: - return "Protocol error layer 3"; - case 0x3304: - return "Another application got that call"; -/*-- T.30 specific reasons -----*/ - case 0x3311: - return "Connecting not successful (remote station is no FAX G3 machine)"; - case 0x3312: - return "Connecting not successful (training error)"; - case 0x3313: - return "Disconnected before transfer (remote station does not support transfer mode, e.g. resolution)"; - case 0x3314: - return "Disconnected during transfer (remote abort)"; - case 0x3315: - return "Disconnected during transfer (remote procedure error, e.g. unsuccessful repetition of T.30 commands)"; - case 0x3316: - return "Disconnected during transfer (local tx data underrun)"; - case 0x3317: - return "Disconnected during transfer (local rx data overflow)"; - case 0x3318: - return "Disconnected during transfer (local abort)"; - case 0x3319: - return "Illegal parameter coding (e.g. SFF coding error)"; - -/*-- disconnect causes from the network according to ETS 300 102-1/Q.931 -----*/ - case 0x3481: return "Unallocated (unassigned) number"; - case 0x3482: return "No route to specified transit network"; - case 0x3483: return "No route to destination"; - case 0x3486: return "Channel unacceptable"; - case 0x3487: - return "Call awarded and being delivered in an established channel"; - case 0x3490: return "Normal call clearing"; - case 0x3491: return "User busy"; - case 0x3492: return "No user responding"; - case 0x3493: return "No answer from user (user alerted)"; - case 0x3495: return "Call rejected"; - case 0x3496: return "Number changed"; - case 0x349A: return "Non-selected user clearing"; - case 0x349B: return "Destination out of order"; - case 0x349C: return "Invalid number format"; - case 0x349D: return "Facility rejected"; - case 0x349E: return "Response to STATUS ENQUIRY"; - case 0x349F: return "Normal, unspecified"; - case 0x34A2: return "No circuit / channel available"; - case 0x34A6: return "Network out of order"; - case 0x34A9: return "Temporary failure"; - case 0x34AA: return "Switching equipment congestion"; - case 0x34AB: return "Access information discarded"; - case 0x34AC: return "Requested circuit / channel not available"; - case 0x34AF: return "Resources unavailable, unspecified"; - case 0x34B1: return "Quality of service unavailable"; - case 0x34B2: return "Requested facility not subscribed"; - case 0x34B9: return "Bearer capability not authorized"; - case 0x34BA: return "Bearer capability not presently available"; - case 0x34BF: return "Service or option not available, unspecified"; - case 0x34C1: return "Bearer capability not implemented"; - case 0x34C2: return "Channel type not implemented"; - case 0x34C5: return "Requested facility not implemented"; - case 0x34C6: return "Only restricted digital information bearer capability is available"; - case 0x34CF: return "Service or option not implemented, unspecified"; - case 0x34D1: return "Invalid call reference value"; - case 0x34D2: return "Identified channel does not exist"; - case 0x34D3: return "A suspended call exists, but this call identity does not"; - case 0x34D4: return "Call identity in use"; - case 0x34D5: return "No call suspended"; - case 0x34D6: return "Call having the requested call identity has been cleared"; - case 0x34D8: return "Incompatible destination"; - case 0x34DB: return "Invalid transit network selection"; - case 0x34DF: return "Invalid message, unspecified"; - case 0x34E0: return "Mandatory information element is missing"; - case 0x34E1: return "Message type non-existent or not implemented"; - case 0x34E2: return "Message not compatible with call state or message type non-existent or not implemented"; - case 0x34E3: return "Information element non-existent or not implemented"; - case 0x34E4: return "Invalid information element contents"; - case 0x34E5: return "Message not compatible with call state"; - case 0x34E6: return "Recovery on timer expiry"; - case 0x34EF: return "Protocol error, unspecified"; - case 0x34FF: return "Interworking, unspecified"; - - default: return "No additional information"; - } -#endif -} - -static void handle_controller(_cmsg *cmsg) -{ - capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); - - if (!card) { - printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController & 0x7f); - return; - } - switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { - - case CAPI_LISTEN_CONF: /* Controller */ - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: listenconf Info=0x%4x (%s) cipmask=0x%x\n", - card->contrnr, cmsg->Info, capi_info2str(cmsg->Info), card->cipmask); - if (cmsg->Info) { - listen_change_state(card, EV_LISTEN_CONF_ERROR); - } else if (card->cipmask == 0) { - listen_change_state(card, EV_LISTEN_CONF_EMPTY); - } else { - listen_change_state(card, EV_LISTEN_CONF_OK); - } - break; - - case CAPI_MANUFACTURER_IND: /* Controller */ - if (cmsg->ManuID == 0x214D5641 - && cmsg->Class == 0 - && cmsg->Function == 1) { - u8 *data = cmsg->ManuData + 3; - u16 len = cmsg->ManuData[0]; - u16 layer; - int direction; - if (len == 255) { - len = (cmsg->ManuData[1] | (cmsg->ManuData[2] << 8)); - data += 2; - } - len -= 2; - layer = ((*(data - 1)) << 8) | *(data - 2); - if (layer & 0x300) - direction = (layer & 0x200) ? 0 : 1; - else direction = (layer & 0x800) ? 0 : 1; - if (layer & 0x0C00) { - if ((layer & 0xff) == 0x80) { - handle_dtrace_data(card, direction, 1, data, len); - break; - } - } else if ((layer & 0xff) < 0x80) { - handle_dtrace_data(card, direction, 0, data, len); - break; - } - printk(KERN_INFO "capidrv-%d: %s from controller 0x%x layer 0x%x, ignored\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController, layer); - break; - } - goto ignored; - case CAPI_MANUFACTURER_CONF: /* Controller */ - if (cmsg->ManuID == 0x214D5641) { - char *s = NULL; - switch (cmsg->Class) { - case 0: break; - case 1: s = "unknown class"; break; - case 2: s = "unknown function"; break; - default: s = "unknown error"; break; - } - if (s) - printk(KERN_INFO "capidrv-%d: %s from controller 0x%x function %d: %s\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController, - cmsg->Function, s); - break; - } - goto ignored; - case CAPI_FACILITY_IND: /* Controller/plci/ncci */ - goto ignored; - case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ - goto ignored; - case CAPI_INFO_IND: /* Controller/plci */ - goto ignored; - case CAPI_INFO_CONF: /* Controller/plci */ - goto ignored; - - default: - printk(KERN_ERR "capidrv-%d: got %s from controller 0x%x ???", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController); - } - return; - -ignored: - printk(KERN_INFO "capidrv-%d: %s from controller 0x%x ignored\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController); -} - -static void handle_incoming_call(capidrv_contr *card, _cmsg *cmsg) -{ - capidrv_plci *plcip; - capidrv_bchan *bchan; - isdn_ctrl cmd; - int chan; - - if ((chan = new_bchan(card)) == -1) { - printk(KERN_ERR "capidrv-%d: incoming call on not existing bchan ?\n", card->contrnr); - return; - } - bchan = &card->bchans[chan]; - if ((plcip = new_plci(card, chan)) == NULL) { - printk(KERN_ERR "capidrv-%d: incoming call: no memory, sorry.\n", card->contrnr); - return; - } - bchan->incoming = 1; - plcip->plci = cmsg->adr.adrPLCI; - plci_change_state(card, plcip, EV_PLCI_CONNECT_IND); - - cmd.command = ISDN_STAT_ICALL; - cmd.driver = card->myid; - cmd.arg = chan; - memset(&cmd.parm.setup, 0, sizeof(cmd.parm.setup)); - strncpy(cmd.parm.setup.phone, - cmsg->CallingPartyNumber + 3, - cmsg->CallingPartyNumber[0] - 2); - strncpy(cmd.parm.setup.eazmsn, - cmsg->CalledPartyNumber + 2, - cmsg->CalledPartyNumber[0] - 1); - cmd.parm.setup.si1 = cip2si1(cmsg->CIPValue); - cmd.parm.setup.si2 = cip2si2(cmsg->CIPValue); - cmd.parm.setup.plan = cmsg->CallingPartyNumber[1]; - cmd.parm.setup.screen = cmsg->CallingPartyNumber[2]; - - printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); - - if (cmd.parm.setup.si1 == 1 && cmd.parm.setup.si2 != 0) { - printk(KERN_INFO "capidrv-%d: patching si2=%d to 0 for VBOX\n", - card->contrnr, - cmd.parm.setup.si2); - cmd.parm.setup.si2 = 0; - } - - switch (card->interface.statcallb(&cmd)) { - case 0: - case 3: - /* No device matching this call. - * and isdn_common.c has send a HANGUP command - * which is ignored in state ST_PLCI_INCOMING, - * so we send RESP to ignore the call - */ - capi_cmsg_answer(cmsg); - cmsg->Reject = 1; /* ignore */ - plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); - send_message(card, cmsg); - printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); - break; - case 1: - /* At least one device matching this call (RING on ttyI) - * HL-driver may send ALERTING on the D-channel in this - * case. - * really means: RING on ttyI or a net interface - * accepted this call already. - * - * If the call was accepted, state has already changed, - * and CONNECT_RESP already sent. - */ - if (plcip->state == ST_PLCI_INCOMING) { - printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s tty alerting\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); - capi_fill_ALERT_REQ(cmsg, - global.ap.applid, - card->msgid++, - plcip->plci, /* adr */ - NULL,/* BChannelinformation */ - NULL,/* Keypadfacility */ - NULL,/* Useruserdata */ - NULL /* Facilitydataarray */ - ); - plcip->msgid = cmsg->Messagenumber; - send_message(card, cmsg); - } else { - printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s on netdev\n", - card->contrnr, - cmd.parm.setup.phone, - cmd.parm.setup.si1, - cmd.parm.setup.si2, - cmd.parm.setup.eazmsn); - } - break; - - case 2: /* Call will be rejected. */ - capi_cmsg_answer(cmsg); - cmsg->Reject = 2; /* reject call, normal call clearing */ - plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); - send_message(card, cmsg); - break; - - default: - /* An error happened. (Invalid parameters for example.) */ - capi_cmsg_answer(cmsg); - cmsg->Reject = 8; /* reject call, - destination out of order */ - plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT); - send_message(card, cmsg); - break; - } - return; -} - -static void handle_plci(_cmsg *cmsg) -{ - capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); - capidrv_plci *plcip; - isdn_ctrl cmd; - _cdebbuf *cdb; - - if (!card) { - printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController & 0x7f); - return; - } - switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { - - case CAPI_DISCONNECT_IND: /* plci */ - if (cmsg->Reason) { - printk(KERN_INFO "capidrv-%d: %s reason 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Reason, capi_info2str(cmsg->Reason), cmsg->adr.adrPLCI); - } - if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) { - capi_cmsg_answer(cmsg); - send_message(card, cmsg); - goto notfound; - } - card->bchans[plcip->chan].disconnecting = 1; - plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND); - capi_cmsg_answer(cmsg); - plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP); - send_message(card, cmsg); - break; - - case CAPI_DISCONNECT_CONF: /* plci */ - if (cmsg->Info) { - printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), - cmsg->adr.adrPLCI); - } - if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) - goto notfound; - - card->bchans[plcip->chan].disconnecting = 1; - break; - - case CAPI_ALERT_CONF: /* plci */ - if (cmsg->Info) { - printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), - cmsg->adr.adrPLCI); - } - break; - - case CAPI_CONNECT_IND: /* plci */ - handle_incoming_call(card, cmsg); - break; - - case CAPI_CONNECT_CONF: /* plci */ - if (cmsg->Info) { - printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for plci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), - cmsg->adr.adrPLCI); - } - if (!(plcip = find_plci_by_msgid(card, cmsg->Messagenumber))) - goto notfound; - - plcip->plci = cmsg->adr.adrPLCI; - if (cmsg->Info) { - plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_ERROR); - } else { - plci_change_state(card, plcip, EV_PLCI_CONNECT_CONF_OK); - } - break; - - case CAPI_CONNECT_ACTIVE_IND: /* plci */ - - if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) - goto notfound; - - if (card->bchans[plcip->chan].incoming) { - capi_cmsg_answer(cmsg); - plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND); - send_message(card, cmsg); - } else { - capidrv_ncci *nccip; - capi_cmsg_answer(cmsg); - send_message(card, cmsg); - - nccip = new_ncci(card, plcip, cmsg->adr.adrPLCI); - - if (!nccip) { - printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr); - break; /* $$$$ */ - } - capi_fill_CONNECT_B3_REQ(cmsg, - global.ap.applid, - card->msgid++, - plcip->plci, /* adr */ - NULL /* NCPI */ - ); - nccip->msgid = cmsg->Messagenumber; - plci_change_state(card, plcip, - EV_PLCI_CONNECT_ACTIVE_IND); - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ); - send_message(card, cmsg); - cmd.command = ISDN_STAT_DCONN; - cmd.driver = card->myid; - cmd.arg = plcip->chan; - card->interface.statcallb(&cmd); - } - break; - - case CAPI_INFO_IND: /* Controller/plci */ - - if (!(plcip = find_plci_by_plci(card, cmsg->adr.adrPLCI))) - goto notfound; - - if (cmsg->InfoNumber == 0x4000) { - if (cmsg->InfoElement[0] == 4) { - cmd.command = ISDN_STAT_CINF; - cmd.driver = card->myid; - cmd.arg = plcip->chan; - sprintf(cmd.parm.num, "%lu", - (unsigned long) - ((u32) cmsg->InfoElement[1] - | ((u32) (cmsg->InfoElement[2]) << 8) - | ((u32) (cmsg->InfoElement[3]) << 16) - | ((u32) (cmsg->InfoElement[4]) << 24))); - card->interface.statcallb(&cmd); - break; - } - } - cdb = capi_cmsg2str(cmsg); - if (cdb) { - printk(KERN_WARNING "capidrv-%d: %s\n", - card->contrnr, cdb->buf); - cdebbuf_free(cdb); - } else - printk(KERN_WARNING "capidrv-%d: CAPI_INFO_IND InfoNumber %x not handled\n", - card->contrnr, cmsg->InfoNumber); - - break; - - case CAPI_CONNECT_ACTIVE_CONF: /* plci */ - goto ignored; - case CAPI_SELECT_B_PROTOCOL_CONF: /* plci */ - goto ignored; - case CAPI_FACILITY_IND: /* Controller/plci/ncci */ - goto ignored; - case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ - goto ignored; - - case CAPI_INFO_CONF: /* Controller/plci */ - goto ignored; - - default: - printk(KERN_ERR "capidrv-%d: got %s for plci 0x%x ???", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrPLCI); - } - return; -ignored: - printk(KERN_INFO "capidrv-%d: %s for plci 0x%x ignored\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrPLCI); - return; -notfound: - printk(KERN_ERR "capidrv-%d: %s: plci 0x%x not found\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrPLCI); - return; -} - -static void handle_ncci(_cmsg *cmsg) -{ - capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); - capidrv_plci *plcip; - capidrv_ncci *nccip; - isdn_ctrl cmd; - int len; - - if (!card) { - printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController & 0x7f); - return; - } - switch (CAPICMD(cmsg->Command, cmsg->Subcommand)) { - - case CAPI_CONNECT_B3_ACTIVE_IND: /* ncci */ - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) - goto notfound; - - capi_cmsg_answer(cmsg); - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND); - send_message(card, cmsg); - - cmd.command = ISDN_STAT_BCONN; - cmd.driver = card->myid; - cmd.arg = nccip->chan; - card->interface.statcallb(&cmd); - - printk(KERN_INFO "capidrv-%d: chan %d up with ncci 0x%x\n", - card->contrnr, nccip->chan, nccip->ncci); - break; - - case CAPI_CONNECT_B3_ACTIVE_CONF: /* ncci */ - goto ignored; - - case CAPI_CONNECT_B3_IND: /* ncci */ - - plcip = find_plci_by_ncci(card, cmsg->adr.adrNCCI); - if (plcip) { - nccip = new_ncci(card, plcip, cmsg->adr.adrNCCI); - if (nccip) { - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_IND); - capi_fill_CONNECT_B3_RESP(cmsg, - global.ap.applid, - card->msgid++, - nccip->ncci, /* adr */ - 0, /* Reject */ - NULL /* NCPI */ - ); - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP); - send_message(card, cmsg); - break; - } - printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr); - } else { - printk(KERN_ERR "capidrv-%d: %s: plci for ncci 0x%x not found\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrNCCI); - } - capi_fill_CONNECT_B3_RESP(cmsg, - global.ap.applid, - card->msgid++, - cmsg->adr.adrNCCI, - 2, /* Reject */ - NULL /* NCPI */ - ); - send_message(card, cmsg); - break; - - case CAPI_CONNECT_B3_CONF: /* ncci */ - - if (!(nccip = find_ncci_by_msgid(card, - cmsg->adr.adrNCCI, - cmsg->Messagenumber))) - goto notfound; - - nccip->ncci = cmsg->adr.adrNCCI; - if (cmsg->Info) { - printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), - cmsg->adr.adrNCCI); - } - - if (cmsg->Info) - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_ERROR); - else - ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_CONF_OK); - break; - - case CAPI_CONNECT_B3_T90_ACTIVE_IND: /* ncci */ - capi_cmsg_answer(cmsg); - send_message(card, cmsg); - break; - - case CAPI_DATA_B3_IND: /* ncci */ - /* handled in handle_data() */ - goto ignored; - - case CAPI_DATA_B3_CONF: /* ncci */ - if (cmsg->Info) { - printk(KERN_WARNING "CAPI_DATA_B3_CONF: Info %x - %s\n", - cmsg->Info, capi_info2str(cmsg->Info)); - } - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) - goto notfound; - - len = capidrv_del_ack(nccip, cmsg->DataHandle); - if (len < 0) - break; - cmd.command = ISDN_STAT_BSENT; - cmd.driver = card->myid; - cmd.arg = nccip->chan; - cmd.parm.length = len; - card->interface.statcallb(&cmd); - break; - - case CAPI_DISCONNECT_B3_IND: /* ncci */ - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) - goto notfound; - - card->bchans[nccip->chan].disconnecting = 1; - ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND); - capi_cmsg_answer(cmsg); - ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP); - send_message(card, cmsg); - break; - - case CAPI_DISCONNECT_B3_CONF: /* ncci */ - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) - goto notfound; - if (cmsg->Info) { - printk(KERN_INFO "capidrv-%d: %s info 0x%x (%s) for ncci 0x%x\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->Info, capi_info2str(cmsg->Info), - cmsg->adr.adrNCCI); - ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_CONF_ERROR); - } - break; - - case CAPI_RESET_B3_IND: /* ncci */ - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) - goto notfound; - ncci_change_state(card, nccip, EV_NCCI_RESET_B3_IND); - capi_cmsg_answer(cmsg); - send_message(card, cmsg); - break; - - case CAPI_RESET_B3_CONF: /* ncci */ - goto ignored; /* $$$$ */ - - case CAPI_FACILITY_IND: /* Controller/plci/ncci */ - goto ignored; - case CAPI_FACILITY_CONF: /* Controller/plci/ncci */ - goto ignored; - - default: - printk(KERN_ERR "capidrv-%d: got %s for ncci 0x%x ???", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrNCCI); - } - return; -ignored: - printk(KERN_INFO "capidrv-%d: %s for ncci 0x%x ignored\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrNCCI); - return; -notfound: - printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrNCCI); -} - - -static void handle_data(_cmsg *cmsg, struct sk_buff *skb) -{ - capidrv_contr *card = findcontrbynumber(cmsg->adr.adrController & 0x7f); - capidrv_ncci *nccip; - - if (!card) { - printk(KERN_ERR "capidrv: %s from unknown controller 0x%x\n", - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrController & 0x7f); - kfree_skb(skb); - return; - } - if (!(nccip = find_ncci(card, cmsg->adr.adrNCCI))) { - printk(KERN_ERR "capidrv-%d: %s: ncci 0x%x not found\n", - card->contrnr, - capi_cmd2str(cmsg->Command, cmsg->Subcommand), - cmsg->adr.adrNCCI); - kfree_skb(skb); - return; - } - (void) skb_pull(skb, CAPIMSG_LEN(skb->data)); - card->interface.rcvcallb_skb(card->myid, nccip->chan, skb); - capi_cmsg_answer(cmsg); - send_message(card, cmsg); -} - -static _cmsg s_cmsg; - -static void capidrv_recv_message(struct capi20_appl *ap, struct sk_buff *skb) -{ - if (capi_message2cmsg(&s_cmsg, skb->data)) { - printk(KERN_ERR "capidrv: applid=%d: received invalid message\n", - ap->applid); - kfree_skb(skb); - return; - } - if (debugmode > 3) { - _cdebbuf *cdb = capi_cmsg2str(&s_cmsg); - - if (cdb) { - printk(KERN_DEBUG "%s: applid=%d %s\n", __func__, - ap->applid, cdb->buf); - cdebbuf_free(cdb); - } else - printk(KERN_DEBUG "%s: applid=%d %s not traced\n", - __func__, ap->applid, - capi_cmd2str(s_cmsg.Command, s_cmsg.Subcommand)); - } - if (s_cmsg.Command == CAPI_DATA_B3 - && s_cmsg.Subcommand == CAPI_IND) { - handle_data(&s_cmsg, skb); - return; - } - if ((s_cmsg.adr.adrController & 0xffffff00) == 0) - handle_controller(&s_cmsg); - else if ((s_cmsg.adr.adrPLCI & 0xffff0000) == 0) - handle_plci(&s_cmsg); - else - handle_ncci(&s_cmsg); - /* - * data of skb used in s_cmsg, - * free data when s_cmsg is not used again - * thanks to Lars Heete <hel@admin.de> - */ - kfree_skb(skb); -} - -/* ------------------------------------------------------------------- */ - -#define PUTBYTE_TO_STATUS(card, byte) \ - do { \ - *(card)->q931_write++ = (byte); \ - if ((card)->q931_write > (card)->q931_end) \ - (card)->q931_write = (card)->q931_buf; \ - } while (0) - -static void handle_dtrace_data(capidrv_contr *card, - int send, int level2, u8 *data, u16 len) -{ - u8 *p, *end; - isdn_ctrl cmd; - - if (!len) { - printk(KERN_DEBUG "capidrv-%d: avmb1_q931_data: len == %d\n", - card->contrnr, len); - return; - } - - if (level2) { - PUTBYTE_TO_STATUS(card, 'D'); - PUTBYTE_TO_STATUS(card, '2'); - PUTBYTE_TO_STATUS(card, send ? '>' : '<'); - PUTBYTE_TO_STATUS(card, ':'); - } else { - PUTBYTE_TO_STATUS(card, 'D'); - PUTBYTE_TO_STATUS(card, '3'); - PUTBYTE_TO_STATUS(card, send ? '>' : '<'); - PUTBYTE_TO_STATUS(card, ':'); - } - - for (p = data, end = data + len; p < end; p++) { - PUTBYTE_TO_STATUS(card, ' '); - PUTBYTE_TO_STATUS(card, hex_asc_hi(*p)); - PUTBYTE_TO_STATUS(card, hex_asc_lo(*p)); - } - PUTBYTE_TO_STATUS(card, '\n'); - - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = len * 3 + 5; - card->interface.statcallb(&cmd); -} - -/* ------------------------------------------------------------------- */ - -static _cmsg cmdcmsg; - -static int capidrv_ioctl(isdn_ctrl *c, capidrv_contr *card) -{ - switch (c->arg) { - case 1: - debugmode = (int)(*((unsigned int *)c->parm.num)); - printk(KERN_DEBUG "capidrv-%d: debugmode=%d\n", - card->contrnr, debugmode); - return 0; - default: - printk(KERN_DEBUG "capidrv-%d: capidrv_ioctl(%ld) called ??\n", - card->contrnr, c->arg); - return -EINVAL; - } - return -EINVAL; -} - -/* - * Handle leased lines (CAPI-Bundling) - */ - -struct internal_bchannelinfo { - unsigned short channelalloc; - unsigned short operation; - unsigned char cmask[31]; -}; - -static int decodeFVteln(char *teln, unsigned long *bmaskp, int *activep) -{ - unsigned long bmask = 0; - int active = !0; - char *s; - int i; - - if (strncmp(teln, "FV:", 3) != 0) - return 1; - s = teln + 3; - while (*s && *s == ' ') s++; - if (!*s) return -2; - if (*s == 'p' || *s == 'P') { - active = 0; - s++; - } - if (*s == 'a' || *s == 'A') { - active = !0; - s++; - } - while (*s) { - int digit1 = 0; - int digit2 = 0; - char *endp; - - digit1 = simple_strtoul(s, &endp, 10); - if (s == endp) - return -3; - s = endp; - - if (digit1 <= 0 || digit1 > 30) return -4; - if (*s == 0 || *s == ',' || *s == ' ') { - bmask |= (1 << digit1); - digit1 = 0; - if (*s) s++; - continue; - } - if (*s != '-') return -5; - s++; - - digit2 = simple_strtoul(s, &endp, 10); - if (s == endp) - return -3; - s = endp; - - if (digit2 <= 0 || digit2 > 30) return -4; - if (*s == 0 || *s == ',' || *s == ' ') { - if (digit1 > digit2) - for (i = digit2; i <= digit1; i++) - bmask |= (1 << i); - else - for (i = digit1; i <= digit2; i++) - bmask |= (1 << i); - digit1 = digit2 = 0; - if (*s) s++; - continue; - } - return -6; - } - if (activep) *activep = active; - if (bmaskp) *bmaskp = bmask; - return 0; -} - -static int FVteln2capi20(char *teln, u8 AdditionalInfo[1 + 2 + 2 + 31]) -{ - unsigned long bmask; - int active; - int rc, i; - - rc = decodeFVteln(teln, &bmask, &active); - if (rc) return rc; - /* Length */ - AdditionalInfo[0] = 2 + 2 + 31; - /* Channel: 3 => use channel allocation */ - AdditionalInfo[1] = 3; AdditionalInfo[2] = 0; - /* Operation: 0 => DTE mode, 1 => DCE mode */ - if (active) { - AdditionalInfo[3] = 0; AdditionalInfo[4] = 0; - } else { - AdditionalInfo[3] = 1; AdditionalInfo[4] = 0; - } - /* Channel mask array */ - AdditionalInfo[5] = 0; /* no D-Channel */ - for (i = 1; i <= 30; i++) - AdditionalInfo[5 + i] = (bmask & (1 << i)) ? 0xff : 0; - return 0; -} - -static int capidrv_command(isdn_ctrl *c, capidrv_contr *card) -{ - isdn_ctrl cmd; - struct capidrv_bchan *bchan; - struct capidrv_plci *plcip; - u8 AdditionalInfo[1 + 2 + 2 + 31]; - int rc, isleasedline = 0; - - if (c->command == ISDN_CMD_IOCTL) - return capidrv_ioctl(c, card); - - switch (c->command) { - case ISDN_CMD_DIAL: { - u8 calling[ISDN_MSNLEN + 3]; - u8 called[ISDN_MSNLEN + 2]; - - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_DIAL(ch=%ld,\"%s,%d,%d,%s\")\n", - card->contrnr, - c->arg, - c->parm.setup.phone, - c->parm.setup.si1, - c->parm.setup.si2, - c->parm.setup.eazmsn); - - bchan = &card->bchans[c->arg % card->nbchan]; - - if (bchan->plcip) { - printk(KERN_ERR "capidrv-%d: dail ch=%ld,\"%s,%d,%d,%s\" in use (plci=0x%x)\n", - card->contrnr, - c->arg, - c->parm.setup.phone, - c->parm.setup.si1, - c->parm.setup.si2, - c->parm.setup.eazmsn, - bchan->plcip->plci); - return 0; - } - bchan->si1 = c->parm.setup.si1; - bchan->si2 = c->parm.setup.si2; - - strncpy(bchan->num, c->parm.setup.phone, sizeof(bchan->num)); - strncpy(bchan->mynum, c->parm.setup.eazmsn, sizeof(bchan->mynum)); - rc = FVteln2capi20(bchan->num, AdditionalInfo); - isleasedline = (rc == 0); - if (rc < 0) - printk(KERN_ERR "capidrv-%d: WARNING: invalid leased linedefinition \"%s\"\n", card->contrnr, bchan->num); - - if (isleasedline) { - calling[0] = 0; - called[0] = 0; - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: connecting leased line\n", card->contrnr); - } else { - calling[0] = strlen(bchan->mynum) + 2; - calling[1] = 0; - calling[2] = 0x80; - strncpy(calling + 3, bchan->mynum, ISDN_MSNLEN); - called[0] = strlen(bchan->num) + 1; - called[1] = 0x80; - strncpy(called + 2, bchan->num, ISDN_MSNLEN); - } - - capi_fill_CONNECT_REQ(&cmdcmsg, - global.ap.applid, - card->msgid++, - card->contrnr, /* adr */ - si2cip(bchan->si1, bchan->si2), /* cipvalue */ - called, /* CalledPartyNumber */ - calling, /* CallingPartyNumber */ - NULL, /* CalledPartySubaddress */ - NULL, /* CallingPartySubaddress */ - b1prot(bchan->l2, bchan->l3), /* B1protocol */ - b2prot(bchan->l2, bchan->l3), /* B2protocol */ - b3prot(bchan->l2, bchan->l3), /* B3protocol */ - b1config(bchan->l2, bchan->l3), /* B1configuration */ - NULL, /* B2configuration */ - NULL, /* B3configuration */ - NULL, /* BC */ - NULL, /* LLC */ - NULL, /* HLC */ - /* BChannelinformation */ - isleasedline ? AdditionalInfo : NULL, - NULL, /* Keypadfacility */ - NULL, /* Useruserdata */ - NULL /* Facilitydataarray */ - ); - if ((plcip = new_plci(card, (c->arg % card->nbchan))) == NULL) { - cmd.command = ISDN_STAT_DHUP; - cmd.driver = card->myid; - cmd.arg = (c->arg % card->nbchan); - card->interface.statcallb(&cmd); - return -1; - } - plcip->msgid = cmdcmsg.Messagenumber; - plcip->leasedline = isleasedline; - plci_change_state(card, plcip, EV_PLCI_CONNECT_REQ); - send_message(card, &cmdcmsg); - return 0; - } - - case ISDN_CMD_ACCEPTD: - - bchan = &card->bchans[c->arg % card->nbchan]; - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTD(ch=%ld) l2=%d l3=%d\n", - card->contrnr, - c->arg, bchan->l2, bchan->l3); - - capi_fill_CONNECT_RESP(&cmdcmsg, - global.ap.applid, - card->msgid++, - bchan->plcip->plci, /* adr */ - 0, /* Reject */ - b1prot(bchan->l2, bchan->l3), /* B1protocol */ - b2prot(bchan->l2, bchan->l3), /* B2protocol */ - b3prot(bchan->l2, bchan->l3), /* B3protocol */ - b1config(bchan->l2, bchan->l3), /* B1configuration */ - NULL, /* B2configuration */ - NULL, /* B3configuration */ - NULL, /* ConnectedNumber */ - NULL, /* ConnectedSubaddress */ - NULL, /* LLC */ - NULL, /* BChannelinformation */ - NULL, /* Keypadfacility */ - NULL, /* Useruserdata */ - NULL /* Facilitydataarray */ - ); - if (capi_cmsg2message(&cmdcmsg, cmdcmsg.buf)) { - printk(KERN_ERR "capidrv-%d: capidrv_command: parser failure\n", - card->contrnr); - return -EINVAL; - } - plci_change_state(card, bchan->plcip, EV_PLCI_CONNECT_RESP); - send_message(card, &cmdcmsg); - return 0; - - case ISDN_CMD_ACCEPTB: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_ACCEPTB(ch=%ld)\n", - card->contrnr, - c->arg); - return -ENOSYS; - - case ISDN_CMD_HANGUP: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: ISDN_CMD_HANGUP(ch=%ld)\n", - card->contrnr, - c->arg); - bchan = &card->bchans[c->arg % card->nbchan]; - - if (bchan->disconnecting) { - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: chan %ld already disconnecting ...\n", - card->contrnr, - c->arg); - return 0; - } - if (bchan->nccip) { - bchan->disconnecting = 1; - capi_fill_DISCONNECT_B3_REQ(&cmdcmsg, - global.ap.applid, - card->msgid++, - bchan->nccip->ncci, - NULL /* NCPI */ - ); - ncci_change_state(card, bchan->nccip, EV_NCCI_DISCONNECT_B3_REQ); - send_message(card, &cmdcmsg); - return 0; - } else if (bchan->plcip) { - if (bchan->plcip->state == ST_PLCI_INCOMING) { - /* - * just ignore, we a called from - * isdn_status_callback(), - * which will return 0 or 2, this is handled - * by the CONNECT_IND handler - */ - bchan->disconnecting = 1; - return 0; - } else if (bchan->plcip->plci) { - bchan->disconnecting = 1; - capi_fill_DISCONNECT_REQ(&cmdcmsg, - global.ap.applid, - card->msgid++, - bchan->plcip->plci, - NULL, /* BChannelinformation */ - NULL, /* Keypadfacility */ - NULL, /* Useruserdata */ - NULL /* Facilitydataarray */ - ); - plci_change_state(card, bchan->plcip, EV_PLCI_DISCONNECT_REQ); - send_message(card, &cmdcmsg); - return 0; - } else { - printk(KERN_ERR "capidrv-%d: chan %ld disconnect request while waiting for CONNECT_CONF\n", - card->contrnr, - c->arg); - return -EINVAL; - } - } - printk(KERN_ERR "capidrv-%d: chan %ld disconnect request on free channel\n", - card->contrnr, - c->arg); - return -EINVAL; -/* ready */ - - case ISDN_CMD_SETL2: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: set L2 on chan %ld to %ld\n", - card->contrnr, - (c->arg & 0xff), (c->arg >> 8)); - bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; - bchan->l2 = (c->arg >> 8); - return 0; - - case ISDN_CMD_SETL3: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: set L3 on chan %ld to %ld\n", - card->contrnr, - (c->arg & 0xff), (c->arg >> 8)); - bchan = &card->bchans[(c->arg & 0xff) % card->nbchan]; - bchan->l3 = (c->arg >> 8); - return 0; - - case ISDN_CMD_SETEAZ: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: set EAZ \"%s\" on chan %ld\n", - card->contrnr, - c->parm.num, c->arg); - bchan = &card->bchans[c->arg % card->nbchan]; - strncpy(bchan->msn, c->parm.num, ISDN_MSNLEN); - return 0; - - case ISDN_CMD_CLREAZ: - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: clearing EAZ on chan %ld\n", - card->contrnr, c->arg); - bchan = &card->bchans[c->arg % card->nbchan]; - bchan->msn[0] = 0; - return 0; - - default: - printk(KERN_ERR "capidrv-%d: ISDN_CMD_%d, Huh?\n", - card->contrnr, c->command); - return -EINVAL; - } - return 0; -} - -static int if_command(isdn_ctrl *c) -{ - capidrv_contr *card = findcontrbydriverid(c->driver); - - if (card) - return capidrv_command(c, card); - - printk(KERN_ERR - "capidrv: if_command %d called with invalid driverId %d!\n", - c->command, c->driver); - return -ENODEV; -} - -static _cmsg sendcmsg; - -static int if_sendbuf(int id, int channel, int doack, struct sk_buff *skb) -{ - capidrv_contr *card = findcontrbydriverid(id); - capidrv_bchan *bchan; - capidrv_ncci *nccip; - int len = skb->len; - int msglen; - u16 errcode; - u16 datahandle; - u32 data; - - if (!card) { - printk(KERN_ERR "capidrv: if_sendbuf called with invalid driverId %d!\n", - id); - return 0; - } - if (debugmode > 4) - printk(KERN_DEBUG "capidrv-%d: sendbuf len=%d skb=%p doack=%d\n", - card->contrnr, len, skb, doack); - bchan = &card->bchans[channel % card->nbchan]; - nccip = bchan->nccip; - if (!nccip || nccip->state != ST_NCCI_ACTIVE) { - printk(KERN_ERR "capidrv-%d: if_sendbuf: %s:%d: chan not up!\n", - card->contrnr, card->name, channel); - return 0; - } - datahandle = nccip->datahandle; - - /* - * Here we copy pointer skb->data into the 32-bit 'Data' field. - * The 'Data' field is not used in practice in linux kernel - * (neither in 32 or 64 bit), but should have some value, - * since a CAPI message trace will display it. - * - * The correct value in the 32 bit case is the address of the - * data, in 64 bit it makes no sense, we use 0 there. - */ - -#ifdef CONFIG_64BIT - data = 0; -#else - data = (unsigned long) skb->data; -#endif - - capi_fill_DATA_B3_REQ(&sendcmsg, global.ap.applid, card->msgid++, - nccip->ncci, /* adr */ - data, /* Data */ - skb->len, /* DataLength */ - datahandle, /* DataHandle */ - 0 /* Flags */ - ); - - if (capidrv_add_ack(nccip, datahandle, doack ? (int)skb->len : -1) < 0) - return 0; - - if (capi_cmsg2message(&sendcmsg, sendcmsg.buf)) { - printk(KERN_ERR "capidrv-%d: if_sendbuf: parser failure\n", - card->contrnr); - return -EINVAL; - } - msglen = CAPIMSG_LEN(sendcmsg.buf); - if (skb_headroom(skb) < msglen) { - struct sk_buff *nskb = skb_realloc_headroom(skb, msglen); - if (!nskb) { - printk(KERN_ERR "capidrv-%d: if_sendbuf: no memory\n", - card->contrnr); - (void)capidrv_del_ack(nccip, datahandle); - return 0; - } - printk(KERN_DEBUG "capidrv-%d: only %d bytes headroom, need %d\n", - card->contrnr, skb_headroom(skb), msglen); - memcpy(skb_push(nskb, msglen), sendcmsg.buf, msglen); - errcode = capi20_put_message(&global.ap, nskb); - if (errcode == CAPI_NOERROR) { - dev_kfree_skb(skb); - nccip->datahandle++; - return len; - } - if (debugmode > 3) - printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n", - card->contrnr, errcode, capi_info2str(errcode)); - (void)capidrv_del_ack(nccip, datahandle); - dev_kfree_skb(nskb); - return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; - } else { - memcpy(skb_push(skb, msglen), sendcmsg.buf, msglen); - errcode = capi20_put_message(&global.ap, skb); - if (errcode == CAPI_NOERROR) { - nccip->datahandle++; - return len; - } - if (debugmode > 3) - printk(KERN_DEBUG "capidrv-%d: sendbuf putmsg ret(%x) - %s\n", - card->contrnr, errcode, capi_info2str(errcode)); - skb_pull(skb, msglen); - (void)capidrv_del_ack(nccip, datahandle); - return errcode == CAPI_SENDQUEUEFULL ? 0 : -1; - } -} - -static int if_readstat(u8 __user *buf, int len, int id, int channel) -{ - capidrv_contr *card = findcontrbydriverid(id); - int count; - u8 __user *p; - - if (!card) { - printk(KERN_ERR "capidrv: if_readstat called with invalid driverId %d!\n", - id); - return -ENODEV; - } - - for (p = buf, count = 0; count < len; p++, count++) { - if (put_user(*card->q931_read++, p)) - return -EFAULT; - if (card->q931_read > card->q931_end) - card->q931_read = card->q931_buf; - } - return count; - -} - -static void enable_dchannel_trace(capidrv_contr *card) -{ - u8 manufacturer[CAPI_MANUFACTURER_LEN]; - capi_version version; - u16 contr = card->contrnr; - u16 errcode; - u16 avmversion[3]; - - errcode = capi20_get_manufacturer(contr, manufacturer); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get manufacturer (0x%x)\n", - card->name, errcode); - return; - } - if (strstr(manufacturer, "AVM") == NULL) { - printk(KERN_ERR "%s: not from AVM, no d-channel trace possible (%s)\n", - card->name, manufacturer); - return; - } - errcode = capi20_get_version(contr, &version); - if (errcode != CAPI_NOERROR) { - printk(KERN_ERR "%s: can't get version (0x%x)\n", - card->name, errcode); - return; - } - avmversion[0] = (version.majormanuversion >> 4) & 0x0f; - avmversion[1] = (version.majormanuversion << 4) & 0xf0; - avmversion[1] |= (version.minormanuversion >> 4) & 0x0f; - avmversion[2] |= version.minormanuversion & 0x0f; - - if (avmversion[0] > 3 || (avmversion[0] == 3 && avmversion[1] > 5)) { - printk(KERN_INFO "%s: D2 trace enabled\n", card->name); - capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid, - card->msgid++, - contr, - 0x214D5641, /* ManuID */ - 0, /* Class */ - 1, /* Function */ - (_cstruct)"\004\200\014\000\000"); - } else { - printk(KERN_INFO "%s: D3 trace enabled\n", card->name); - capi_fill_MANUFACTURER_REQ(&cmdcmsg, global.ap.applid, - card->msgid++, - contr, - 0x214D5641, /* ManuID */ - 0, /* Class */ - 1, /* Function */ - (_cstruct)"\004\002\003\000\000"); - } - send_message(card, &cmdcmsg); -} - - -static void send_listen(capidrv_contr *card) -{ - capi_fill_LISTEN_REQ(&cmdcmsg, global.ap.applid, - card->msgid++, - card->contrnr, /* controller */ - 1 << 6, /* Infomask */ - card->cipmask, - card->cipmask2, - NULL, NULL); - listen_change_state(card, EV_LISTEN_REQ); - send_message(card, &cmdcmsg); -} - -static void listentimerfunc(struct timer_list *t) -{ - capidrv_contr *card = from_timer(card, t, listentimer); - if (card->state != ST_LISTEN_NONE && card->state != ST_LISTEN_ACTIVE) - printk(KERN_ERR "%s: controller dead ??\n", card->name); - send_listen(card); - mod_timer(&card->listentimer, jiffies + 60 * HZ); -} - - -static int capidrv_addcontr(u16 contr, struct capi_profile *profp) -{ - capidrv_contr *card; - unsigned long flags; - isdn_ctrl cmd; - char id[20]; - int i; - - sprintf(id, "capidrv-%d", contr); - if (!try_module_get(THIS_MODULE)) { - printk(KERN_WARNING "capidrv: (%s) Could not reserve module\n", id); - return -1; - } - if (!(card = kzalloc(sizeof(capidrv_contr), GFP_ATOMIC))) { - printk(KERN_WARNING - "capidrv: (%s) Could not allocate contr-struct.\n", id); - return -1; - } - card->owner = THIS_MODULE; - timer_setup(&card->listentimer, listentimerfunc, 0); - strcpy(card->name, id); - card->contrnr = contr; - card->nbchan = profp->nbchannel; - card->bchans = kmalloc_array(card->nbchan, sizeof(capidrv_bchan), - GFP_ATOMIC); - if (!card->bchans) { - printk(KERN_WARNING - "capidrv: (%s) Could not allocate bchan-structs.\n", id); - module_put(card->owner); - kfree(card); - return -1; - } - card->interface.channels = profp->nbchannel; - card->interface.maxbufsize = 2048; - card->interface.command = if_command; - card->interface.writebuf_skb = if_sendbuf; - card->interface.writecmd = NULL; - card->interface.readstat = if_readstat; - card->interface.features = - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_P_UNKNOWN | - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L2_X75UI | - ISDN_FEATURE_L2_X75BUI; - if (profp->support1 & (1 << 2)) - card->interface.features |= - ISDN_FEATURE_L2_V11096 | - ISDN_FEATURE_L2_V11019 | - ISDN_FEATURE_L2_V11038; - if (profp->support1 & (1 << 8)) - card->interface.features |= ISDN_FEATURE_L2_MODEM; - card->interface.hl_hdrlen = 22; /* len of DATA_B3_REQ */ - strncpy(card->interface.id, id, sizeof(card->interface.id) - 1); - - - card->q931_read = card->q931_buf; - card->q931_write = card->q931_buf; - card->q931_end = card->q931_buf + sizeof(card->q931_buf) - 1; - - if (!register_isdn(&card->interface)) { - printk(KERN_ERR "capidrv: Unable to register contr %s\n", id); - kfree(card->bchans); - module_put(card->owner); - kfree(card); - return -1; - } - card->myid = card->interface.channels; - memset(card->bchans, 0, sizeof(capidrv_bchan) * card->nbchan); - for (i = 0; i < card->nbchan; i++) { - card->bchans[i].contr = card; - } - - spin_lock_irqsave(&global_lock, flags); - card->next = global.contr_list; - global.contr_list = card; - global.ncontr++; - spin_unlock_irqrestore(&global_lock, flags); - - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - - card->cipmask = 0x1FFF03FF; /* any */ - card->cipmask2 = 0; - - send_listen(card); - mod_timer(&card->listentimer, jiffies + 60 * HZ); - - printk(KERN_INFO "%s: now up (%d B channels)\n", - card->name, card->nbchan); - - enable_dchannel_trace(card); - - return 0; -} - -static int capidrv_delcontr(u16 contr) -{ - capidrv_contr **pp, *card; - unsigned long flags; - isdn_ctrl cmd; - - spin_lock_irqsave(&global_lock, flags); - for (card = global.contr_list; card; card = card->next) { - if (card->contrnr == contr) - break; - } - if (!card) { - spin_unlock_irqrestore(&global_lock, flags); - printk(KERN_ERR "capidrv: delcontr: no contr %u\n", contr); - return -1; - } - - /* FIXME: maybe a race condition the card should be removed - * here from global list /kkeil - */ - spin_unlock_irqrestore(&global_lock, flags); - - del_timer(&card->listentimer); - - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: id=%d unloading\n", - card->contrnr, card->myid); - - cmd.command = ISDN_STAT_STOP; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - - while (card->nbchan) { - - cmd.command = ISDN_STAT_DISCH; - cmd.driver = card->myid; - cmd.arg = card->nbchan - 1; - cmd.parm.num[0] = 0; - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: id=%d disable chan=%ld\n", - card->contrnr, card->myid, cmd.arg); - card->interface.statcallb(&cmd); - - if (card->bchans[card->nbchan - 1].nccip) - free_ncci(card, card->bchans[card->nbchan - 1].nccip); - if (card->bchans[card->nbchan - 1].plcip) - free_plci(card, card->bchans[card->nbchan - 1].plcip); - if (card->plci_list) - printk(KERN_ERR "capidrv: bug in free_plci()\n"); - card->nbchan--; - } - kfree(card->bchans); - card->bchans = NULL; - - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: id=%d isdn unload\n", - card->contrnr, card->myid); - - cmd.command = ISDN_STAT_UNLOAD; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - - if (debugmode) - printk(KERN_DEBUG "capidrv-%d: id=%d remove contr from list\n", - card->contrnr, card->myid); - - spin_lock_irqsave(&global_lock, flags); - for (pp = &global.contr_list; *pp; pp = &(*pp)->next) { - if (*pp == card) { - *pp = (*pp)->next; - card->next = NULL; - global.ncontr--; - break; - } - } - spin_unlock_irqrestore(&global_lock, flags); - - module_put(card->owner); - printk(KERN_INFO "%s: now down.\n", card->name); - kfree(card); - return 0; -} - - -static int -lower_callback(struct notifier_block *nb, unsigned long val, void *v) -{ - capi_profile profile; - u32 contr = (long)v; - - switch (val) { - case CAPICTR_UP: - printk(KERN_INFO "capidrv: controller %hu up\n", contr); - if (capi20_get_profile(contr, &profile) == CAPI_NOERROR) - (void) capidrv_addcontr(contr, &profile); - break; - case CAPICTR_DOWN: - printk(KERN_INFO "capidrv: controller %hu down\n", contr); - (void) capidrv_delcontr(contr); - break; - } - return NOTIFY_OK; -} - -/* - * /proc/capi/capidrv: - * nrecvctlpkt nrecvdatapkt nsendctlpkt nsenddatapkt - */ -static int __maybe_unused capidrv_proc_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%lu %lu %lu %lu\n", - global.ap.nrecvctlpkt, - global.ap.nrecvdatapkt, - global.ap.nsentctlpkt, - global.ap.nsentdatapkt); - return 0; -} - -static void __init proc_init(void) -{ - proc_create_single("capi/capidrv", 0, NULL, capidrv_proc_show); -} - -static void __exit proc_exit(void) -{ - remove_proc_entry("capi/capidrv", NULL); -} - -static struct notifier_block capictr_nb = { - .notifier_call = lower_callback, -}; - -static int __init capidrv_init(void) -{ - capi_profile profile; - u32 ncontr, contr; - u16 errcode; - - global.ap.rparam.level3cnt = -2; /* number of bchannels twice */ - global.ap.rparam.datablkcnt = 16; - global.ap.rparam.datablklen = 2048; - - global.ap.recv_message = capidrv_recv_message; - errcode = capi20_register(&global.ap); - if (errcode) { - return -EIO; - } - - register_capictr_notifier(&capictr_nb); - - errcode = capi20_get_profile(0, &profile); - if (errcode != CAPI_NOERROR) { - unregister_capictr_notifier(&capictr_nb); - capi20_release(&global.ap); - return -EIO; - } - - ncontr = profile.ncontroller; - for (contr = 1; contr <= ncontr; contr++) { - errcode = capi20_get_profile(contr, &profile); - if (errcode != CAPI_NOERROR) - continue; - (void) capidrv_addcontr(contr, &profile); - } - proc_init(); - - return 0; -} - -static void __exit capidrv_exit(void) -{ - unregister_capictr_notifier(&capictr_nb); - capi20_release(&global.ap); - - proc_exit(); -} - -module_init(capidrv_init); -module_exit(capidrv_exit); diff --git a/drivers/isdn/capi/capidrv.h b/drivers/isdn/capi/capidrv.h deleted file mode 100644 index 4466b2e0176d..000000000000 --- a/drivers/isdn/capi/capidrv.h +++ /dev/null @@ -1,140 +0,0 @@ -/* $Id: capidrv.h,v 1.2.8.2 2001/09/23 22:24:33 kai Exp $ - * - * ISDN4Linux Driver, using capi20 interface (kernelcapi) - * - * Copyright 1997 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __CAPIDRV_H__ -#define __CAPIDRV_H__ - -/* - * LISTEN state machine - */ -#define ST_LISTEN_NONE 0 /* L-0 */ -#define ST_LISTEN_WAIT_CONF 1 /* L-0.1 */ -#define ST_LISTEN_ACTIVE 2 /* L-1 */ -#define ST_LISTEN_ACTIVE_WAIT_CONF 3 /* L-1.1 */ - - -#define EV_LISTEN_REQ 1 /* L-0 -> L-0.1 - L-1 -> L-1.1 */ -#define EV_LISTEN_CONF_ERROR 2 /* L-0.1 -> L-0 - L-1.1 -> L-1 */ -#define EV_LISTEN_CONF_EMPTY 3 /* L-0.1 -> L-0 - L-1.1 -> L-0 */ -#define EV_LISTEN_CONF_OK 4 /* L-0.1 -> L-1 - L-1.1 -> L.1 */ - -/* - * per plci state machine - */ -#define ST_PLCI_NONE 0 /* P-0 */ -#define ST_PLCI_OUTGOING 1 /* P-0.1 */ -#define ST_PLCI_ALLOCATED 2 /* P-1 */ -#define ST_PLCI_ACTIVE 3 /* P-ACT */ -#define ST_PLCI_INCOMING 4 /* P-2 */ -#define ST_PLCI_FACILITY_IND 5 /* P-3 */ -#define ST_PLCI_ACCEPTING 6 /* P-4 */ -#define ST_PLCI_DISCONNECTING 7 /* P-5 */ -#define ST_PLCI_DISCONNECTED 8 /* P-6 */ -#define ST_PLCI_RESUMEING 9 /* P-0.Res */ -#define ST_PLCI_RESUME 10 /* P-Res */ -#define ST_PLCI_HELD 11 /* P-HELD */ - -#define EV_PLCI_CONNECT_REQ 1 /* P-0 -> P-0.1 - */ -#define EV_PLCI_CONNECT_CONF_ERROR 2 /* P-0.1 -> P-0 - */ -#define EV_PLCI_CONNECT_CONF_OK 3 /* P-0.1 -> P-1 - */ -#define EV_PLCI_FACILITY_IND_UP 4 /* P-0 -> P-1 - */ -#define EV_PLCI_CONNECT_IND 5 /* P-0 -> P-2 - */ -#define EV_PLCI_CONNECT_ACTIVE_IND 6 /* P-1 -> P-ACT - */ -#define EV_PLCI_CONNECT_REJECT 7 /* P-2 -> P-5 - P-3 -> P-5 - */ -#define EV_PLCI_DISCONNECT_REQ 8 /* P-1 -> P-5 - P-2 -> P-5 - P-3 -> P-5 - P-4 -> P-5 - P-ACT -> P-5 - P-Res -> P-5 (*) - P-HELD -> P-5 (*) - */ -#define EV_PLCI_DISCONNECT_IND 9 /* P-1 -> P-6 - P-2 -> P-6 - P-3 -> P-6 - P-4 -> P-6 - P-5 -> P-6 - P-ACT -> P-6 - P-Res -> P-6 (*) - P-HELD -> P-6 (*) - */ -#define EV_PLCI_FACILITY_IND_DOWN 10 /* P-0.1 -> P-5 - P-1 -> P-5 - P-ACT -> P-5 - P-2 -> P-5 - P-3 -> P-5 - P-4 -> P-5 - */ -#define EV_PLCI_DISCONNECT_RESP 11 /* P-6 -> P-0 - */ -#define EV_PLCI_CONNECT_RESP 12 /* P-6 -> P-0 - */ - -#define EV_PLCI_RESUME_REQ 13 /* P-0 -> P-0.Res - */ -#define EV_PLCI_RESUME_CONF_OK 14 /* P-0.Res -> P-Res - */ -#define EV_PLCI_RESUME_CONF_ERROR 15 /* P-0.Res -> P-0 - */ -#define EV_PLCI_RESUME_IND 16 /* P-Res -> P-ACT - */ -#define EV_PLCI_HOLD_IND 17 /* P-ACT -> P-HELD - */ -#define EV_PLCI_RETRIEVE_IND 18 /* P-HELD -> P-ACT - */ -#define EV_PLCI_SUSPEND_IND 19 /* P-ACT -> P-5 - */ -#define EV_PLCI_CD_IND 20 /* P-2 -> P-5 - */ - -/* - * per ncci state machine - */ -#define ST_NCCI_PREVIOUS -1 -#define ST_NCCI_NONE 0 /* N-0 */ -#define ST_NCCI_OUTGOING 1 /* N-0.1 */ -#define ST_NCCI_INCOMING 2 /* N-1 */ -#define ST_NCCI_ALLOCATED 3 /* N-2 */ -#define ST_NCCI_ACTIVE 4 /* N-ACT */ -#define ST_NCCI_RESETING 5 /* N-3 */ -#define ST_NCCI_DISCONNECTING 6 /* N-4 */ -#define ST_NCCI_DISCONNECTED 7 /* N-5 */ - -#define EV_NCCI_CONNECT_B3_REQ 1 /* N-0 -> N-0.1 */ -#define EV_NCCI_CONNECT_B3_IND 2 /* N-0 -> N.1 */ -#define EV_NCCI_CONNECT_B3_CONF_OK 3 /* N-0.1 -> N.2 */ -#define EV_NCCI_CONNECT_B3_CONF_ERROR 4 /* N-0.1 -> N.0 */ -#define EV_NCCI_CONNECT_B3_REJECT 5 /* N-1 -> N-4 */ -#define EV_NCCI_CONNECT_B3_RESP 6 /* N-1 -> N-2 */ -#define EV_NCCI_CONNECT_B3_ACTIVE_IND 7 /* N-2 -> N-ACT */ -#define EV_NCCI_RESET_B3_REQ 8 /* N-ACT -> N-3 */ -#define EV_NCCI_RESET_B3_IND 9 /* N-3 -> N-ACT */ -#define EV_NCCI_DISCONNECT_B3_IND 10 /* N-4 -> N.5 */ -#define EV_NCCI_DISCONNECT_B3_CONF_ERROR 11 /* N-4 -> previous */ -#define EV_NCCI_DISCONNECT_B3_REQ 12 /* N-1 -> N-4 - N-2 -> N-4 - N-3 -> N-4 - N-ACT -> N-4 */ -#define EV_NCCI_DISCONNECT_B3_RESP 13 /* N-5 -> N-0 */ - -#endif /* __CAPIDRV_H__ */ diff --git a/drivers/isdn/divert/Makefile b/drivers/isdn/divert/Makefile deleted file mode 100644 index 07684fe53537..000000000000 --- a/drivers/isdn/divert/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Makefile for the dss1_divert ISDN module - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o - -# Multipart objects. - -dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c deleted file mode 100644 index 267dede13bfd..000000000000 --- a/drivers/isdn/divert/divert_init.c +++ /dev/null @@ -1,82 +0,0 @@ -/* $Id divert_init.c,v 1.5.6.2 2001/01/24 22:18:17 kai Exp $ - * - * Module init for DSS1 diversion services for i4l. - * - * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> - -#include "isdn_divert.h" - -MODULE_DESCRIPTION("ISDN4Linux: Call diversion support"); -MODULE_AUTHOR("Werner Cornelius"); -MODULE_LICENSE("GPL"); - -/****************************************/ -/* structure containing interface to hl */ -/****************************************/ -isdn_divert_if divert_if = { - DIVERT_IF_MAGIC, /* magic value */ - DIVERT_CMD_REG, /* register cmd */ - ll_callback, /* callback routine from ll */ - NULL, /* command still not specified */ - NULL, /* drv_to_name */ - NULL, /* name_to_drv */ -}; - -/*************************/ -/* Module interface code */ -/* no cmd line parms */ -/*************************/ -static int __init divert_init(void) -{ - int i; - - if (divert_dev_init()) { - printk(KERN_WARNING "dss1_divert: cannot install device, not loaded\n"); - return (-EIO); - } - if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) { - divert_dev_deinit(); - printk(KERN_WARNING "dss1_divert: error %d registering module, not loaded\n", i); - return (-EIO); - } - printk(KERN_INFO "dss1_divert module successfully installed\n"); - return (0); -} - -/**********************/ -/* Module deinit code */ -/**********************/ -static void __exit divert_exit(void) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&divert_lock, flags); - divert_if.cmd = DIVERT_CMD_REL; /* release */ - if ((i = DIVERT_REG_NAME(&divert_if)) != DIVERT_NO_ERR) { - printk(KERN_WARNING "dss1_divert: error %d releasing module\n", i); - spin_unlock_irqrestore(&divert_lock, flags); - return; - } - if (divert_dev_deinit()) { - printk(KERN_WARNING "dss1_divert: device busy, remove cancelled\n"); - spin_unlock_irqrestore(&divert_lock, flags); - return; - } - spin_unlock_irqrestore(&divert_lock, flags); - deleterule(-1); /* delete all rules and free mem */ - deleteprocs(); - printk(KERN_INFO "dss1_divert module successfully removed \n"); -} - -module_init(divert_init); -module_exit(divert_exit); diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c deleted file mode 100644 index 342585e04fd3..000000000000 --- a/drivers/isdn/divert/divert_procfs.c +++ /dev/null @@ -1,336 +0,0 @@ -/* $Id: divert_procfs.c,v 1.11.6.2 2001/09/23 22:24:36 kai Exp $ - * - * Filesystem handling for the diversion supplementary services. - * - * Copyright 1998 by Werner Cornelius (werner@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/poll.h> -#include <linux/slab.h> -#ifdef CONFIG_PROC_FS -#include <linux/proc_fs.h> -#else -#include <linux/fs.h> -#endif -#include <linux/sched.h> -#include <linux/isdnif.h> -#include <net/net_namespace.h> -#include <linux/mutex.h> -#include "isdn_divert.h" - - -/*********************************/ -/* Variables for interface queue */ -/*********************************/ -ulong if_used = 0; /* number of interface users */ -static DEFINE_MUTEX(isdn_divert_mutex); -static struct divert_info *divert_info_head = NULL; /* head of queue */ -static struct divert_info *divert_info_tail = NULL; /* pointer to last entry */ -static DEFINE_SPINLOCK(divert_info_lock);/* lock for queue */ -static wait_queue_head_t rd_queue; - -/*********************************/ -/* put an info buffer into queue */ -/*********************************/ -void -put_info_buffer(char *cp) -{ - struct divert_info *ib; - unsigned long flags; - - if (if_used <= 0) - return; - if (!cp) - return; - if (!*cp) - return; - if (!(ib = kmalloc(sizeof(struct divert_info) + strlen(cp), GFP_ATOMIC))) - return; /* no memory */ - strcpy(ib->info_start, cp); /* set output string */ - ib->next = NULL; - spin_lock_irqsave(&divert_info_lock, flags); - ib->usage_cnt = if_used; - if (!divert_info_head) - divert_info_head = ib; /* new head */ - else - divert_info_tail->next = ib; /* follows existing messages */ - divert_info_tail = ib; /* new tail */ - - /* delete old entrys */ - while (divert_info_head->next) { - if ((divert_info_head->usage_cnt <= 0) && - (divert_info_head->next->usage_cnt <= 0)) { - ib = divert_info_head; - divert_info_head = divert_info_head->next; - kfree(ib); - } else - break; - } /* divert_info_head->next */ - spin_unlock_irqrestore(&divert_info_lock, flags); - wake_up_interruptible(&(rd_queue)); -} /* put_info_buffer */ - -#ifdef CONFIG_PROC_FS - -/**********************************/ -/* deflection device read routine */ -/**********************************/ -static ssize_t -isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t *off) -{ - struct divert_info *inf; - int len; - - if (!(inf = *((struct divert_info **) file->private_data))) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - wait_event_interruptible(rd_queue, (inf = - *((struct divert_info **) file->private_data))); - } - if (!inf) - return (0); - - inf->usage_cnt--; /* new usage count */ - file->private_data = &inf->next; /* next structure */ - if ((len = strlen(inf->info_start)) <= count) { - if (copy_to_user(buf, inf->info_start, len)) - return -EFAULT; - *off += len; - return (len); - } - return (0); -} /* isdn_divert_read */ - -/**********************************/ -/* deflection device write routine */ -/**********************************/ -static ssize_t -isdn_divert_write(struct file *file, const char __user *buf, size_t count, loff_t *off) -{ - return (-ENODEV); -} /* isdn_divert_write */ - - -/***************************************/ -/* select routines for various kernels */ -/***************************************/ -static __poll_t -isdn_divert_poll(struct file *file, poll_table *wait) -{ - __poll_t mask = 0; - - poll_wait(file, &(rd_queue), wait); - /* mask = EPOLLOUT | EPOLLWRNORM; */ - if (*((struct divert_info **) file->private_data)) { - mask |= EPOLLIN | EPOLLRDNORM; - } - return mask; -} /* isdn_divert_poll */ - -/****************/ -/* Open routine */ -/****************/ -static int -isdn_divert_open(struct inode *ino, struct file *filep) -{ - unsigned long flags; - - spin_lock_irqsave(&divert_info_lock, flags); - if_used++; - if (divert_info_head) - filep->private_data = &(divert_info_tail->next); - else - filep->private_data = &divert_info_head; - spin_unlock_irqrestore(&divert_info_lock, flags); - /* start_divert(); */ - return nonseekable_open(ino, filep); -} /* isdn_divert_open */ - -/*******************/ -/* close routine */ -/*******************/ -static int -isdn_divert_close(struct inode *ino, struct file *filep) -{ - struct divert_info *inf; - unsigned long flags; - - spin_lock_irqsave(&divert_info_lock, flags); - if_used--; - inf = *((struct divert_info **) filep->private_data); - while (inf) { - inf->usage_cnt--; - inf = inf->next; - } - if (if_used <= 0) - while (divert_info_head) { - inf = divert_info_head; - divert_info_head = divert_info_head->next; - kfree(inf); - } - spin_unlock_irqrestore(&divert_info_lock, flags); - return (0); -} /* isdn_divert_close */ - -/*********/ -/* IOCTL */ -/*********/ -static int isdn_divert_ioctl_unlocked(struct file *file, uint cmd, ulong arg) -{ - divert_ioctl dioctl; - int i; - unsigned long flags; - divert_rule *rulep; - char *cp; - - if (copy_from_user(&dioctl, (void __user *) arg, sizeof(dioctl))) - return -EFAULT; - - switch (cmd) { - case IIOCGETVER: - dioctl.drv_version = DIVERT_IIOC_VERSION; /* set version */ - break; - - case IIOCGETDRV: - if ((dioctl.getid.drvid = divert_if.name_to_drv(dioctl.getid.drvnam)) < 0) - return (-EINVAL); - break; - - case IIOCGETNAM: - cp = divert_if.drv_to_name(dioctl.getid.drvid); - if (!cp) - return (-EINVAL); - if (!*cp) - return (-EINVAL); - strcpy(dioctl.getid.drvnam, cp); - break; - - case IIOCGETRULE: - if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx))) - return (-EINVAL); - dioctl.getsetrule.rule = *rulep; /* copy data */ - break; - - case IIOCMODRULE: - if (!(rulep = getruleptr(dioctl.getsetrule.ruleidx))) - return (-EINVAL); - spin_lock_irqsave(&divert_lock, flags); - *rulep = dioctl.getsetrule.rule; /* copy data */ - spin_unlock_irqrestore(&divert_lock, flags); - return (0); /* no copy required */ - break; - - case IIOCINSRULE: - return (insertrule(dioctl.getsetrule.ruleidx, &dioctl.getsetrule.rule)); - break; - - case IIOCDELRULE: - return (deleterule(dioctl.getsetrule.ruleidx)); - break; - - case IIOCDODFACT: - return (deflect_extern_action(dioctl.fwd_ctrl.subcmd, - dioctl.fwd_ctrl.callid, - dioctl.fwd_ctrl.to_nr)); - - case IIOCDOCFACT: - case IIOCDOCFDIS: - case IIOCDOCFINT: - if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid)) - return (-EINVAL); /* invalid driver */ - if (strnlen(dioctl.cf_ctrl.msn, sizeof(dioctl.cf_ctrl.msn)) == - sizeof(dioctl.cf_ctrl.msn)) - return -EINVAL; - if (strnlen(dioctl.cf_ctrl.fwd_nr, sizeof(dioctl.cf_ctrl.fwd_nr)) == - sizeof(dioctl.cf_ctrl.fwd_nr)) - return -EINVAL; - if ((i = cf_command(dioctl.cf_ctrl.drvid, - (cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2, - dioctl.cf_ctrl.cfproc, - dioctl.cf_ctrl.msn, - dioctl.cf_ctrl.service, - dioctl.cf_ctrl.fwd_nr, - &dioctl.cf_ctrl.procid))) - return (i); - break; - - default: - return (-EINVAL); - } /* switch cmd */ - return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0; -} /* isdn_divert_ioctl */ - -static long isdn_divert_ioctl(struct file *file, uint cmd, ulong arg) -{ - long ret; - - mutex_lock(&isdn_divert_mutex); - ret = isdn_divert_ioctl_unlocked(file, cmd, arg); - mutex_unlock(&isdn_divert_mutex); - - return ret; -} - -static const struct file_operations isdn_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = isdn_divert_read, - .write = isdn_divert_write, - .poll = isdn_divert_poll, - .unlocked_ioctl = isdn_divert_ioctl, - .open = isdn_divert_open, - .release = isdn_divert_close, -}; - -/****************************/ -/* isdn subdir in /proc/net */ -/****************************/ -static struct proc_dir_entry *isdn_proc_entry = NULL; -static struct proc_dir_entry *isdn_divert_entry = NULL; -#endif /* CONFIG_PROC_FS */ - -/***************************************************************************/ -/* divert_dev_init must be called before the proc filesystem may be used */ -/***************************************************************************/ -int -divert_dev_init(void) -{ - - init_waitqueue_head(&rd_queue); - -#ifdef CONFIG_PROC_FS - isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net); - if (!isdn_proc_entry) - return (-1); - isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO, - isdn_proc_entry, &isdn_fops); - if (!isdn_divert_entry) { - remove_proc_entry("isdn", init_net.proc_net); - return (-1); - } -#endif /* CONFIG_PROC_FS */ - - return (0); -} /* divert_dev_init */ - -/***************************************************************************/ -/* divert_dev_deinit must be called before leaving isdn when included as */ -/* a module. */ -/***************************************************************************/ -int -divert_dev_deinit(void) -{ - -#ifdef CONFIG_PROC_FS - remove_proc_entry("divert", isdn_proc_entry); - remove_proc_entry("isdn", init_net.proc_net); -#endif /* CONFIG_PROC_FS */ - - return (0); -} /* divert_dev_deinit */ diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c deleted file mode 100644 index 5620fd2c6009..000000000000 --- a/drivers/isdn/divert/isdn_divert.c +++ /dev/null @@ -1,846 +0,0 @@ -/* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $ - * - * DSS1 main diversion supplementary handling for i4l. - * - * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/proc_fs.h> -#include <linux/slab.h> -#include <linux/timer.h> -#include <linux/jiffies.h> - -#include "isdn_divert.h" - -/**********************************/ -/* structure keeping calling info */ -/**********************************/ -struct call_struc { - isdn_ctrl ics; /* delivered setup + driver parameters */ - ulong divert_id; /* Id delivered to user */ - unsigned char akt_state; /* actual state */ - char deflect_dest[35]; /* deflection destination */ - struct timer_list timer; /* timer control structure */ - char info[90]; /* device info output */ - struct call_struc *next; /* pointer to next entry */ - struct call_struc *prev; -}; - - -/********************************************/ -/* structure keeping deflection table entry */ -/********************************************/ -struct deflect_struc { - struct deflect_struc *next, *prev; - divert_rule rule; /* used rule */ -}; - - -/*****************************************/ -/* variables for main diversion services */ -/*****************************************/ -/* diversion/deflection processes */ -static struct call_struc *divert_head = NULL; /* head of remembered entrys */ -static ulong next_id = 1; /* next info id */ -static struct deflect_struc *table_head = NULL; -static struct deflect_struc *table_tail = NULL; -static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */ - -DEFINE_SPINLOCK(divert_lock); - -/***************************/ -/* timer callback function */ -/***************************/ -static void deflect_timer_expire(struct timer_list *t) -{ - unsigned long flags; - struct call_struc *cs = from_timer(cs, t, timer); - - spin_lock_irqsave(&divert_lock, flags); - del_timer(&cs->timer); /* delete active timer */ - spin_unlock_irqrestore(&divert_lock, flags); - - switch (cs->akt_state) { - case DEFLECT_PROCEED: - cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */ - divert_if.ll_cmd(&cs->ics); - spin_lock_irqsave(&divert_lock, flags); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - break; - - case DEFLECT_ALERT: - cs->ics.command = ISDN_CMD_REDIR; /* protocol */ - strlcpy(cs->ics.parm.setup.phone, cs->deflect_dest, sizeof(cs->ics.parm.setup.phone)); - strcpy(cs->ics.parm.setup.eazmsn, "Testtext delayed"); - divert_if.ll_cmd(&cs->ics); - spin_lock_irqsave(&divert_lock, flags); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - break; - - case DEFLECT_AUTODEL: - default: - spin_lock_irqsave(&divert_lock, flags); - if (cs->prev) - cs->prev->next = cs->next; /* forward link */ - else - divert_head = cs->next; - if (cs->next) - cs->next->prev = cs->prev; /* back link */ - spin_unlock_irqrestore(&divert_lock, flags); - kfree(cs); - return; - - } /* switch */ -} /* deflect_timer_func */ - - -/*****************************************/ -/* handle call forwarding de/activations */ -/* 0 = deact, 1 = act, 2 = interrogate */ -/*****************************************/ -int cf_command(int drvid, int mode, - u_char proc, char *msn, - u_char service, char *fwd_nr, ulong *procid) -{ - unsigned long flags; - int retval, msnlen; - int fwd_len; - char *p, *ielenp, tmp[60]; - struct call_struc *cs; - - if (strchr(msn, '.')) return (-EINVAL); /* subaddress not allowed in msn */ - if ((proc & 0x7F) > 2) return (-EINVAL); - proc &= 3; - p = tmp; - *p++ = 0x30; /* enumeration */ - ielenp = p++; /* remember total length position */ - *p++ = 0xa; /* proc tag */ - *p++ = 1; /* length */ - *p++ = proc & 0x7F; /* procedure to de/activate/interrogate */ - *p++ = 0xa; /* service tag */ - *p++ = 1; /* length */ - *p++ = service; /* service to handle */ - - if (mode == 1) { - if (!*fwd_nr) return (-EINVAL); /* destination missing */ - if (strchr(fwd_nr, '.')) return (-EINVAL); /* subaddress not allowed */ - fwd_len = strlen(fwd_nr); - *p++ = 0x30; /* number enumeration */ - *p++ = fwd_len + 2; /* complete forward to len */ - *p++ = 0x80; /* fwd to nr */ - *p++ = fwd_len; /* length of number */ - strcpy(p, fwd_nr); /* copy number */ - p += fwd_len; /* pointer beyond fwd */ - } /* activate */ - - msnlen = strlen(msn); - *p++ = 0x80; /* msn number */ - if (msnlen > 1) { - *p++ = msnlen; /* length */ - strcpy(p, msn); - p += msnlen; - } else - *p++ = 0; - - *ielenp = p - ielenp - 1; /* set total IE length */ - - /* allocate mem for information struct */ - if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC))) - return (-ENOMEM); /* no memory */ - timer_setup(&cs->timer, deflect_timer_expire, 0); - cs->info[0] = '\0'; - cs->ics.driver = drvid; - cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */ - cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */ - cs->ics.parm.dss1_io.proc = (mode == 1) ? 7 : (mode == 2) ? 11 : 8; /* operation */ - cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */ - cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */ - cs->ics.parm.dss1_io.data = tmp; /* start of buffer */ - - spin_lock_irqsave(&divert_lock, flags); - cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */ - spin_unlock_irqrestore(&divert_lock, flags); - *procid = cs->ics.parm.dss1_io.ll_id; - - sprintf(cs->info, "%d 0x%lx %s%s 0 %s %02x %d%s%s\n", - (!mode) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT, - cs->ics.parm.dss1_io.ll_id, - (mode != 2) ? "" : "0 ", - divert_if.drv_to_name(cs->ics.driver), - msn, - service & 0xFF, - proc, - (mode != 1) ? "" : " 0 ", - (mode != 1) ? "" : fwd_nr); - - retval = divert_if.ll_cmd(&cs->ics); /* execute command */ - - if (!retval) { - cs->prev = NULL; - spin_lock_irqsave(&divert_lock, flags); - cs->next = divert_head; - divert_head = cs; - spin_unlock_irqrestore(&divert_lock, flags); - } else - kfree(cs); - return (retval); -} /* cf_command */ - - -/****************************************/ -/* handle a external deflection command */ -/****************************************/ -int deflect_extern_action(u_char cmd, ulong callid, char *to_nr) -{ - struct call_struc *cs; - isdn_ctrl ic; - unsigned long flags; - int i; - - if ((cmd & 0x7F) > 2) return (-EINVAL); /* invalid command */ - cs = divert_head; /* start of parameter list */ - while (cs) { - if (cs->divert_id == callid) break; /* found */ - cs = cs->next; - } /* search entry */ - if (!cs) return (-EINVAL); /* invalid callid */ - - ic.driver = cs->ics.driver; - ic.arg = cs->ics.arg; - i = -EINVAL; - if (cs->akt_state == DEFLECT_AUTODEL) return (i); /* no valid call */ - switch (cmd & 0x7F) { - case 0: /* hangup */ - del_timer(&cs->timer); - ic.command = ISDN_CMD_HANGUP; - i = divert_if.ll_cmd(&ic); - spin_lock_irqsave(&divert_lock, flags); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - break; - - case 1: /* alert */ - if (cs->akt_state == DEFLECT_ALERT) return (0); - cmd &= 0x7F; /* never wait */ - del_timer(&cs->timer); - ic.command = ISDN_CMD_ALERT; - if ((i = divert_if.ll_cmd(&ic))) { - spin_lock_irqsave(&divert_lock, flags); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - } else - cs->akt_state = DEFLECT_ALERT; - break; - - case 2: /* redir */ - del_timer(&cs->timer); - strlcpy(cs->ics.parm.setup.phone, to_nr, sizeof(cs->ics.parm.setup.phone)); - strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual"); - ic.command = ISDN_CMD_REDIR; - if ((i = divert_if.ll_cmd(&ic))) { - spin_lock_irqsave(&divert_lock, flags); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - } else - cs->akt_state = DEFLECT_ALERT; - break; - - } /* switch */ - return (i); -} /* deflect_extern_action */ - -/********************************/ -/* insert a new rule before idx */ -/********************************/ -int insertrule(int idx, divert_rule *newrule) -{ - struct deflect_struc *ds, *ds1 = NULL; - unsigned long flags; - - if (!(ds = kmalloc(sizeof(struct deflect_struc), GFP_KERNEL))) - return (-ENOMEM); /* no memory */ - - ds->rule = *newrule; /* set rule */ - - spin_lock_irqsave(&divert_lock, flags); - - if (idx >= 0) { - ds1 = table_head; - while ((ds1) && (idx > 0)) - { idx--; - ds1 = ds1->next; - } - if (!ds1) idx = -1; - } - - if (idx < 0) { - ds->prev = table_tail; /* previous entry */ - ds->next = NULL; /* end of chain */ - if (ds->prev) - ds->prev->next = ds; /* last forward */ - else - table_head = ds; /* is first entry */ - table_tail = ds; /* end of queue */ - } else { - ds->next = ds1; /* next entry */ - ds->prev = ds1->prev; /* prev entry */ - ds1->prev = ds; /* backward chain old element */ - if (!ds->prev) - table_head = ds; /* first element */ - } - - spin_unlock_irqrestore(&divert_lock, flags); - return (0); -} /* insertrule */ - -/***********************************/ -/* delete the rule at position idx */ -/***********************************/ -int deleterule(int idx) -{ - struct deflect_struc *ds, *ds1; - unsigned long flags; - - if (idx < 0) { - spin_lock_irqsave(&divert_lock, flags); - ds = table_head; - table_head = NULL; - table_tail = NULL; - spin_unlock_irqrestore(&divert_lock, flags); - while (ds) { - ds1 = ds; - ds = ds->next; - kfree(ds1); - } - return (0); - } - - spin_lock_irqsave(&divert_lock, flags); - ds = table_head; - - while ((ds) && (idx > 0)) { - idx--; - ds = ds->next; - } - - if (!ds) { - spin_unlock_irqrestore(&divert_lock, flags); - return (-EINVAL); - } - - if (ds->next) - ds->next->prev = ds->prev; /* backward chain */ - else - table_tail = ds->prev; /* end of chain */ - - if (ds->prev) - ds->prev->next = ds->next; /* forward chain */ - else - table_head = ds->next; /* start of chain */ - - spin_unlock_irqrestore(&divert_lock, flags); - kfree(ds); - return (0); -} /* deleterule */ - -/*******************************************/ -/* get a pointer to a specific rule number */ -/*******************************************/ -divert_rule *getruleptr(int idx) -{ - struct deflect_struc *ds = table_head; - - if (idx < 0) return (NULL); - while ((ds) && (idx >= 0)) { - if (!(idx--)) { - return (&ds->rule); - break; - } - ds = ds->next; - } - return (NULL); -} /* getruleptr */ - -/*************************************************/ -/* called from common module on an incoming call */ -/*************************************************/ -static int isdn_divert_icall(isdn_ctrl *ic) -{ - int retval = 0; - unsigned long flags; - struct call_struc *cs = NULL; - struct deflect_struc *dv; - char *p, *p1; - u_char accept; - - /* first check the internal deflection table */ - for (dv = table_head; dv; dv = dv->next) { - /* scan table */ - if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) || - ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL))) - continue; /* call option check */ - if (!(dv->rule.drvid & (1L << ic->driver))) - continue; /* driver not matching */ - if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1)) - continue; /* si1 not matching */ - if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2)) - continue; /* si2 not matching */ - - p = dv->rule.my_msn; - p1 = ic->parm.setup.eazmsn; - accept = 0; - while (*p) { - /* complete compare */ - if (*p == '-') { - accept = 1; /* call accepted */ - break; - } - if (*p++ != *p1++) - break; /* not accepted */ - if ((!*p) && (!*p1)) - accept = 1; - } /* complete compare */ - if (!accept) continue; /* not accepted */ - - if ((strcmp(dv->rule.caller, "0")) || - (ic->parm.setup.phone[0])) { - p = dv->rule.caller; - p1 = ic->parm.setup.phone; - accept = 0; - while (*p) { - /* complete compare */ - if (*p == '-') { - accept = 1; /* call accepted */ - break; - } - if (*p++ != *p1++) - break; /* not accepted */ - if ((!*p) && (!*p1)) - accept = 1; - } /* complete compare */ - if (!accept) continue; /* not accepted */ - } - - switch (dv->rule.action) { - case DEFLECT_IGNORE: - return 0; - - case DEFLECT_ALERT: - case DEFLECT_PROCEED: - case DEFLECT_REPORT: - case DEFLECT_REJECT: - if (dv->rule.action == DEFLECT_PROCEED) - if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime))) - return (0); /* no external deflection needed */ - if (!(cs = kmalloc(sizeof(struct call_struc), GFP_ATOMIC))) - return (0); /* no memory */ - timer_setup(&cs->timer, deflect_timer_expire, 0); - cs->info[0] = '\0'; - - cs->ics = *ic; /* copy incoming data */ - if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone, "0"); - if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn, "0"); - cs->ics.parm.setup.screen = dv->rule.screen; - if (dv->rule.waittime) - cs->timer.expires = jiffies + (HZ * dv->rule.waittime); - else if (dv->rule.action == DEFLECT_PROCEED) - cs->timer.expires = jiffies + (HZ * extern_wait_max); - else - cs->timer.expires = 0; - cs->akt_state = dv->rule.action; - spin_lock_irqsave(&divert_lock, flags); - cs->divert_id = next_id++; /* new sequence number */ - spin_unlock_irqrestore(&divert_lock, flags); - cs->prev = NULL; - if (cs->akt_state == DEFLECT_ALERT) { - strcpy(cs->deflect_dest, dv->rule.to_nr); - if (!cs->timer.expires) { - strcpy(ic->parm.setup.eazmsn, - "Testtext direct"); - ic->parm.setup.screen = dv->rule.screen; - strlcpy(ic->parm.setup.phone, dv->rule.to_nr, sizeof(ic->parm.setup.phone)); - cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ - cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - retval = 5; - } else - retval = 1; /* alerting */ - } else { - cs->deflect_dest[0] = '\0'; - retval = 4; /* only proceed */ - } - snprintf(cs->info, sizeof(cs->info), - "%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n", - cs->akt_state, - cs->divert_id, - divert_if.drv_to_name(cs->ics.driver), - (ic->command == ISDN_STAT_ICALLW) ? "1" : "0", - cs->ics.parm.setup.phone, - cs->ics.parm.setup.eazmsn, - cs->ics.parm.setup.si1, - cs->ics.parm.setup.si2, - cs->ics.parm.setup.screen, - dv->rule.waittime, - cs->deflect_dest); - if ((dv->rule.action == DEFLECT_REPORT) || - (dv->rule.action == DEFLECT_REJECT)) { - put_info_buffer(cs->info); - kfree(cs); /* remove */ - return ((dv->rule.action == DEFLECT_REPORT) ? 0 : 2); /* nothing to do */ - } - break; - - default: - return 0; /* ignore call */ - } /* switch action */ - break; /* will break the 'for' looping */ - } /* scan_table */ - - if (cs) { - cs->prev = NULL; - spin_lock_irqsave(&divert_lock, flags); - cs->next = divert_head; - divert_head = cs; - if (cs->timer.expires) add_timer(&cs->timer); - spin_unlock_irqrestore(&divert_lock, flags); - - put_info_buffer(cs->info); - return (retval); - } else - return (0); -} /* isdn_divert_icall */ - - -void deleteprocs(void) -{ - struct call_struc *cs, *cs1; - unsigned long flags; - - spin_lock_irqsave(&divert_lock, flags); - cs = divert_head; - divert_head = NULL; - while (cs) { - del_timer(&cs->timer); - cs1 = cs; - cs = cs->next; - kfree(cs1); - } - spin_unlock_irqrestore(&divert_lock, flags); -} /* deleteprocs */ - -/****************************************************/ -/* put a address including address type into buffer */ -/****************************************************/ -static int put_address(char *st, u_char *p, int len) -{ - u_char retval = 0; - u_char adr_typ = 0; /* network standard */ - - if (len < 2) return (retval); - if (*p == 0xA1) { - retval = *(++p) + 2; /* total length */ - if (retval > len) return (0); /* too short */ - len = retval - 2; /* remaining length */ - if (len < 3) return (0); - if ((*(++p) != 0x0A) || (*(++p) != 1)) return (0); - adr_typ = *(++p); - len -= 3; - p++; - if (len < 2) return (0); - if (*p++ != 0x12) return (0); - if (*p > len) return (0); /* check number length */ - len = *p++; - } else if (*p == 0x80) { - retval = *(++p) + 2; /* total length */ - if (retval > len) return (0); - len = retval - 2; - p++; - } else - return (0); /* invalid address information */ - - sprintf(st, "%d ", adr_typ); - st += strlen(st); - if (!len) - *st++ = '-'; - else - while (len--) - *st++ = *p++; - *st = '\0'; - return (retval); -} /* put_address */ - -/*************************************/ -/* report a successful interrogation */ -/*************************************/ -static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs) -{ - char *src = ic->parm.dss1_io.data; - int restlen = ic->parm.dss1_io.datalen; - int cnt = 1; - u_char n, n1; - char st[90], *p, *stp; - - if (restlen < 2) return (-100); /* frame too short */ - if (*src++ != 0x30) return (-101); - if ((n = *src++) > 0x81) return (-102); /* invalid length field */ - restlen -= 2; /* remaining bytes */ - if (n == 0x80) { - if (restlen < 2) return (-103); - if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-104); - restlen -= 2; - } else if (n == 0x81) { - n = *src++; - restlen--; - if (n > restlen) return (-105); - restlen = n; - } else if (n > restlen) - return (-106); - else - restlen = n; /* standard format */ - if (restlen < 3) return (-107); /* no procedure */ - if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return (-108); - restlen -= 3; - if (restlen < 2) return (-109); /* list missing */ - if (*src == 0x31) { - src++; - if ((n = *src++) > 0x81) return (-110); /* invalid length field */ - restlen -= 2; /* remaining bytes */ - if (n == 0x80) { - if (restlen < 2) return (-111); - if ((*(src + restlen - 1)) || (*(src + restlen - 2))) return (-112); - restlen -= 2; - } else if (n == 0x81) { - n = *src++; - restlen--; - if (n > restlen) return (-113); - restlen = n; - } else if (n > restlen) - return (-114); - else - restlen = n; /* standard format */ - } /* result list header */ - - while (restlen >= 2) { - stp = st; - sprintf(stp, "%d 0x%lx %d %s ", DIVERT_REPORT, ic->parm.dss1_io.ll_id, - cnt++, divert_if.drv_to_name(ic->driver)); - stp += strlen(stp); - if (*src++ != 0x30) return (-115); /* invalid enum */ - n = *src++; - restlen -= 2; - if (n > restlen) return (-116); /* enum length wrong */ - restlen -= n; - p = src; /* one entry */ - src += n; - if (!(n1 = put_address(stp, p, n & 0xFF))) continue; - stp += strlen(stp); - p += n1; - n -= n1; - if (n < 6) continue; /* no service and proc */ - if ((*p++ != 0x0A) || (*p++ != 1)) continue; - sprintf(stp, " 0x%02x ", (*p++) & 0xFF); - stp += strlen(stp); - if ((*p++ != 0x0A) || (*p++ != 1)) continue; - sprintf(stp, "%d ", (*p++) & 0xFF); - stp += strlen(stp); - n -= 6; - if (n > 2) { - if (*p++ != 0x30) continue; - if (*p > (n - 2)) continue; - n = *p++; - if (!(n1 = put_address(stp, p, n & 0xFF))) continue; - stp += strlen(stp); - } - sprintf(stp, "\n"); - put_info_buffer(st); - } /* while restlen */ - if (restlen) return (-117); - return (0); -} /* interrogate_success */ - -/*********************************************/ -/* callback for protocol specific extensions */ -/*********************************************/ -static int prot_stat_callback(isdn_ctrl *ic) -{ - struct call_struc *cs, *cs1; - int i; - unsigned long flags; - - cs = divert_head; /* start of list */ - cs1 = NULL; - while (cs) { - if (ic->driver == cs->ics.driver) { - switch (cs->ics.arg) { - case DSS1_CMD_INVOKE: - if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) && - (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id)) { - switch (ic->arg) { - case DSS1_STAT_INVOKE_ERR: - sprintf(cs->info, "128 0x%lx 0x%x\n", - ic->parm.dss1_io.ll_id, - ic->parm.dss1_io.timeout); - put_info_buffer(cs->info); - break; - - case DSS1_STAT_INVOKE_RES: - switch (cs->ics.parm.dss1_io.proc) { - case 7: - case 8: - put_info_buffer(cs->info); - break; - - case 11: - i = interrogate_success(ic, cs); - if (i) - sprintf(cs->info, "%d 0x%lx %d\n", DIVERT_REPORT, - ic->parm.dss1_io.ll_id, i); - put_info_buffer(cs->info); - break; - - default: - printk(KERN_WARNING "dss1_divert: unknown proc %d\n", cs->ics.parm.dss1_io.proc); - break; - } - - break; - - default: - printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n", ic->arg); - break; - } - cs1 = cs; /* remember structure */ - cs = NULL; - continue; /* abort search */ - } /* id found */ - break; - - case DSS1_CMD_INVOKE_ABORT: - printk(KERN_WARNING "dss1_divert unhandled invoke abort\n"); - break; - - default: - printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n", cs->ics.arg); - break; - } /* switch ics.arg */ - cs = cs->next; - } /* driver ok */ - } - - if (!cs1) { - printk(KERN_WARNING "dss1_divert unhandled process\n"); - return (0); - } - - if (cs1->ics.driver == -1) { - spin_lock_irqsave(&divert_lock, flags); - del_timer(&cs1->timer); - if (cs1->prev) - cs1->prev->next = cs1->next; /* forward link */ - else - divert_head = cs1->next; - if (cs1->next) - cs1->next->prev = cs1->prev; /* back link */ - spin_unlock_irqrestore(&divert_lock, flags); - kfree(cs1); - } - - return (0); -} /* prot_stat_callback */ - - -/***************************/ -/* status callback from HL */ -/***************************/ -static int isdn_divert_stat_callback(isdn_ctrl *ic) -{ - struct call_struc *cs, *cs1; - unsigned long flags; - int retval; - - retval = -1; - cs = divert_head; /* start of list */ - while (cs) { - if ((ic->driver == cs->ics.driver) && - (ic->arg == cs->ics.arg)) { - switch (ic->command) { - case ISDN_STAT_DHUP: - sprintf(cs->info, "129 0x%lx\n", cs->divert_id); - del_timer(&cs->timer); - cs->ics.driver = -1; - break; - - case ISDN_STAT_CAUSE: - sprintf(cs->info, "130 0x%lx %s\n", cs->divert_id, ic->parm.num); - break; - - case ISDN_STAT_REDIR: - sprintf(cs->info, "131 0x%lx\n", cs->divert_id); - del_timer(&cs->timer); - cs->ics.driver = -1; - break; - - default: - sprintf(cs->info, "999 0x%lx 0x%x\n", cs->divert_id, (int)(ic->command)); - break; - } - put_info_buffer(cs->info); - retval = 0; - } - cs1 = cs; - cs = cs->next; - if (cs1->ics.driver == -1) { - spin_lock_irqsave(&divert_lock, flags); - if (cs1->prev) - cs1->prev->next = cs1->next; /* forward link */ - else - divert_head = cs1->next; - if (cs1->next) - cs1->next->prev = cs1->prev; /* back link */ - spin_unlock_irqrestore(&divert_lock, flags); - kfree(cs1); - } - } - return (retval); /* not found */ -} /* isdn_divert_stat_callback */ - - -/********************/ -/* callback from ll */ -/********************/ -int ll_callback(isdn_ctrl *ic) -{ - switch (ic->command) { - case ISDN_STAT_ICALL: - case ISDN_STAT_ICALLW: - return (isdn_divert_icall(ic)); - break; - - case ISDN_STAT_PROT: - if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO) { - if (ic->arg != DSS1_STAT_INVOKE_BRD) - return (prot_stat_callback(ic)); - else - return (0); /* DSS1 invoke broadcast */ - } else - return (-1); /* protocol not euro */ - - default: - return (isdn_divert_stat_callback(ic)); - } -} /* ll_callback */ diff --git a/drivers/isdn/divert/isdn_divert.h b/drivers/isdn/divert/isdn_divert.h deleted file mode 100644 index 55033dd872c0..000000000000 --- a/drivers/isdn/divert/isdn_divert.h +++ /dev/null @@ -1,132 +0,0 @@ -/* $Id: isdn_divert.h,v 1.5.6.1 2001/09/23 22:24:36 kai Exp $ - * - * Header for the diversion supplementary ioctl interface. - * - * Copyright 1998 by Werner Cornelius (werner@ikt.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/ioctl.h> -#include <linux/types.h> - -/******************************************/ -/* IOCTL codes for interface to user prog */ -/******************************************/ -#define DIVERT_IIOC_VERSION 0x01 /* actual version */ -#define IIOCGETVER _IO('I', 1) /* get version of interface */ -#define IIOCGETDRV _IO('I', 2) /* get driver number */ -#define IIOCGETNAM _IO('I', 3) /* get driver name */ -#define IIOCGETRULE _IO('I', 4) /* read one rule */ -#define IIOCMODRULE _IO('I', 5) /* modify/replace a rule */ -#define IIOCINSRULE _IO('I', 6) /* insert/append one rule */ -#define IIOCDELRULE _IO('I', 7) /* delete a rule */ -#define IIOCDODFACT _IO('I', 8) /* hangup/reject/alert/immediately deflect a call */ -#define IIOCDOCFACT _IO('I', 9) /* activate control forwarding in PBX */ -#define IIOCDOCFDIS _IO('I', 10) /* deactivate control forwarding in PBX */ -#define IIOCDOCFINT _IO('I', 11) /* interrogate control forwarding in PBX */ - -/*************************************/ -/* states reported through interface */ -/*************************************/ -#define DEFLECT_IGNORE 0 /* ignore incoming call */ -#define DEFLECT_REPORT 1 /* only report */ -#define DEFLECT_PROCEED 2 /* deflect when externally triggered */ -#define DEFLECT_ALERT 3 /* alert and deflect after delay */ -#define DEFLECT_REJECT 4 /* reject immediately */ -#define DIVERT_ACTIVATE 5 /* diversion activate */ -#define DIVERT_DEACTIVATE 6 /* diversion deactivate */ -#define DIVERT_REPORT 7 /* interrogation result */ -#define DEFLECT_AUTODEL 255 /* only for internal use */ - -#define DEFLECT_ALL_IDS 0xFFFFFFFF /* all drivers selected */ - -typedef struct { - ulong drvid; /* driver ids, bit mapped */ - char my_msn[35]; /* desired msn, subaddr allowed */ - char caller[35]; /* caller id, partial string with * + subaddr allowed */ - char to_nr[35]; /* deflected to number incl. subaddress */ - u_char si1, si2; /* service indicators, si1=bitmask, si1+2 0 = all */ - u_char screen; /* screening: 0 = no info, 1 = info, 2 = nfo with nr */ - u_char callopt; /* option for call handling: - 0 = all calls - 1 = only non waiting calls - 2 = only waiting calls */ - u_char action; /* desired action: - 0 = don't report call -> ignore - 1 = report call, do not allow/proceed for deflection - 2 = report call, send proceed, wait max waittime secs - 3 = report call, alert and deflect after waittime - 4 = report call, reject immediately - actions 1-2 only take place if interface is opened - */ - u_char waittime; /* maximum wait time for proceeding */ -} divert_rule; - -typedef union { - int drv_version; /* return of driver version */ - struct { - int drvid; /* id of driver */ - char drvnam[30]; /* name of driver */ - } getid; - struct { - int ruleidx; /* index of rule */ - divert_rule rule; /* rule parms */ - } getsetrule; - struct { - u_char subcmd; /* 0 = hangup/reject, - 1 = alert, - 2 = deflect */ - ulong callid; /* id of call delivered by ascii output */ - char to_nr[35]; /* destination when deflect, - else uus1 string (maxlen 31), - data from rule used if empty */ - } fwd_ctrl; - struct { - int drvid; /* id of driver */ - u_char cfproc; /* cfu = 0, cfb = 1, cfnr = 2 */ - ulong procid; /* process id returned when no error */ - u_char service; /* basically coded service, 0 = all */ - char msn[25]; /* desired msn, empty = all */ - char fwd_nr[35];/* forwarded to number + subaddress */ - } cf_ctrl; -} divert_ioctl; - -#ifdef __KERNEL__ - -#include <linux/isdnif.h> -#include <linux/isdn_divertif.h> - -#define AUTODEL_TIME 30 /* timeout in s to delete internal entries */ - -/**************************************************/ -/* structure keeping ascii info for device output */ -/**************************************************/ -struct divert_info { - struct divert_info *next; - ulong usage_cnt; /* number of files still to work */ - char info_start[2]; /* info string start */ -}; - - -/**************/ -/* Prototypes */ -/**************/ -extern spinlock_t divert_lock; - -extern ulong if_used; /* number of interface users */ -extern int divert_dev_deinit(void); -extern int divert_dev_init(void); -extern void put_info_buffer(char *); -extern int ll_callback(isdn_ctrl *); -extern isdn_divert_if divert_if; -extern divert_rule *getruleptr(int); -extern int insertrule(int, divert_rule *); -extern int deleterule(int); -extern void deleteprocs(void); -extern int deflect_extern_action(u_char, ulong, char *); -extern int cf_command(int, int, u_char, char *, u_char, char *, ulong *); - -#endif /* __KERNEL__ */ diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig deleted file mode 100644 index fe41e9cfb672..000000000000 --- a/drivers/isdn/gigaset/Kconfig +++ /dev/null @@ -1,71 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -menuconfig ISDN_DRV_GIGASET - tristate "Siemens Gigaset support" - depends on TTY - select CRC_CCITT - select BITREVERSE - help - This driver supports the Siemens Gigaset SX205/255 family of - ISDN DECT bases, including the predecessors Gigaset 3070/3075 - and 4170/4175 and their T-Com versions Sinus 45isdn and Sinus - 721X. - If you have one of these devices, say M here and for at least - one of the connection specific parts that follow. - This will build a module called "gigaset". - Note: If you build your ISDN subsystem (ISDN_CAPI or ISDN_I4L) - as a module, you have to build this driver as a module too, - otherwise the Gigaset device won't show up as an ISDN device. - -if ISDN_DRV_GIGASET - -config GIGASET_CAPI - bool "Gigaset CAPI support" - depends on ISDN_CAPI='y'||(ISDN_CAPI='m'&&ISDN_DRV_GIGASET='m') - default 'y' - help - Build the Gigaset driver as a CAPI 2.0 driver interfacing with - the Kernel CAPI subsystem. To use it with the old ISDN4Linux - subsystem you'll have to enable the capidrv glue driver. - (select ISDN_CAPI_CAPIDRV.) - Say N to build the old native ISDN4Linux variant. - If unsure, say Y. - -config GIGASET_I4L - bool - depends on ISDN_I4L='y'||(ISDN_I4L='m'&&ISDN_DRV_GIGASET='m') - default !GIGASET_CAPI - -config GIGASET_DUMMYLL - bool - default !GIGASET_CAPI&&!GIGASET_I4L - -config GIGASET_BASE - tristate "Gigaset base station support" - depends on USB - help - Say M here if you want to use the USB interface of the Gigaset - base for connection to your system. - This will build a module called "bas_gigaset". - -config GIGASET_M105 - tristate "Gigaset M105 support" - depends on USB - help - Say M here if you want to connect to the Gigaset base via DECT - using a Gigaset M105 (Sinus 45 Data 2) USB DECT device. - This will build a module called "usb_gigaset". - -config GIGASET_M101 - tristate "Gigaset M101 support" - help - Say M here if you want to connect to the Gigaset base via DECT - using a Gigaset M101 (Sinus 45 Data 1) RS232 DECT device. - This will build a module called "ser_gigaset". - -config GIGASET_DEBUG - bool "Gigaset debugging" - help - This enables debugging code in the Gigaset drivers. - If in doubt, say yes. - -endif # ISDN_DRV_GIGASET diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile deleted file mode 100644 index ac45a2739f56..000000000000 --- a/drivers/isdn/gigaset/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -gigaset-y := common.o interface.o proc.o ev-layer.o asyncdata.o -gigaset-$(CONFIG_GIGASET_CAPI) += capi.o -gigaset-$(CONFIG_GIGASET_I4L) += i4l.o -gigaset-$(CONFIG_GIGASET_DUMMYLL) += dummyll.o -usb_gigaset-y := usb-gigaset.o -ser_gigaset-y := ser-gigaset.o -bas_gigaset-y := bas-gigaset.o isocdata.o - -obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset.o -obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o -obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o -obj-$(CONFIG_GIGASET_M101) += ser_gigaset.o diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c deleted file mode 100644 index a34b3c9d8a71..000000000000 --- a/drivers/isdn/gigaset/asyncdata.c +++ /dev/null @@ -1,606 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Common data handling layer for ser_gigaset and usb_gigaset - * - * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>, - * Hansjoerg Lipp <hjlipp@web.de>, - * Stefan Eilers. - * - * ===================================================================== - * ===================================================================== - */ - -#include "gigaset.h" -#include <linux/crc-ccitt.h> -#include <linux/bitrev.h> -#include <linux/export.h> - -/* check if byte must be stuffed/escaped - * I'm not sure which data should be encoded. - * Therefore I will go the hard way and encode every value - * less than 0x20, the flag sequence and the control escape char. - */ -static inline int muststuff(unsigned char c) -{ - if (c < PPP_TRANS) return 1; - if (c == PPP_FLAG) return 1; - if (c == PPP_ESCAPE) return 1; - /* other possible candidates: */ - /* 0x91: XON with parity set */ - /* 0x93: XOFF with parity set */ - return 0; -} - -/* == data input =========================================================== */ - -/* process a block of received bytes in command mode - * (mstate != MS_LOCKED && (inputstate & INS_command)) - * Append received bytes to the command response buffer and forward them - * line by line to the response handler. Exit whenever a mode/state change - * might have occurred. - * Note: Received lines may be terminated by CR, LF, or CR LF, which will be - * removed before passing the line to the response handler. - * Return value: - * number of processed bytes - */ -static unsigned cmd_loop(unsigned numbytes, struct inbuf_t *inbuf) -{ - unsigned char *src = inbuf->data + inbuf->head; - struct cardstate *cs = inbuf->cs; - unsigned cbytes = cs->cbytes; - unsigned procbytes = 0; - unsigned char c; - - while (procbytes < numbytes) { - c = *src++; - procbytes++; - - switch (c) { - case '\n': - if (cbytes == 0 && cs->respdata[0] == '\r') { - /* collapse LF with preceding CR */ - cs->respdata[0] = 0; - break; - } - /* fall through */ - case '\r': - /* end of message line, pass to response handler */ - if (cbytes >= MAX_RESP_SIZE) { - dev_warn(cs->dev, "response too large (%d)\n", - cbytes); - cbytes = MAX_RESP_SIZE; - } - cs->cbytes = cbytes; - gigaset_dbg_buffer(DEBUG_TRANSCMD, "received response", - cbytes, cs->respdata); - gigaset_handle_modem_response(cs); - cbytes = 0; - - /* store EOL byte for CRLF collapsing */ - cs->respdata[0] = c; - - /* cs->dle may have changed */ - if (cs->dle && !(inbuf->inputstate & INS_DLE_command)) - inbuf->inputstate &= ~INS_command; - - /* return for reevaluating state */ - goto exit; - - case DLE_FLAG: - if (inbuf->inputstate & INS_DLE_char) { - /* quoted DLE: clear quote flag */ - inbuf->inputstate &= ~INS_DLE_char; - } else if (cs->dle || - (inbuf->inputstate & INS_DLE_command)) { - /* DLE escape, pass up for handling */ - inbuf->inputstate |= INS_DLE_char; - goto exit; - } - /* quoted or not in DLE mode: treat as regular data */ - /* fall through */ - default: - /* append to line buffer if possible */ - if (cbytes < MAX_RESP_SIZE) - cs->respdata[cbytes] = c; - cbytes++; - } - } -exit: - cs->cbytes = cbytes; - return procbytes; -} - -/* process a block of received bytes in lock mode - * All received bytes are passed unmodified to the tty i/f. - * Return value: - * number of processed bytes - */ -static unsigned lock_loop(unsigned numbytes, struct inbuf_t *inbuf) -{ - unsigned char *src = inbuf->data + inbuf->head; - - gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src); - gigaset_if_receive(inbuf->cs, src, numbytes); - return numbytes; -} - -/* process a block of received bytes in HDLC data mode - * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC) - * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. - * When a frame is complete, check the FCS and pass valid frames to the LL. - * If DLE is encountered, return immediately to let the caller handle it. - * Return value: - * number of processed bytes - */ -static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) -{ - struct cardstate *cs = inbuf->cs; - struct bc_state *bcs = cs->bcs; - int inputstate = bcs->inputstate; - __u16 fcs = bcs->rx_fcs; - struct sk_buff *skb = bcs->rx_skb; - unsigned char *src = inbuf->data + inbuf->head; - unsigned procbytes = 0; - unsigned char c; - - if (inputstate & INS_byte_stuff) { - if (!numbytes) - return 0; - inputstate &= ~INS_byte_stuff; - goto byte_stuff; - } - - while (procbytes < numbytes) { - c = *src++; - procbytes++; - if (c == DLE_FLAG) { - if (inputstate & INS_DLE_char) { - /* quoted DLE: clear quote flag */ - inputstate &= ~INS_DLE_char; - } else if (cs->dle || (inputstate & INS_DLE_command)) { - /* DLE escape, pass up for handling */ - inputstate |= INS_DLE_char; - break; - } - } - - if (c == PPP_ESCAPE) { - /* byte stuffing indicator: pull in next byte */ - if (procbytes >= numbytes) { - /* end of buffer, save for later processing */ - inputstate |= INS_byte_stuff; - break; - } -byte_stuff: - c = *src++; - procbytes++; - if (c == DLE_FLAG) { - if (inputstate & INS_DLE_char) { - /* quoted DLE: clear quote flag */ - inputstate &= ~INS_DLE_char; - } else if (cs->dle || - (inputstate & INS_DLE_command)) { - /* DLE escape, pass up for handling */ - inputstate |= - INS_DLE_char | INS_byte_stuff; - break; - } - } - c ^= PPP_TRANS; -#ifdef CONFIG_GIGASET_DEBUG - if (!muststuff(c)) - gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c); -#endif - } else if (c == PPP_FLAG) { - /* end of frame: process content if any */ - if (inputstate & INS_have_data) { - gig_dbg(DEBUG_HDLC, - "7e----------------------------"); - - /* check and pass received frame */ - if (!skb) { - /* skipped frame */ - gigaset_isdn_rcv_err(bcs); - } else if (skb->len < 2) { - /* frame too short for FCS */ - dev_warn(cs->dev, - "short frame (%d)\n", - skb->len); - gigaset_isdn_rcv_err(bcs); - dev_kfree_skb_any(skb); - } else if (fcs != PPP_GOODFCS) { - /* frame check error */ - dev_err(cs->dev, - "Checksum failed, %u bytes corrupted!\n", - skb->len); - gigaset_isdn_rcv_err(bcs); - dev_kfree_skb_any(skb); - } else { - /* good frame */ - __skb_trim(skb, skb->len - 2); - gigaset_skb_rcvd(bcs, skb); - } - - /* prepare reception of next frame */ - inputstate &= ~INS_have_data; - skb = gigaset_new_rx_skb(bcs); - } else { - /* empty frame (7E 7E) */ -#ifdef CONFIG_GIGASET_DEBUG - ++bcs->emptycount; -#endif - if (!skb) { - /* skipped (?) */ - gigaset_isdn_rcv_err(bcs); - skb = gigaset_new_rx_skb(bcs); - } - } - - fcs = PPP_INITFCS; - continue; -#ifdef CONFIG_GIGASET_DEBUG - } else if (muststuff(c)) { - /* Should not happen. Possible after ZDLE=1<CR><LF>. */ - gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); -#endif - } - - /* regular data byte, append to skb */ -#ifdef CONFIG_GIGASET_DEBUG - if (!(inputstate & INS_have_data)) { - gig_dbg(DEBUG_HDLC, "7e (%d x) ================", - bcs->emptycount); - bcs->emptycount = 0; - } -#endif - inputstate |= INS_have_data; - if (skb) { - if (skb->len >= bcs->rx_bufsize) { - dev_warn(cs->dev, "received packet too long\n"); - dev_kfree_skb_any(skb); - /* skip remainder of packet */ - bcs->rx_skb = skb = NULL; - } else { - __skb_put_u8(skb, c); - fcs = crc_ccitt_byte(fcs, c); - } - } - } - - bcs->inputstate = inputstate; - bcs->rx_fcs = fcs; - return procbytes; -} - -/* process a block of received bytes in transparent data mode - * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 != L2_HDLC) - * Invert bytes, undoing byte stuffing and watching for DLE escapes. - * If DLE is encountered, return immediately to let the caller handle it. - * Return value: - * number of processed bytes - */ -static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) -{ - struct cardstate *cs = inbuf->cs; - struct bc_state *bcs = cs->bcs; - int inputstate = bcs->inputstate; - struct sk_buff *skb = bcs->rx_skb; - unsigned char *src = inbuf->data + inbuf->head; - unsigned procbytes = 0; - unsigned char c; - - if (!skb) { - /* skip this block */ - gigaset_new_rx_skb(bcs); - return numbytes; - } - - while (procbytes < numbytes && skb->len < bcs->rx_bufsize) { - c = *src++; - procbytes++; - - if (c == DLE_FLAG) { - if (inputstate & INS_DLE_char) { - /* quoted DLE: clear quote flag */ - inputstate &= ~INS_DLE_char; - } else if (cs->dle || (inputstate & INS_DLE_command)) { - /* DLE escape, pass up for handling */ - inputstate |= INS_DLE_char; - break; - } - } - - /* regular data byte: append to current skb */ - inputstate |= INS_have_data; - __skb_put_u8(skb, bitrev8(c)); - } - - /* pass data up */ - if (inputstate & INS_have_data) { - gigaset_skb_rcvd(bcs, skb); - inputstate &= ~INS_have_data; - gigaset_new_rx_skb(bcs); - } - - bcs->inputstate = inputstate; - return procbytes; -} - -/* process DLE escapes - * Called whenever a DLE sequence might be encountered in the input stream. - * Either processes the entire DLE sequence or, if that isn't possible, - * notes the fact that an initial DLE has been received in the INS_DLE_char - * inputstate flag and resumes processing of the sequence on the next call. - */ -static void handle_dle(struct inbuf_t *inbuf) -{ - struct cardstate *cs = inbuf->cs; - - if (cs->mstate == MS_LOCKED) - return; /* no DLE processing in lock mode */ - - if (!(inbuf->inputstate & INS_DLE_char)) { - /* no DLE pending */ - if (inbuf->data[inbuf->head] == DLE_FLAG && - (cs->dle || inbuf->inputstate & INS_DLE_command)) { - /* start of DLE sequence */ - inbuf->head++; - if (inbuf->head == inbuf->tail || - inbuf->head == RBUFSIZE) { - /* end of buffer, save for later processing */ - inbuf->inputstate |= INS_DLE_char; - return; - } - } else { - /* regular data byte */ - return; - } - } - - /* consume pending DLE */ - inbuf->inputstate &= ~INS_DLE_char; - - switch (inbuf->data[inbuf->head]) { - case 'X': /* begin of event message */ - if (inbuf->inputstate & INS_command) - dev_notice(cs->dev, - "received <DLE>X in command mode\n"); - inbuf->inputstate |= INS_command | INS_DLE_command; - inbuf->head++; /* byte consumed */ - break; - case '.': /* end of event message */ - if (!(inbuf->inputstate & INS_DLE_command)) - dev_notice(cs->dev, - "received <DLE>. without <DLE>X\n"); - inbuf->inputstate &= ~INS_DLE_command; - /* return to data mode if in DLE mode */ - if (cs->dle) - inbuf->inputstate &= ~INS_command; - inbuf->head++; /* byte consumed */ - break; - case DLE_FLAG: /* DLE in data stream */ - /* mark as quoted */ - inbuf->inputstate |= INS_DLE_char; - if (!(cs->dle || inbuf->inputstate & INS_DLE_command)) - dev_notice(cs->dev, - "received <DLE><DLE> not in DLE mode\n"); - break; /* quoted byte left in buffer */ - default: - dev_notice(cs->dev, "received <DLE><%02x>\n", - inbuf->data[inbuf->head]); - /* quoted byte left in buffer */ - } -} - -/** - * gigaset_m10x_input() - process a block of data received from the device - * @inbuf: received data and device descriptor structure. - * - * Called by hardware module {ser,usb}_gigaset with a block of received - * bytes. Separates the bytes received over the serial data channel into - * user data and command replies (locked/unlocked) according to the - * current state of the interface. - */ -void gigaset_m10x_input(struct inbuf_t *inbuf) -{ - struct cardstate *cs = inbuf->cs; - unsigned numbytes, procbytes; - - gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", inbuf->head, inbuf->tail); - - while (inbuf->head != inbuf->tail) { - /* check for DLE escape */ - handle_dle(inbuf); - - /* process a contiguous block of bytes */ - numbytes = (inbuf->head > inbuf->tail ? - RBUFSIZE : inbuf->tail) - inbuf->head; - gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes); - /* - * numbytes may be 0 if handle_dle() ate the last byte. - * This does no harm, *_loop() will just return 0 immediately. - */ - - if (cs->mstate == MS_LOCKED) - procbytes = lock_loop(numbytes, inbuf); - else if (inbuf->inputstate & INS_command) - procbytes = cmd_loop(numbytes, inbuf); - else if (cs->bcs->proto2 == L2_HDLC) - procbytes = hdlc_loop(numbytes, inbuf); - else - procbytes = iraw_loop(numbytes, inbuf); - inbuf->head += procbytes; - - /* check for buffer wraparound */ - if (inbuf->head >= RBUFSIZE) - inbuf->head = 0; - - gig_dbg(DEBUG_INTR, "head set to %u", inbuf->head); - } -} -EXPORT_SYMBOL_GPL(gigaset_m10x_input); - - -/* == data output ========================================================== */ - -/* - * Encode a data packet into an octet stuffed HDLC frame with FCS, - * opening and closing flags, preserving headroom data. - * parameters: - * skb skb containing original packet (freed upon return) - * Return value: - * pointer to newly allocated skb containing the result frame - * and the original link layer header, NULL on error - */ -static struct sk_buff *HDLC_Encode(struct sk_buff *skb) -{ - struct sk_buff *hdlc_skb; - __u16 fcs; - unsigned char c; - unsigned char *cp; - int len; - unsigned int stuf_cnt; - - stuf_cnt = 0; - fcs = PPP_INITFCS; - cp = skb->data; - len = skb->len; - while (len--) { - if (muststuff(*cp)) - stuf_cnt++; - fcs = crc_ccitt_byte(fcs, *cp++); - } - fcs ^= 0xffff; /* complement */ - - /* size of new buffer: original size + number of stuffing bytes - * + 2 bytes FCS + 2 stuffing bytes for FCS (if needed) + 2 flag bytes - * + room for link layer header - */ - hdlc_skb = dev_alloc_skb(skb->len + stuf_cnt + 6 + skb->mac_len); - if (!hdlc_skb) { - dev_kfree_skb_any(skb); - return NULL; - } - - /* Copy link layer header into new skb */ - skb_reset_mac_header(hdlc_skb); - skb_reserve(hdlc_skb, skb->mac_len); - memcpy(skb_mac_header(hdlc_skb), skb_mac_header(skb), skb->mac_len); - hdlc_skb->mac_len = skb->mac_len; - - /* Add flag sequence in front of everything.. */ - skb_put_u8(hdlc_skb, PPP_FLAG); - - /* Perform byte stuffing while copying data. */ - while (skb->len--) { - if (muststuff(*skb->data)) { - skb_put_u8(hdlc_skb, PPP_ESCAPE); - skb_put_u8(hdlc_skb, (*skb->data++) ^ PPP_TRANS); - } else - skb_put_u8(hdlc_skb, *skb->data++); - } - - /* Finally add FCS (byte stuffed) and flag sequence */ - c = (fcs & 0x00ff); /* least significant byte first */ - if (muststuff(c)) { - skb_put_u8(hdlc_skb, PPP_ESCAPE); - c ^= PPP_TRANS; - } - skb_put_u8(hdlc_skb, c); - - c = ((fcs >> 8) & 0x00ff); - if (muststuff(c)) { - skb_put_u8(hdlc_skb, PPP_ESCAPE); - c ^= PPP_TRANS; - } - skb_put_u8(hdlc_skb, c); - - skb_put_u8(hdlc_skb, PPP_FLAG); - - dev_kfree_skb_any(skb); - return hdlc_skb; -} - -/* - * Encode a data packet into an octet stuffed raw bit inverted frame, - * preserving headroom data. - * parameters: - * skb skb containing original packet (freed upon return) - * Return value: - * pointer to newly allocated skb containing the result frame - * and the original link layer header, NULL on error - */ -static struct sk_buff *iraw_encode(struct sk_buff *skb) -{ - struct sk_buff *iraw_skb; - unsigned char c; - unsigned char *cp; - int len; - - /* size of new buffer (worst case = every byte must be stuffed): - * 2 * original size + room for link layer header - */ - iraw_skb = dev_alloc_skb(2 * skb->len + skb->mac_len); - if (!iraw_skb) { - dev_kfree_skb_any(skb); - return NULL; - } - - /* copy link layer header into new skb */ - skb_reset_mac_header(iraw_skb); - skb_reserve(iraw_skb, skb->mac_len); - memcpy(skb_mac_header(iraw_skb), skb_mac_header(skb), skb->mac_len); - iraw_skb->mac_len = skb->mac_len; - - /* copy and stuff data */ - cp = skb->data; - len = skb->len; - while (len--) { - c = bitrev8(*cp++); - if (c == DLE_FLAG) - skb_put_u8(iraw_skb, c); - skb_put_u8(iraw_skb, c); - } - dev_kfree_skb_any(skb); - return iraw_skb; -} - -/** - * gigaset_m10x_send_skb() - queue an skb for sending - * @bcs: B channel descriptor structure. - * @skb: data to send. - * - * Called by LL to encode and queue an skb for sending, and start - * transmission if necessary. - * Once the payload data has been transmitted completely, gigaset_skb_sent() - * will be called with the skb's link layer header preserved. - * - * Return value: - * number of bytes accepted for sending (skb->len) if ok, - * error code < 0 (eg. -ENOMEM) on error - */ -int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb) -{ - struct cardstate *cs = bcs->cs; - unsigned len = skb->len; - unsigned long flags; - - if (bcs->proto2 == L2_HDLC) - skb = HDLC_Encode(skb); - else - skb = iraw_encode(skb); - if (!skb) { - dev_err(cs->dev, - "unable to allocate memory for encoding!\n"); - return -ENOMEM; - } - - skb_queue_tail(&bcs->squeue, skb); - spin_lock_irqsave(&cs->lock, flags); - if (cs->connected) - tasklet_schedule(&cs->write_tasklet); - spin_unlock_irqrestore(&cs->lock, flags); - - return len; /* ok so far */ -} -EXPORT_SYMBOL_GPL(gigaset_m10x_send_skb); diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c deleted file mode 100644 index c334525a5f63..000000000000 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ /dev/null @@ -1,2672 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * USB driver for Gigaset 307x base via direct USB connection. - * - * Copyright (c) 2001 by Hansjoerg Lipp <hjlipp@web.de>, - * Tilman Schmidt <tilman@imap.cc>, - * Stefan Eilers. - * - * ===================================================================== - * ===================================================================== - */ - -#include "gigaset.h" -#include <linux/usb.h> -#include <linux/module.h> -#include <linux/moduleparam.h> - -/* Version Information */ -#define DRIVER_AUTHOR "Tilman Schmidt <tilman@imap.cc>, Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers" -#define DRIVER_DESC "USB Driver for Gigaset 307x" - - -/* Module parameters */ - -static int startmode = SM_ISDN; -static int cidmode = 1; - -module_param(startmode, int, S_IRUGO); -module_param(cidmode, int, S_IRUGO); -MODULE_PARM_DESC(startmode, "start in isdn4linux mode"); -MODULE_PARM_DESC(cidmode, "Call-ID mode"); - -#define GIGASET_MINORS 1 -#define GIGASET_MINOR 16 -#define GIGASET_MODULENAME "bas_gigaset" -#define GIGASET_DEVNAME "ttyGB" - -/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */ -#define IF_WRITEBUF 264 - -/* interrupt pipe message size according to ibid. ch. 2.2 */ -#define IP_MSGSIZE 3 - -/* Values for the Gigaset 307x */ -#define USB_GIGA_VENDOR_ID 0x0681 -#define USB_3070_PRODUCT_ID 0x0001 -#define USB_3075_PRODUCT_ID 0x0002 -#define USB_SX303_PRODUCT_ID 0x0021 -#define USB_SX353_PRODUCT_ID 0x0022 - -/* table of devices that work with this driver */ -static const struct usb_device_id gigaset_table[] = { - { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3070_PRODUCT_ID) }, - { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_3075_PRODUCT_ID) }, - { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX303_PRODUCT_ID) }, - { USB_DEVICE(USB_GIGA_VENDOR_ID, USB_SX353_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, gigaset_table); - -/*======================= local function prototypes ==========================*/ - -/* function called if a new device belonging to this driver is connected */ -static int gigaset_probe(struct usb_interface *interface, - const struct usb_device_id *id); - -/* Function will be called if the device is unplugged */ -static void gigaset_disconnect(struct usb_interface *interface); - -/* functions called before/after suspend */ -static int gigaset_suspend(struct usb_interface *intf, pm_message_t message); -static int gigaset_resume(struct usb_interface *intf); - -/* functions called before/after device reset */ -static int gigaset_pre_reset(struct usb_interface *intf); -static int gigaset_post_reset(struct usb_interface *intf); - -static int atread_submit(struct cardstate *, int); -static void stopurbs(struct bas_bc_state *); -static int req_submit(struct bc_state *, int, int, int); -static int atwrite_submit(struct cardstate *, unsigned char *, int); -static int start_cbsend(struct cardstate *); - -/*============================================================================*/ - -struct bas_cardstate { - struct usb_device *udev; /* USB device pointer */ - struct cardstate *cs; - struct usb_interface *interface; /* interface for this device */ - unsigned char minor; /* starting minor number */ - - struct urb *urb_ctrl; /* control pipe default URB */ - struct usb_ctrlrequest dr_ctrl; - struct timer_list timer_ctrl; /* control request timeout */ - int retry_ctrl; - - struct timer_list timer_atrdy; /* AT command ready timeout */ - struct urb *urb_cmd_out; /* for sending AT commands */ - struct usb_ctrlrequest dr_cmd_out; - int retry_cmd_out; - - struct urb *urb_cmd_in; /* for receiving AT replies */ - struct usb_ctrlrequest dr_cmd_in; - struct timer_list timer_cmd_in; /* receive request timeout */ - unsigned char *rcvbuf; /* AT reply receive buffer */ - - struct urb *urb_int_in; /* URB for interrupt pipe */ - unsigned char *int_in_buf; - struct work_struct int_in_wq; /* for usb_clear_halt() */ - struct timer_list timer_int_in; /* int read retry delay */ - int retry_int_in; - - spinlock_t lock; /* locks all following */ - int basstate; /* bitmap (BS_*) */ - int pending; /* uncompleted base request */ - wait_queue_head_t waitqueue; - int rcvbuf_size; /* size of AT receive buffer */ - /* 0: no receive in progress */ - int retry_cmd_in; /* receive req retry count */ -}; - -/* status of direct USB connection to 307x base (bits in basstate) */ -#define BS_ATOPEN 0x001 /* AT channel open */ -#define BS_B1OPEN 0x002 /* B channel 1 open */ -#define BS_B2OPEN 0x004 /* B channel 2 open */ -#define BS_ATREADY 0x008 /* base ready for AT command */ -#define BS_INIT 0x010 /* base has signalled INIT_OK */ -#define BS_ATTIMER 0x020 /* waiting for HD_READY_SEND_ATDATA */ -#define BS_ATRDPEND 0x040 /* urb_cmd_in in use */ -#define BS_ATWRPEND 0x080 /* urb_cmd_out in use */ -#define BS_SUSPEND 0x100 /* USB port suspended */ -#define BS_RESETTING 0x200 /* waiting for HD_RESET_INTERRUPT_PIPE_ACK */ - - -static struct gigaset_driver *driver; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver gigaset_usb_driver = { - .name = GIGASET_MODULENAME, - .probe = gigaset_probe, - .disconnect = gigaset_disconnect, - .id_table = gigaset_table, - .suspend = gigaset_suspend, - .resume = gigaset_resume, - .reset_resume = gigaset_post_reset, - .pre_reset = gigaset_pre_reset, - .post_reset = gigaset_post_reset, - .disable_hub_initiated_lpm = 1, -}; - -/* get message text for usb_submit_urb return code - */ -static char *get_usb_rcmsg(int rc) -{ - static char unkmsg[28]; - - switch (rc) { - case 0: - return "success"; - case -ENOMEM: - return "out of memory"; - case -ENODEV: - return "device not present"; - case -ENOENT: - return "endpoint not present"; - case -ENXIO: - return "URB type not supported"; - case -EINVAL: - return "invalid argument"; - case -EAGAIN: - return "start frame too early or too much scheduled"; - case -EFBIG: - return "too many isoc frames requested"; - case -EPIPE: - return "endpoint stalled"; - case -EMSGSIZE: - return "invalid packet size"; - case -ENOSPC: - return "would overcommit USB bandwidth"; - case -ESHUTDOWN: - return "device shut down"; - case -EPERM: - return "reject flag set"; - case -EHOSTUNREACH: - return "device suspended"; - default: - snprintf(unkmsg, sizeof(unkmsg), "unknown error %d", rc); - return unkmsg; - } -} - -/* get message text for USB status code - */ -static char *get_usb_statmsg(int status) -{ - static char unkmsg[28]; - - switch (status) { - case 0: - return "success"; - case -ENOENT: - return "unlinked (sync)"; - case -EINPROGRESS: - return "URB still pending"; - case -EPROTO: - return "bitstuff error, timeout, or unknown USB error"; - case -EILSEQ: - return "CRC mismatch, timeout, or unknown USB error"; - case -ETIME: - return "USB response timeout"; - case -EPIPE: - return "endpoint stalled"; - case -ECOMM: - return "IN buffer overrun"; - case -ENOSR: - return "OUT buffer underrun"; - case -EOVERFLOW: - return "endpoint babble"; - case -EREMOTEIO: - return "short packet"; - case -ENODEV: - return "device removed"; - case -EXDEV: - return "partial isoc transfer"; - case -EINVAL: - return "ISO madness"; - case -ECONNRESET: - return "unlinked (async)"; - case -ESHUTDOWN: - return "device shut down"; - default: - snprintf(unkmsg, sizeof(unkmsg), "unknown status %d", status); - return unkmsg; - } -} - -/* usb_pipetype_str - * retrieve string representation of USB pipe type - */ -static inline char *usb_pipetype_str(int pipe) -{ - if (usb_pipeisoc(pipe)) - return "Isoc"; - if (usb_pipeint(pipe)) - return "Int"; - if (usb_pipecontrol(pipe)) - return "Ctrl"; - if (usb_pipebulk(pipe)) - return "Bulk"; - return "?"; -} - -/* dump_urb - * write content of URB to syslog for debugging - */ -static inline void dump_urb(enum debuglevel level, const char *tag, - struct urb *urb) -{ -#ifdef CONFIG_GIGASET_DEBUG - int i; - gig_dbg(level, "%s urb(0x%08lx)->{", tag, (unsigned long) urb); - if (urb) { - gig_dbg(level, - " dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, " - "hcpriv=0x%08lx, transfer_flags=0x%x,", - (unsigned long) urb->dev, - usb_pipetype_str(urb->pipe), - usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe), - usb_pipein(urb->pipe) ? "in" : "out", - (unsigned long) urb->hcpriv, - urb->transfer_flags); - gig_dbg(level, - " transfer_buffer=0x%08lx[%d], actual_length=%d, " - "setup_packet=0x%08lx,", - (unsigned long) urb->transfer_buffer, - urb->transfer_buffer_length, urb->actual_length, - (unsigned long) urb->setup_packet); - gig_dbg(level, - " start_frame=%d, number_of_packets=%d, interval=%d, " - "error_count=%d,", - urb->start_frame, urb->number_of_packets, urb->interval, - urb->error_count); - gig_dbg(level, - " context=0x%08lx, complete=0x%08lx, " - "iso_frame_desc[]={", - (unsigned long) urb->context, - (unsigned long) urb->complete); - for (i = 0; i < urb->number_of_packets; i++) { - struct usb_iso_packet_descriptor *pifd - = &urb->iso_frame_desc[i]; - gig_dbg(level, - " {offset=%u, length=%u, actual_length=%u, " - "status=%u}", - pifd->offset, pifd->length, pifd->actual_length, - pifd->status); - } - } - gig_dbg(level, "}}"); -#endif -} - -/* read/set modem control bits etc. (m10x only) */ -static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, - unsigned new_state) -{ - return -EINVAL; -} - -static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) -{ - return -EINVAL; -} - -static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) -{ - return -EINVAL; -} - -/* set/clear bits in base connection state, return previous state - */ -static inline int update_basstate(struct bas_cardstate *ucs, - int set, int clear) -{ - unsigned long flags; - int state; - - spin_lock_irqsave(&ucs->lock, flags); - state = ucs->basstate; - ucs->basstate = (state & ~clear) | set; - spin_unlock_irqrestore(&ucs->lock, flags); - return state; -} - -/* error_hangup - * hang up any existing connection because of an unrecoverable error - * This function may be called from any context and takes care of scheduling - * the necessary actions for execution outside of interrupt context. - * cs->lock must not be held. - * argument: - * B channel control structure - */ -static inline void error_hangup(struct bc_state *bcs) -{ - struct cardstate *cs = bcs->cs; - - gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL); - gigaset_schedule_event(cs); -} - -/* error_reset - * reset Gigaset device because of an unrecoverable error - * This function may be called from any context, and takes care of - * scheduling the necessary actions for execution outside of interrupt context. - * cs->hw.bas->lock must not be held. - * argument: - * controller state structure - */ -static inline void error_reset(struct cardstate *cs) -{ - /* reset interrupt pipe to recover (ignore errors) */ - update_basstate(cs->hw.bas, BS_RESETTING, 0); - if (req_submit(cs->bcs, HD_RESET_INTERRUPT_PIPE, 0, BAS_TIMEOUT)) - /* submission failed, escalate to USB port reset */ - usb_queue_reset_device(cs->hw.bas->interface); -} - -/* check_pending - * check for completion of pending control request - * parameter: - * ucs hardware specific controller state structure - */ -static void check_pending(struct bas_cardstate *ucs) -{ - unsigned long flags; - - spin_lock_irqsave(&ucs->lock, flags); - switch (ucs->pending) { - case 0: - break; - case HD_OPEN_ATCHANNEL: - if (ucs->basstate & BS_ATOPEN) - ucs->pending = 0; - break; - case HD_OPEN_B1CHANNEL: - if (ucs->basstate & BS_B1OPEN) - ucs->pending = 0; - break; - case HD_OPEN_B2CHANNEL: - if (ucs->basstate & BS_B2OPEN) - ucs->pending = 0; - break; - case HD_CLOSE_ATCHANNEL: - if (!(ucs->basstate & BS_ATOPEN)) - ucs->pending = 0; - break; - case HD_CLOSE_B1CHANNEL: - if (!(ucs->basstate & BS_B1OPEN)) - ucs->pending = 0; - break; - case HD_CLOSE_B2CHANNEL: - if (!(ucs->basstate & BS_B2OPEN)) - ucs->pending = 0; - break; - case HD_DEVICE_INIT_ACK: /* no reply expected */ - ucs->pending = 0; - break; - case HD_RESET_INTERRUPT_PIPE: - if (!(ucs->basstate & BS_RESETTING)) - ucs->pending = 0; - break; - /* - * HD_READ_ATMESSAGE and HD_WRITE_ATMESSAGE are handled separately - * and should never end up here - */ - default: - dev_warn(&ucs->interface->dev, - "unknown pending request 0x%02x cleared\n", - ucs->pending); - ucs->pending = 0; - } - - if (!ucs->pending) - del_timer(&ucs->timer_ctrl); - - spin_unlock_irqrestore(&ucs->lock, flags); -} - -/* cmd_in_timeout - * timeout routine for command input request - * argument: - * controller state structure - */ -static void cmd_in_timeout(struct timer_list *t) -{ - struct bas_cardstate *ucs = from_timer(ucs, t, timer_cmd_in); - struct cardstate *cs = ucs->cs; - int rc; - - if (!ucs->rcvbuf_size) { - gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__); - return; - } - - if (ucs->retry_cmd_in++ >= BAS_RETRY) { - dev_err(cs->dev, - "control read: timeout, giving up after %d tries\n", - ucs->retry_cmd_in); - kfree(ucs->rcvbuf); - ucs->rcvbuf = NULL; - ucs->rcvbuf_size = 0; - error_reset(cs); - return; - } - - gig_dbg(DEBUG_USBREQ, "%s: timeout, retry %d", - __func__, ucs->retry_cmd_in); - rc = atread_submit(cs, BAS_TIMEOUT); - if (rc < 0) { - kfree(ucs->rcvbuf); - ucs->rcvbuf = NULL; - ucs->rcvbuf_size = 0; - if (rc != -ENODEV) - error_reset(cs); - } -} - -/* read_ctrl_callback - * USB completion handler for control pipe input - * called by the USB subsystem in interrupt context - * parameter: - * urb USB request block - * urb->context = inbuf structure for controller state - */ -static void read_ctrl_callback(struct urb *urb) -{ - struct inbuf_t *inbuf = urb->context; - struct cardstate *cs = inbuf->cs; - struct bas_cardstate *ucs = cs->hw.bas; - int status = urb->status; - unsigned numbytes; - int rc; - - update_basstate(ucs, 0, BS_ATRDPEND); - wake_up(&ucs->waitqueue); - del_timer(&ucs->timer_cmd_in); - - switch (status) { - case 0: /* normal completion */ - numbytes = urb->actual_length; - if (unlikely(numbytes != ucs->rcvbuf_size)) { - dev_warn(cs->dev, - "control read: received %d chars, expected %d\n", - numbytes, ucs->rcvbuf_size); - if (numbytes > ucs->rcvbuf_size) - numbytes = ucs->rcvbuf_size; - } - - /* copy received bytes to inbuf, notify event layer */ - if (gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes)) { - gig_dbg(DEBUG_INTR, "%s-->BH", __func__); - gigaset_schedule_event(cs); - } - break; - - case -ENOENT: /* cancelled */ - case -ECONNRESET: /* cancelled (async) */ - case -EINPROGRESS: /* pending */ - case -ENODEV: /* device removed */ - case -ESHUTDOWN: /* device shut down */ - /* no further action necessary */ - gig_dbg(DEBUG_USBREQ, "%s: %s", - __func__, get_usb_statmsg(status)); - break; - - default: /* other errors: retry */ - if (ucs->retry_cmd_in++ < BAS_RETRY) { - gig_dbg(DEBUG_USBREQ, "%s: %s, retry %d", __func__, - get_usb_statmsg(status), ucs->retry_cmd_in); - rc = atread_submit(cs, BAS_TIMEOUT); - if (rc >= 0) - /* successfully resubmitted, skip freeing */ - return; - if (rc == -ENODEV) - /* disconnect, no further action necessary */ - break; - } - dev_err(cs->dev, "control read: %s, giving up after %d tries\n", - get_usb_statmsg(status), ucs->retry_cmd_in); - error_reset(cs); - } - - /* read finished, free buffer */ - kfree(ucs->rcvbuf); - ucs->rcvbuf = NULL; - ucs->rcvbuf_size = 0; -} - -/* atread_submit - * submit an HD_READ_ATMESSAGE command URB and optionally start a timeout - * parameters: - * cs controller state structure - * timeout timeout in 1/10 sec., 0: none - * return value: - * 0 on success - * -EBUSY if another request is pending - * any URB submission error code - */ -static int atread_submit(struct cardstate *cs, int timeout) -{ - struct bas_cardstate *ucs = cs->hw.bas; - int basstate; - int ret; - - gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", - ucs->rcvbuf_size); - - basstate = update_basstate(ucs, BS_ATRDPEND, 0); - if (basstate & BS_ATRDPEND) { - dev_err(cs->dev, - "could not submit HD_READ_ATMESSAGE: URB busy\n"); - return -EBUSY; - } - - if (basstate & BS_SUSPEND) { - dev_notice(cs->dev, - "HD_READ_ATMESSAGE not submitted, " - "suspend in progress\n"); - update_basstate(ucs, 0, BS_ATRDPEND); - /* treat like disconnect */ - return -ENODEV; - } - - ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ; - ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE; - ucs->dr_cmd_in.wValue = 0; - ucs->dr_cmd_in.wIndex = 0; - ucs->dr_cmd_in.wLength = cpu_to_le16(ucs->rcvbuf_size); - usb_fill_control_urb(ucs->urb_cmd_in, ucs->udev, - usb_rcvctrlpipe(ucs->udev, 0), - (unsigned char *) &ucs->dr_cmd_in, - ucs->rcvbuf, ucs->rcvbuf_size, - read_ctrl_callback, cs->inbuf); - - ret = usb_submit_urb(ucs->urb_cmd_in, GFP_ATOMIC); - if (ret != 0) { - update_basstate(ucs, 0, BS_ATRDPEND); - dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n", - get_usb_rcmsg(ret)); - return ret; - } - - if (timeout > 0) { - gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); - mod_timer(&ucs->timer_cmd_in, jiffies + timeout * HZ / 10); - } - return 0; -} - -/* int_in_work - * workqueue routine to clear halt on interrupt in endpoint - */ - -static void int_in_work(struct work_struct *work) -{ - struct bas_cardstate *ucs = - container_of(work, struct bas_cardstate, int_in_wq); - struct urb *urb = ucs->urb_int_in; - struct cardstate *cs = urb->context; - int rc; - - /* clear halt condition */ - rc = usb_clear_halt(ucs->udev, urb->pipe); - gig_dbg(DEBUG_USBREQ, "clear_halt: %s", get_usb_rcmsg(rc)); - if (rc == 0) - /* success, resubmit interrupt read URB */ - rc = usb_submit_urb(urb, GFP_ATOMIC); - - switch (rc) { - case 0: /* success */ - case -ENODEV: /* device gone */ - case -EINVAL: /* URB already resubmitted, or terminal badness */ - break; - default: /* failure: try to recover by resetting the device */ - dev_err(cs->dev, "clear halt failed: %s\n", get_usb_rcmsg(rc)); - rc = usb_lock_device_for_reset(ucs->udev, ucs->interface); - if (rc == 0) { - rc = usb_reset_device(ucs->udev); - usb_unlock_device(ucs->udev); - } - } - ucs->retry_int_in = 0; -} - -/* int_in_resubmit - * timer routine for interrupt read delayed resubmit - * argument: - * controller state structure - */ -static void int_in_resubmit(struct timer_list *t) -{ - struct bas_cardstate *ucs = from_timer(ucs, t, timer_int_in); - struct cardstate *cs = ucs->cs; - int rc; - - if (ucs->retry_int_in++ >= BAS_RETRY) { - dev_err(cs->dev, "interrupt read: giving up after %d tries\n", - ucs->retry_int_in); - usb_queue_reset_device(ucs->interface); - return; - } - - gig_dbg(DEBUG_USBREQ, "%s: retry %d", __func__, ucs->retry_int_in); - rc = usb_submit_urb(ucs->urb_int_in, GFP_ATOMIC); - if (rc != 0 && rc != -ENODEV) { - dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", - get_usb_rcmsg(rc)); - usb_queue_reset_device(ucs->interface); - } -} - -/* read_int_callback - * USB completion handler for interrupt pipe input - * called by the USB subsystem in interrupt context - * parameter: - * urb USB request block - * urb->context = controller state structure - */ -static void read_int_callback(struct urb *urb) -{ - struct cardstate *cs = urb->context; - struct bas_cardstate *ucs = cs->hw.bas; - struct bc_state *bcs; - int status = urb->status; - unsigned long flags; - int rc; - unsigned l; - int channel; - - switch (status) { - case 0: /* success */ - ucs->retry_int_in = 0; - break; - case -EPIPE: /* endpoint stalled */ - schedule_work(&ucs->int_in_wq); - /* fall through */ - case -ENOENT: /* cancelled */ - case -ECONNRESET: /* cancelled (async) */ - case -EINPROGRESS: /* pending */ - case -ENODEV: /* device removed */ - case -ESHUTDOWN: /* device shut down */ - /* no further action necessary */ - gig_dbg(DEBUG_USBREQ, "%s: %s", - __func__, get_usb_statmsg(status)); - return; - case -EPROTO: /* protocol error or unplug */ - case -EILSEQ: - case -ETIME: - /* resubmit after delay */ - gig_dbg(DEBUG_USBREQ, "%s: %s", - __func__, get_usb_statmsg(status)); - mod_timer(&ucs->timer_int_in, jiffies + HZ / 10); - return; - default: /* other errors: just resubmit */ - dev_warn(cs->dev, "interrupt read: %s\n", - get_usb_statmsg(status)); - goto resubmit; - } - - /* drop incomplete packets even if the missing bytes wouldn't matter */ - if (unlikely(urb->actual_length < IP_MSGSIZE)) { - dev_warn(cs->dev, "incomplete interrupt packet (%d bytes)\n", - urb->actual_length); - goto resubmit; - } - - l = (unsigned) ucs->int_in_buf[1] + - (((unsigned) ucs->int_in_buf[2]) << 8); - - gig_dbg(DEBUG_USBREQ, "<-------%d: 0x%02x (%u [0x%02x 0x%02x])", - urb->actual_length, (int)ucs->int_in_buf[0], l, - (int)ucs->int_in_buf[1], (int)ucs->int_in_buf[2]); - - channel = 0; - - switch (ucs->int_in_buf[0]) { - case HD_DEVICE_INIT_OK: - update_basstate(ucs, BS_INIT, 0); - break; - - case HD_READY_SEND_ATDATA: - del_timer(&ucs->timer_atrdy); - update_basstate(ucs, BS_ATREADY, BS_ATTIMER); - start_cbsend(cs); - break; - - case HD_OPEN_B2CHANNEL_ACK: - ++channel; - /* fall through */ - case HD_OPEN_B1CHANNEL_ACK: - bcs = cs->bcs + channel; - update_basstate(ucs, BS_B1OPEN << channel, 0); - gigaset_bchannel_up(bcs); - break; - - case HD_OPEN_ATCHANNEL_ACK: - update_basstate(ucs, BS_ATOPEN, 0); - start_cbsend(cs); - break; - - case HD_CLOSE_B2CHANNEL_ACK: - ++channel; - /* fall through */ - case HD_CLOSE_B1CHANNEL_ACK: - bcs = cs->bcs + channel; - update_basstate(ucs, 0, BS_B1OPEN << channel); - stopurbs(bcs->hw.bas); - gigaset_bchannel_down(bcs); - break; - - case HD_CLOSE_ATCHANNEL_ACK: - update_basstate(ucs, 0, BS_ATOPEN); - break; - - case HD_B2_FLOW_CONTROL: - ++channel; - /* fall through */ - case HD_B1_FLOW_CONTROL: - bcs = cs->bcs + channel; - atomic_add((l - BAS_NORMFRAME) * BAS_CORRFRAMES, - &bcs->hw.bas->corrbytes); - gig_dbg(DEBUG_ISO, - "Flow control (channel %d, sub %d): 0x%02x => %d", - channel, bcs->hw.bas->numsub, l, - atomic_read(&bcs->hw.bas->corrbytes)); - break; - - case HD_RECEIVEATDATA_ACK: /* AT response ready to be received */ - if (!l) { - dev_warn(cs->dev, - "HD_RECEIVEATDATA_ACK with length 0 ignored\n"); - break; - } - spin_lock_irqsave(&cs->lock, flags); - if (ucs->basstate & BS_ATRDPEND) { - spin_unlock_irqrestore(&cs->lock, flags); - dev_warn(cs->dev, - "HD_RECEIVEATDATA_ACK(%d) during HD_READ_ATMESSAGE(%d) ignored\n", - l, ucs->rcvbuf_size); - break; - } - if (ucs->rcvbuf_size) { - /* throw away previous buffer - we have no queue */ - dev_err(cs->dev, - "receive AT data overrun, %d bytes lost\n", - ucs->rcvbuf_size); - kfree(ucs->rcvbuf); - ucs->rcvbuf_size = 0; - } - ucs->rcvbuf = kmalloc(l, GFP_ATOMIC); - if (ucs->rcvbuf == NULL) { - spin_unlock_irqrestore(&cs->lock, flags); - dev_err(cs->dev, "out of memory receiving AT data\n"); - break; - } - ucs->rcvbuf_size = l; - ucs->retry_cmd_in = 0; - rc = atread_submit(cs, BAS_TIMEOUT); - if (rc < 0) { - kfree(ucs->rcvbuf); - ucs->rcvbuf = NULL; - ucs->rcvbuf_size = 0; - } - spin_unlock_irqrestore(&cs->lock, flags); - if (rc < 0 && rc != -ENODEV) - error_reset(cs); - break; - - case HD_RESET_INTERRUPT_PIPE_ACK: - update_basstate(ucs, 0, BS_RESETTING); - dev_notice(cs->dev, "interrupt pipe reset\n"); - break; - - case HD_SUSPEND_END: - gig_dbg(DEBUG_USBREQ, "HD_SUSPEND_END"); - break; - - default: - dev_warn(cs->dev, - "unknown Gigaset signal 0x%02x (%u) ignored\n", - (int) ucs->int_in_buf[0], l); - } - - check_pending(ucs); - wake_up(&ucs->waitqueue); - -resubmit: - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(rc != 0 && rc != -ENODEV)) { - dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", - get_usb_rcmsg(rc)); - error_reset(cs); - } -} - -/* read_iso_callback - * USB completion handler for B channel isochronous input - * called by the USB subsystem in interrupt context - * parameter: - * urb USB request block of completed request - * urb->context = bc_state structure - */ -static void read_iso_callback(struct urb *urb) -{ - struct bc_state *bcs; - struct bas_bc_state *ubc; - int status = urb->status; - unsigned long flags; - int i, rc; - - /* status codes not worth bothering the tasklet with */ - if (unlikely(status == -ENOENT || - status == -ECONNRESET || - status == -EINPROGRESS || - status == -ENODEV || - status == -ESHUTDOWN)) { - gig_dbg(DEBUG_ISO, "%s: %s", - __func__, get_usb_statmsg(status)); - return; - } - - bcs = urb->context; - ubc = bcs->hw.bas; - - spin_lock_irqsave(&ubc->isoinlock, flags); - if (likely(ubc->isoindone == NULL)) { - /* pass URB to tasklet */ - ubc->isoindone = urb; - ubc->isoinstatus = status; - tasklet_hi_schedule(&ubc->rcvd_tasklet); - } else { - /* tasklet still busy, drop data and resubmit URB */ - gig_dbg(DEBUG_ISO, "%s: overrun", __func__); - ubc->loststatus = status; - for (i = 0; i < BAS_NUMFRAMES; i++) { - ubc->isoinlost += urb->iso_frame_desc[i].actual_length; - if (unlikely(urb->iso_frame_desc[i].status != 0 && - urb->iso_frame_desc[i].status != -EINPROGRESS)) - ubc->loststatus = urb->iso_frame_desc[i].status; - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - if (likely(ubc->running)) { - /* urb->dev is clobbered by USB subsystem */ - urb->dev = bcs->cs->hw.bas->udev; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = BAS_NUMFRAMES; - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(rc != 0 && rc != -ENODEV)) { - dev_err(bcs->cs->dev, - "could not resubmit isoc read URB: %s\n", - get_usb_rcmsg(rc)); - dump_urb(DEBUG_ISO, "isoc read", urb); - error_hangup(bcs); - } - } - } - spin_unlock_irqrestore(&ubc->isoinlock, flags); -} - -/* write_iso_callback - * USB completion handler for B channel isochronous output - * called by the USB subsystem in interrupt context - * parameter: - * urb USB request block of completed request - * urb->context = isow_urbctx_t structure - */ -static void write_iso_callback(struct urb *urb) -{ - struct isow_urbctx_t *ucx; - struct bas_bc_state *ubc; - int status = urb->status; - unsigned long flags; - - /* status codes not worth bothering the tasklet with */ - if (unlikely(status == -ENOENT || - status == -ECONNRESET || - status == -EINPROGRESS || - status == -ENODEV || - status == -ESHUTDOWN)) { - gig_dbg(DEBUG_ISO, "%s: %s", - __func__, get_usb_statmsg(status)); - return; - } - - /* pass URB context to tasklet */ - ucx = urb->context; - ubc = ucx->bcs->hw.bas; - ucx->status = status; - - spin_lock_irqsave(&ubc->isooutlock, flags); - ubc->isooutovfl = ubc->isooutdone; - ubc->isooutdone = ucx; - spin_unlock_irqrestore(&ubc->isooutlock, flags); - tasklet_hi_schedule(&ubc->sent_tasklet); -} - -/* starturbs - * prepare and submit USB request blocks for isochronous input and output - * argument: - * B channel control structure - * return value: - * 0 on success - * < 0 on error (no URBs submitted) - */ -static int starturbs(struct bc_state *bcs) -{ - struct usb_device *udev = bcs->cs->hw.bas->udev; - struct bas_bc_state *ubc = bcs->hw.bas; - struct urb *urb; - int j, k; - int rc; - - /* initialize L2 reception */ - if (bcs->proto2 == L2_HDLC) - bcs->inputstate |= INS_flag_hunt; - - /* submit all isochronous input URBs */ - ubc->running = 1; - for (k = 0; k < BAS_INURBS; k++) { - urb = ubc->isoinurbs[k]; - if (!urb) { - rc = -EFAULT; - goto error; - } - usb_fill_int_urb(urb, udev, - usb_rcvisocpipe(udev, 3 + 2 * bcs->channel), - ubc->isoinbuf + k * BAS_INBUFSIZE, - BAS_INBUFSIZE, read_iso_callback, bcs, - BAS_FRAMETIME); - - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = BAS_NUMFRAMES; - for (j = 0; j < BAS_NUMFRAMES; j++) { - urb->iso_frame_desc[j].offset = j * BAS_MAXFRAME; - urb->iso_frame_desc[j].length = BAS_MAXFRAME; - urb->iso_frame_desc[j].status = 0; - urb->iso_frame_desc[j].actual_length = 0; - } - - dump_urb(DEBUG_ISO, "Initial isoc read", urb); - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (rc != 0) - goto error; - } - - /* initialize L2 transmission */ - gigaset_isowbuf_init(ubc->isooutbuf, PPP_FLAG); - - /* set up isochronous output URBs for flag idling */ - for (k = 0; k < BAS_OUTURBS; ++k) { - urb = ubc->isoouturbs[k].urb; - if (!urb) { - rc = -EFAULT; - goto error; - } - usb_fill_int_urb(urb, udev, - usb_sndisocpipe(udev, 4 + 2 * bcs->channel), - ubc->isooutbuf->data, - sizeof(ubc->isooutbuf->data), - write_iso_callback, &ubc->isoouturbs[k], - BAS_FRAMETIME); - - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = BAS_NUMFRAMES; - for (j = 0; j < BAS_NUMFRAMES; ++j) { - urb->iso_frame_desc[j].offset = BAS_OUTBUFSIZE; - urb->iso_frame_desc[j].length = BAS_NORMFRAME; - urb->iso_frame_desc[j].status = 0; - urb->iso_frame_desc[j].actual_length = 0; - } - ubc->isoouturbs[k].limit = -1; - } - - /* keep one URB free, submit the others */ - for (k = 0; k < BAS_OUTURBS - 1; ++k) { - dump_urb(DEBUG_ISO, "Initial isoc write", urb); - rc = usb_submit_urb(ubc->isoouturbs[k].urb, GFP_ATOMIC); - if (rc != 0) - goto error; - } - dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb); - ubc->isooutfree = &ubc->isoouturbs[BAS_OUTURBS - 1]; - ubc->isooutdone = ubc->isooutovfl = NULL; - return 0; -error: - stopurbs(ubc); - return rc; -} - -/* stopurbs - * cancel the USB request blocks for isochronous input and output - * errors are silently ignored - * argument: - * B channel control structure - */ -static void stopurbs(struct bas_bc_state *ubc) -{ - int k, rc; - - ubc->running = 0; - - for (k = 0; k < BAS_INURBS; ++k) { - rc = usb_unlink_urb(ubc->isoinurbs[k]); - gig_dbg(DEBUG_ISO, - "%s: isoc input URB %d unlinked, result = %s", - __func__, k, get_usb_rcmsg(rc)); - } - - for (k = 0; k < BAS_OUTURBS; ++k) { - rc = usb_unlink_urb(ubc->isoouturbs[k].urb); - gig_dbg(DEBUG_ISO, - "%s: isoc output URB %d unlinked, result = %s", - __func__, k, get_usb_rcmsg(rc)); - } -} - -/* Isochronous Write - Bottom Half */ -/* =============================== */ - -/* submit_iso_write_urb - * fill and submit the next isochronous write URB - * parameters: - * ucx context structure containing URB - * return value: - * number of frames submitted in URB - * 0 if URB not submitted because no data available (isooutbuf busy) - * error code < 0 on error - */ -static int submit_iso_write_urb(struct isow_urbctx_t *ucx) -{ - struct urb *urb = ucx->urb; - struct bas_bc_state *ubc = ucx->bcs->hw.bas; - struct usb_iso_packet_descriptor *ifd; - int corrbytes, nframe, rc; - - /* urb->dev is clobbered by USB subsystem */ - urb->dev = ucx->bcs->cs->hw.bas->udev; - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = ubc->isooutbuf->data; - urb->transfer_buffer_length = sizeof(ubc->isooutbuf->data); - - for (nframe = 0; nframe < BAS_NUMFRAMES; nframe++) { - ifd = &urb->iso_frame_desc[nframe]; - - /* compute frame length according to flow control */ - ifd->length = BAS_NORMFRAME; - corrbytes = atomic_read(&ubc->corrbytes); - if (corrbytes != 0) { - gig_dbg(DEBUG_ISO, "%s: corrbytes=%d", - __func__, corrbytes); - if (corrbytes > BAS_HIGHFRAME - BAS_NORMFRAME) - corrbytes = BAS_HIGHFRAME - BAS_NORMFRAME; - else if (corrbytes < BAS_LOWFRAME - BAS_NORMFRAME) - corrbytes = BAS_LOWFRAME - BAS_NORMFRAME; - ifd->length += corrbytes; - atomic_add(-corrbytes, &ubc->corrbytes); - } - - /* retrieve block of data to send */ - rc = gigaset_isowbuf_getbytes(ubc->isooutbuf, ifd->length); - if (rc < 0) { - if (rc == -EBUSY) { - gig_dbg(DEBUG_ISO, - "%s: buffer busy at frame %d", - __func__, nframe); - /* tasklet will be restarted from - gigaset_isoc_send_skb() */ - } else { - dev_err(ucx->bcs->cs->dev, - "%s: buffer error %d at frame %d\n", - __func__, rc, nframe); - return rc; - } - break; - } - ifd->offset = rc; - ucx->limit = ubc->isooutbuf->nextread; - ifd->status = 0; - ifd->actual_length = 0; - } - if (unlikely(nframe == 0)) - return 0; /* no data to send */ - urb->number_of_packets = nframe; - - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(rc)) { - if (rc == -ENODEV) - /* device removed - give up silently */ - gig_dbg(DEBUG_ISO, "%s: disconnected", __func__); - else - dev_err(ucx->bcs->cs->dev, - "could not submit isoc write URB: %s\n", - get_usb_rcmsg(rc)); - return rc; - } - ++ubc->numsub; - return nframe; -} - -/* write_iso_tasklet - * tasklet scheduled when an isochronous output URB from the Gigaset device - * has completed - * parameter: - * data B channel state structure - */ -static void write_iso_tasklet(unsigned long data) -{ - struct bc_state *bcs = (struct bc_state *) data; - struct bas_bc_state *ubc = bcs->hw.bas; - struct cardstate *cs = bcs->cs; - struct isow_urbctx_t *done, *next, *ovfl; - struct urb *urb; - int status; - struct usb_iso_packet_descriptor *ifd; - unsigned long flags; - int i; - struct sk_buff *skb; - int len; - int rc; - - /* loop while completed URBs arrive in time */ - for (;;) { - if (unlikely(!(ubc->running))) { - gig_dbg(DEBUG_ISO, "%s: not running", __func__); - return; - } - - /* retrieve completed URBs */ - spin_lock_irqsave(&ubc->isooutlock, flags); - done = ubc->isooutdone; - ubc->isooutdone = NULL; - ovfl = ubc->isooutovfl; - ubc->isooutovfl = NULL; - spin_unlock_irqrestore(&ubc->isooutlock, flags); - if (ovfl) { - dev_err(cs->dev, "isoc write underrun\n"); - error_hangup(bcs); - break; - } - if (!done) - break; - - /* submit free URB if available */ - spin_lock_irqsave(&ubc->isooutlock, flags); - next = ubc->isooutfree; - ubc->isooutfree = NULL; - spin_unlock_irqrestore(&ubc->isooutlock, flags); - if (next) { - rc = submit_iso_write_urb(next); - if (unlikely(rc <= 0 && rc != -ENODEV)) { - /* could not submit URB, put it back */ - spin_lock_irqsave(&ubc->isooutlock, flags); - if (ubc->isooutfree == NULL) { - ubc->isooutfree = next; - next = NULL; - } - spin_unlock_irqrestore(&ubc->isooutlock, flags); - if (next) { - /* couldn't put it back */ - dev_err(cs->dev, - "losing isoc write URB\n"); - error_hangup(bcs); - } - } - } - - /* process completed URB */ - urb = done->urb; - status = done->status; - switch (status) { - case -EXDEV: /* partial completion */ - gig_dbg(DEBUG_ISO, "%s: URB partially completed", - __func__); - /* fall through - what's the difference anyway? */ - case 0: /* normal completion */ - /* inspect individual frames - * assumptions (for lack of documentation): - * - actual_length bytes of first frame in error are - * successfully sent - * - all following frames are not sent at all - */ - for (i = 0; i < BAS_NUMFRAMES; i++) { - ifd = &urb->iso_frame_desc[i]; - if (ifd->status || - ifd->actual_length != ifd->length) { - dev_warn(cs->dev, - "isoc write: frame %d[%d/%d]: %s\n", - i, ifd->actual_length, - ifd->length, - get_usb_statmsg(ifd->status)); - break; - } - } - break; - case -EPIPE: /* stall - probably underrun */ - dev_err(cs->dev, "isoc write: stalled\n"); - error_hangup(bcs); - break; - default: /* other errors */ - dev_warn(cs->dev, "isoc write: %s\n", - get_usb_statmsg(status)); - } - - /* mark the write buffer area covered by this URB as free */ - if (done->limit >= 0) - ubc->isooutbuf->read = done->limit; - - /* mark URB as free */ - spin_lock_irqsave(&ubc->isooutlock, flags); - next = ubc->isooutfree; - ubc->isooutfree = done; - spin_unlock_irqrestore(&ubc->isooutlock, flags); - if (next) { - /* only one URB still active - resubmit one */ - rc = submit_iso_write_urb(next); - if (unlikely(rc <= 0 && rc != -ENODEV)) { - /* couldn't submit */ - error_hangup(bcs); - } - } - } - - /* process queued SKBs */ - while ((skb = skb_dequeue(&bcs->squeue))) { - /* copy to output buffer, doing L2 encapsulation */ - len = skb->len; - if (gigaset_isoc_buildframe(bcs, skb->data, len) == -EAGAIN) { - /* insufficient buffer space, push back onto queue */ - skb_queue_head(&bcs->squeue, skb); - gig_dbg(DEBUG_ISO, "%s: skb requeued, qlen=%d", - __func__, skb_queue_len(&bcs->squeue)); - break; - } - skb_pull(skb, len); - gigaset_skb_sent(bcs, skb); - dev_kfree_skb_any(skb); - } -} - -/* Isochronous Read - Bottom Half */ -/* ============================== */ - -/* read_iso_tasklet - * tasklet scheduled when an isochronous input URB from the Gigaset device - * has completed - * parameter: - * data B channel state structure - */ -static void read_iso_tasklet(unsigned long data) -{ - struct bc_state *bcs = (struct bc_state *) data; - struct bas_bc_state *ubc = bcs->hw.bas; - struct cardstate *cs = bcs->cs; - struct urb *urb; - int status; - struct usb_iso_packet_descriptor *ifd; - char *rcvbuf; - unsigned long flags; - int totleft, numbytes, offset, frame, rc; - - /* loop while more completed URBs arrive in the meantime */ - for (;;) { - /* retrieve URB */ - spin_lock_irqsave(&ubc->isoinlock, flags); - urb = ubc->isoindone; - if (!urb) { - spin_unlock_irqrestore(&ubc->isoinlock, flags); - return; - } - status = ubc->isoinstatus; - ubc->isoindone = NULL; - if (unlikely(ubc->loststatus != -EINPROGRESS)) { - dev_warn(cs->dev, - "isoc read overrun, URB dropped (status: %s, %d bytes)\n", - get_usb_statmsg(ubc->loststatus), - ubc->isoinlost); - ubc->loststatus = -EINPROGRESS; - } - spin_unlock_irqrestore(&ubc->isoinlock, flags); - - if (unlikely(!(ubc->running))) { - gig_dbg(DEBUG_ISO, - "%s: channel not running, " - "dropped URB with status: %s", - __func__, get_usb_statmsg(status)); - return; - } - - switch (status) { - case 0: /* normal completion */ - break; - case -EXDEV: /* inspect individual frames - (we do that anyway) */ - gig_dbg(DEBUG_ISO, "%s: URB partially completed", - __func__); - break; - case -ENOENT: - case -ECONNRESET: - case -EINPROGRESS: - gig_dbg(DEBUG_ISO, "%s: %s", - __func__, get_usb_statmsg(status)); - continue; /* -> skip */ - case -EPIPE: - dev_err(cs->dev, "isoc read: stalled\n"); - error_hangup(bcs); - continue; /* -> skip */ - default: /* other error */ - dev_warn(cs->dev, "isoc read: %s\n", - get_usb_statmsg(status)); - goto error; - } - - rcvbuf = urb->transfer_buffer; - totleft = urb->actual_length; - for (frame = 0; totleft > 0 && frame < BAS_NUMFRAMES; frame++) { - ifd = &urb->iso_frame_desc[frame]; - numbytes = ifd->actual_length; - switch (ifd->status) { - case 0: /* success */ - break; - case -EPROTO: /* protocol error or unplug */ - case -EILSEQ: - case -ETIME: - /* probably just disconnected, ignore */ - gig_dbg(DEBUG_ISO, - "isoc read: frame %d[%d]: %s\n", - frame, numbytes, - get_usb_statmsg(ifd->status)); - break; - default: /* other error */ - /* report, assume transferred bytes are ok */ - dev_warn(cs->dev, - "isoc read: frame %d[%d]: %s\n", - frame, numbytes, - get_usb_statmsg(ifd->status)); - } - if (unlikely(numbytes > BAS_MAXFRAME)) - dev_warn(cs->dev, - "isoc read: frame %d[%d]: %s\n", - frame, numbytes, - "exceeds max frame size"); - if (unlikely(numbytes > totleft)) { - dev_warn(cs->dev, - "isoc read: frame %d[%d]: %s\n", - frame, numbytes, - "exceeds total transfer length"); - numbytes = totleft; - } - offset = ifd->offset; - if (unlikely(offset + numbytes > BAS_INBUFSIZE)) { - dev_warn(cs->dev, - "isoc read: frame %d[%d]: %s\n", - frame, numbytes, - "exceeds end of buffer"); - numbytes = BAS_INBUFSIZE - offset; - } - gigaset_isoc_receive(rcvbuf + offset, numbytes, bcs); - totleft -= numbytes; - } - if (unlikely(totleft > 0)) - dev_warn(cs->dev, "isoc read: %d data bytes missing\n", - totleft); - -error: - /* URB processed, resubmit */ - for (frame = 0; frame < BAS_NUMFRAMES; frame++) { - urb->iso_frame_desc[frame].status = 0; - urb->iso_frame_desc[frame].actual_length = 0; - } - /* urb->dev is clobbered by USB subsystem */ - urb->dev = bcs->cs->hw.bas->udev; - urb->transfer_flags = URB_ISO_ASAP; - urb->number_of_packets = BAS_NUMFRAMES; - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(rc != 0 && rc != -ENODEV)) { - dev_err(cs->dev, - "could not resubmit isoc read URB: %s\n", - get_usb_rcmsg(rc)); - dump_urb(DEBUG_ISO, "resubmit isoc read", urb); - error_hangup(bcs); - } - } -} - -/* Channel Operations */ -/* ================== */ - -/* req_timeout - * timeout routine for control output request - * argument: - * controller state structure - */ -static void req_timeout(struct timer_list *t) -{ - struct bas_cardstate *ucs = from_timer(ucs, t, timer_ctrl); - struct cardstate *cs = ucs->cs; - int pending; - unsigned long flags; - - check_pending(ucs); - - spin_lock_irqsave(&ucs->lock, flags); - pending = ucs->pending; - ucs->pending = 0; - spin_unlock_irqrestore(&ucs->lock, flags); - - switch (pending) { - case 0: /* no pending request */ - gig_dbg(DEBUG_USBREQ, "%s: no request pending", __func__); - break; - - case HD_OPEN_ATCHANNEL: - dev_err(cs->dev, "timeout opening AT channel\n"); - error_reset(cs); - break; - - case HD_OPEN_B1CHANNEL: - dev_err(cs->dev, "timeout opening channel 1\n"); - error_hangup(&cs->bcs[0]); - break; - - case HD_OPEN_B2CHANNEL: - dev_err(cs->dev, "timeout opening channel 2\n"); - error_hangup(&cs->bcs[1]); - break; - - case HD_CLOSE_ATCHANNEL: - dev_err(cs->dev, "timeout closing AT channel\n"); - error_reset(cs); - break; - - case HD_CLOSE_B1CHANNEL: - dev_err(cs->dev, "timeout closing channel 1\n"); - error_reset(cs); - break; - - case HD_CLOSE_B2CHANNEL: - dev_err(cs->dev, "timeout closing channel 2\n"); - error_reset(cs); - break; - - case HD_RESET_INTERRUPT_PIPE: - /* error recovery escalation */ - dev_err(cs->dev, - "reset interrupt pipe timeout, attempting USB reset\n"); - usb_queue_reset_device(ucs->interface); - break; - - default: - dev_warn(cs->dev, "request 0x%02x timed out, clearing\n", - pending); - } - - wake_up(&ucs->waitqueue); -} - -/* write_ctrl_callback - * USB completion handler for control pipe output - * called by the USB subsystem in interrupt context - * parameter: - * urb USB request block of completed request - * urb->context = hardware specific controller state structure - */ -static void write_ctrl_callback(struct urb *urb) -{ - struct bas_cardstate *ucs = urb->context; - int status = urb->status; - int rc; - unsigned long flags; - - /* check status */ - switch (status) { - case 0: /* normal completion */ - spin_lock_irqsave(&ucs->lock, flags); - switch (ucs->pending) { - case HD_DEVICE_INIT_ACK: /* no reply expected */ - del_timer(&ucs->timer_ctrl); - ucs->pending = 0; - break; - } - spin_unlock_irqrestore(&ucs->lock, flags); - return; - - case -ENOENT: /* cancelled */ - case -ECONNRESET: /* cancelled (async) */ - case -EINPROGRESS: /* pending */ - case -ENODEV: /* device removed */ - case -ESHUTDOWN: /* device shut down */ - /* ignore silently */ - gig_dbg(DEBUG_USBREQ, "%s: %s", - __func__, get_usb_statmsg(status)); - break; - - default: /* any failure */ - /* don't retry if suspend requested */ - if (++ucs->retry_ctrl > BAS_RETRY || - (ucs->basstate & BS_SUSPEND)) { - dev_err(&ucs->interface->dev, - "control request 0x%02x failed: %s\n", - ucs->dr_ctrl.bRequest, - get_usb_statmsg(status)); - break; /* give up */ - } - dev_notice(&ucs->interface->dev, - "control request 0x%02x: %s, retry %d\n", - ucs->dr_ctrl.bRequest, get_usb_statmsg(status), - ucs->retry_ctrl); - /* urb->dev is clobbered by USB subsystem */ - urb->dev = ucs->udev; - rc = usb_submit_urb(urb, GFP_ATOMIC); - if (unlikely(rc)) { - dev_err(&ucs->interface->dev, - "could not resubmit request 0x%02x: %s\n", - ucs->dr_ctrl.bRequest, get_usb_rcmsg(rc)); - break; - } - /* resubmitted */ - return; - } - - /* failed, clear pending request */ - spin_lock_irqsave(&ucs->lock, flags); - del_timer(&ucs->timer_ctrl); - ucs->pending = 0; - spin_unlock_irqrestore(&ucs->lock, flags); - wake_up(&ucs->waitqueue); -} - -/* req_submit - * submit a control output request without message buffer to the Gigaset base - * and optionally start a timeout - * parameters: - * bcs B channel control structure - * req control request code (HD_*) - * val control request parameter value (set to 0 if unused) - * timeout timeout in seconds (0: no timeout) - * return value: - * 0 on success - * -EBUSY if another request is pending - * any URB submission error code - */ -static int req_submit(struct bc_state *bcs, int req, int val, int timeout) -{ - struct bas_cardstate *ucs = bcs->cs->hw.bas; - int ret; - unsigned long flags; - - gig_dbg(DEBUG_USBREQ, "-------> 0x%02x (%d)", req, val); - - spin_lock_irqsave(&ucs->lock, flags); - if (ucs->pending) { - spin_unlock_irqrestore(&ucs->lock, flags); - dev_err(bcs->cs->dev, - "submission of request 0x%02x failed: " - "request 0x%02x still pending\n", - req, ucs->pending); - return -EBUSY; - } - - ucs->dr_ctrl.bRequestType = OUT_VENDOR_REQ; - ucs->dr_ctrl.bRequest = req; - ucs->dr_ctrl.wValue = cpu_to_le16(val); - ucs->dr_ctrl.wIndex = 0; - ucs->dr_ctrl.wLength = 0; - usb_fill_control_urb(ucs->urb_ctrl, ucs->udev, - usb_sndctrlpipe(ucs->udev, 0), - (unsigned char *) &ucs->dr_ctrl, NULL, 0, - write_ctrl_callback, ucs); - ucs->retry_ctrl = 0; - ret = usb_submit_urb(ucs->urb_ctrl, GFP_ATOMIC); - if (unlikely(ret)) { - dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n", - req, get_usb_rcmsg(ret)); - spin_unlock_irqrestore(&ucs->lock, flags); - return ret; - } - ucs->pending = req; - - if (timeout > 0) { - gig_dbg(DEBUG_USBREQ, "setting timeout of %d/10 secs", timeout); - mod_timer(&ucs->timer_ctrl, jiffies + timeout * HZ / 10); - } - - spin_unlock_irqrestore(&ucs->lock, flags); - return 0; -} - -/* gigaset_init_bchannel - * called by common.c to connect a B channel - * initialize isochronous I/O and tell the Gigaset base to open the channel - * argument: - * B channel control structure - * return value: - * 0 on success, error code < 0 on error - */ -static int gigaset_init_bchannel(struct bc_state *bcs) -{ - struct cardstate *cs = bcs->cs; - int req, ret; - unsigned long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (unlikely(!cs->connected)) { - gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); - spin_unlock_irqrestore(&cs->lock, flags); - return -ENODEV; - } - - if (cs->hw.bas->basstate & BS_SUSPEND) { - dev_notice(cs->dev, - "not starting isoc I/O, suspend in progress\n"); - spin_unlock_irqrestore(&cs->lock, flags); - return -EHOSTUNREACH; - } - - ret = starturbs(bcs); - if (ret < 0) { - spin_unlock_irqrestore(&cs->lock, flags); - dev_err(cs->dev, - "could not start isoc I/O for channel B%d: %s\n", - bcs->channel + 1, - ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret)); - if (ret != -ENODEV) - error_hangup(bcs); - return ret; - } - - req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL; - ret = req_submit(bcs, req, 0, BAS_TIMEOUT); - if (ret < 0) { - dev_err(cs->dev, "could not open channel B%d\n", - bcs->channel + 1); - stopurbs(bcs->hw.bas); - } - - spin_unlock_irqrestore(&cs->lock, flags); - if (ret < 0 && ret != -ENODEV) - error_hangup(bcs); - return ret; -} - -/* gigaset_close_bchannel - * called by common.c to disconnect a B channel - * tell the Gigaset base to close the channel - * stopping isochronous I/O and LL notification will be done when the - * acknowledgement for the close arrives - * argument: - * B channel control structure - * return value: - * 0 on success, error code < 0 on error - */ -static int gigaset_close_bchannel(struct bc_state *bcs) -{ - struct cardstate *cs = bcs->cs; - int req, ret; - unsigned long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (unlikely(!cs->connected)) { - spin_unlock_irqrestore(&cs->lock, flags); - gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); - return -ENODEV; - } - - if (!(cs->hw.bas->basstate & (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) { - /* channel not running: just signal common.c */ - spin_unlock_irqrestore(&cs->lock, flags); - gigaset_bchannel_down(bcs); - return 0; - } - - /* channel running: tell device to close it */ - req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL; - ret = req_submit(bcs, req, 0, BAS_TIMEOUT); - if (ret < 0) - dev_err(cs->dev, "closing channel B%d failed\n", - bcs->channel + 1); - - spin_unlock_irqrestore(&cs->lock, flags); - return ret; -} - -/* Device Operations */ -/* ================= */ - -/* complete_cb - * unqueue first command buffer from queue, waking any sleepers - * must be called with cs->cmdlock held - * parameter: - * cs controller state structure - */ -static void complete_cb(struct cardstate *cs) -{ - struct cmdbuf_t *cb = cs->cmdbuf; - - /* unqueue completed buffer */ - cs->cmdbytes -= cs->curlen; - gig_dbg(DEBUG_OUTPUT, "write_command: sent %u bytes, %u left", - cs->curlen, cs->cmdbytes); - if (cb->next != NULL) { - cs->cmdbuf = cb->next; - cs->cmdbuf->prev = NULL; - cs->curlen = cs->cmdbuf->len; - } else { - cs->cmdbuf = NULL; - cs->lastcmdbuf = NULL; - cs->curlen = 0; - } - - if (cb->wake_tasklet) - tasklet_schedule(cb->wake_tasklet); - - kfree(cb); -} - -/* write_command_callback - * USB completion handler for AT command transmission - * called by the USB subsystem in interrupt context - * parameter: - * urb USB request block of completed request - * urb->context = controller state structure - */ -static void write_command_callback(struct urb *urb) -{ - struct cardstate *cs = urb->context; - struct bas_cardstate *ucs = cs->hw.bas; - int status = urb->status; - unsigned long flags; - - update_basstate(ucs, 0, BS_ATWRPEND); - wake_up(&ucs->waitqueue); - - /* check status */ - switch (status) { - case 0: /* normal completion */ - break; - case -ENOENT: /* cancelled */ - case -ECONNRESET: /* cancelled (async) */ - case -EINPROGRESS: /* pending */ - case -ENODEV: /* device removed */ - case -ESHUTDOWN: /* device shut down */ - /* ignore silently */ - gig_dbg(DEBUG_USBREQ, "%s: %s", - __func__, get_usb_statmsg(status)); - return; - default: /* any failure */ - if (++ucs->retry_cmd_out > BAS_RETRY) { - dev_warn(cs->dev, - "command write: %s, " - "giving up after %d retries\n", - get_usb_statmsg(status), - ucs->retry_cmd_out); - break; - } - if (ucs->basstate & BS_SUSPEND) { - dev_warn(cs->dev, - "command write: %s, " - "won't retry - suspend requested\n", - get_usb_statmsg(status)); - break; - } - if (cs->cmdbuf == NULL) { - dev_warn(cs->dev, - "command write: %s, " - "cannot retry - cmdbuf gone\n", - get_usb_statmsg(status)); - break; - } - dev_notice(cs->dev, "command write: %s, retry %d\n", - get_usb_statmsg(status), ucs->retry_cmd_out); - if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0) - /* resubmitted - bypass regular exit block */ - return; - /* command send failed, assume base still waiting */ - update_basstate(ucs, BS_ATREADY, 0); - } - - spin_lock_irqsave(&cs->cmdlock, flags); - if (cs->cmdbuf != NULL) - complete_cb(cs); - spin_unlock_irqrestore(&cs->cmdlock, flags); -} - -/* atrdy_timeout - * timeout routine for AT command transmission - * argument: - * controller state structure - */ -static void atrdy_timeout(struct timer_list *t) -{ - struct bas_cardstate *ucs = from_timer(ucs, t, timer_atrdy); - struct cardstate *cs = ucs->cs; - - dev_warn(cs->dev, "timeout waiting for HD_READY_SEND_ATDATA\n"); - - /* fake the missing signal - what else can I do? */ - update_basstate(ucs, BS_ATREADY, BS_ATTIMER); - start_cbsend(cs); -} - -/* atwrite_submit - * submit an HD_WRITE_ATMESSAGE command URB - * parameters: - * cs controller state structure - * buf buffer containing command to send - * len length of command to send - * return value: - * 0 on success - * -EBUSY if another request is pending - * any URB submission error code - */ -static int atwrite_submit(struct cardstate *cs, unsigned char *buf, int len) -{ - struct bas_cardstate *ucs = cs->hw.bas; - int rc; - - gig_dbg(DEBUG_USBREQ, "-------> HD_WRITE_ATMESSAGE (%d)", len); - - if (update_basstate(ucs, BS_ATWRPEND, 0) & BS_ATWRPEND) { - dev_err(cs->dev, - "could not submit HD_WRITE_ATMESSAGE: URB busy\n"); - return -EBUSY; - } - - ucs->dr_cmd_out.bRequestType = OUT_VENDOR_REQ; - ucs->dr_cmd_out.bRequest = HD_WRITE_ATMESSAGE; - ucs->dr_cmd_out.wValue = 0; - ucs->dr_cmd_out.wIndex = 0; - ucs->dr_cmd_out.wLength = cpu_to_le16(len); - usb_fill_control_urb(ucs->urb_cmd_out, ucs->udev, - usb_sndctrlpipe(ucs->udev, 0), - (unsigned char *) &ucs->dr_cmd_out, buf, len, - write_command_callback, cs); - rc = usb_submit_urb(ucs->urb_cmd_out, GFP_ATOMIC); - if (unlikely(rc)) { - update_basstate(ucs, 0, BS_ATWRPEND); - dev_err(cs->dev, "could not submit HD_WRITE_ATMESSAGE: %s\n", - get_usb_rcmsg(rc)); - return rc; - } - - /* submitted successfully, start timeout if necessary */ - if (!(update_basstate(ucs, BS_ATTIMER, BS_ATREADY) & BS_ATTIMER)) { - gig_dbg(DEBUG_OUTPUT, "setting ATREADY timeout of %d/10 secs", - ATRDY_TIMEOUT); - mod_timer(&ucs->timer_atrdy, jiffies + ATRDY_TIMEOUT * HZ / 10); - } - return 0; -} - -/* start_cbsend - * start transmission of AT command queue if necessary - * parameter: - * cs controller state structure - * return value: - * 0 on success - * error code < 0 on error - */ -static int start_cbsend(struct cardstate *cs) -{ - struct cmdbuf_t *cb; - struct bas_cardstate *ucs = cs->hw.bas; - unsigned long flags; - int rc; - int retval = 0; - - /* check if suspend requested */ - if (ucs->basstate & BS_SUSPEND) { - gig_dbg(DEBUG_OUTPUT, "suspending"); - return -EHOSTUNREACH; - } - - /* check if AT channel is open */ - if (!(ucs->basstate & BS_ATOPEN)) { - gig_dbg(DEBUG_OUTPUT, "AT channel not open"); - rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT); - if (rc < 0) { - /* flush command queue */ - spin_lock_irqsave(&cs->cmdlock, flags); - while (cs->cmdbuf != NULL) - complete_cb(cs); - spin_unlock_irqrestore(&cs->cmdlock, flags); - } - return rc; - } - - /* try to send first command in queue */ - spin_lock_irqsave(&cs->cmdlock, flags); - - while ((cb = cs->cmdbuf) != NULL && (ucs->basstate & BS_ATREADY)) { - ucs->retry_cmd_out = 0; - rc = atwrite_submit(cs, cb->buf, cb->len); - if (unlikely(rc)) { - retval = rc; - complete_cb(cs); - } - } - - spin_unlock_irqrestore(&cs->cmdlock, flags); - return retval; -} - -/* gigaset_write_cmd - * This function is called by the device independent part of the driver - * to transmit an AT command string to the Gigaset device. - * It encapsulates the device specific method for transmission over the - * direct USB connection to the base. - * The command string is added to the queue of commands to send, and - * USB transmission is started if necessary. - * parameters: - * cs controller state structure - * cb command buffer structure - * return value: - * number of bytes queued on success - * error code < 0 on error - */ -static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb) -{ - unsigned long flags; - int rc; - - gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? - DEBUG_TRANSCMD : DEBUG_LOCKCMD, - "CMD Transmit", cb->len, cb->buf); - - /* translate "+++" escape sequence sent as a single separate command - * into "close AT channel" command for error recovery - * The next command will reopen the AT channel automatically. - */ - if (cb->len == 3 && !memcmp(cb->buf, "+++", 3)) { - /* If an HD_RECEIVEATDATA_ACK message remains unhandled - * because of an error, the base never sends another one. - * The response channel is thus effectively blocked. - * Closing and reopening the AT channel does *not* clear - * this condition. - * As a stopgap measure, submit a zero-length AT read - * before closing the AT channel. This has the undocumented - * effect of triggering a new HD_RECEIVEATDATA_ACK message - * from the base if necessary. - * The subsequent AT channel close then discards any pending - * messages. - */ - spin_lock_irqsave(&cs->lock, flags); - if (!(cs->hw.bas->basstate & BS_ATRDPEND)) { - kfree(cs->hw.bas->rcvbuf); - cs->hw.bas->rcvbuf = NULL; - cs->hw.bas->rcvbuf_size = 0; - cs->hw.bas->retry_cmd_in = 0; - atread_submit(cs, 0); - } - spin_unlock_irqrestore(&cs->lock, flags); - - rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT); - if (cb->wake_tasklet) - tasklet_schedule(cb->wake_tasklet); - if (!rc) - rc = cb->len; - kfree(cb); - return rc; - } - - spin_lock_irqsave(&cs->cmdlock, flags); - cb->prev = cs->lastcmdbuf; - if (cs->lastcmdbuf) - cs->lastcmdbuf->next = cb; - else { - cs->cmdbuf = cb; - cs->curlen = cb->len; - } - cs->cmdbytes += cb->len; - cs->lastcmdbuf = cb; - spin_unlock_irqrestore(&cs->cmdlock, flags); - - spin_lock_irqsave(&cs->lock, flags); - if (unlikely(!cs->connected)) { - spin_unlock_irqrestore(&cs->lock, flags); - gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); - /* flush command queue */ - spin_lock_irqsave(&cs->cmdlock, flags); - while (cs->cmdbuf != NULL) - complete_cb(cs); - spin_unlock_irqrestore(&cs->cmdlock, flags); - return -ENODEV; - } - rc = start_cbsend(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return rc < 0 ? rc : cb->len; -} - -/* gigaset_write_room - * tty_driver.write_room interface routine - * return number of characters the driver will accept to be written via - * gigaset_write_cmd - * parameter: - * controller state structure - * return value: - * number of characters - */ -static int gigaset_write_room(struct cardstate *cs) -{ - return IF_WRITEBUF; -} - -/* gigaset_chars_in_buffer - * tty_driver.chars_in_buffer interface routine - * return number of characters waiting to be sent - * parameter: - * controller state structure - * return value: - * number of characters - */ -static int gigaset_chars_in_buffer(struct cardstate *cs) -{ - return cs->cmdbytes; -} - -/* gigaset_brkchars - * implementation of ioctl(GIGASET_BRKCHARS) - * parameter: - * controller state structure - * return value: - * -EINVAL (unimplemented function) - */ -static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) -{ - return -EINVAL; -} - - -/* Device Initialization/Shutdown */ -/* ============================== */ - -/* Free hardware dependent part of the B channel structure - * parameter: - * bcs B channel structure - */ -static void gigaset_freebcshw(struct bc_state *bcs) -{ - struct bas_bc_state *ubc = bcs->hw.bas; - int i; - - if (!ubc) - return; - - /* kill URBs and tasklets before freeing - better safe than sorry */ - ubc->running = 0; - gig_dbg(DEBUG_INIT, "%s: killing isoc URBs", __func__); - for (i = 0; i < BAS_OUTURBS; ++i) { - usb_kill_urb(ubc->isoouturbs[i].urb); - usb_free_urb(ubc->isoouturbs[i].urb); - } - for (i = 0; i < BAS_INURBS; ++i) { - usb_kill_urb(ubc->isoinurbs[i]); - usb_free_urb(ubc->isoinurbs[i]); - } - tasklet_kill(&ubc->sent_tasklet); - tasklet_kill(&ubc->rcvd_tasklet); - kfree(ubc->isooutbuf); - kfree(ubc); - bcs->hw.bas = NULL; -} - -/* Initialize hardware dependent part of the B channel structure - * parameter: - * bcs B channel structure - * return value: - * 0 on success, error code < 0 on failure - */ -static int gigaset_initbcshw(struct bc_state *bcs) -{ - int i; - struct bas_bc_state *ubc; - - bcs->hw.bas = ubc = kmalloc(sizeof(struct bas_bc_state), GFP_KERNEL); - if (!ubc) { - pr_err("out of memory\n"); - return -ENOMEM; - } - - ubc->running = 0; - atomic_set(&ubc->corrbytes, 0); - spin_lock_init(&ubc->isooutlock); - for (i = 0; i < BAS_OUTURBS; ++i) { - ubc->isoouturbs[i].urb = NULL; - ubc->isoouturbs[i].bcs = bcs; - } - ubc->isooutdone = ubc->isooutfree = ubc->isooutovfl = NULL; - ubc->numsub = 0; - ubc->isooutbuf = kmalloc(sizeof(struct isowbuf_t), GFP_KERNEL); - if (!ubc->isooutbuf) { - pr_err("out of memory\n"); - kfree(ubc); - bcs->hw.bas = NULL; - return -ENOMEM; - } - tasklet_init(&ubc->sent_tasklet, - write_iso_tasklet, (unsigned long) bcs); - - spin_lock_init(&ubc->isoinlock); - for (i = 0; i < BAS_INURBS; ++i) - ubc->isoinurbs[i] = NULL; - ubc->isoindone = NULL; - ubc->loststatus = -EINPROGRESS; - ubc->isoinlost = 0; - ubc->seqlen = 0; - ubc->inbyte = 0; - ubc->inbits = 0; - ubc->goodbytes = 0; - ubc->alignerrs = 0; - ubc->fcserrs = 0; - ubc->frameerrs = 0; - ubc->giants = 0; - ubc->runts = 0; - ubc->aborts = 0; - ubc->shared0s = 0; - ubc->stolen0s = 0; - tasklet_init(&ubc->rcvd_tasklet, - read_iso_tasklet, (unsigned long) bcs); - return 0; -} - -static void gigaset_reinitbcshw(struct bc_state *bcs) -{ - struct bas_bc_state *ubc = bcs->hw.bas; - - bcs->hw.bas->running = 0; - atomic_set(&bcs->hw.bas->corrbytes, 0); - bcs->hw.bas->numsub = 0; - spin_lock_init(&ubc->isooutlock); - spin_lock_init(&ubc->isoinlock); - ubc->loststatus = -EINPROGRESS; -} - -static void gigaset_freecshw(struct cardstate *cs) -{ - /* timers, URBs and rcvbuf are disposed of in disconnect */ - kfree(cs->hw.bas->int_in_buf); - kfree(cs->hw.bas); - cs->hw.bas = NULL; -} - -/* Initialize hardware dependent part of the cardstate structure - * parameter: - * cs cardstate structure - * return value: - * 0 on success, error code < 0 on failure - */ -static int gigaset_initcshw(struct cardstate *cs) -{ - struct bas_cardstate *ucs; - - cs->hw.bas = ucs = kzalloc(sizeof(*ucs), GFP_KERNEL); - if (!ucs) { - pr_err("out of memory\n"); - return -ENOMEM; - } - ucs->int_in_buf = kmalloc(IP_MSGSIZE, GFP_KERNEL); - if (!ucs->int_in_buf) { - kfree(ucs); - pr_err("out of memory\n"); - return -ENOMEM; - } - - spin_lock_init(&ucs->lock); - ucs->cs = cs; - timer_setup(&ucs->timer_ctrl, req_timeout, 0); - timer_setup(&ucs->timer_atrdy, atrdy_timeout, 0); - timer_setup(&ucs->timer_cmd_in, cmd_in_timeout, 0); - timer_setup(&ucs->timer_int_in, int_in_resubmit, 0); - init_waitqueue_head(&ucs->waitqueue); - INIT_WORK(&ucs->int_in_wq, int_in_work); - - return 0; -} - -/* freeurbs - * unlink and deallocate all URBs unconditionally - * caller must make sure that no commands are still in progress - * parameter: - * cs controller state structure - */ -static void freeurbs(struct cardstate *cs) -{ - struct bas_cardstate *ucs = cs->hw.bas; - struct bas_bc_state *ubc; - int i, j; - - gig_dbg(DEBUG_INIT, "%s: killing URBs", __func__); - for (j = 0; j < BAS_CHANNELS; ++j) { - ubc = cs->bcs[j].hw.bas; - for (i = 0; i < BAS_OUTURBS; ++i) { - usb_kill_urb(ubc->isoouturbs[i].urb); - usb_free_urb(ubc->isoouturbs[i].urb); - ubc->isoouturbs[i].urb = NULL; - } - for (i = 0; i < BAS_INURBS; ++i) { - usb_kill_urb(ubc->isoinurbs[i]); - usb_free_urb(ubc->isoinurbs[i]); - ubc->isoinurbs[i] = NULL; - } - } - usb_kill_urb(ucs->urb_int_in); - usb_free_urb(ucs->urb_int_in); - ucs->urb_int_in = NULL; - usb_kill_urb(ucs->urb_cmd_out); - usb_free_urb(ucs->urb_cmd_out); - ucs->urb_cmd_out = NULL; - usb_kill_urb(ucs->urb_cmd_in); - usb_free_urb(ucs->urb_cmd_in); - ucs->urb_cmd_in = NULL; - usb_kill_urb(ucs->urb_ctrl); - usb_free_urb(ucs->urb_ctrl); - ucs->urb_ctrl = NULL; -} - -/* gigaset_probe - * This function is called when a new USB device is connected. - * It checks whether the new device is handled by this driver. - */ -static int gigaset_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_host_interface *hostif; - struct usb_device *udev = interface_to_usbdev(interface); - struct cardstate *cs = NULL; - struct bas_cardstate *ucs = NULL; - struct bas_bc_state *ubc; - struct usb_endpoint_descriptor *endpoint; - int i, j; - int rc; - - gig_dbg(DEBUG_INIT, - "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", - __func__, le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - - /* set required alternate setting */ - hostif = interface->cur_altsetting; - if (hostif->desc.bAlternateSetting != 3) { - gig_dbg(DEBUG_INIT, - "%s: wrong alternate setting %d - trying to switch", - __func__, hostif->desc.bAlternateSetting); - if (usb_set_interface(udev, hostif->desc.bInterfaceNumber, 3) - < 0) { - dev_warn(&udev->dev, "usb_set_interface failed, " - "device %d interface %d altsetting %d\n", - udev->devnum, hostif->desc.bInterfaceNumber, - hostif->desc.bAlternateSetting); - return -ENODEV; - } - hostif = interface->cur_altsetting; - } - - /* Reject application specific interfaces - */ - if (hostif->desc.bInterfaceClass != 255) { - dev_warn(&udev->dev, "%s: bInterfaceClass == %d\n", - __func__, hostif->desc.bInterfaceClass); - return -ENODEV; - } - - if (hostif->desc.bNumEndpoints < 1) - return -ENODEV; - - dev_info(&udev->dev, - "%s: Device matched (Vendor: 0x%x, Product: 0x%x)\n", - __func__, le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - - /* allocate memory for our device state and initialize it */ - cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode, - GIGASET_MODULENAME); - if (!cs) - return -ENODEV; - ucs = cs->hw.bas; - - /* save off device structure ptrs for later use */ - usb_get_dev(udev); - ucs->udev = udev; - ucs->interface = interface; - cs->dev = &interface->dev; - - /* allocate URBs: - * - one for the interrupt pipe - * - three for the different uses of the default control pipe - * - three for each isochronous pipe - */ - if (!(ucs->urb_int_in = usb_alloc_urb(0, GFP_KERNEL)) || - !(ucs->urb_cmd_in = usb_alloc_urb(0, GFP_KERNEL)) || - !(ucs->urb_cmd_out = usb_alloc_urb(0, GFP_KERNEL)) || - !(ucs->urb_ctrl = usb_alloc_urb(0, GFP_KERNEL))) - goto allocerr; - - for (j = 0; j < BAS_CHANNELS; ++j) { - ubc = cs->bcs[j].hw.bas; - for (i = 0; i < BAS_OUTURBS; ++i) - if (!(ubc->isoouturbs[i].urb = - usb_alloc_urb(BAS_NUMFRAMES, GFP_KERNEL))) - goto allocerr; - for (i = 0; i < BAS_INURBS; ++i) - if (!(ubc->isoinurbs[i] = - usb_alloc_urb(BAS_NUMFRAMES, GFP_KERNEL))) - goto allocerr; - } - - ucs->rcvbuf = NULL; - ucs->rcvbuf_size = 0; - - /* Fill the interrupt urb and send it to the core */ - endpoint = &hostif->endpoint[0].desc; - usb_fill_int_urb(ucs->urb_int_in, udev, - usb_rcvintpipe(udev, - usb_endpoint_num(endpoint)), - ucs->int_in_buf, IP_MSGSIZE, read_int_callback, cs, - endpoint->bInterval); - rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL); - if (rc != 0) { - dev_err(cs->dev, "could not submit interrupt URB: %s\n", - get_usb_rcmsg(rc)); - goto error; - } - ucs->retry_int_in = 0; - - /* tell the device that the driver is ready */ - rc = req_submit(cs->bcs, HD_DEVICE_INIT_ACK, 0, 0); - if (rc != 0) - goto error; - - /* tell common part that the device is ready */ - if (startmode == SM_LOCKED) - cs->mstate = MS_LOCKED; - - /* save address of controller structure */ - usb_set_intfdata(interface, cs); - - rc = gigaset_start(cs); - if (rc < 0) - goto error; - - return 0; - -allocerr: - dev_err(cs->dev, "could not allocate URBs\n"); - rc = -ENOMEM; -error: - freeurbs(cs); - usb_set_intfdata(interface, NULL); - usb_put_dev(udev); - gigaset_freecs(cs); - return rc; -} - -/* gigaset_disconnect - * This function is called when the Gigaset base is unplugged. - */ -static void gigaset_disconnect(struct usb_interface *interface) -{ - struct cardstate *cs; - struct bas_cardstate *ucs; - int j; - - cs = usb_get_intfdata(interface); - - ucs = cs->hw.bas; - - dev_info(cs->dev, "disconnecting Gigaset base\n"); - - /* mark base as not ready, all channels disconnected */ - ucs->basstate = 0; - - /* tell LL all channels are down */ - for (j = 0; j < BAS_CHANNELS; ++j) - gigaset_bchannel_down(cs->bcs + j); - - /* stop driver (common part) */ - gigaset_stop(cs); - - /* stop delayed work and URBs, free ressources */ - del_timer_sync(&ucs->timer_ctrl); - del_timer_sync(&ucs->timer_atrdy); - del_timer_sync(&ucs->timer_cmd_in); - del_timer_sync(&ucs->timer_int_in); - cancel_work_sync(&ucs->int_in_wq); - freeurbs(cs); - usb_set_intfdata(interface, NULL); - kfree(ucs->rcvbuf); - ucs->rcvbuf = NULL; - ucs->rcvbuf_size = 0; - usb_put_dev(ucs->udev); - ucs->interface = NULL; - ucs->udev = NULL; - cs->dev = NULL; - gigaset_freecs(cs); -} - -/* gigaset_suspend - * This function is called before the USB connection is suspended - * or before the USB device is reset. - * In the latter case, message == PMSG_ON. - */ -static int gigaset_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct cardstate *cs = usb_get_intfdata(intf); - struct bas_cardstate *ucs = cs->hw.bas; - int rc; - - /* set suspend flag; this stops AT command/response traffic */ - if (update_basstate(ucs, BS_SUSPEND, 0) & BS_SUSPEND) { - gig_dbg(DEBUG_SUSPEND, "already suspended"); - return 0; - } - - /* wait a bit for blocking conditions to go away */ - rc = wait_event_timeout(ucs->waitqueue, - !(ucs->basstate & - (BS_B1OPEN | BS_B2OPEN | BS_ATRDPEND | BS_ATWRPEND)), - BAS_TIMEOUT * HZ / 10); - gig_dbg(DEBUG_SUSPEND, "wait_event_timeout() -> %d", rc); - - /* check for conditions preventing suspend */ - if (ucs->basstate & (BS_B1OPEN | BS_B2OPEN | BS_ATRDPEND | BS_ATWRPEND)) { - dev_warn(cs->dev, "cannot suspend:\n"); - if (ucs->basstate & BS_B1OPEN) - dev_warn(cs->dev, " B channel 1 open\n"); - if (ucs->basstate & BS_B2OPEN) - dev_warn(cs->dev, " B channel 2 open\n"); - if (ucs->basstate & BS_ATRDPEND) - dev_warn(cs->dev, " receiving AT reply\n"); - if (ucs->basstate & BS_ATWRPEND) - dev_warn(cs->dev, " sending AT command\n"); - update_basstate(ucs, 0, BS_SUSPEND); - return -EBUSY; - } - - /* close AT channel if open */ - if (ucs->basstate & BS_ATOPEN) { - gig_dbg(DEBUG_SUSPEND, "closing AT channel"); - rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, 0); - if (rc) { - update_basstate(ucs, 0, BS_SUSPEND); - return rc; - } - wait_event_timeout(ucs->waitqueue, !ucs->pending, - BAS_TIMEOUT * HZ / 10); - /* in case of timeout, proceed anyway */ - } - - /* kill all URBs and delayed work that might still be pending */ - usb_kill_urb(ucs->urb_ctrl); - usb_kill_urb(ucs->urb_int_in); - del_timer_sync(&ucs->timer_ctrl); - del_timer_sync(&ucs->timer_atrdy); - del_timer_sync(&ucs->timer_cmd_in); - del_timer_sync(&ucs->timer_int_in); - - /* don't try to cancel int_in_wq from within reset as it - * might be the one requesting the reset - */ - if (message.event != PM_EVENT_ON) - cancel_work_sync(&ucs->int_in_wq); - - gig_dbg(DEBUG_SUSPEND, "suspend complete"); - return 0; -} - -/* gigaset_resume - * This function is called after the USB connection has been resumed. - */ -static int gigaset_resume(struct usb_interface *intf) -{ - struct cardstate *cs = usb_get_intfdata(intf); - struct bas_cardstate *ucs = cs->hw.bas; - int rc; - - /* resubmit interrupt URB for spontaneous messages from base */ - rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL); - if (rc) { - dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", - get_usb_rcmsg(rc)); - return rc; - } - ucs->retry_int_in = 0; - - /* clear suspend flag to reallow activity */ - update_basstate(ucs, 0, BS_SUSPEND); - - gig_dbg(DEBUG_SUSPEND, "resume complete"); - return 0; -} - -/* gigaset_pre_reset - * This function is called before the USB connection is reset. - */ -static int gigaset_pre_reset(struct usb_interface *intf) -{ - /* handle just like suspend */ - return gigaset_suspend(intf, PMSG_ON); -} - -/* gigaset_post_reset - * This function is called after the USB connection has been reset. - */ -static int gigaset_post_reset(struct usb_interface *intf) -{ - /* FIXME: send HD_DEVICE_INIT_ACK? */ - - /* resume operations */ - return gigaset_resume(intf); -} - - -static const struct gigaset_ops gigops = { - .write_cmd = gigaset_write_cmd, - .write_room = gigaset_write_room, - .chars_in_buffer = gigaset_chars_in_buffer, - .brkchars = gigaset_brkchars, - .init_bchannel = gigaset_init_bchannel, - .close_bchannel = gigaset_close_bchannel, - .initbcshw = gigaset_initbcshw, - .freebcshw = gigaset_freebcshw, - .reinitbcshw = gigaset_reinitbcshw, - .initcshw = gigaset_initcshw, - .freecshw = gigaset_freecshw, - .set_modem_ctrl = gigaset_set_modem_ctrl, - .baud_rate = gigaset_baud_rate, - .set_line_ctrl = gigaset_set_line_ctrl, - .send_skb = gigaset_isoc_send_skb, - .handle_input = gigaset_isoc_input, -}; - -/* bas_gigaset_init - * This function is called after the kernel module is loaded. - */ -static int __init bas_gigaset_init(void) -{ - int result; - - /* allocate memory for our driver state and initialize it */ - driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, - GIGASET_MODULENAME, GIGASET_DEVNAME, - &gigops, THIS_MODULE); - if (driver == NULL) - goto error; - - /* register this driver with the USB subsystem */ - result = usb_register(&gigaset_usb_driver); - if (result < 0) { - pr_err("error %d registering USB driver\n", -result); - goto error; - } - - pr_info(DRIVER_DESC "\n"); - return 0; - -error: - if (driver) - gigaset_freedriver(driver); - driver = NULL; - return -1; -} - -/* bas_gigaset_exit - * This function is called before the kernel module is unloaded. - */ -static void __exit bas_gigaset_exit(void) -{ - struct bas_cardstate *ucs; - int i; - - gigaset_blockdriver(driver); /* => probe will fail - * => no gigaset_start any more - */ - - /* stop all connected devices */ - for (i = 0; i < driver->minors; i++) { - if (gigaset_shutdown(driver->cs + i) < 0) - continue; /* no device */ - /* from now on, no isdn callback should be possible */ - - /* close all still open channels */ - ucs = driver->cs[i].hw.bas; - if (ucs->basstate & BS_B1OPEN) { - gig_dbg(DEBUG_INIT, "closing B1 channel"); - usb_control_msg(ucs->udev, - usb_sndctrlpipe(ucs->udev, 0), - HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, - 0, 0, NULL, 0, BAS_TIMEOUT); - } - if (ucs->basstate & BS_B2OPEN) { - gig_dbg(DEBUG_INIT, "closing B2 channel"); - usb_control_msg(ucs->udev, - usb_sndctrlpipe(ucs->udev, 0), - HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, - 0, 0, NULL, 0, BAS_TIMEOUT); - } - if (ucs->basstate & BS_ATOPEN) { - gig_dbg(DEBUG_INIT, "closing AT channel"); - usb_control_msg(ucs->udev, - usb_sndctrlpipe(ucs->udev, 0), - HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, - 0, 0, NULL, 0, BAS_TIMEOUT); - } - ucs->basstate = 0; - } - - /* deregister this driver with the USB subsystem */ - usb_deregister(&gigaset_usb_driver); - /* this will call the disconnect-callback */ - /* from now on, no disconnect/probe callback should be running */ - - gigaset_freedriver(driver); - driver = NULL; -} - - -module_init(bas_gigaset_init); -module_exit(bas_gigaset_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c deleted file mode 100644 index 83d7dd48c61d..000000000000 --- a/drivers/isdn/gigaset/capi.c +++ /dev/null @@ -1,2517 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Kernel CAPI interface for the Gigaset driver - * - * Copyright (c) 2009 by Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * ===================================================================== - */ - -#include "gigaset.h" -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/ratelimit.h> -#include <linux/isdn/capilli.h> -#include <linux/isdn/capicmd.h> -#include <linux/isdn/capiutil.h> -#include <linux/export.h> - -/* missing from kernelcapi.h */ -#define CapiNcpiNotSupportedByProtocol 0x0001 -#define CapiFlagsNotSupportedByProtocol 0x0002 -#define CapiAlertAlreadySent 0x0003 -#define CapiFacilitySpecificFunctionNotSupported 0x3011 - -/* missing from capicmd.h */ -#define CAPI_CONNECT_IND_BASELEN (CAPI_MSG_BASELEN + 4 + 2 + 8 * 1) -#define CAPI_CONNECT_ACTIVE_IND_BASELEN (CAPI_MSG_BASELEN + 4 + 3 * 1) -#define CAPI_CONNECT_B3_IND_BASELEN (CAPI_MSG_BASELEN + 4 + 1) -#define CAPI_CONNECT_B3_ACTIVE_IND_BASELEN (CAPI_MSG_BASELEN + 4 + 1) -#define CAPI_DATA_B3_REQ_LEN64 (CAPI_MSG_BASELEN + 4 + 4 + 2 + 2 + 2 + 8) -#define CAPI_DATA_B3_CONF_LEN (CAPI_MSG_BASELEN + 4 + 2 + 2) -#define CAPI_DISCONNECT_IND_LEN (CAPI_MSG_BASELEN + 4 + 2) -#define CAPI_DISCONNECT_B3_IND_BASELEN (CAPI_MSG_BASELEN + 4 + 2 + 1) -#define CAPI_FACILITY_CONF_BASELEN (CAPI_MSG_BASELEN + 4 + 2 + 2 + 1) -/* most _CONF messages contain only Controller/PLCI/NCCI and Info parameters */ -#define CAPI_STDCONF_LEN (CAPI_MSG_BASELEN + 4 + 2) - -#define CAPI_FACILITY_HANDSET 0x0000 -#define CAPI_FACILITY_DTMF 0x0001 -#define CAPI_FACILITY_V42BIS 0x0002 -#define CAPI_FACILITY_SUPPSVC 0x0003 -#define CAPI_FACILITY_WAKEUP 0x0004 -#define CAPI_FACILITY_LI 0x0005 - -#define CAPI_SUPPSVC_GETSUPPORTED 0x0000 -#define CAPI_SUPPSVC_LISTEN 0x0001 - -/* missing from capiutil.h */ -#define CAPIMSG_PLCI_PART(m) CAPIMSG_U8(m, 9) -#define CAPIMSG_NCCI_PART(m) CAPIMSG_U16(m, 10) -#define CAPIMSG_HANDLE_REQ(m) CAPIMSG_U16(m, 18) /* DATA_B3_REQ/_IND only! */ -#define CAPIMSG_FLAGS(m) CAPIMSG_U16(m, 20) -#define CAPIMSG_SETCONTROLLER(m, contr) capimsg_setu8(m, 8, contr) -#define CAPIMSG_SETPLCI_PART(m, plci) capimsg_setu8(m, 9, plci) -#define CAPIMSG_SETNCCI_PART(m, ncci) capimsg_setu16(m, 10, ncci) -#define CAPIMSG_SETFLAGS(m, flags) capimsg_setu16(m, 20, flags) - -/* parameters with differing location in DATA_B3_CONF/_RESP: */ -#define CAPIMSG_SETHANDLE_CONF(m, handle) capimsg_setu16(m, 12, handle) -#define CAPIMSG_SETINFO_CONF(m, info) capimsg_setu16(m, 14, info) - -/* Flags (DATA_B3_REQ/_IND) */ -#define CAPI_FLAGS_DELIVERY_CONFIRMATION 0x04 -#define CAPI_FLAGS_RESERVED (~0x1f) - -/* buffer sizes */ -#define MAX_BC_OCTETS 11 -#define MAX_HLC_OCTETS 3 -#define MAX_NUMBER_DIGITS 20 -#define MAX_FMT_IE_LEN 20 - -/* values for bcs->apconnstate */ -#define APCONN_NONE 0 /* inactive/listening */ -#define APCONN_SETUP 1 /* connecting */ -#define APCONN_ACTIVE 2 /* B channel up */ - -/* registered application data structure */ -struct gigaset_capi_appl { - struct list_head ctrlist; - struct gigaset_capi_appl *bcnext; - u16 id; - struct capi_register_params rp; - u16 nextMessageNumber; - u32 listenInfoMask; - u32 listenCIPmask; -}; - -/* CAPI specific controller data structure */ -struct gigaset_capi_ctr { - struct capi_ctr ctr; - struct list_head appls; - struct sk_buff_head sendqueue; - atomic_t sendqlen; - /* two _cmsg structures possibly used concurrently: */ - _cmsg hcmsg; /* for message composition triggered from hardware */ - _cmsg acmsg; /* for dissection of messages sent from application */ - u8 bc_buf[MAX_BC_OCTETS + 1]; - u8 hlc_buf[MAX_HLC_OCTETS + 1]; - u8 cgpty_buf[MAX_NUMBER_DIGITS + 3]; - u8 cdpty_buf[MAX_NUMBER_DIGITS + 2]; -}; - -/* CIP Value table (from CAPI 2.0 standard, ch. 6.1) */ -static struct { - u8 *bc; - u8 *hlc; -} cip2bchlc[] = { - [1] = { "8090A3", NULL }, /* Speech (A-law) */ - [2] = { "8890", NULL }, /* Unrestricted digital information */ - [3] = { "8990", NULL }, /* Restricted digital information */ - [4] = { "9090A3", NULL }, /* 3,1 kHz audio (A-law) */ - [5] = { "9190", NULL }, /* 7 kHz audio */ - [6] = { "9890", NULL }, /* Video */ - [7] = { "88C0C6E6", NULL }, /* Packet mode */ - [8] = { "8890218F", NULL }, /* 56 kbit/s rate adaptation */ - [9] = { "9190A5", NULL }, /* Unrestricted digital information - * with tones/announcements */ - [16] = { "8090A3", "9181" }, /* Telephony */ - [17] = { "9090A3", "9184" }, /* Group 2/3 facsimile */ - [18] = { "8890", "91A1" }, /* Group 4 facsimile Class 1 */ - [19] = { "8890", "91A4" }, /* Teletex service basic and mixed mode - * and Group 4 facsimile service - * Classes II and III */ - [20] = { "8890", "91A8" }, /* Teletex service basic and - * processable mode */ - [21] = { "8890", "91B1" }, /* Teletex service basic mode */ - [22] = { "8890", "91B2" }, /* International interworking for - * Videotex */ - [23] = { "8890", "91B5" }, /* Telex */ - [24] = { "8890", "91B8" }, /* Message Handling Systems - * in accordance with X.400 */ - [25] = { "8890", "91C1" }, /* OSI application - * in accordance with X.200 */ - [26] = { "9190A5", "9181" }, /* 7 kHz telephony */ - [27] = { "9190A5", "916001" }, /* Video telephony, first connection */ - [28] = { "8890", "916002" }, /* Video telephony, second connection */ -}; - -/* - * helper functions - * ================ - */ - -/* - * emit unsupported parameter warning - */ -static inline void ignore_cstruct_param(struct cardstate *cs, _cstruct param, - char *msgname, char *paramname) -{ - if (param && *param) - dev_warn(cs->dev, "%s: ignoring unsupported parameter: %s\n", - msgname, paramname); -} - -/* - * convert an IE from Gigaset hex string to ETSI binary representation - * including length byte - * return value: result length, -1 on error - */ -static int encode_ie(char *in, u8 *out, int maxlen) -{ - int l = 0; - while (*in) { - if (!isxdigit(in[0]) || !isxdigit(in[1]) || l >= maxlen) - return -1; - out[++l] = (hex_to_bin(in[0]) << 4) + hex_to_bin(in[1]); - in += 2; - } - out[0] = l; - return l; -} - -/* - * convert an IE from ETSI binary representation including length byte - * to Gigaset hex string - */ -static void decode_ie(u8 *in, char *out) -{ - int i = *in; - while (i-- > 0) { - /* ToDo: conversion to upper case necessary? */ - *out++ = toupper(hex_asc_hi(*++in)); - *out++ = toupper(hex_asc_lo(*in)); - } -} - -/* - * retrieve application data structure for an application ID - */ -static inline struct gigaset_capi_appl * -get_appl(struct gigaset_capi_ctr *iif, u16 appl) -{ - struct gigaset_capi_appl *ap; - - list_for_each_entry(ap, &iif->appls, ctrlist) - if (ap->id == appl) - return ap; - return NULL; -} - -/* - * dump CAPI message to kernel messages for debugging - */ -static inline void dump_cmsg(enum debuglevel level, const char *tag, _cmsg *p) -{ -#ifdef CONFIG_GIGASET_DEBUG - /* dump at most 20 messages in 20 secs */ - static DEFINE_RATELIMIT_STATE(msg_dump_ratelimit, 20 * HZ, 20); - _cdebbuf *cdb; - - if (!(gigaset_debuglevel & level)) - return; - if (!___ratelimit(&msg_dump_ratelimit, tag)) - return; - - cdb = capi_cmsg2str(p); - if (cdb) { - gig_dbg(level, "%s: [%d] %s", tag, p->ApplId, cdb->buf); - cdebbuf_free(cdb); - } else { - gig_dbg(level, "%s: [%d] %s", tag, p->ApplId, - capi_cmd2str(p->Command, p->Subcommand)); - } -#endif -} - -static inline void dump_rawmsg(enum debuglevel level, const char *tag, - unsigned char *data) -{ -#ifdef CONFIG_GIGASET_DEBUG - char *dbgline; - int i, l; - - if (!(gigaset_debuglevel & level)) - return; - - l = CAPIMSG_LEN(data); - if (l < 12) { - gig_dbg(level, "%s: ??? LEN=%04d", tag, l); - return; - } - gig_dbg(level, "%s: 0x%02x:0x%02x: ID=%03d #0x%04x LEN=%04d NCCI=0x%x", - tag, CAPIMSG_COMMAND(data), CAPIMSG_SUBCOMMAND(data), - CAPIMSG_APPID(data), CAPIMSG_MSGID(data), l, - CAPIMSG_CONTROL(data)); - l -= 12; - if (l <= 0) - return; - if (l > 64) - l = 64; /* arbitrary limit */ - dbgline = kmalloc_array(3, l, GFP_ATOMIC); - if (!dbgline) - return; - for (i = 0; i < l; i++) { - dbgline[3 * i] = hex_asc_hi(data[12 + i]); - dbgline[3 * i + 1] = hex_asc_lo(data[12 + i]); - dbgline[3 * i + 2] = ' '; - } - dbgline[3 * l - 1] = '\0'; - gig_dbg(level, " %s", dbgline); - kfree(dbgline); - if (CAPIMSG_COMMAND(data) == CAPI_DATA_B3 && - (CAPIMSG_SUBCOMMAND(data) == CAPI_REQ || - CAPIMSG_SUBCOMMAND(data) == CAPI_IND)) { - l = CAPIMSG_DATALEN(data); - gig_dbg(level, " DataLength=%d", l); - if (l <= 0 || !(gigaset_debuglevel & DEBUG_LLDATA)) - return; - if (l > 64) - l = 64; /* arbitrary limit */ - dbgline = kmalloc_array(3, l, GFP_ATOMIC); - if (!dbgline) - return; - data += CAPIMSG_LEN(data); - for (i = 0; i < l; i++) { - dbgline[3 * i] = hex_asc_hi(data[i]); - dbgline[3 * i + 1] = hex_asc_lo(data[i]); - dbgline[3 * i + 2] = ' '; - } - dbgline[3 * l - 1] = '\0'; - gig_dbg(level, " %s", dbgline); - kfree(dbgline); - } -#endif -} - -/* - * format CAPI IE as string - */ - -#ifdef CONFIG_GIGASET_DEBUG -static const char *format_ie(const char *ie) -{ - static char result[3 * MAX_FMT_IE_LEN]; - int len, count; - char *pout = result; - - if (!ie) - return "NULL"; - - count = len = ie[0]; - if (count > MAX_FMT_IE_LEN) - count = MAX_FMT_IE_LEN - 1; - while (count--) { - *pout++ = hex_asc_hi(*++ie); - *pout++ = hex_asc_lo(*ie); - *pout++ = ' '; - } - if (len > MAX_FMT_IE_LEN) { - *pout++ = '.'; - *pout++ = '.'; - *pout++ = '.'; - } - *--pout = 0; - return result; -} -#endif - -/* - * emit DATA_B3_CONF message - */ -static void send_data_b3_conf(struct cardstate *cs, struct capi_ctr *ctr, - u16 appl, u16 msgid, int channel, - u16 handle, u16 info) -{ - struct sk_buff *cskb; - u8 *msg; - - cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); - if (!cskb) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return; - } - /* frequent message, avoid _cmsg overhead */ - msg = __skb_put(cskb, CAPI_DATA_B3_CONF_LEN); - CAPIMSG_SETLEN(msg, CAPI_DATA_B3_CONF_LEN); - CAPIMSG_SETAPPID(msg, appl); - CAPIMSG_SETCOMMAND(msg, CAPI_DATA_B3); - CAPIMSG_SETSUBCOMMAND(msg, CAPI_CONF); - CAPIMSG_SETMSGID(msg, msgid); - CAPIMSG_SETCONTROLLER(msg, ctr->cnr); - CAPIMSG_SETPLCI_PART(msg, channel); - CAPIMSG_SETNCCI_PART(msg, 1); - CAPIMSG_SETHANDLE_CONF(msg, handle); - CAPIMSG_SETINFO_CONF(msg, info); - - /* emit message */ - dump_rawmsg(DEBUG_MCMD, __func__, msg); - capi_ctr_handle_message(ctr, appl, cskb); -} - - -/* - * driver interface functions - * ========================== - */ - -/** - * gigaset_skb_sent() - acknowledge transmission of outgoing skb - * @bcs: B channel descriptor structure. - * @skb: sent data. - * - * Called by hardware module {bas,ser,usb}_gigaset when the data in a - * skb has been successfully sent, for signalling completion to the LL. - */ -void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) -{ - struct cardstate *cs = bcs->cs; - struct gigaset_capi_ctr *iif = cs->iif; - struct gigaset_capi_appl *ap = bcs->ap; - unsigned char *req = skb_mac_header(dskb); - u16 flags; - - /* update statistics */ - ++bcs->trans_up; - - if (!ap) { - gig_dbg(DEBUG_MCMD, "%s: application gone", __func__); - return; - } - - /* don't send further B3 messages if disconnected */ - if (bcs->apconnstate < APCONN_ACTIVE) { - gig_dbg(DEBUG_MCMD, "%s: disconnected", __func__); - return; - } - - /* - * send DATA_B3_CONF if "delivery confirmation" bit was set in request; - * otherwise it has already been sent by do_data_b3_req() - */ - flags = CAPIMSG_FLAGS(req); - if (flags & CAPI_FLAGS_DELIVERY_CONFIRMATION) - send_data_b3_conf(cs, &iif->ctr, ap->id, CAPIMSG_MSGID(req), - bcs->channel + 1, CAPIMSG_HANDLE_REQ(req), - (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) ? - CapiFlagsNotSupportedByProtocol : - CAPI_NOERROR); -} -EXPORT_SYMBOL_GPL(gigaset_skb_sent); - -/** - * gigaset_skb_rcvd() - pass received skb to LL - * @bcs: B channel descriptor structure. - * @skb: received data. - * - * Called by hardware module {bas,ser,usb}_gigaset when user data has - * been successfully received, for passing to the LL. - * Warning: skb must not be accessed anymore! - */ -void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb) -{ - struct cardstate *cs = bcs->cs; - struct gigaset_capi_ctr *iif = cs->iif; - struct gigaset_capi_appl *ap = bcs->ap; - int len = skb->len; - - /* update statistics */ - bcs->trans_down++; - - if (!ap) { - gig_dbg(DEBUG_MCMD, "%s: application gone", __func__); - dev_kfree_skb_any(skb); - return; - } - - /* don't send further B3 messages if disconnected */ - if (bcs->apconnstate < APCONN_ACTIVE) { - gig_dbg(DEBUG_MCMD, "%s: disconnected", __func__); - dev_kfree_skb_any(skb); - return; - } - - /* - * prepend DATA_B3_IND message to payload - * Parameters: NCCI = 1, all others 0/unused - * frequent message, avoid _cmsg overhead - */ - skb_push(skb, CAPI_DATA_B3_REQ_LEN); - CAPIMSG_SETLEN(skb->data, CAPI_DATA_B3_REQ_LEN); - CAPIMSG_SETAPPID(skb->data, ap->id); - CAPIMSG_SETCOMMAND(skb->data, CAPI_DATA_B3); - CAPIMSG_SETSUBCOMMAND(skb->data, CAPI_IND); - CAPIMSG_SETMSGID(skb->data, ap->nextMessageNumber++); - CAPIMSG_SETCONTROLLER(skb->data, iif->ctr.cnr); - CAPIMSG_SETPLCI_PART(skb->data, bcs->channel + 1); - CAPIMSG_SETNCCI_PART(skb->data, 1); - /* Data parameter not used */ - CAPIMSG_SETDATALEN(skb->data, len); - /* Data handle parameter not used */ - CAPIMSG_SETFLAGS(skb->data, 0); - /* Data64 parameter not present */ - - /* emit message */ - dump_rawmsg(DEBUG_MCMD, __func__, skb->data); - capi_ctr_handle_message(&iif->ctr, ap->id, skb); -} -EXPORT_SYMBOL_GPL(gigaset_skb_rcvd); - -/** - * gigaset_isdn_rcv_err() - signal receive error - * @bcs: B channel descriptor structure. - * - * Called by hardware module {bas,ser,usb}_gigaset when a receive error - * has occurred, for signalling to the LL. - */ -void gigaset_isdn_rcv_err(struct bc_state *bcs) -{ - /* if currently ignoring packets, just count down */ - if (bcs->ignore) { - bcs->ignore--; - return; - } - - /* update statistics */ - bcs->corrupted++; - - /* ToDo: signal error -> LL */ -} -EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err); - -/** - * gigaset_isdn_icall() - signal incoming call - * @at_state: connection state structure. - * - * Called by main module at tasklet level to notify the LL that an incoming - * call has been received. @at_state contains the parameters of the call. - * - * Return value: call disposition (ICALL_*) - */ -int gigaset_isdn_icall(struct at_state_t *at_state) -{ - struct cardstate *cs = at_state->cs; - struct bc_state *bcs = at_state->bcs; - struct gigaset_capi_ctr *iif = cs->iif; - struct gigaset_capi_appl *ap; - u32 actCIPmask; - struct sk_buff *skb; - unsigned int msgsize; - unsigned long flags; - int i; - - /* - * ToDo: signal calls without a free B channel, too - * (requires a u8 handle for the at_state structure that can - * be stored in the PLCI and used in the CONNECT_RESP message - * handler to retrieve it) - */ - if (!bcs) - return ICALL_IGNORE; - - /* prepare CONNECT_IND message, using B channel number as PLCI */ - capi_cmsg_header(&iif->hcmsg, 0, CAPI_CONNECT, CAPI_IND, 0, - iif->ctr.cnr | ((bcs->channel + 1) << 8)); - - /* minimum size, all structs empty */ - msgsize = CAPI_CONNECT_IND_BASELEN; - - /* Bearer Capability (mandatory) */ - if (at_state->str_var[STR_ZBC]) { - /* pass on BC from Gigaset */ - if (encode_ie(at_state->str_var[STR_ZBC], iif->bc_buf, - MAX_BC_OCTETS) < 0) { - dev_warn(cs->dev, "RING ignored - bad BC %s\n", - at_state->str_var[STR_ZBC]); - return ICALL_IGNORE; - } - - /* look up corresponding CIP value */ - iif->hcmsg.CIPValue = 0; /* default if nothing found */ - for (i = 0; i < ARRAY_SIZE(cip2bchlc); i++) - if (cip2bchlc[i].bc != NULL && - cip2bchlc[i].hlc == NULL && - !strcmp(cip2bchlc[i].bc, - at_state->str_var[STR_ZBC])) { - iif->hcmsg.CIPValue = i; - break; - } - } else { - /* no BC (internal call): assume CIP 1 (speech, A-law) */ - iif->hcmsg.CIPValue = 1; - encode_ie(cip2bchlc[1].bc, iif->bc_buf, MAX_BC_OCTETS); - } - iif->hcmsg.BC = iif->bc_buf; - msgsize += iif->hcmsg.BC[0]; - - /* High Layer Compatibility (optional) */ - if (at_state->str_var[STR_ZHLC]) { - /* pass on HLC from Gigaset */ - if (encode_ie(at_state->str_var[STR_ZHLC], iif->hlc_buf, - MAX_HLC_OCTETS) < 0) { - dev_warn(cs->dev, "RING ignored - bad HLC %s\n", - at_state->str_var[STR_ZHLC]); - return ICALL_IGNORE; - } - iif->hcmsg.HLC = iif->hlc_buf; - msgsize += iif->hcmsg.HLC[0]; - - /* look up corresponding CIP value */ - /* keep BC based CIP value if none found */ - if (at_state->str_var[STR_ZBC]) - for (i = 0; i < ARRAY_SIZE(cip2bchlc); i++) - if (cip2bchlc[i].hlc != NULL && - !strcmp(cip2bchlc[i].hlc, - at_state->str_var[STR_ZHLC]) && - !strcmp(cip2bchlc[i].bc, - at_state->str_var[STR_ZBC])) { - iif->hcmsg.CIPValue = i; - break; - } - } - - /* Called Party Number (optional) */ - if (at_state->str_var[STR_ZCPN]) { - i = strlen(at_state->str_var[STR_ZCPN]); - if (i > MAX_NUMBER_DIGITS) { - dev_warn(cs->dev, "RING ignored - bad number %s\n", - at_state->str_var[STR_ZBC]); - return ICALL_IGNORE; - } - iif->cdpty_buf[0] = i + 1; - iif->cdpty_buf[1] = 0x80; /* type / numbering plan unknown */ - memcpy(iif->cdpty_buf + 2, at_state->str_var[STR_ZCPN], i); - iif->hcmsg.CalledPartyNumber = iif->cdpty_buf; - msgsize += iif->hcmsg.CalledPartyNumber[0]; - } - - /* Calling Party Number (optional) */ - if (at_state->str_var[STR_NMBR]) { - i = strlen(at_state->str_var[STR_NMBR]); - if (i > MAX_NUMBER_DIGITS) { - dev_warn(cs->dev, "RING ignored - bad number %s\n", - at_state->str_var[STR_ZBC]); - return ICALL_IGNORE; - } - iif->cgpty_buf[0] = i + 2; - iif->cgpty_buf[1] = 0x00; /* type / numbering plan unknown */ - iif->cgpty_buf[2] = 0x80; /* pres. allowed, not screened */ - memcpy(iif->cgpty_buf + 3, at_state->str_var[STR_NMBR], i); - iif->hcmsg.CallingPartyNumber = iif->cgpty_buf; - msgsize += iif->hcmsg.CallingPartyNumber[0]; - } - - /* remaining parameters (not supported, always left NULL): - * - CalledPartySubaddress - * - CallingPartySubaddress - * - AdditionalInfo - * - BChannelinformation - * - Keypadfacility - * - Useruserdata - * - Facilitydataarray - */ - - gig_dbg(DEBUG_CMD, "icall: PLCI %x CIP %d BC %s", - iif->hcmsg.adr.adrPLCI, iif->hcmsg.CIPValue, - format_ie(iif->hcmsg.BC)); - gig_dbg(DEBUG_CMD, "icall: HLC %s", - format_ie(iif->hcmsg.HLC)); - gig_dbg(DEBUG_CMD, "icall: CgPty %s", - format_ie(iif->hcmsg.CallingPartyNumber)); - gig_dbg(DEBUG_CMD, "icall: CdPty %s", - format_ie(iif->hcmsg.CalledPartyNumber)); - - /* scan application list for matching listeners */ - spin_lock_irqsave(&bcs->aplock, flags); - if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) { - dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", - __func__, bcs->ap, bcs->apconnstate); - bcs->ap = NULL; - bcs->apconnstate = APCONN_NONE; - } - spin_unlock_irqrestore(&bcs->aplock, flags); - actCIPmask = 1 | (1 << iif->hcmsg.CIPValue); - list_for_each_entry(ap, &iif->appls, ctrlist) - if (actCIPmask & ap->listenCIPmask) { - /* build CONNECT_IND message for this application */ - iif->hcmsg.ApplId = ap->id; - iif->hcmsg.Messagenumber = ap->nextMessageNumber++; - - skb = alloc_skb(msgsize, GFP_ATOMIC); - if (!skb) { - dev_err(cs->dev, "%s: out of memory\n", - __func__); - break; - } - if (capi_cmsg2message(&iif->hcmsg, - __skb_put(skb, msgsize))) { - dev_err(cs->dev, "%s: message parser failure\n", - __func__); - dev_kfree_skb_any(skb); - break; - } - dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); - - /* add to listeners on this B channel, update state */ - spin_lock_irqsave(&bcs->aplock, flags); - ap->bcnext = bcs->ap; - bcs->ap = ap; - bcs->chstate |= CHS_NOTIFY_LL; - bcs->apconnstate = APCONN_SETUP; - spin_unlock_irqrestore(&bcs->aplock, flags); - - /* emit message */ - capi_ctr_handle_message(&iif->ctr, ap->id, skb); - } - - /* - * Return "accept" if any listeners. - * Gigaset will send ALERTING. - * There doesn't seem to be a way to avoid this. - */ - return bcs->ap ? ICALL_ACCEPT : ICALL_IGNORE; -} - -/* - * send a DISCONNECT_IND message to an application - * does not sleep, clobbers the controller's hcmsg structure - */ -static void send_disconnect_ind(struct bc_state *bcs, - struct gigaset_capi_appl *ap, u16 reason) -{ - struct cardstate *cs = bcs->cs; - struct gigaset_capi_ctr *iif = cs->iif; - struct sk_buff *skb; - - if (bcs->apconnstate == APCONN_NONE) - return; - - capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND, - ap->nextMessageNumber++, - iif->ctr.cnr | ((bcs->channel + 1) << 8)); - iif->hcmsg.Reason = reason; - skb = alloc_skb(CAPI_DISCONNECT_IND_LEN, GFP_ATOMIC); - if (!skb) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return; - } - if (capi_cmsg2message(&iif->hcmsg, - __skb_put(skb, CAPI_DISCONNECT_IND_LEN))) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); - capi_ctr_handle_message(&iif->ctr, ap->id, skb); -} - -/* - * send a DISCONNECT_B3_IND message to an application - * Parameters: NCCI = 1, NCPI empty, Reason_B3 = 0 - * does not sleep, clobbers the controller's hcmsg structure - */ -static void send_disconnect_b3_ind(struct bc_state *bcs, - struct gigaset_capi_appl *ap) -{ - struct cardstate *cs = bcs->cs; - struct gigaset_capi_ctr *iif = cs->iif; - struct sk_buff *skb; - - /* nothing to do if no logical connection active */ - if (bcs->apconnstate < APCONN_ACTIVE) - return; - bcs->apconnstate = APCONN_SETUP; - - capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND, - ap->nextMessageNumber++, - iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); - skb = alloc_skb(CAPI_DISCONNECT_B3_IND_BASELEN, GFP_ATOMIC); - if (!skb) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return; - } - if (capi_cmsg2message(&iif->hcmsg, - __skb_put(skb, CAPI_DISCONNECT_B3_IND_BASELEN))) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); - capi_ctr_handle_message(&iif->ctr, ap->id, skb); -} - -/** - * gigaset_isdn_connD() - signal D channel connect - * @bcs: B channel descriptor structure. - * - * Called by main module at tasklet level to notify the LL that the D channel - * connection has been established. - */ -void gigaset_isdn_connD(struct bc_state *bcs) -{ - struct cardstate *cs = bcs->cs; - struct gigaset_capi_ctr *iif = cs->iif; - struct gigaset_capi_appl *ap; - struct sk_buff *skb; - unsigned int msgsize; - unsigned long flags; - - spin_lock_irqsave(&bcs->aplock, flags); - ap = bcs->ap; - if (!ap) { - spin_unlock_irqrestore(&bcs->aplock, flags); - gig_dbg(DEBUG_CMD, "%s: application gone", __func__); - return; - } - if (bcs->apconnstate == APCONN_NONE) { - spin_unlock_irqrestore(&bcs->aplock, flags); - dev_warn(cs->dev, "%s: application %u not connected\n", - __func__, ap->id); - return; - } - spin_unlock_irqrestore(&bcs->aplock, flags); - while (ap->bcnext) { - /* this should never happen */ - dev_warn(cs->dev, "%s: dropping extra application %u\n", - __func__, ap->bcnext->id); - send_disconnect_ind(bcs, ap->bcnext, - CapiCallGivenToOtherApplication); - ap->bcnext = ap->bcnext->bcnext; - } - - /* prepare CONNECT_ACTIVE_IND message - * Note: LLC not supported by device - */ - capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_CONNECT_ACTIVE, CAPI_IND, - ap->nextMessageNumber++, - iif->ctr.cnr | ((bcs->channel + 1) << 8)); - - /* minimum size, all structs empty */ - msgsize = CAPI_CONNECT_ACTIVE_IND_BASELEN; - - /* ToDo: set parameter: Connected number - * (requires ev-layer state machine extension to collect - * ZCON device reply) - */ - - /* build and emit CONNECT_ACTIVE_IND message */ - skb = alloc_skb(msgsize, GFP_ATOMIC); - if (!skb) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return; - } - if (capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize))) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); - capi_ctr_handle_message(&iif->ctr, ap->id, skb); -} - -/** - * gigaset_isdn_hupD() - signal D channel hangup - * @bcs: B channel descriptor structure. - * - * Called by main module at tasklet level to notify the LL that the D channel - * connection has been shut down. - */ -void gigaset_isdn_hupD(struct bc_state *bcs) -{ - struct gigaset_capi_appl *ap; - unsigned long flags; - - /* - * ToDo: pass on reason code reported by device - * (requires ev-layer state machine extension to collect - * ZCAU device reply) - */ - spin_lock_irqsave(&bcs->aplock, flags); - while (bcs->ap != NULL) { - ap = bcs->ap; - bcs->ap = ap->bcnext; - spin_unlock_irqrestore(&bcs->aplock, flags); - send_disconnect_b3_ind(bcs, ap); - send_disconnect_ind(bcs, ap, 0); - spin_lock_irqsave(&bcs->aplock, flags); - } - bcs->apconnstate = APCONN_NONE; - spin_unlock_irqrestore(&bcs->aplock, flags); -} - -/** - * gigaset_isdn_connB() - signal B channel connect - * @bcs: B channel descriptor structure. - * - * Called by main module at tasklet level to notify the LL that the B channel - * connection has been established. - */ -void gigaset_isdn_connB(struct bc_state *bcs) -{ - struct cardstate *cs = bcs->cs; - struct gigaset_capi_ctr *iif = cs->iif; - struct gigaset_capi_appl *ap; - struct sk_buff *skb; - unsigned long flags; - unsigned int msgsize; - u8 command; - - spin_lock_irqsave(&bcs->aplock, flags); - ap = bcs->ap; - if (!ap) { - spin_unlock_irqrestore(&bcs->aplock, flags); - gig_dbg(DEBUG_CMD, "%s: application gone", __func__); - return; - } - if (!bcs->apconnstate) { - spin_unlock_irqrestore(&bcs->aplock, flags); - dev_warn(cs->dev, "%s: application %u not connected\n", - __func__, ap->id); - return; - } - - /* - * emit CONNECT_B3_ACTIVE_IND if we already got CONNECT_B3_REQ; - * otherwise we have to emit CONNECT_B3_IND first, and follow up with - * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP - * Parameters in both cases always: NCCI = 1, NCPI empty - */ - if (bcs->apconnstate >= APCONN_ACTIVE) { - command = CAPI_CONNECT_B3_ACTIVE; - msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN; - } else { - command = CAPI_CONNECT_B3; - msgsize = CAPI_CONNECT_B3_IND_BASELEN; - } - bcs->apconnstate = APCONN_ACTIVE; - - spin_unlock_irqrestore(&bcs->aplock, flags); - - while (ap->bcnext) { - /* this should never happen */ - dev_warn(cs->dev, "%s: dropping extra application %u\n", - __func__, ap->bcnext->id); - send_disconnect_ind(bcs, ap->bcnext, - CapiCallGivenToOtherApplication); - ap->bcnext = ap->bcnext->bcnext; - } - - capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND, - ap->nextMessageNumber++, - iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); - skb = alloc_skb(msgsize, GFP_ATOMIC); - if (!skb) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return; - } - if (capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize))) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); - capi_ctr_handle_message(&iif->ctr, ap->id, skb); -} - -/** - * gigaset_isdn_hupB() - signal B channel hangup - * @bcs: B channel descriptor structure. - * - * Called by main module to notify the LL that the B channel connection has - * been shut down. - */ -void gigaset_isdn_hupB(struct bc_state *bcs) -{ - struct gigaset_capi_appl *ap = bcs->ap; - - /* ToDo: assure order of DISCONNECT_B3_IND and DISCONNECT_IND ? */ - - if (!ap) { - gig_dbg(DEBUG_CMD, "%s: application gone", __func__); - return; - } - - send_disconnect_b3_ind(bcs, ap); -} - -/** - * gigaset_isdn_start() - signal device availability - * @cs: device descriptor structure. - * - * Called by main module to notify the LL that the device is available for - * use. - */ -void gigaset_isdn_start(struct cardstate *cs) -{ - struct gigaset_capi_ctr *iif = cs->iif; - - /* fill profile data: manufacturer name */ - strcpy(iif->ctr.manu, "Siemens"); - /* CAPI and device version */ - iif->ctr.version.majorversion = 2; /* CAPI 2.0 */ - iif->ctr.version.minorversion = 0; - /* ToDo: check/assert cs->gotfwver? */ - iif->ctr.version.majormanuversion = cs->fwver[0]; - iif->ctr.version.minormanuversion = cs->fwver[1]; - /* number of B channels supported */ - iif->ctr.profile.nbchannel = cs->channels; - /* global options: internal controller, supplementary services */ - iif->ctr.profile.goptions = 0x11; - /* B1 protocols: 64 kbit/s HDLC or transparent */ - iif->ctr.profile.support1 = 0x03; - /* B2 protocols: transparent only */ - /* ToDo: X.75 SLP ? */ - iif->ctr.profile.support2 = 0x02; - /* B3 protocols: transparent only */ - iif->ctr.profile.support3 = 0x01; - /* no serial number */ - strcpy(iif->ctr.serial, "0"); - capi_ctr_ready(&iif->ctr); -} - -/** - * gigaset_isdn_stop() - signal device unavailability - * @cs: device descriptor structure. - * - * Called by main module to notify the LL that the device is no longer - * available for use. - */ -void gigaset_isdn_stop(struct cardstate *cs) -{ - struct gigaset_capi_ctr *iif = cs->iif; - capi_ctr_down(&iif->ctr); -} - -/* - * kernel CAPI callback methods - * ============================ - */ - -/* - * register CAPI application - */ -static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl, - capi_register_params *rp) -{ - struct gigaset_capi_ctr *iif - = container_of(ctr, struct gigaset_capi_ctr, ctr); - struct cardstate *cs = ctr->driverdata; - struct gigaset_capi_appl *ap; - - gig_dbg(DEBUG_CMD, "%s [%u] l3cnt=%u blkcnt=%u blklen=%u", - __func__, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen); - - list_for_each_entry(ap, &iif->appls, ctrlist) - if (ap->id == appl) { - dev_notice(cs->dev, - "application %u already registered\n", appl); - return; - } - - ap = kzalloc(sizeof(*ap), GFP_KERNEL); - if (!ap) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return; - } - ap->id = appl; - ap->rp = *rp; - - list_add(&ap->ctrlist, &iif->appls); - dev_info(cs->dev, "application %u registered\n", ap->id); -} - -/* - * remove CAPI application from channel - * helper function to keep indentation levels down and stay in 80 columns - */ - -static inline void remove_appl_from_channel(struct bc_state *bcs, - struct gigaset_capi_appl *ap) -{ - struct cardstate *cs = bcs->cs; - struct gigaset_capi_appl *bcap; - unsigned long flags; - int prevconnstate; - - spin_lock_irqsave(&bcs->aplock, flags); - bcap = bcs->ap; - if (bcap == NULL) { - spin_unlock_irqrestore(&bcs->aplock, flags); - return; - } - - /* check first application on channel */ - if (bcap == ap) { - bcs->ap = ap->bcnext; - if (bcs->ap != NULL) { - spin_unlock_irqrestore(&bcs->aplock, flags); - return; - } - - /* none left, clear channel state */ - prevconnstate = bcs->apconnstate; - bcs->apconnstate = APCONN_NONE; - spin_unlock_irqrestore(&bcs->aplock, flags); - - if (prevconnstate == APCONN_ACTIVE) { - dev_notice(cs->dev, "%s: hanging up channel %u\n", - __func__, bcs->channel); - gigaset_add_event(cs, &bcs->at_state, - EV_HUP, NULL, 0, NULL); - gigaset_schedule_event(cs); - } - return; - } - - /* check remaining list */ - do { - if (bcap->bcnext == ap) { - bcap->bcnext = bcap->bcnext->bcnext; - spin_unlock_irqrestore(&bcs->aplock, flags); - return; - } - bcap = bcap->bcnext; - } while (bcap != NULL); - spin_unlock_irqrestore(&bcs->aplock, flags); -} - -/* - * release CAPI application - */ -static void gigaset_release_appl(struct capi_ctr *ctr, u16 appl) -{ - struct gigaset_capi_ctr *iif - = container_of(ctr, struct gigaset_capi_ctr, ctr); - struct cardstate *cs = iif->ctr.driverdata; - struct gigaset_capi_appl *ap, *tmp; - unsigned ch; - - gig_dbg(DEBUG_CMD, "%s [%u]", __func__, appl); - - list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist) - if (ap->id == appl) { - /* remove from any channels */ - for (ch = 0; ch < cs->channels; ch++) - remove_appl_from_channel(&cs->bcs[ch], ap); - - /* remove from registration list */ - list_del(&ap->ctrlist); - kfree(ap); - dev_info(cs->dev, "application %u released\n", appl); - } -} - -/* - * ===================================================================== - * outgoing CAPI message handler - * ===================================================================== - */ - -/* - * helper function: emit reply message with given Info value - */ -static void send_conf(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb, - u16 info) -{ - struct cardstate *cs = iif->ctr.driverdata; - - /* - * _CONF replies always only have NCCI and Info parameters - * so they'll fit into the _REQ message skb - */ - capi_cmsg_answer(&iif->acmsg); - iif->acmsg.Info = info; - if (capi_cmsg2message(&iif->acmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - __skb_trim(skb, CAPI_STDCONF_LEN); - dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); - capi_ctr_handle_message(&iif->ctr, ap->id, skb); -} - -/* - * process FACILITY_REQ message - */ -static void do_facility_req(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - _cmsg *cmsg = &iif->acmsg; - struct sk_buff *cskb; - u8 *pparam; - unsigned int msgsize = CAPI_FACILITY_CONF_BASELEN; - u16 function, info; - static u8 confparam[10]; /* max. 9 octets + length byte */ - - /* decode message */ - if (capi_message2cmsg(cmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, cmsg); - - /* - * Facility Request Parameter is not decoded by capi_message2cmsg() - * encoding depends on Facility Selector - */ - switch (cmsg->FacilitySelector) { - case CAPI_FACILITY_DTMF: /* ToDo */ - info = CapiFacilityNotSupported; - confparam[0] = 2; /* length */ - /* DTMF information: Unknown DTMF request */ - capimsg_setu16(confparam, 1, 2); - break; - - case CAPI_FACILITY_V42BIS: /* not supported */ - info = CapiFacilityNotSupported; - confparam[0] = 2; /* length */ - /* V.42 bis information: not available */ - capimsg_setu16(confparam, 1, 1); - break; - - case CAPI_FACILITY_SUPPSVC: - /* decode Function parameter */ - pparam = cmsg->FacilityRequestParameter; - if (pparam == NULL || pparam[0] < 2) { - dev_notice(cs->dev, "%s: %s missing\n", "FACILITY_REQ", - "Facility Request Parameter"); - send_conf(iif, ap, skb, CapiIllMessageParmCoding); - return; - } - function = CAPIMSG_U16(pparam, 1); - switch (function) { - case CAPI_SUPPSVC_GETSUPPORTED: - info = CapiSuccess; - /* Supplementary Service specific parameter */ - confparam[3] = 6; /* length */ - /* Supplementary services info: Success */ - capimsg_setu16(confparam, 4, CapiSuccess); - /* Supported Services: none */ - capimsg_setu32(confparam, 6, 0); - break; - case CAPI_SUPPSVC_LISTEN: - if (pparam[0] < 7 || pparam[3] < 4) { - dev_notice(cs->dev, "%s: %s missing\n", - "FACILITY_REQ", "Notification Mask"); - send_conf(iif, ap, skb, - CapiIllMessageParmCoding); - return; - } - if (CAPIMSG_U32(pparam, 4) != 0) { - dev_notice(cs->dev, - "%s: unsupported supplementary service notification mask 0x%x\n", - "FACILITY_REQ", CAPIMSG_U32(pparam, 4)); - info = CapiFacilitySpecificFunctionNotSupported; - confparam[3] = 2; /* length */ - capimsg_setu16(confparam, 4, - CapiSupplementaryServiceNotSupported); - break; - } - info = CapiSuccess; - confparam[3] = 2; /* length */ - capimsg_setu16(confparam, 4, CapiSuccess); - break; - - /* ToDo: add supported services */ - - default: - dev_notice(cs->dev, - "%s: unsupported supplementary service function 0x%04x\n", - "FACILITY_REQ", function); - info = CapiFacilitySpecificFunctionNotSupported; - /* Supplementary Service specific parameter */ - confparam[3] = 2; /* length */ - /* Supplementary services info: not supported */ - capimsg_setu16(confparam, 4, - CapiSupplementaryServiceNotSupported); - } - - /* Facility confirmation parameter */ - confparam[0] = confparam[3] + 3; /* total length */ - /* Function: copy from _REQ message */ - capimsg_setu16(confparam, 1, function); - /* Supplementary Service specific parameter already set above */ - break; - - case CAPI_FACILITY_WAKEUP: /* ToDo */ - info = CapiFacilityNotSupported; - confparam[0] = 2; /* length */ - /* Number of accepted awake request parameters: 0 */ - capimsg_setu16(confparam, 1, 0); - break; - - default: - info = CapiFacilityNotSupported; - confparam[0] = 0; /* empty struct */ - } - - /* send FACILITY_CONF with given Info and confirmation parameter */ - dev_kfree_skb_any(skb); - capi_cmsg_answer(cmsg); - cmsg->Info = info; - cmsg->FacilityConfirmationParameter = confparam; - msgsize += confparam[0]; /* length */ - cskb = alloc_skb(msgsize, GFP_ATOMIC); - if (!cskb) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return; - } - if (capi_cmsg2message(cmsg, __skb_put(cskb, msgsize))) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(cskb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, cmsg); - capi_ctr_handle_message(&iif->ctr, ap->id, cskb); -} - - -/* - * process LISTEN_REQ message - * just store the masks in the application data structure - */ -static void do_listen_req(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - - /* decode message */ - if (capi_message2cmsg(&iif->acmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); - - /* store listening parameters */ - ap->listenInfoMask = iif->acmsg.InfoMask; - ap->listenCIPmask = iif->acmsg.CIPmask; - send_conf(iif, ap, skb, CapiSuccess); -} - -/* - * process ALERT_REQ message - * nothing to do, Gigaset always alerts anyway - */ -static void do_alert_req(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - - /* decode message */ - if (capi_message2cmsg(&iif->acmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); - send_conf(iif, ap, skb, CapiAlertAlreadySent); -} - -/* - * process CONNECT_REQ message - * allocate a B channel, prepare dial commands, queue a DIAL event, - * emit CONNECT_CONF reply - */ -static void do_connect_req(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - _cmsg *cmsg = &iif->acmsg; - struct bc_state *bcs; - char **commands; - char *s; - u8 *pp; - unsigned long flags; - int i, l, lbc, lhlc; - u16 info; - - /* decode message */ - if (capi_message2cmsg(cmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, cmsg); - - /* get free B channel & construct PLCI */ - bcs = gigaset_get_free_channel(cs); - if (!bcs) { - dev_notice(cs->dev, "%s: no B channel available\n", - "CONNECT_REQ"); - send_conf(iif, ap, skb, CapiNoPlciAvailable); - return; - } - spin_lock_irqsave(&bcs->aplock, flags); - if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) - dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", - __func__, bcs->ap, bcs->apconnstate); - ap->bcnext = NULL; - bcs->ap = ap; - bcs->apconnstate = APCONN_SETUP; - spin_unlock_irqrestore(&bcs->aplock, flags); - - bcs->rx_bufsize = ap->rp.datablklen; - dev_kfree_skb(bcs->rx_skb); - gigaset_new_rx_skb(bcs); - cmsg->adr.adrPLCI |= (bcs->channel + 1) << 8; - - /* build command table */ - commands = kcalloc(AT_NUM, sizeof(*commands), GFP_KERNEL); - if (!commands) - goto oom; - - /* encode parameter: Called party number */ - pp = cmsg->CalledPartyNumber; - if (pp == NULL || *pp == 0) { - dev_notice(cs->dev, "%s: %s missing\n", - "CONNECT_REQ", "Called party number"); - info = CapiIllMessageParmCoding; - goto error; - } - l = *pp++; - /* check type of number/numbering plan byte */ - switch (*pp) { - case 0x80: /* unknown type / unknown numbering plan */ - case 0x81: /* unknown type / ISDN/Telephony numbering plan */ - break; - default: /* others: warn about potential misinterpretation */ - dev_notice(cs->dev, "%s: %s type/plan 0x%02x unsupported\n", - "CONNECT_REQ", "Called party number", *pp); - } - pp++; - l--; - /* translate "**" internal call prefix to CTP value */ - if (l >= 2 && pp[0] == '*' && pp[1] == '*') { - s = "^SCTP=0\r"; - pp += 2; - l -= 2; - } else { - s = "^SCTP=1\r"; - } - commands[AT_TYPE] = kstrdup(s, GFP_KERNEL); - if (!commands[AT_TYPE]) - goto oom; - commands[AT_DIAL] = kmalloc(l + 3, GFP_KERNEL); - if (!commands[AT_DIAL]) - goto oom; - snprintf(commands[AT_DIAL], l + 3, "D%.*s\r", l, pp); - - /* encode parameter: Calling party number */ - pp = cmsg->CallingPartyNumber; - if (pp != NULL && *pp > 0) { - l = *pp++; - - /* check type of number/numbering plan byte */ - /* ToDo: allow for/handle Ext=1? */ - switch (*pp) { - case 0x00: /* unknown type / unknown numbering plan */ - case 0x01: /* unknown type / ISDN/Telephony num. plan */ - break; - default: - dev_notice(cs->dev, - "%s: %s type/plan 0x%02x unsupported\n", - "CONNECT_REQ", "Calling party number", *pp); - } - pp++; - l--; - - /* check presentation indicator */ - if (!l) { - dev_notice(cs->dev, "%s: %s IE truncated\n", - "CONNECT_REQ", "Calling party number"); - info = CapiIllMessageParmCoding; - goto error; - } - switch (*pp & 0xfc) { /* ignore Screening indicator */ - case 0x80: /* Presentation allowed */ - s = "^SCLIP=1\r"; - break; - case 0xa0: /* Presentation restricted */ - s = "^SCLIP=0\r"; - break; - default: - dev_notice(cs->dev, "%s: invalid %s 0x%02x\n", - "CONNECT_REQ", - "Presentation/Screening indicator", - *pp); - s = "^SCLIP=1\r"; - } - commands[AT_CLIP] = kstrdup(s, GFP_KERNEL); - if (!commands[AT_CLIP]) - goto oom; - pp++; - l--; - - if (l) { - /* number */ - commands[AT_MSN] = kmalloc(l + 8, GFP_KERNEL); - if (!commands[AT_MSN]) - goto oom; - snprintf(commands[AT_MSN], l + 8, "^SMSN=%*s\r", l, pp); - } - } - - /* check parameter: CIP Value */ - if (cmsg->CIPValue >= ARRAY_SIZE(cip2bchlc) || - (cmsg->CIPValue > 0 && cip2bchlc[cmsg->CIPValue].bc == NULL)) { - dev_notice(cs->dev, "%s: unknown CIP value %d\n", - "CONNECT_REQ", cmsg->CIPValue); - info = CapiCipValueUnknown; - goto error; - } - - /* - * check/encode parameters: BC & HLC - * must be encoded together as device doesn't accept HLC separately - * explicit parameters override values derived from CIP - */ - - /* determine lengths */ - if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ - lbc = 2 * cmsg->BC[0]; - else if (cip2bchlc[cmsg->CIPValue].bc) /* BC derived from CIP */ - lbc = strlen(cip2bchlc[cmsg->CIPValue].bc); - else /* no BC */ - lbc = 0; - if (cmsg->HLC && cmsg->HLC[0]) /* HLC specified explicitly */ - lhlc = 2 * cmsg->HLC[0]; - else if (cip2bchlc[cmsg->CIPValue].hlc) /* HLC derived from CIP */ - lhlc = strlen(cip2bchlc[cmsg->CIPValue].hlc); - else /* no HLC */ - lhlc = 0; - - if (lbc) { - /* have BC: allocate and assemble command string */ - l = lbc + 7; /* "^SBC=" + value + "\r" + null byte */ - if (lhlc) - l += lhlc + 7; /* ";^SHLC=" + value */ - commands[AT_BC] = kmalloc(l, GFP_KERNEL); - if (!commands[AT_BC]) - goto oom; - strcpy(commands[AT_BC], "^SBC="); - if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ - decode_ie(cmsg->BC, commands[AT_BC] + 5); - else /* BC derived from CIP */ - strcpy(commands[AT_BC] + 5, - cip2bchlc[cmsg->CIPValue].bc); - if (lhlc) { - strcpy(commands[AT_BC] + lbc + 5, ";^SHLC="); - if (cmsg->HLC && cmsg->HLC[0]) - /* HLC specified explicitly */ - decode_ie(cmsg->HLC, - commands[AT_BC] + lbc + 12); - else /* HLC derived from CIP */ - strcpy(commands[AT_BC] + lbc + 12, - cip2bchlc[cmsg->CIPValue].hlc); - } - strcpy(commands[AT_BC] + l - 2, "\r"); - } else { - /* no BC */ - if (lhlc) { - dev_notice(cs->dev, "%s: cannot set HLC without BC\n", - "CONNECT_REQ"); - info = CapiIllMessageParmCoding; /* ? */ - goto error; - } - } - - /* check/encode parameter: B Protocol */ - if (cmsg->BProtocol == CAPI_DEFAULT) { - bcs->proto2 = L2_HDLC; - dev_warn(cs->dev, - "B2 Protocol X.75 SLP unsupported, using Transparent\n"); - } else { - switch (cmsg->B1protocol) { - case 0: - bcs->proto2 = L2_HDLC; - break; - case 1: - bcs->proto2 = L2_VOICE; - break; - default: - dev_warn(cs->dev, - "B1 Protocol %u unsupported, using Transparent\n", - cmsg->B1protocol); - bcs->proto2 = L2_VOICE; - } - if (cmsg->B2protocol != 1) - dev_warn(cs->dev, - "B2 Protocol %u unsupported, using Transparent\n", - cmsg->B2protocol); - if (cmsg->B3protocol != 0) - dev_warn(cs->dev, - "B3 Protocol %u unsupported, using Transparent\n", - cmsg->B3protocol); - ignore_cstruct_param(cs, cmsg->B1configuration, - "CONNECT_REQ", "B1 Configuration"); - ignore_cstruct_param(cs, cmsg->B2configuration, - "CONNECT_REQ", "B2 Configuration"); - ignore_cstruct_param(cs, cmsg->B3configuration, - "CONNECT_REQ", "B3 Configuration"); - } - commands[AT_PROTO] = kmalloc(9, GFP_KERNEL); - if (!commands[AT_PROTO]) - goto oom; - snprintf(commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2); - - /* ToDo: check/encode remaining parameters */ - ignore_cstruct_param(cs, cmsg->CalledPartySubaddress, - "CONNECT_REQ", "Called pty subaddr"); - ignore_cstruct_param(cs, cmsg->CallingPartySubaddress, - "CONNECT_REQ", "Calling pty subaddr"); - ignore_cstruct_param(cs, cmsg->LLC, - "CONNECT_REQ", "LLC"); - if (cmsg->AdditionalInfo != CAPI_DEFAULT) { - ignore_cstruct_param(cs, cmsg->BChannelinformation, - "CONNECT_REQ", "B Channel Information"); - ignore_cstruct_param(cs, cmsg->Keypadfacility, - "CONNECT_REQ", "Keypad Facility"); - ignore_cstruct_param(cs, cmsg->Useruserdata, - "CONNECT_REQ", "User-User Data"); - ignore_cstruct_param(cs, cmsg->Facilitydataarray, - "CONNECT_REQ", "Facility Data Array"); - } - - /* encode parameter: B channel to use */ - commands[AT_ISO] = kmalloc(9, GFP_KERNEL); - if (!commands[AT_ISO]) - goto oom; - snprintf(commands[AT_ISO], 9, "^SISO=%u\r", - (unsigned) bcs->channel + 1); - - /* queue & schedule EV_DIAL event */ - if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, commands, - bcs->at_state.seq_index, NULL)) { - info = CAPI_MSGOSRESOURCEERR; - goto error; - } - gigaset_schedule_event(cs); - send_conf(iif, ap, skb, CapiSuccess); - return; - -oom: - dev_err(cs->dev, "%s: out of memory\n", __func__); - info = CAPI_MSGOSRESOURCEERR; -error: - if (commands) - for (i = 0; i < AT_NUM; i++) - kfree(commands[i]); - kfree(commands); - gigaset_free_channel(bcs); - send_conf(iif, ap, skb, info); -} - -/* - * process CONNECT_RESP message - * checks protocol parameters and queues an ACCEPT or HUP event - */ -static void do_connect_resp(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - _cmsg *cmsg = &iif->acmsg; - struct bc_state *bcs; - struct gigaset_capi_appl *oap; - unsigned long flags; - int channel; - - /* decode message */ - if (capi_message2cmsg(cmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, cmsg); - dev_kfree_skb_any(skb); - - /* extract and check channel number from PLCI */ - channel = (cmsg->adr.adrPLCI >> 8) & 0xff; - if (!channel || channel > cs->channels) { - dev_notice(cs->dev, "%s: invalid %s 0x%02x\n", - "CONNECT_RESP", "PLCI", cmsg->adr.adrPLCI); - return; - } - bcs = cs->bcs + channel - 1; - - switch (cmsg->Reject) { - case 0: /* Accept */ - /* drop all competing applications, keep only this one */ - spin_lock_irqsave(&bcs->aplock, flags); - while (bcs->ap != NULL) { - oap = bcs->ap; - bcs->ap = oap->bcnext; - if (oap != ap) { - spin_unlock_irqrestore(&bcs->aplock, flags); - send_disconnect_ind(bcs, oap, - CapiCallGivenToOtherApplication); - spin_lock_irqsave(&bcs->aplock, flags); - } - } - ap->bcnext = NULL; - bcs->ap = ap; - spin_unlock_irqrestore(&bcs->aplock, flags); - - bcs->rx_bufsize = ap->rp.datablklen; - dev_kfree_skb(bcs->rx_skb); - gigaset_new_rx_skb(bcs); - bcs->chstate |= CHS_NOTIFY_LL; - - /* check/encode B channel protocol */ - if (cmsg->BProtocol == CAPI_DEFAULT) { - bcs->proto2 = L2_HDLC; - dev_warn(cs->dev, - "B2 Protocol X.75 SLP unsupported, using Transparent\n"); - } else { - switch (cmsg->B1protocol) { - case 0: - bcs->proto2 = L2_HDLC; - break; - case 1: - bcs->proto2 = L2_VOICE; - break; - default: - dev_warn(cs->dev, - "B1 Protocol %u unsupported, using Transparent\n", - cmsg->B1protocol); - bcs->proto2 = L2_VOICE; - } - if (cmsg->B2protocol != 1) - dev_warn(cs->dev, - "B2 Protocol %u unsupported, using Transparent\n", - cmsg->B2protocol); - if (cmsg->B3protocol != 0) - dev_warn(cs->dev, - "B3 Protocol %u unsupported, using Transparent\n", - cmsg->B3protocol); - ignore_cstruct_param(cs, cmsg->B1configuration, - "CONNECT_RESP", "B1 Configuration"); - ignore_cstruct_param(cs, cmsg->B2configuration, - "CONNECT_RESP", "B2 Configuration"); - ignore_cstruct_param(cs, cmsg->B3configuration, - "CONNECT_RESP", "B3 Configuration"); - } - - /* ToDo: check/encode remaining parameters */ - ignore_cstruct_param(cs, cmsg->ConnectedNumber, - "CONNECT_RESP", "Connected Number"); - ignore_cstruct_param(cs, cmsg->ConnectedSubaddress, - "CONNECT_RESP", "Connected Subaddress"); - ignore_cstruct_param(cs, cmsg->LLC, - "CONNECT_RESP", "LLC"); - if (cmsg->AdditionalInfo != CAPI_DEFAULT) { - ignore_cstruct_param(cs, cmsg->BChannelinformation, - "CONNECT_RESP", "BChannel Information"); - ignore_cstruct_param(cs, cmsg->Keypadfacility, - "CONNECT_RESP", "Keypad Facility"); - ignore_cstruct_param(cs, cmsg->Useruserdata, - "CONNECT_RESP", "User-User Data"); - ignore_cstruct_param(cs, cmsg->Facilitydataarray, - "CONNECT_RESP", "Facility Data Array"); - } - - /* Accept call */ - if (!gigaset_add_event(cs, &cs->bcs[channel - 1].at_state, - EV_ACCEPT, NULL, 0, NULL)) - return; - gigaset_schedule_event(cs); - return; - - case 1: /* Ignore */ - /* send DISCONNECT_IND to this application */ - send_disconnect_ind(bcs, ap, 0); - - /* remove it from the list of listening apps */ - spin_lock_irqsave(&bcs->aplock, flags); - if (bcs->ap == ap) { - bcs->ap = ap->bcnext; - if (bcs->ap == NULL) { - /* last one: stop ev-layer hupD notifications */ - bcs->apconnstate = APCONN_NONE; - bcs->chstate &= ~CHS_NOTIFY_LL; - } - spin_unlock_irqrestore(&bcs->aplock, flags); - return; - } - for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) { - if (oap->bcnext == ap) { - oap->bcnext = oap->bcnext->bcnext; - spin_unlock_irqrestore(&bcs->aplock, flags); - return; - } - } - spin_unlock_irqrestore(&bcs->aplock, flags); - dev_err(cs->dev, "%s: application %u not found\n", - __func__, ap->id); - return; - - default: /* Reject */ - /* drop all competing applications, keep only this one */ - spin_lock_irqsave(&bcs->aplock, flags); - while (bcs->ap != NULL) { - oap = bcs->ap; - bcs->ap = oap->bcnext; - if (oap != ap) { - spin_unlock_irqrestore(&bcs->aplock, flags); - send_disconnect_ind(bcs, oap, - CapiCallGivenToOtherApplication); - spin_lock_irqsave(&bcs->aplock, flags); - } - } - ap->bcnext = NULL; - bcs->ap = ap; - spin_unlock_irqrestore(&bcs->aplock, flags); - - /* reject call - will trigger DISCONNECT_IND for this app */ - dev_info(cs->dev, "%s: Reject=%x\n", - "CONNECT_RESP", cmsg->Reject); - if (!gigaset_add_event(cs, &cs->bcs[channel - 1].at_state, - EV_HUP, NULL, 0, NULL)) - return; - gigaset_schedule_event(cs); - return; - } -} - -/* - * process CONNECT_B3_REQ message - * build NCCI and emit CONNECT_B3_CONF reply - */ -static void do_connect_b3_req(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - _cmsg *cmsg = &iif->acmsg; - struct bc_state *bcs; - int channel; - - /* decode message */ - if (capi_message2cmsg(cmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, cmsg); - - /* extract and check channel number from PLCI */ - channel = (cmsg->adr.adrPLCI >> 8) & 0xff; - if (!channel || channel > cs->channels) { - dev_notice(cs->dev, "%s: invalid %s 0x%02x\n", - "CONNECT_B3_REQ", "PLCI", cmsg->adr.adrPLCI); - send_conf(iif, ap, skb, CapiIllContrPlciNcci); - return; - } - bcs = &cs->bcs[channel - 1]; - - /* mark logical connection active */ - bcs->apconnstate = APCONN_ACTIVE; - - /* build NCCI: always 1 (one B3 connection only) */ - cmsg->adr.adrNCCI |= 1 << 16; - - /* NCPI parameter: not applicable for B3 Transparent */ - ignore_cstruct_param(cs, cmsg->NCPI, "CONNECT_B3_REQ", "NCPI"); - send_conf(iif, ap, skb, - (cmsg->NCPI && cmsg->NCPI[0]) ? - CapiNcpiNotSupportedByProtocol : CapiSuccess); -} - -/* - * process CONNECT_B3_RESP message - * Depending on the Reject parameter, either emit CONNECT_B3_ACTIVE_IND - * or queue EV_HUP and emit DISCONNECT_B3_IND. - * The emitted message is always shorter than the received one, - * allowing to reuse the skb. - */ -static void do_connect_b3_resp(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - _cmsg *cmsg = &iif->acmsg; - struct bc_state *bcs; - int channel; - unsigned int msgsize; - u8 command; - - /* decode message */ - if (capi_message2cmsg(cmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, cmsg); - - /* extract and check channel number and NCCI */ - channel = (cmsg->adr.adrNCCI >> 8) & 0xff; - if (!channel || channel > cs->channels || - ((cmsg->adr.adrNCCI >> 16) & 0xffff) != 1) { - dev_notice(cs->dev, "%s: invalid %s 0x%02x\n", - "CONNECT_B3_RESP", "NCCI", cmsg->adr.adrNCCI); - dev_kfree_skb_any(skb); - return; - } - bcs = &cs->bcs[channel - 1]; - - if (cmsg->Reject) { - /* Reject: clear B3 connect received flag */ - bcs->apconnstate = APCONN_SETUP; - - /* trigger hangup, causing eventual DISCONNECT_IND */ - if (!gigaset_add_event(cs, &bcs->at_state, - EV_HUP, NULL, 0, NULL)) { - dev_kfree_skb_any(skb); - return; - } - gigaset_schedule_event(cs); - - /* emit DISCONNECT_B3_IND */ - command = CAPI_DISCONNECT_B3; - msgsize = CAPI_DISCONNECT_B3_IND_BASELEN; - } else { - /* - * Accept: emit CONNECT_B3_ACTIVE_IND immediately, as - * we only send CONNECT_B3_IND if the B channel is up - */ - command = CAPI_CONNECT_B3_ACTIVE; - msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN; - } - capi_cmsg_header(cmsg, ap->id, command, CAPI_IND, - ap->nextMessageNumber++, cmsg->adr.adrNCCI); - __skb_trim(skb, msgsize); - if (capi_cmsg2message(cmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, cmsg); - capi_ctr_handle_message(&iif->ctr, ap->id, skb); -} - -/* - * process DISCONNECT_REQ message - * schedule EV_HUP and emit DISCONNECT_B3_IND if necessary, - * emit DISCONNECT_CONF reply - */ -static void do_disconnect_req(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - _cmsg *cmsg = &iif->acmsg; - struct bc_state *bcs; - _cmsg *b3cmsg; - struct sk_buff *b3skb; - int channel; - - /* decode message */ - if (capi_message2cmsg(cmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, cmsg); - - /* extract and check channel number from PLCI */ - channel = (cmsg->adr.adrPLCI >> 8) & 0xff; - if (!channel || channel > cs->channels) { - dev_notice(cs->dev, "%s: invalid %s 0x%02x\n", - "DISCONNECT_REQ", "PLCI", cmsg->adr.adrPLCI); - send_conf(iif, ap, skb, CapiIllContrPlciNcci); - return; - } - bcs = cs->bcs + channel - 1; - - /* ToDo: process parameter: Additional info */ - if (cmsg->AdditionalInfo != CAPI_DEFAULT) { - ignore_cstruct_param(cs, cmsg->BChannelinformation, - "DISCONNECT_REQ", "B Channel Information"); - ignore_cstruct_param(cs, cmsg->Keypadfacility, - "DISCONNECT_REQ", "Keypad Facility"); - ignore_cstruct_param(cs, cmsg->Useruserdata, - "DISCONNECT_REQ", "User-User Data"); - ignore_cstruct_param(cs, cmsg->Facilitydataarray, - "DISCONNECT_REQ", "Facility Data Array"); - } - - /* skip if DISCONNECT_IND already sent */ - if (!bcs->apconnstate) - return; - - /* check for active logical connection */ - if (bcs->apconnstate >= APCONN_ACTIVE) { - /* clear it */ - bcs->apconnstate = APCONN_SETUP; - - /* - * emit DISCONNECT_B3_IND with cause 0x3301 - * use separate cmsg structure, as the content of iif->acmsg - * is still needed for creating the _CONF message - */ - b3cmsg = kmalloc(sizeof(*b3cmsg), GFP_KERNEL); - if (!b3cmsg) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); - return; - } - capi_cmsg_header(b3cmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND, - ap->nextMessageNumber++, - cmsg->adr.adrPLCI | (1 << 16)); - b3cmsg->Reason_B3 = CapiProtocolErrorLayer1; - b3skb = alloc_skb(CAPI_DISCONNECT_B3_IND_BASELEN, GFP_KERNEL); - if (b3skb == NULL) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); - kfree(b3cmsg); - return; - } - if (capi_cmsg2message(b3cmsg, - __skb_put(b3skb, CAPI_DISCONNECT_B3_IND_BASELEN))) { - dev_err(cs->dev, "%s: message parser failure\n", - __func__); - kfree(b3cmsg); - dev_kfree_skb_any(b3skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, b3cmsg); - kfree(b3cmsg); - capi_ctr_handle_message(&iif->ctr, ap->id, b3skb); - } - - /* trigger hangup, causing eventual DISCONNECT_IND */ - if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { - send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); - return; - } - gigaset_schedule_event(cs); - - /* emit reply */ - send_conf(iif, ap, skb, CapiSuccess); -} - -/* - * process DISCONNECT_B3_REQ message - * schedule EV_HUP and emit DISCONNECT_B3_CONF reply - */ -static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - _cmsg *cmsg = &iif->acmsg; - struct bc_state *bcs; - int channel; - - /* decode message */ - if (capi_message2cmsg(cmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, cmsg); - - /* extract and check channel number and NCCI */ - channel = (cmsg->adr.adrNCCI >> 8) & 0xff; - if (!channel || channel > cs->channels || - ((cmsg->adr.adrNCCI >> 16) & 0xffff) != 1) { - dev_notice(cs->dev, "%s: invalid %s 0x%02x\n", - "DISCONNECT_B3_REQ", "NCCI", cmsg->adr.adrNCCI); - send_conf(iif, ap, skb, CapiIllContrPlciNcci); - return; - } - bcs = &cs->bcs[channel - 1]; - - /* reject if logical connection not active */ - if (bcs->apconnstate < APCONN_ACTIVE) { - send_conf(iif, ap, skb, - CapiMessageNotSupportedInCurrentState); - return; - } - - /* trigger hangup, causing eventual DISCONNECT_B3_IND */ - if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { - send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); - return; - } - gigaset_schedule_event(cs); - - /* NCPI parameter: not applicable for B3 Transparent */ - ignore_cstruct_param(cs, cmsg->NCPI, - "DISCONNECT_B3_REQ", "NCPI"); - send_conf(iif, ap, skb, - (cmsg->NCPI && cmsg->NCPI[0]) ? - CapiNcpiNotSupportedByProtocol : CapiSuccess); -} - -/* - * process DATA_B3_REQ message - */ -static void do_data_b3_req(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - struct bc_state *bcs; - int channel = CAPIMSG_PLCI_PART(skb->data); - u16 ncci = CAPIMSG_NCCI_PART(skb->data); - u16 msglen = CAPIMSG_LEN(skb->data); - u16 datalen = CAPIMSG_DATALEN(skb->data); - u16 flags = CAPIMSG_FLAGS(skb->data); - u16 msgid = CAPIMSG_MSGID(skb->data); - u16 handle = CAPIMSG_HANDLE_REQ(skb->data); - - /* frequent message, avoid _cmsg overhead */ - dump_rawmsg(DEBUG_MCMD, __func__, skb->data); - - /* check parameters */ - if (channel == 0 || channel > cs->channels || ncci != 1) { - dev_notice(cs->dev, "%s: invalid %s 0x%02x\n", - "DATA_B3_REQ", "NCCI", CAPIMSG_NCCI(skb->data)); - send_conf(iif, ap, skb, CapiIllContrPlciNcci); - return; - } - bcs = &cs->bcs[channel - 1]; - if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64) - dev_notice(cs->dev, "%s: unexpected length %d\n", - "DATA_B3_REQ", msglen); - if (msglen + datalen != skb->len) - dev_notice(cs->dev, "%s: length mismatch (%d+%d!=%d)\n", - "DATA_B3_REQ", msglen, datalen, skb->len); - if (msglen + datalen > skb->len) { - /* message too short for announced data length */ - send_conf(iif, ap, skb, CapiIllMessageParmCoding); /* ? */ - return; - } - if (flags & CAPI_FLAGS_RESERVED) { - dev_notice(cs->dev, "%s: reserved flags set (%x)\n", - "DATA_B3_REQ", flags); - send_conf(iif, ap, skb, CapiIllMessageParmCoding); - return; - } - - /* reject if logical connection not active */ - if (bcs->apconnstate < APCONN_ACTIVE) { - send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); - return; - } - - /* pull CAPI message into link layer header */ - skb_reset_mac_header(skb); - skb->mac_len = msglen; - skb_pull(skb, msglen); - - /* pass to device-specific module */ - if (cs->ops->send_skb(bcs, skb) < 0) { - send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); - return; - } - - /* - * DATA_B3_CONF will be sent by gigaset_skb_sent() only if "delivery - * confirmation" bit is set; otherwise we have to send it now - */ - if (!(flags & CAPI_FLAGS_DELIVERY_CONFIRMATION)) - send_data_b3_conf(cs, &iif->ctr, ap->id, msgid, channel, handle, - flags ? CapiFlagsNotSupportedByProtocol - : CAPI_NOERROR); -} - -/* - * process RESET_B3_REQ message - * just always reply "not supported by current protocol" - */ -static void do_reset_b3_req(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - - /* decode message */ - if (capi_message2cmsg(&iif->acmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); - send_conf(iif, ap, skb, - CapiResetProcedureNotSupportedByCurrentProtocol); -} - -/* - * unsupported CAPI message handler - */ -static void do_unsupported(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - - /* decode message */ - if (capi_message2cmsg(&iif->acmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); - send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); -} - -/* - * CAPI message handler: no-op - */ -static void do_nothing(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - struct cardstate *cs = iif->ctr.driverdata; - - /* decode message */ - if (capi_message2cmsg(&iif->acmsg, skb->data)) { - dev_err(cs->dev, "%s: message parser failure\n", __func__); - dev_kfree_skb_any(skb); - return; - } - dump_cmsg(DEBUG_CMD, __func__, &iif->acmsg); - dev_kfree_skb_any(skb); -} - -static void do_data_b3_resp(struct gigaset_capi_ctr *iif, - struct gigaset_capi_appl *ap, - struct sk_buff *skb) -{ - dump_rawmsg(DEBUG_MCMD, __func__, skb->data); - dev_kfree_skb_any(skb); -} - -/* table of outgoing CAPI message handlers with lookup function */ -typedef void (*capi_send_handler_t)(struct gigaset_capi_ctr *, - struct gigaset_capi_appl *, - struct sk_buff *); - -static struct { - u16 cmd; - capi_send_handler_t handler; -} capi_send_handler_table[] = { - /* most frequent messages first for faster lookup */ - { CAPI_DATA_B3_REQ, do_data_b3_req }, - { CAPI_DATA_B3_RESP, do_data_b3_resp }, - - { CAPI_ALERT_REQ, do_alert_req }, - { CAPI_CONNECT_ACTIVE_RESP, do_nothing }, - { CAPI_CONNECT_B3_ACTIVE_RESP, do_nothing }, - { CAPI_CONNECT_B3_REQ, do_connect_b3_req }, - { CAPI_CONNECT_B3_RESP, do_connect_b3_resp }, - { CAPI_CONNECT_B3_T90_ACTIVE_RESP, do_nothing }, - { CAPI_CONNECT_REQ, do_connect_req }, - { CAPI_CONNECT_RESP, do_connect_resp }, - { CAPI_DISCONNECT_B3_REQ, do_disconnect_b3_req }, - { CAPI_DISCONNECT_B3_RESP, do_nothing }, - { CAPI_DISCONNECT_REQ, do_disconnect_req }, - { CAPI_DISCONNECT_RESP, do_nothing }, - { CAPI_FACILITY_REQ, do_facility_req }, - { CAPI_FACILITY_RESP, do_nothing }, - { CAPI_LISTEN_REQ, do_listen_req }, - { CAPI_SELECT_B_PROTOCOL_REQ, do_unsupported }, - { CAPI_RESET_B3_REQ, do_reset_b3_req }, - { CAPI_RESET_B3_RESP, do_nothing }, - - /* - * ToDo: support overlap sending (requires ev-layer state - * machine extension to generate additional ATD commands) - */ - { CAPI_INFO_REQ, do_unsupported }, - { CAPI_INFO_RESP, do_nothing }, - - /* - * ToDo: what's the proper response for these? - */ - { CAPI_MANUFACTURER_REQ, do_nothing }, - { CAPI_MANUFACTURER_RESP, do_nothing }, -}; - -/* look up handler */ -static inline capi_send_handler_t lookup_capi_send_handler(const u16 cmd) -{ - size_t i; - - for (i = 0; i < ARRAY_SIZE(capi_send_handler_table); i++) - if (capi_send_handler_table[i].cmd == cmd) - return capi_send_handler_table[i].handler; - return NULL; -} - - -/** - * gigaset_send_message() - accept a CAPI message from an application - * @ctr: controller descriptor structure. - * @skb: CAPI message. - * - * Return value: CAPI error code - * Note: capidrv (and probably others, too) only uses the return value to - * decide whether it has to free the skb (only if result != CAPI_NOERROR (0)) - */ -static u16 gigaset_send_message(struct capi_ctr *ctr, struct sk_buff *skb) -{ - struct gigaset_capi_ctr *iif - = container_of(ctr, struct gigaset_capi_ctr, ctr); - struct cardstate *cs = ctr->driverdata; - struct gigaset_capi_appl *ap; - capi_send_handler_t handler; - - /* can only handle linear sk_buffs */ - if (skb_linearize(skb) < 0) { - dev_warn(cs->dev, "%s: skb_linearize failed\n", __func__); - return CAPI_MSGOSRESOURCEERR; - } - - /* retrieve application data structure */ - ap = get_appl(iif, CAPIMSG_APPID(skb->data)); - if (!ap) { - dev_notice(cs->dev, "%s: application %u not registered\n", - __func__, CAPIMSG_APPID(skb->data)); - return CAPI_ILLAPPNR; - } - - /* look up command */ - handler = lookup_capi_send_handler(CAPIMSG_CMD(skb->data)); - if (!handler) { - /* unknown/unsupported message type */ - if (printk_ratelimit()) - dev_notice(cs->dev, "%s: unsupported message %u\n", - __func__, CAPIMSG_CMD(skb->data)); - return CAPI_ILLCMDORSUBCMDORMSGTOSMALL; - } - - /* serialize */ - if (atomic_add_return(1, &iif->sendqlen) > 1) { - /* queue behind other messages */ - skb_queue_tail(&iif->sendqueue, skb); - return CAPI_NOERROR; - } - - /* process message */ - handler(iif, ap, skb); - - /* process other messages arrived in the meantime */ - while (atomic_sub_return(1, &iif->sendqlen) > 0) { - skb = skb_dequeue(&iif->sendqueue); - if (!skb) { - /* should never happen */ - dev_err(cs->dev, "%s: send queue empty\n", __func__); - continue; - } - ap = get_appl(iif, CAPIMSG_APPID(skb->data)); - if (!ap) { - /* could that happen? */ - dev_warn(cs->dev, "%s: application %u vanished\n", - __func__, CAPIMSG_APPID(skb->data)); - continue; - } - handler = lookup_capi_send_handler(CAPIMSG_CMD(skb->data)); - if (!handler) { - /* should never happen */ - dev_err(cs->dev, "%s: handler %x vanished\n", - __func__, CAPIMSG_CMD(skb->data)); - continue; - } - handler(iif, ap, skb); - } - - return CAPI_NOERROR; -} - -/** - * gigaset_procinfo() - build single line description for controller - * @ctr: controller descriptor structure. - * - * Return value: pointer to generated string (null terminated) - */ -static char *gigaset_procinfo(struct capi_ctr *ctr) -{ - return ctr->name; /* ToDo: more? */ -} - -static int gigaset_proc_show(struct seq_file *m, void *v) -{ - struct capi_ctr *ctr = m->private; - struct cardstate *cs = ctr->driverdata; - char *s; - int i; - - seq_printf(m, "%-16s %s\n", "name", ctr->name); - seq_printf(m, "%-16s %s %s\n", "dev", - dev_driver_string(cs->dev), dev_name(cs->dev)); - seq_printf(m, "%-16s %d\n", "id", cs->myid); - if (cs->gotfwver) - seq_printf(m, "%-16s %d.%d.%d.%d\n", "firmware", - cs->fwver[0], cs->fwver[1], cs->fwver[2], cs->fwver[3]); - seq_printf(m, "%-16s %d\n", "channels", cs->channels); - seq_printf(m, "%-16s %s\n", "onechannel", cs->onechannel ? "yes" : "no"); - - switch (cs->mode) { - case M_UNKNOWN: - s = "unknown"; - break; - case M_CONFIG: - s = "config"; - break; - case M_UNIMODEM: - s = "Unimodem"; - break; - case M_CID: - s = "CID"; - break; - default: - s = "??"; - } - seq_printf(m, "%-16s %s\n", "mode", s); - - switch (cs->mstate) { - case MS_UNINITIALIZED: - s = "uninitialized"; - break; - case MS_INIT: - s = "init"; - break; - case MS_LOCKED: - s = "locked"; - break; - case MS_SHUTDOWN: - s = "shutdown"; - break; - case MS_RECOVER: - s = "recover"; - break; - case MS_READY: - s = "ready"; - break; - default: - s = "??"; - } - seq_printf(m, "%-16s %s\n", "mstate", s); - - seq_printf(m, "%-16s %s\n", "running", cs->running ? "yes" : "no"); - seq_printf(m, "%-16s %s\n", "connected", cs->connected ? "yes" : "no"); - seq_printf(m, "%-16s %s\n", "isdn_up", cs->isdn_up ? "yes" : "no"); - seq_printf(m, "%-16s %s\n", "cidmode", cs->cidmode ? "yes" : "no"); - - for (i = 0; i < cs->channels; i++) { - seq_printf(m, "[%d]%-13s %d\n", i, "corrupted", - cs->bcs[i].corrupted); - seq_printf(m, "[%d]%-13s %d\n", i, "trans_down", - cs->bcs[i].trans_down); - seq_printf(m, "[%d]%-13s %d\n", i, "trans_up", - cs->bcs[i].trans_up); - seq_printf(m, "[%d]%-13s %d\n", i, "chstate", - cs->bcs[i].chstate); - switch (cs->bcs[i].proto2) { - case L2_BITSYNC: - s = "bitsync"; - break; - case L2_HDLC: - s = "HDLC"; - break; - case L2_VOICE: - s = "voice"; - break; - default: - s = "??"; - } - seq_printf(m, "[%d]%-13s %s\n", i, "proto2", s); - } - return 0; -} - -/** - * gigaset_isdn_regdev() - register device to LL - * @cs: device descriptor structure. - * @isdnid: device name. - * - * Return value: 0 on success, error code < 0 on failure - */ -int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) -{ - struct gigaset_capi_ctr *iif; - int rc; - - iif = kzalloc(sizeof(*iif), GFP_KERNEL); - if (!iif) { - pr_err("%s: out of memory\n", __func__); - return -ENOMEM; - } - - /* prepare controller structure */ - iif->ctr.owner = THIS_MODULE; - iif->ctr.driverdata = cs; - strncpy(iif->ctr.name, isdnid, sizeof(iif->ctr.name) - 1); - iif->ctr.driver_name = "gigaset"; - iif->ctr.load_firmware = NULL; - iif->ctr.reset_ctr = NULL; - iif->ctr.register_appl = gigaset_register_appl; - iif->ctr.release_appl = gigaset_release_appl; - iif->ctr.send_message = gigaset_send_message; - iif->ctr.procinfo = gigaset_procinfo; - iif->ctr.proc_show = gigaset_proc_show, - INIT_LIST_HEAD(&iif->appls); - skb_queue_head_init(&iif->sendqueue); - atomic_set(&iif->sendqlen, 0); - - /* register controller with CAPI */ - rc = attach_capi_ctr(&iif->ctr); - if (rc) { - pr_err("attach_capi_ctr failed (%d)\n", rc); - kfree(iif); - return rc; - } - - cs->iif = iif; - cs->hw_hdr_len = CAPI_DATA_B3_REQ_LEN; - return 0; -} - -/** - * gigaset_isdn_unregdev() - unregister device from LL - * @cs: device descriptor structure. - */ -void gigaset_isdn_unregdev(struct cardstate *cs) -{ - struct gigaset_capi_ctr *iif = cs->iif; - - detach_capi_ctr(&iif->ctr); - kfree(iif); - cs->iif = NULL; -} - -static struct capi_driver capi_driver_gigaset = { - .name = "gigaset", - .revision = "1.0", -}; - -/** - * gigaset_isdn_regdrv() - register driver to LL - */ -void gigaset_isdn_regdrv(void) -{ - pr_info("Kernel CAPI interface\n"); - register_capi_driver(&capi_driver_gigaset); -} - -/** - * gigaset_isdn_unregdrv() - unregister driver from LL - */ -void gigaset_isdn_unregdrv(void) -{ - unregister_capi_driver(&capi_driver_gigaset); -} diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c deleted file mode 100644 index 3bb8092858ab..000000000000 --- a/drivers/isdn/gigaset/common.c +++ /dev/null @@ -1,1153 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Stuff used by all variants of the driver - * - * Copyright (c) 2001 by Stefan Eilers, - * Hansjoerg Lipp <hjlipp@web.de>, - * Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * ===================================================================== - */ - -#include "gigaset.h" -#include <linux/module.h> -#include <linux/moduleparam.h> - -/* Version Information */ -#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers" -#define DRIVER_DESC "Driver for Gigaset 307x" - -#ifdef CONFIG_GIGASET_DEBUG -#define DRIVER_DESC_DEBUG " (debug build)" -#else -#define DRIVER_DESC_DEBUG "" -#endif - -/* Module parameters */ -int gigaset_debuglevel; -EXPORT_SYMBOL_GPL(gigaset_debuglevel); -module_param_named(debug, gigaset_debuglevel, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "debug level"); - -/* driver state flags */ -#define VALID_MINOR 0x01 -#define VALID_ID 0x02 - -/** - * gigaset_dbg_buffer() - dump data in ASCII and hex for debugging - * @level: debugging level. - * @msg: message prefix. - * @len: number of bytes to dump. - * @buf: data to dump. - * - * If the current debugging level includes one of the bits set in @level, - * @len bytes starting at @buf are logged to dmesg at KERN_DEBUG prio, - * prefixed by the text @msg. - */ -void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, - size_t len, const unsigned char *buf) -{ - unsigned char outbuf[80]; - unsigned char c; - size_t space = sizeof outbuf - 1; - unsigned char *out = outbuf; - size_t numin = len; - - while (numin--) { - c = *buf++; - if (c == '~' || c == '^' || c == '\\') { - if (!space--) - break; - *out++ = '\\'; - } - if (c & 0x80) { - if (!space--) - break; - *out++ = '~'; - c ^= 0x80; - } - if (c < 0x20 || c == 0x7f) { - if (!space--) - break; - *out++ = '^'; - c ^= 0x40; - } - if (!space--) - break; - *out++ = c; - } - *out = 0; - - gig_dbg(level, "%s (%u bytes): %s", msg, (unsigned) len, outbuf); -} -EXPORT_SYMBOL_GPL(gigaset_dbg_buffer); - -static int setflags(struct cardstate *cs, unsigned flags, unsigned delay) -{ - int r; - - r = cs->ops->set_modem_ctrl(cs, cs->control_state, flags); - cs->control_state = flags; - if (r < 0) - return r; - - if (delay) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(delay * HZ / 1000); - } - - return 0; -} - -int gigaset_enterconfigmode(struct cardstate *cs) -{ - int i, r; - - cs->control_state = TIOCM_RTS; - - r = setflags(cs, TIOCM_DTR, 200); - if (r < 0) - goto error; - r = setflags(cs, 0, 200); - if (r < 0) - goto error; - for (i = 0; i < 5; ++i) { - r = setflags(cs, TIOCM_RTS, 100); - if (r < 0) - goto error; - r = setflags(cs, 0, 100); - if (r < 0) - goto error; - } - r = setflags(cs, TIOCM_RTS | TIOCM_DTR, 800); - if (r < 0) - goto error; - - return 0; - -error: - dev_err(cs->dev, "error %d on setuartbits\n", -r); - cs->control_state = TIOCM_RTS | TIOCM_DTR; - cs->ops->set_modem_ctrl(cs, 0, TIOCM_RTS | TIOCM_DTR); - - return -1; -} - -static int test_timeout(struct at_state_t *at_state) -{ - if (!at_state->timer_expires) - return 0; - - if (--at_state->timer_expires) { - gig_dbg(DEBUG_MCMD, "decreased timer of %p to %lu", - at_state, at_state->timer_expires); - return 0; - } - - gigaset_add_event(at_state->cs, at_state, EV_TIMEOUT, NULL, - at_state->timer_index, NULL); - return 1; -} - -static void timer_tick(struct timer_list *t) -{ - struct cardstate *cs = from_timer(cs, t, timer); - unsigned long flags; - unsigned channel; - struct at_state_t *at_state; - int timeout = 0; - - spin_lock_irqsave(&cs->lock, flags); - - for (channel = 0; channel < cs->channels; ++channel) - if (test_timeout(&cs->bcs[channel].at_state)) - timeout = 1; - - if (test_timeout(&cs->at_state)) - timeout = 1; - - list_for_each_entry(at_state, &cs->temp_at_states, list) - if (test_timeout(at_state)) - timeout = 1; - - if (cs->running) { - mod_timer(&cs->timer, jiffies + msecs_to_jiffies(GIG_TICK)); - if (timeout) { - gig_dbg(DEBUG_EVENT, "scheduling timeout"); - tasklet_schedule(&cs->event_tasklet); - } - } - - spin_unlock_irqrestore(&cs->lock, flags); -} - -int gigaset_get_channel(struct bc_state *bcs) -{ - unsigned long flags; - - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) { - gig_dbg(DEBUG_CHANNEL, "could not allocate channel %d", - bcs->channel); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - return -EBUSY; - } - ++bcs->use_count; - bcs->busy = 1; - gig_dbg(DEBUG_CHANNEL, "allocated channel %d", bcs->channel); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - return 0; -} - -struct bc_state *gigaset_get_free_channel(struct cardstate *cs) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&cs->lock, flags); - if (!try_module_get(cs->driver->owner)) { - gig_dbg(DEBUG_CHANNEL, - "could not get module for allocating channel"); - spin_unlock_irqrestore(&cs->lock, flags); - return NULL; - } - for (i = 0; i < cs->channels; ++i) - if (!cs->bcs[i].use_count) { - ++cs->bcs[i].use_count; - cs->bcs[i].busy = 1; - spin_unlock_irqrestore(&cs->lock, flags); - gig_dbg(DEBUG_CHANNEL, "allocated channel %d", i); - return cs->bcs + i; - } - module_put(cs->driver->owner); - spin_unlock_irqrestore(&cs->lock, flags); - gig_dbg(DEBUG_CHANNEL, "no free channel"); - return NULL; -} - -void gigaset_free_channel(struct bc_state *bcs) -{ - unsigned long flags; - - spin_lock_irqsave(&bcs->cs->lock, flags); - if (!bcs->busy) { - gig_dbg(DEBUG_CHANNEL, "could not free channel %d", - bcs->channel); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - return; - } - --bcs->use_count; - bcs->busy = 0; - module_put(bcs->cs->driver->owner); - gig_dbg(DEBUG_CHANNEL, "freed channel %d", bcs->channel); - spin_unlock_irqrestore(&bcs->cs->lock, flags); -} - -int gigaset_get_channels(struct cardstate *cs) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&cs->lock, flags); - for (i = 0; i < cs->channels; ++i) - if (cs->bcs[i].use_count) { - spin_unlock_irqrestore(&cs->lock, flags); - gig_dbg(DEBUG_CHANNEL, - "could not allocate all channels"); - return -EBUSY; - } - for (i = 0; i < cs->channels; ++i) - ++cs->bcs[i].use_count; - spin_unlock_irqrestore(&cs->lock, flags); - - gig_dbg(DEBUG_CHANNEL, "allocated all channels"); - - return 0; -} - -void gigaset_free_channels(struct cardstate *cs) -{ - unsigned long flags; - int i; - - gig_dbg(DEBUG_CHANNEL, "unblocking all channels"); - spin_lock_irqsave(&cs->lock, flags); - for (i = 0; i < cs->channels; ++i) - --cs->bcs[i].use_count; - spin_unlock_irqrestore(&cs->lock, flags); -} - -void gigaset_block_channels(struct cardstate *cs) -{ - unsigned long flags; - int i; - - gig_dbg(DEBUG_CHANNEL, "blocking all channels"); - spin_lock_irqsave(&cs->lock, flags); - for (i = 0; i < cs->channels; ++i) - ++cs->bcs[i].use_count; - spin_unlock_irqrestore(&cs->lock, flags); -} - -static void clear_events(struct cardstate *cs) -{ - struct event_t *ev; - unsigned head, tail; - unsigned long flags; - - spin_lock_irqsave(&cs->ev_lock, flags); - - head = cs->ev_head; - tail = cs->ev_tail; - - while (tail != head) { - ev = cs->events + head; - kfree(ev->ptr); - head = (head + 1) % MAX_EVENTS; - } - - cs->ev_head = tail; - - spin_unlock_irqrestore(&cs->ev_lock, flags); -} - -/** - * gigaset_add_event() - add event to device event queue - * @cs: device descriptor structure. - * @at_state: connection state structure. - * @type: event type. - * @ptr: pointer parameter for event. - * @parameter: integer parameter for event. - * @arg: pointer parameter for event. - * - * Allocate an event queue entry from the device's event queue, and set it up - * with the parameters given. - * - * Return value: added event - */ -struct event_t *gigaset_add_event(struct cardstate *cs, - struct at_state_t *at_state, int type, - void *ptr, int parameter, void *arg) -{ - unsigned long flags; - unsigned next, tail; - struct event_t *event = NULL; - - gig_dbg(DEBUG_EVENT, "queueing event %d", type); - - spin_lock_irqsave(&cs->ev_lock, flags); - - tail = cs->ev_tail; - next = (tail + 1) % MAX_EVENTS; - if (unlikely(next == cs->ev_head)) - dev_err(cs->dev, "event queue full\n"); - else { - event = cs->events + tail; - event->type = type; - event->at_state = at_state; - event->cid = -1; - event->ptr = ptr; - event->arg = arg; - event->parameter = parameter; - cs->ev_tail = next; - } - - spin_unlock_irqrestore(&cs->ev_lock, flags); - - return event; -} -EXPORT_SYMBOL_GPL(gigaset_add_event); - -static void clear_at_state(struct at_state_t *at_state) -{ - int i; - - for (i = 0; i < STR_NUM; ++i) { - kfree(at_state->str_var[i]); - at_state->str_var[i] = NULL; - } -} - -static void dealloc_temp_at_states(struct cardstate *cs) -{ - struct at_state_t *cur, *next; - - list_for_each_entry_safe(cur, next, &cs->temp_at_states, list) { - list_del(&cur->list); - clear_at_state(cur); - kfree(cur); - } -} - -static void gigaset_freebcs(struct bc_state *bcs) -{ - int i; - - gig_dbg(DEBUG_INIT, "freeing bcs[%d]->hw", bcs->channel); - bcs->cs->ops->freebcshw(bcs); - - gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel); - clear_at_state(&bcs->at_state); - gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel); - dev_kfree_skb(bcs->rx_skb); - bcs->rx_skb = NULL; - - for (i = 0; i < AT_NUM; ++i) { - kfree(bcs->commands[i]); - bcs->commands[i] = NULL; - } -} - -static struct cardstate *alloc_cs(struct gigaset_driver *drv) -{ - unsigned long flags; - unsigned i; - struct cardstate *cs; - struct cardstate *ret = NULL; - - spin_lock_irqsave(&drv->lock, flags); - if (drv->blocked) - goto exit; - for (i = 0; i < drv->minors; ++i) { - cs = drv->cs + i; - if (!(cs->flags & VALID_MINOR)) { - cs->flags = VALID_MINOR; - ret = cs; - break; - } - } -exit: - spin_unlock_irqrestore(&drv->lock, flags); - return ret; -} - -static void free_cs(struct cardstate *cs) -{ - cs->flags = 0; -} - -static void make_valid(struct cardstate *cs, unsigned mask) -{ - unsigned long flags; - struct gigaset_driver *drv = cs->driver; - spin_lock_irqsave(&drv->lock, flags); - cs->flags |= mask; - spin_unlock_irqrestore(&drv->lock, flags); -} - -static void make_invalid(struct cardstate *cs, unsigned mask) -{ - unsigned long flags; - struct gigaset_driver *drv = cs->driver; - spin_lock_irqsave(&drv->lock, flags); - cs->flags &= ~mask; - spin_unlock_irqrestore(&drv->lock, flags); -} - -/** - * gigaset_freecs() - free all associated ressources of a device - * @cs: device descriptor structure. - * - * Stops all tasklets and timers, unregisters the device from all - * subsystems it was registered to, deallocates the device structure - * @cs and all structures referenced from it. - * Operations on the device should be stopped before calling this. - */ -void gigaset_freecs(struct cardstate *cs) -{ - int i; - unsigned long flags; - - if (!cs) - return; - - mutex_lock(&cs->mutex); - - spin_lock_irqsave(&cs->lock, flags); - cs->running = 0; - spin_unlock_irqrestore(&cs->lock, flags); /* event handler and timer are - not rescheduled below */ - - tasklet_kill(&cs->event_tasklet); - del_timer_sync(&cs->timer); - - switch (cs->cs_init) { - default: - /* clear B channel structures */ - for (i = 0; i < cs->channels; ++i) { - gig_dbg(DEBUG_INIT, "clearing bcs[%d]", i); - gigaset_freebcs(cs->bcs + i); - } - - /* clear device sysfs */ - gigaset_free_dev_sysfs(cs); - - gigaset_if_free(cs); - - gig_dbg(DEBUG_INIT, "clearing hw"); - cs->ops->freecshw(cs); - - /* fall through */ - case 2: /* error in initcshw */ - /* Deregister from LL */ - make_invalid(cs, VALID_ID); - gigaset_isdn_unregdev(cs); - - /* fall through */ - case 1: /* error when registering to LL */ - gig_dbg(DEBUG_INIT, "clearing at_state"); - clear_at_state(&cs->at_state); - dealloc_temp_at_states(cs); - clear_events(cs); - tty_port_destroy(&cs->port); - - /* fall through */ - case 0: /* error in basic setup */ - gig_dbg(DEBUG_INIT, "freeing inbuf"); - kfree(cs->inbuf); - kfree(cs->bcs); - } - - mutex_unlock(&cs->mutex); - free_cs(cs); -} -EXPORT_SYMBOL_GPL(gigaset_freecs); - -void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs, - struct cardstate *cs, int cid) -{ - int i; - - INIT_LIST_HEAD(&at_state->list); - at_state->waiting = 0; - at_state->getstring = 0; - at_state->pending_commands = 0; - at_state->timer_expires = 0; - at_state->timer_active = 0; - at_state->timer_index = 0; - at_state->seq_index = 0; - at_state->ConState = 0; - for (i = 0; i < STR_NUM; ++i) - at_state->str_var[i] = NULL; - at_state->int_var[VAR_ZDLE] = 0; - at_state->int_var[VAR_ZCTP] = -1; - at_state->int_var[VAR_ZSAU] = ZSAU_NULL; - at_state->cs = cs; - at_state->bcs = bcs; - at_state->cid = cid; - if (!cid) - at_state->replystruct = cs->tabnocid; - else - at_state->replystruct = cs->tabcid; -} - - -static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct cardstate *cs) -/* inbuf->read must be allocated before! */ -{ - inbuf->head = 0; - inbuf->tail = 0; - inbuf->cs = cs; - inbuf->inputstate = INS_command; -} - -/** - * gigaset_fill_inbuf() - append received data to input buffer - * @inbuf: buffer structure. - * @src: received data. - * @numbytes: number of bytes received. - * - * Return value: !=0 if some data was appended - */ -int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, - unsigned numbytes) -{ - unsigned n, head, tail, bytesleft; - - gig_dbg(DEBUG_INTR, "received %u bytes", numbytes); - - if (!numbytes) - return 0; - - bytesleft = numbytes; - tail = inbuf->tail; - head = inbuf->head; - gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); - - while (bytesleft) { - if (head > tail) - n = head - 1 - tail; - else if (head == 0) - n = (RBUFSIZE - 1) - tail; - else - n = RBUFSIZE - tail; - if (!n) { - dev_err(inbuf->cs->dev, - "buffer overflow (%u bytes lost)\n", - bytesleft); - break; - } - if (n > bytesleft) - n = bytesleft; - memcpy(inbuf->data + tail, src, n); - bytesleft -= n; - tail = (tail + n) % RBUFSIZE; - src += n; - } - gig_dbg(DEBUG_INTR, "setting tail to %u", tail); - inbuf->tail = tail; - return numbytes != bytesleft; -} -EXPORT_SYMBOL_GPL(gigaset_fill_inbuf); - -/* Initialize the b-channel structure */ -static int gigaset_initbcs(struct bc_state *bcs, struct cardstate *cs, - int channel) -{ - int i; - - bcs->tx_skb = NULL; - - skb_queue_head_init(&bcs->squeue); - - bcs->corrupted = 0; - bcs->trans_down = 0; - bcs->trans_up = 0; - - gig_dbg(DEBUG_INIT, "setting up bcs[%d]->at_state", channel); - gigaset_at_init(&bcs->at_state, bcs, cs, -1); - -#ifdef CONFIG_GIGASET_DEBUG - bcs->emptycount = 0; -#endif - - bcs->rx_bufsize = 0; - bcs->rx_skb = NULL; - bcs->rx_fcs = PPP_INITFCS; - bcs->inputstate = 0; - bcs->channel = channel; - bcs->cs = cs; - - bcs->chstate = 0; - bcs->use_count = 1; - bcs->busy = 0; - bcs->ignore = cs->ignoreframes; - - for (i = 0; i < AT_NUM; ++i) - bcs->commands[i] = NULL; - - spin_lock_init(&bcs->aplock); - bcs->ap = NULL; - bcs->apconnstate = 0; - - gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); - return cs->ops->initbcshw(bcs); -} - -/** - * gigaset_initcs() - initialize device structure - * @drv: hardware driver the device belongs to - * @channels: number of B channels supported by device - * @onechannel: !=0 if B channel data and AT commands share one - * communication channel (M10x), - * ==0 if B channels have separate communication channels (base) - * @ignoreframes: number of frames to ignore after setting up B channel - * @cidmode: !=0: start in CallID mode - * @modulename: name of driver module for LL registration - * - * Allocate and initialize cardstate structure for Gigaset driver - * Calls hardware dependent gigaset_initcshw() function - * Calls B channel initialization function gigaset_initbcs() for each B channel - * - * Return value: - * pointer to cardstate structure - */ -struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, - int onechannel, int ignoreframes, - int cidmode, const char *modulename) -{ - struct cardstate *cs; - unsigned long flags; - int i; - - gig_dbg(DEBUG_INIT, "allocating cs"); - cs = alloc_cs(drv); - if (!cs) { - pr_err("maximum number of devices exceeded\n"); - return NULL; - } - - cs->cs_init = 0; - cs->channels = channels; - cs->onechannel = onechannel; - cs->ignoreframes = ignoreframes; - INIT_LIST_HEAD(&cs->temp_at_states); - cs->running = 0; - timer_setup(&cs->timer, timer_tick, 0); - spin_lock_init(&cs->ev_lock); - cs->ev_tail = 0; - cs->ev_head = 0; - - tasklet_init(&cs->event_tasklet, gigaset_handle_event, - (unsigned long) cs); - tty_port_init(&cs->port); - cs->commands_pending = 0; - cs->cur_at_seq = 0; - cs->gotfwver = -1; - cs->dev = NULL; - cs->tty_dev = NULL; - cs->cidmode = cidmode != 0; - cs->tabnocid = gigaset_tab_nocid; - cs->tabcid = gigaset_tab_cid; - - init_waitqueue_head(&cs->waitqueue); - cs->waiting = 0; - - cs->mode = M_UNKNOWN; - cs->mstate = MS_UNINITIALIZED; - - cs->bcs = kmalloc_array(channels, sizeof(struct bc_state), GFP_KERNEL); - cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL); - if (!cs->bcs || !cs->inbuf) { - pr_err("out of memory\n"); - goto error; - } - ++cs->cs_init; - - gig_dbg(DEBUG_INIT, "setting up at_state"); - spin_lock_init(&cs->lock); - gigaset_at_init(&cs->at_state, NULL, cs, 0); - cs->dle = 0; - cs->cbytes = 0; - - gig_dbg(DEBUG_INIT, "setting up inbuf"); - gigaset_inbuf_init(cs->inbuf, cs); - - cs->connected = 0; - cs->isdn_up = 0; - - gig_dbg(DEBUG_INIT, "setting up cmdbuf"); - cs->cmdbuf = cs->lastcmdbuf = NULL; - spin_lock_init(&cs->cmdlock); - cs->curlen = 0; - cs->cmdbytes = 0; - - gig_dbg(DEBUG_INIT, "setting up iif"); - if (gigaset_isdn_regdev(cs, modulename) < 0) { - pr_err("error registering ISDN device\n"); - goto error; - } - - make_valid(cs, VALID_ID); - ++cs->cs_init; - gig_dbg(DEBUG_INIT, "setting up hw"); - if (cs->ops->initcshw(cs) < 0) - goto error; - - ++cs->cs_init; - - /* set up character device */ - gigaset_if_init(cs); - - /* set up device sysfs */ - gigaset_init_dev_sysfs(cs); - - /* set up channel data structures */ - for (i = 0; i < channels; ++i) { - gig_dbg(DEBUG_INIT, "setting up bcs[%d]", i); - if (gigaset_initbcs(cs->bcs + i, cs, i) < 0) { - pr_err("could not allocate channel %d data\n", i); - goto error; - } - } - - spin_lock_irqsave(&cs->lock, flags); - cs->running = 1; - spin_unlock_irqrestore(&cs->lock, flags); - cs->timer.expires = jiffies + msecs_to_jiffies(GIG_TICK); - add_timer(&cs->timer); - - gig_dbg(DEBUG_INIT, "cs initialized"); - return cs; - -error: - gig_dbg(DEBUG_INIT, "failed"); - gigaset_freecs(cs); - return NULL; -} -EXPORT_SYMBOL_GPL(gigaset_initcs); - -/* ReInitialize the b-channel structure on hangup */ -void gigaset_bcs_reinit(struct bc_state *bcs) -{ - struct sk_buff *skb; - struct cardstate *cs = bcs->cs; - unsigned long flags; - - while ((skb = skb_dequeue(&bcs->squeue)) != NULL) - dev_kfree_skb(skb); - - spin_lock_irqsave(&cs->lock, flags); - clear_at_state(&bcs->at_state); - bcs->at_state.ConState = 0; - bcs->at_state.timer_active = 0; - bcs->at_state.timer_expires = 0; - bcs->at_state.cid = -1; /* No CID defined */ - spin_unlock_irqrestore(&cs->lock, flags); - - bcs->inputstate = 0; - -#ifdef CONFIG_GIGASET_DEBUG - bcs->emptycount = 0; -#endif - - bcs->rx_fcs = PPP_INITFCS; - bcs->chstate = 0; - - bcs->ignore = cs->ignoreframes; - dev_kfree_skb(bcs->rx_skb); - bcs->rx_skb = NULL; - - cs->ops->reinitbcshw(bcs); -} - -static void cleanup_cs(struct cardstate *cs) -{ - struct cmdbuf_t *cb, *tcb; - int i; - unsigned long flags; - - spin_lock_irqsave(&cs->lock, flags); - - cs->mode = M_UNKNOWN; - cs->mstate = MS_UNINITIALIZED; - - clear_at_state(&cs->at_state); - dealloc_temp_at_states(cs); - gigaset_at_init(&cs->at_state, NULL, cs, 0); - - cs->inbuf->inputstate = INS_command; - cs->inbuf->head = 0; - cs->inbuf->tail = 0; - - cb = cs->cmdbuf; - while (cb) { - tcb = cb; - cb = cb->next; - kfree(tcb); - } - cs->cmdbuf = cs->lastcmdbuf = NULL; - cs->curlen = 0; - cs->cmdbytes = 0; - cs->gotfwver = -1; - cs->dle = 0; - cs->cur_at_seq = 0; - cs->commands_pending = 0; - cs->cbytes = 0; - - spin_unlock_irqrestore(&cs->lock, flags); - - for (i = 0; i < cs->channels; ++i) { - gigaset_freebcs(cs->bcs + i); - if (gigaset_initbcs(cs->bcs + i, cs, i) < 0) - pr_err("could not allocate channel %d data\n", i); - } - - if (cs->waiting) { - cs->cmd_result = -ENODEV; - cs->waiting = 0; - wake_up_interruptible(&cs->waitqueue); - } -} - - -/** - * gigaset_start() - start device operations - * @cs: device descriptor structure. - * - * Prepares the device for use by setting up communication parameters, - * scheduling an EV_START event to initiate device initialization, and - * waiting for completion of the initialization. - * - * Return value: - * 0 on success, error code < 0 on failure - */ -int gigaset_start(struct cardstate *cs) -{ - unsigned long flags; - - if (mutex_lock_interruptible(&cs->mutex)) - return -EBUSY; - - spin_lock_irqsave(&cs->lock, flags); - cs->connected = 1; - spin_unlock_irqrestore(&cs->lock, flags); - - if (cs->mstate != MS_LOCKED) { - cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR | TIOCM_RTS); - cs->ops->baud_rate(cs, B115200); - cs->ops->set_line_ctrl(cs, CS8); - cs->control_state = TIOCM_DTR | TIOCM_RTS; - } - - cs->waiting = 1; - - if (!gigaset_add_event(cs, &cs->at_state, EV_START, NULL, 0, NULL)) { - cs->waiting = 0; - goto error; - } - gigaset_schedule_event(cs); - - wait_event(cs->waitqueue, !cs->waiting); - - mutex_unlock(&cs->mutex); - return 0; - -error: - mutex_unlock(&cs->mutex); - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(gigaset_start); - -/** - * gigaset_shutdown() - shut down device operations - * @cs: device descriptor structure. - * - * Deactivates the device by scheduling an EV_SHUTDOWN event and - * waiting for completion of the shutdown. - * - * Return value: - * 0 - success, -ENODEV - error (no device associated) - */ -int gigaset_shutdown(struct cardstate *cs) -{ - mutex_lock(&cs->mutex); - - if (!(cs->flags & VALID_MINOR)) { - mutex_unlock(&cs->mutex); - return -ENODEV; - } - - cs->waiting = 1; - - if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) - goto exit; - gigaset_schedule_event(cs); - - wait_event(cs->waitqueue, !cs->waiting); - - cleanup_cs(cs); - -exit: - mutex_unlock(&cs->mutex); - return 0; -} -EXPORT_SYMBOL_GPL(gigaset_shutdown); - -/** - * gigaset_stop() - stop device operations - * @cs: device descriptor structure. - * - * Stops operations on the device by scheduling an EV_STOP event and - * waiting for completion of the shutdown. - */ -void gigaset_stop(struct cardstate *cs) -{ - mutex_lock(&cs->mutex); - - cs->waiting = 1; - - if (!gigaset_add_event(cs, &cs->at_state, EV_STOP, NULL, 0, NULL)) - goto exit; - gigaset_schedule_event(cs); - - wait_event(cs->waitqueue, !cs->waiting); - - cleanup_cs(cs); - -exit: - mutex_unlock(&cs->mutex); -} -EXPORT_SYMBOL_GPL(gigaset_stop); - -static LIST_HEAD(drivers); -static DEFINE_SPINLOCK(driver_lock); - -struct cardstate *gigaset_get_cs_by_id(int id) -{ - unsigned long flags; - struct cardstate *ret = NULL; - struct cardstate *cs; - struct gigaset_driver *drv; - unsigned i; - - spin_lock_irqsave(&driver_lock, flags); - list_for_each_entry(drv, &drivers, list) { - spin_lock(&drv->lock); - for (i = 0; i < drv->minors; ++i) { - cs = drv->cs + i; - if ((cs->flags & VALID_ID) && cs->myid == id) { - ret = cs; - break; - } - } - spin_unlock(&drv->lock); - if (ret) - break; - } - spin_unlock_irqrestore(&driver_lock, flags); - return ret; -} - -static struct cardstate *gigaset_get_cs_by_minor(unsigned minor) -{ - unsigned long flags; - struct cardstate *ret = NULL; - struct gigaset_driver *drv; - unsigned index; - - spin_lock_irqsave(&driver_lock, flags); - list_for_each_entry(drv, &drivers, list) { - if (minor < drv->minor || minor >= drv->minor + drv->minors) - continue; - index = minor - drv->minor; - spin_lock(&drv->lock); - if (drv->cs[index].flags & VALID_MINOR) - ret = drv->cs + index; - spin_unlock(&drv->lock); - if (ret) - break; - } - spin_unlock_irqrestore(&driver_lock, flags); - return ret; -} - -struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty) -{ - return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start); -} - -/** - * gigaset_freedriver() - free all associated ressources of a driver - * @drv: driver descriptor structure. - * - * Unregisters the driver from the system and deallocates the driver - * structure @drv and all structures referenced from it. - * All devices should be shut down before calling this. - */ -void gigaset_freedriver(struct gigaset_driver *drv) -{ - unsigned long flags; - - spin_lock_irqsave(&driver_lock, flags); - list_del(&drv->list); - spin_unlock_irqrestore(&driver_lock, flags); - - gigaset_if_freedriver(drv); - - kfree(drv->cs); - kfree(drv); -} -EXPORT_SYMBOL_GPL(gigaset_freedriver); - -/** - * gigaset_initdriver() - initialize driver structure - * @minor: First minor number - * @minors: Number of minors this driver can handle - * @procname: Name of the driver - * @devname: Name of the device files (prefix without minor number) - * - * Allocate and initialize gigaset_driver structure. Initialize interface. - * - * Return value: - * Pointer to the gigaset_driver structure on success, NULL on failure. - */ -struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, - const char *procname, - const char *devname, - const struct gigaset_ops *ops, - struct module *owner) -{ - struct gigaset_driver *drv; - unsigned long flags; - unsigned i; - - drv = kmalloc(sizeof *drv, GFP_KERNEL); - if (!drv) - return NULL; - - drv->have_tty = 0; - drv->minor = minor; - drv->minors = minors; - spin_lock_init(&drv->lock); - drv->blocked = 0; - drv->ops = ops; - drv->owner = owner; - INIT_LIST_HEAD(&drv->list); - - drv->cs = kmalloc_array(minors, sizeof(*drv->cs), GFP_KERNEL); - if (!drv->cs) - goto error; - - for (i = 0; i < minors; ++i) { - drv->cs[i].flags = 0; - drv->cs[i].driver = drv; - drv->cs[i].ops = drv->ops; - drv->cs[i].minor_index = i; - mutex_init(&drv->cs[i].mutex); - } - - gigaset_if_initdriver(drv, procname, devname); - - spin_lock_irqsave(&driver_lock, flags); - list_add(&drv->list, &drivers); - spin_unlock_irqrestore(&driver_lock, flags); - - return drv; - -error: - kfree(drv); - return NULL; -} -EXPORT_SYMBOL_GPL(gigaset_initdriver); - -/** - * gigaset_blockdriver() - block driver - * @drv: driver descriptor structure. - * - * Prevents the driver from attaching new devices, in preparation for - * deregistration. - */ -void gigaset_blockdriver(struct gigaset_driver *drv) -{ - drv->blocked = 1; -} -EXPORT_SYMBOL_GPL(gigaset_blockdriver); - -static int __init gigaset_init_module(void) -{ - /* in accordance with the principle of least astonishment, - * setting the 'debug' parameter to 1 activates a sensible - * set of default debug levels - */ - if (gigaset_debuglevel == 1) - gigaset_debuglevel = DEBUG_DEFAULT; - - pr_info(DRIVER_DESC DRIVER_DESC_DEBUG "\n"); - gigaset_isdn_regdrv(); - return 0; -} - -static void __exit gigaset_exit_module(void) -{ - gigaset_isdn_unregdrv(); -} - -module_init(gigaset_init_module); -module_exit(gigaset_exit_module); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); - -MODULE_LICENSE("GPL"); diff --git a/drivers/isdn/gigaset/dummyll.c b/drivers/isdn/gigaset/dummyll.c deleted file mode 100644 index 4b9637e5da6e..000000000000 --- a/drivers/isdn/gigaset/dummyll.c +++ /dev/null @@ -1,74 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Dummy LL interface for the Gigaset driver - * - * Copyright (c) 2009 by Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * ===================================================================== - */ - -#include <linux/export.h> -#include "gigaset.h" - -void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) -{ -} -EXPORT_SYMBOL_GPL(gigaset_skb_sent); - -void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb) -{ -} -EXPORT_SYMBOL_GPL(gigaset_skb_rcvd); - -void gigaset_isdn_rcv_err(struct bc_state *bcs) -{ -} -EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err); - -int gigaset_isdn_icall(struct at_state_t *at_state) -{ - return ICALL_IGNORE; -} - -void gigaset_isdn_connD(struct bc_state *bcs) -{ -} - -void gigaset_isdn_hupD(struct bc_state *bcs) -{ -} - -void gigaset_isdn_connB(struct bc_state *bcs) -{ -} - -void gigaset_isdn_hupB(struct bc_state *bcs) -{ -} - -void gigaset_isdn_start(struct cardstate *cs) -{ -} - -void gigaset_isdn_stop(struct cardstate *cs) -{ -} - -int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) -{ - return 0; -} - -void gigaset_isdn_unregdev(struct cardstate *cs) -{ -} - -void gigaset_isdn_regdrv(void) -{ - pr_info("no ISDN subsystem interface\n"); -} - -void gigaset_isdn_unregdrv(void) -{ -} diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c deleted file mode 100644 index f8bb1869c600..000000000000 --- a/drivers/isdn/gigaset/ev-layer.c +++ /dev/null @@ -1,1910 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Stuff used by all variants of the driver - * - * Copyright (c) 2001 by Stefan Eilers, - * Hansjoerg Lipp <hjlipp@web.de>, - * Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * ===================================================================== - */ - -#include <linux/export.h> -#include "gigaset.h" - -/* ========================================================== */ -/* bit masks for pending commands */ -#define PC_DIAL 0x001 -#define PC_HUP 0x002 -#define PC_INIT 0x004 -#define PC_DLE0 0x008 -#define PC_DLE1 0x010 -#define PC_SHUTDOWN 0x020 -#define PC_ACCEPT 0x040 -#define PC_CID 0x080 -#define PC_NOCID 0x100 -#define PC_CIDMODE 0x200 -#define PC_UMMODE 0x400 - -/* types of modem responses */ -#define RT_NOTHING 0 -#define RT_ZSAU 1 -#define RT_RING 2 -#define RT_NUMBER 3 -#define RT_STRING 4 -#define RT_ZCAU 6 - -/* Possible ASCII responses */ -#define RSP_OK 0 -#define RSP_ERROR 1 -#define RSP_ZGCI 3 -#define RSP_RING 4 -#define RSP_ZVLS 5 -#define RSP_ZCAU 6 - -/* responses with values to store in at_state */ -/* - numeric */ -#define RSP_VAR 100 -#define RSP_ZSAU (RSP_VAR + VAR_ZSAU) -#define RSP_ZDLE (RSP_VAR + VAR_ZDLE) -#define RSP_ZCTP (RSP_VAR + VAR_ZCTP) -/* - string */ -#define RSP_STR (RSP_VAR + VAR_NUM) -#define RSP_NMBR (RSP_STR + STR_NMBR) -#define RSP_ZCPN (RSP_STR + STR_ZCPN) -#define RSP_ZCON (RSP_STR + STR_ZCON) -#define RSP_ZBC (RSP_STR + STR_ZBC) -#define RSP_ZHLC (RSP_STR + STR_ZHLC) - -#define RSP_WRONG_CID -2 /* unknown cid in cmd */ -#define RSP_INVAL -6 /* invalid response */ -#define RSP_NODEV -9 /* device not connected */ - -#define RSP_NONE -19 -#define RSP_STRING -20 -#define RSP_NULL -21 -#define RSP_INIT -27 -#define RSP_ANY -26 -#define RSP_LAST -28 - -/* actions for process_response */ -#define ACT_NOTHING 0 -#define ACT_SETDLE1 1 -#define ACT_SETDLE0 2 -#define ACT_FAILINIT 3 -#define ACT_HUPMODEM 4 -#define ACT_CONFIGMODE 5 -#define ACT_INIT 6 -#define ACT_DLE0 7 -#define ACT_DLE1 8 -#define ACT_FAILDLE0 9 -#define ACT_FAILDLE1 10 -#define ACT_RING 11 -#define ACT_CID 12 -#define ACT_FAILCID 13 -#define ACT_SDOWN 14 -#define ACT_FAILSDOWN 15 -#define ACT_DEBUG 16 -#define ACT_WARN 17 -#define ACT_DIALING 18 -#define ACT_ABORTDIAL 19 -#define ACT_DISCONNECT 20 -#define ACT_CONNECT 21 -#define ACT_REMOTEREJECT 22 -#define ACT_CONNTIMEOUT 23 -#define ACT_REMOTEHUP 24 -#define ACT_ABORTHUP 25 -#define ACT_ICALL 26 -#define ACT_ACCEPTED 27 -#define ACT_ABORTACCEPT 28 -#define ACT_TIMEOUT 29 -#define ACT_GETSTRING 30 -#define ACT_SETVER 31 -#define ACT_FAILVER 32 -#define ACT_GOTVER 33 -#define ACT_TEST 34 -#define ACT_ERROR 35 -#define ACT_ABORTCID 36 -#define ACT_ZCAU 37 -#define ACT_NOTIFY_BC_DOWN 38 -#define ACT_NOTIFY_BC_UP 39 -#define ACT_DIAL 40 -#define ACT_ACCEPT 41 -#define ACT_HUP 43 -#define ACT_IF_LOCK 44 -#define ACT_START 45 -#define ACT_STOP 46 -#define ACT_FAKEDLE0 47 -#define ACT_FAKEHUP 48 -#define ACT_FAKESDOWN 49 -#define ACT_SHUTDOWN 50 -#define ACT_PROC_CIDMODE 51 -#define ACT_UMODESET 52 -#define ACT_FAILUMODE 53 -#define ACT_CMODESET 54 -#define ACT_FAILCMODE 55 -#define ACT_IF_VER 56 -#define ACT_CMD 100 - -/* at command sequences */ -#define SEQ_NONE 0 -#define SEQ_INIT 100 -#define SEQ_DLE0 200 -#define SEQ_DLE1 250 -#define SEQ_CID 300 -#define SEQ_NOCID 350 -#define SEQ_HUP 400 -#define SEQ_DIAL 600 -#define SEQ_ACCEPT 720 -#define SEQ_SHUTDOWN 500 -#define SEQ_CIDMODE 10 -#define SEQ_UMMODE 11 - - -/* 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid), - * 400: hup, 500: reset, 600: dial, 700: ring */ -struct reply_t gigaset_tab_nocid[] = -{ -/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, - * action, command */ - -/* initialize device, set cid mode if possible */ - {RSP_INIT, -1, -1, SEQ_INIT, 100, 1, {ACT_TIMEOUT} }, - - {EV_TIMEOUT, 100, 100, -1, 101, 3, {0}, "Z\r"}, - {RSP_OK, 101, 103, -1, 120, 5, {ACT_GETSTRING}, - "+GMR\r"}, - - {EV_TIMEOUT, 101, 101, -1, 102, 5, {0}, "Z\r"}, - {RSP_ERROR, 101, 101, -1, 102, 5, {0}, "Z\r"}, - - {EV_TIMEOUT, 102, 102, -1, 108, 5, {ACT_SETDLE1}, - "^SDLE=0\r"}, - {RSP_OK, 108, 108, -1, 104, -1}, - {RSP_ZDLE, 104, 104, 0, 103, 5, {0}, "Z\r"}, - {EV_TIMEOUT, 104, 104, -1, 0, 0, {ACT_FAILINIT} }, - {RSP_ERROR, 108, 108, -1, 0, 0, {ACT_FAILINIT} }, - - {EV_TIMEOUT, 108, 108, -1, 105, 2, {ACT_SETDLE0, - ACT_HUPMODEM, - ACT_TIMEOUT} }, - {EV_TIMEOUT, 105, 105, -1, 103, 5, {0}, "Z\r"}, - - {RSP_ERROR, 102, 102, -1, 107, 5, {0}, "^GETPRE\r"}, - {RSP_OK, 107, 107, -1, 0, 0, {ACT_CONFIGMODE} }, - {RSP_ERROR, 107, 107, -1, 0, 0, {ACT_FAILINIT} }, - {EV_TIMEOUT, 107, 107, -1, 0, 0, {ACT_FAILINIT} }, - - {RSP_ERROR, 103, 103, -1, 0, 0, {ACT_FAILINIT} }, - {EV_TIMEOUT, 103, 103, -1, 0, 0, {ACT_FAILINIT} }, - - {RSP_STRING, 120, 120, -1, 121, -1, {ACT_SETVER} }, - - {EV_TIMEOUT, 120, 121, -1, 0, 0, {ACT_FAILVER, - ACT_INIT} }, - {RSP_ERROR, 120, 121, -1, 0, 0, {ACT_FAILVER, - ACT_INIT} }, - {RSP_OK, 121, 121, -1, 0, 0, {ACT_GOTVER, - ACT_INIT} }, - {RSP_NONE, 121, 121, -1, 120, 0, {ACT_GETSTRING} }, - -/* leave dle mode */ - {RSP_INIT, 0, 0, SEQ_DLE0, 201, 5, {0}, "^SDLE=0\r"}, - {RSP_OK, 201, 201, -1, 202, -1}, - {RSP_ZDLE, 202, 202, 0, 0, 0, {ACT_DLE0} }, - {RSP_NODEV, 200, 249, -1, 0, 0, {ACT_FAKEDLE0} }, - {RSP_ERROR, 200, 249, -1, 0, 0, {ACT_FAILDLE0} }, - {EV_TIMEOUT, 200, 249, -1, 0, 0, {ACT_FAILDLE0} }, - -/* enter dle mode */ - {RSP_INIT, 0, 0, SEQ_DLE1, 251, 5, {0}, "^SDLE=1\r"}, - {RSP_OK, 251, 251, -1, 252, -1}, - {RSP_ZDLE, 252, 252, 1, 0, 0, {ACT_DLE1} }, - {RSP_ERROR, 250, 299, -1, 0, 0, {ACT_FAILDLE1} }, - {EV_TIMEOUT, 250, 299, -1, 0, 0, {ACT_FAILDLE1} }, - -/* incoming call */ - {RSP_RING, -1, -1, -1, -1, -1, {ACT_RING} }, - -/* get cid */ - {RSP_INIT, 0, 0, SEQ_CID, 301, 5, {0}, "^SGCI?\r"}, - {RSP_OK, 301, 301, -1, 302, -1}, - {RSP_ZGCI, 302, 302, -1, 0, 0, {ACT_CID} }, - {RSP_ERROR, 301, 349, -1, 0, 0, {ACT_FAILCID} }, - {EV_TIMEOUT, 301, 349, -1, 0, 0, {ACT_FAILCID} }, - -/* enter cid mode */ - {RSP_INIT, 0, 0, SEQ_CIDMODE, 150, 5, {0}, "^SGCI=1\r"}, - {RSP_OK, 150, 150, -1, 0, 0, {ACT_CMODESET} }, - {RSP_ERROR, 150, 150, -1, 0, 0, {ACT_FAILCMODE} }, - {EV_TIMEOUT, 150, 150, -1, 0, 0, {ACT_FAILCMODE} }, - -/* leave cid mode */ - {RSP_INIT, 0, 0, SEQ_UMMODE, 160, 5, {0}, "Z\r"}, - {RSP_OK, 160, 160, -1, 0, 0, {ACT_UMODESET} }, - {RSP_ERROR, 160, 160, -1, 0, 0, {ACT_FAILUMODE} }, - {EV_TIMEOUT, 160, 160, -1, 0, 0, {ACT_FAILUMODE} }, - -/* abort getting cid */ - {RSP_INIT, 0, 0, SEQ_NOCID, 0, 0, {ACT_ABORTCID} }, - -/* reset */ - {RSP_INIT, 0, 0, SEQ_SHUTDOWN, 504, 5, {0}, "Z\r"}, - {RSP_OK, 504, 504, -1, 0, 0, {ACT_SDOWN} }, - {RSP_ERROR, 501, 599, -1, 0, 0, {ACT_FAILSDOWN} }, - {EV_TIMEOUT, 501, 599, -1, 0, 0, {ACT_FAILSDOWN} }, - {RSP_NODEV, 501, 599, -1, 0, 0, {ACT_FAKESDOWN} }, - - {EV_PROC_CIDMODE, -1, -1, -1, -1, -1, {ACT_PROC_CIDMODE} }, - {EV_IF_LOCK, -1, -1, -1, -1, -1, {ACT_IF_LOCK} }, - {EV_IF_VER, -1, -1, -1, -1, -1, {ACT_IF_VER} }, - {EV_START, -1, -1, -1, -1, -1, {ACT_START} }, - {EV_STOP, -1, -1, -1, -1, -1, {ACT_STOP} }, - {EV_SHUTDOWN, -1, -1, -1, -1, -1, {ACT_SHUTDOWN} }, - -/* misc. */ - {RSP_ERROR, -1, -1, -1, -1, -1, {ACT_ERROR} }, - {RSP_ZCAU, -1, -1, -1, -1, -1, {ACT_ZCAU} }, - {RSP_NONE, -1, -1, -1, -1, -1, {ACT_DEBUG} }, - {RSP_ANY, -1, -1, -1, -1, -1, {ACT_WARN} }, - {RSP_LAST} -}; - -/* 600: start dialing, 650: dial in progress, 800: connection is up, 700: ring, - * 400: hup, 750: accepted icall */ -struct reply_t gigaset_tab_cid[] = -{ -/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, - * action, command */ - -/* dial */ - {EV_DIAL, -1, -1, -1, -1, -1, {ACT_DIAL} }, - {RSP_INIT, 0, 0, SEQ_DIAL, 601, 5, {ACT_CMD + AT_BC} }, - {RSP_OK, 601, 601, -1, 603, 5, {ACT_CMD + AT_PROTO} }, - {RSP_OK, 603, 603, -1, 604, 5, {ACT_CMD + AT_TYPE} }, - {RSP_OK, 604, 604, -1, 605, 5, {ACT_CMD + AT_MSN} }, - {RSP_NULL, 605, 605, -1, 606, 5, {ACT_CMD + AT_CLIP} }, - {RSP_OK, 605, 605, -1, 606, 5, {ACT_CMD + AT_CLIP} }, - {RSP_NULL, 606, 606, -1, 607, 5, {ACT_CMD + AT_ISO} }, - {RSP_OK, 606, 606, -1, 607, 5, {ACT_CMD + AT_ISO} }, - {RSP_OK, 607, 607, -1, 608, 5, {0}, "+VLS=17\r"}, - {RSP_OK, 608, 608, -1, 609, -1}, - {RSP_ZSAU, 609, 609, ZSAU_PROCEEDING, 610, 5, {ACT_CMD + AT_DIAL} }, - {RSP_OK, 610, 610, -1, 650, 0, {ACT_DIALING} }, - - {RSP_ERROR, 601, 610, -1, 0, 0, {ACT_ABORTDIAL} }, - {EV_TIMEOUT, 601, 610, -1, 0, 0, {ACT_ABORTDIAL} }, - -/* optional dialing responses */ - {EV_BC_OPEN, 650, 650, -1, 651, -1}, - {RSP_ZVLS, 609, 651, 17, -1, -1, {ACT_DEBUG} }, - {RSP_ZCTP, 610, 651, -1, -1, -1, {ACT_DEBUG} }, - {RSP_ZCPN, 610, 651, -1, -1, -1, {ACT_DEBUG} }, - {RSP_ZSAU, 650, 651, ZSAU_CALL_DELIVERED, -1, -1, {ACT_DEBUG} }, - -/* connect */ - {RSP_ZSAU, 650, 650, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT} }, - {RSP_ZSAU, 651, 651, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT, - ACT_NOTIFY_BC_UP} }, - {RSP_ZSAU, 750, 750, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT} }, - {RSP_ZSAU, 751, 751, ZSAU_ACTIVE, 800, -1, {ACT_CONNECT, - ACT_NOTIFY_BC_UP} }, - {EV_BC_OPEN, 800, 800, -1, 800, -1, {ACT_NOTIFY_BC_UP} }, - -/* remote hangup */ - {RSP_ZSAU, 650, 651, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEREJECT} }, - {RSP_ZSAU, 750, 751, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP} }, - {RSP_ZSAU, 800, 800, ZSAU_DISCONNECT_IND, 0, 0, {ACT_REMOTEHUP} }, - -/* hangup */ - {EV_HUP, -1, -1, -1, -1, -1, {ACT_HUP} }, - {RSP_INIT, -1, -1, SEQ_HUP, 401, 5, {0}, "+VLS=0\r"}, - {RSP_OK, 401, 401, -1, 402, 5}, - {RSP_ZVLS, 402, 402, 0, 403, 5}, - {RSP_ZSAU, 403, 403, ZSAU_DISCONNECT_REQ, -1, -1, {ACT_DEBUG} }, - {RSP_ZSAU, 403, 403, ZSAU_NULL, 0, 0, {ACT_DISCONNECT} }, - {RSP_NODEV, 401, 403, -1, 0, 0, {ACT_FAKEHUP} }, - {RSP_ERROR, 401, 401, -1, 0, 0, {ACT_ABORTHUP} }, - {EV_TIMEOUT, 401, 403, -1, 0, 0, {ACT_ABORTHUP} }, - - {EV_BC_CLOSED, 0, 0, -1, 0, -1, {ACT_NOTIFY_BC_DOWN} }, - -/* ring */ - {RSP_ZBC, 700, 700, -1, -1, -1, {0} }, - {RSP_ZHLC, 700, 700, -1, -1, -1, {0} }, - {RSP_NMBR, 700, 700, -1, -1, -1, {0} }, - {RSP_ZCPN, 700, 700, -1, -1, -1, {0} }, - {RSP_ZCTP, 700, 700, -1, -1, -1, {0} }, - {EV_TIMEOUT, 700, 700, -1, 720, 720, {ACT_ICALL} }, - {EV_BC_CLOSED, 720, 720, -1, 0, -1, {ACT_NOTIFY_BC_DOWN} }, - -/*accept icall*/ - {EV_ACCEPT, -1, -1, -1, -1, -1, {ACT_ACCEPT} }, - {RSP_INIT, 720, 720, SEQ_ACCEPT, 721, 5, {ACT_CMD + AT_PROTO} }, - {RSP_OK, 721, 721, -1, 722, 5, {ACT_CMD + AT_ISO} }, - {RSP_OK, 722, 722, -1, 723, 5, {0}, "+VLS=17\r"}, - {RSP_OK, 723, 723, -1, 724, 5, {0} }, - {RSP_ZVLS, 724, 724, 17, 750, 50, {ACT_ACCEPTED} }, - {RSP_ERROR, 721, 729, -1, 0, 0, {ACT_ABORTACCEPT} }, - {EV_TIMEOUT, 721, 729, -1, 0, 0, {ACT_ABORTACCEPT} }, - {RSP_ZSAU, 700, 729, ZSAU_NULL, 0, 0, {ACT_ABORTACCEPT} }, - {RSP_ZSAU, 700, 729, ZSAU_ACTIVE, 0, 0, {ACT_ABORTACCEPT} }, - {RSP_ZSAU, 700, 729, ZSAU_DISCONNECT_IND, 0, 0, {ACT_ABORTACCEPT} }, - - {EV_BC_OPEN, 750, 750, -1, 751, -1}, - {EV_TIMEOUT, 750, 751, -1, 0, 0, {ACT_CONNTIMEOUT} }, - -/* B channel closed (general case) */ - {EV_BC_CLOSED, -1, -1, -1, -1, -1, {ACT_NOTIFY_BC_DOWN} }, - -/* misc. */ - {RSP_ZCON, -1, -1, -1, -1, -1, {ACT_DEBUG} }, - {RSP_ZCAU, -1, -1, -1, -1, -1, {ACT_ZCAU} }, - {RSP_NONE, -1, -1, -1, -1, -1, {ACT_DEBUG} }, - {RSP_ANY, -1, -1, -1, -1, -1, {ACT_WARN} }, - {RSP_LAST} -}; - - -static const struct resp_type_t { - char *response; - int resp_code; - int type; -} -resp_type[] = -{ - {"OK", RSP_OK, RT_NOTHING}, - {"ERROR", RSP_ERROR, RT_NOTHING}, - {"ZSAU", RSP_ZSAU, RT_ZSAU}, - {"ZCAU", RSP_ZCAU, RT_ZCAU}, - {"RING", RSP_RING, RT_RING}, - {"ZGCI", RSP_ZGCI, RT_NUMBER}, - {"ZVLS", RSP_ZVLS, RT_NUMBER}, - {"ZCTP", RSP_ZCTP, RT_NUMBER}, - {"ZDLE", RSP_ZDLE, RT_NUMBER}, - {"ZHLC", RSP_ZHLC, RT_STRING}, - {"ZBC", RSP_ZBC, RT_STRING}, - {"NMBR", RSP_NMBR, RT_STRING}, - {"ZCPN", RSP_ZCPN, RT_STRING}, - {"ZCON", RSP_ZCON, RT_STRING}, - {NULL, 0, 0} -}; - -static const struct zsau_resp_t { - char *str; - int code; -} -zsau_resp[] = -{ - {"OUTGOING_CALL_PROCEEDING", ZSAU_PROCEEDING}, - {"CALL_DELIVERED", ZSAU_CALL_DELIVERED}, - {"ACTIVE", ZSAU_ACTIVE}, - {"DISCONNECT_IND", ZSAU_DISCONNECT_IND}, - {"NULL", ZSAU_NULL}, - {"DISCONNECT_REQ", ZSAU_DISCONNECT_REQ}, - {NULL, ZSAU_UNKNOWN} -}; - -/* check for and remove fixed string prefix - * If s starts with prefix terminated by a non-alphanumeric character, - * return pointer to the first character after that, otherwise return NULL. - */ -static char *skip_prefix(char *s, const char *prefix) -{ - while (*prefix) - if (*s++ != *prefix++) - return NULL; - if (isalnum(*s)) - return NULL; - return s; -} - -/* queue event with CID */ -static void add_cid_event(struct cardstate *cs, int cid, int type, - void *ptr, int parameter) -{ - unsigned long flags; - unsigned next, tail; - struct event_t *event; - - gig_dbg(DEBUG_EVENT, "queueing event %d for cid %d", type, cid); - - spin_lock_irqsave(&cs->ev_lock, flags); - - tail = cs->ev_tail; - next = (tail + 1) % MAX_EVENTS; - if (unlikely(next == cs->ev_head)) { - dev_err(cs->dev, "event queue full\n"); - kfree(ptr); - } else { - event = cs->events + tail; - event->type = type; - event->cid = cid; - event->ptr = ptr; - event->arg = NULL; - event->parameter = parameter; - event->at_state = NULL; - cs->ev_tail = next; - } - - spin_unlock_irqrestore(&cs->ev_lock, flags); -} - -/** - * gigaset_handle_modem_response() - process received modem response - * @cs: device descriptor structure. - * - * Called by asyncdata/isocdata if a block of data received from the - * device must be processed as a modem command response. The data is - * already in the cs structure. - */ -void gigaset_handle_modem_response(struct cardstate *cs) -{ - char *eoc, *psep, *ptr; - const struct resp_type_t *rt; - const struct zsau_resp_t *zr; - int cid, parameter; - u8 type, value; - - if (!cs->cbytes) { - /* ignore additional LFs/CRs (M10x config mode or cx100) */ - gig_dbg(DEBUG_MCMD, "skipped EOL [%02X]", cs->respdata[0]); - return; - } - cs->respdata[cs->cbytes] = 0; - - if (cs->at_state.getstring) { - /* state machine wants next line verbatim */ - cs->at_state.getstring = 0; - ptr = kstrdup(cs->respdata, GFP_ATOMIC); - gig_dbg(DEBUG_EVENT, "string==%s", ptr ? ptr : "NULL"); - add_cid_event(cs, 0, RSP_STRING, ptr, 0); - return; - } - - /* look up response type */ - for (rt = resp_type; rt->response; ++rt) { - eoc = skip_prefix(cs->respdata, rt->response); - if (eoc) - break; - } - if (!rt->response) { - add_cid_event(cs, 0, RSP_NONE, NULL, 0); - gig_dbg(DEBUG_EVENT, "unknown modem response: '%s'\n", - cs->respdata); - return; - } - - /* check for CID */ - psep = strrchr(cs->respdata, ';'); - if (psep && - !kstrtoint(psep + 1, 10, &cid) && - cid >= 1 && cid <= 65535) { - /* valid CID: chop it off */ - *psep = 0; - } else { - /* no valid CID: leave unchanged */ - cid = 0; - } - - gig_dbg(DEBUG_EVENT, "CMD received: %s", cs->respdata); - if (cid) - gig_dbg(DEBUG_EVENT, "CID: %d", cid); - - switch (rt->type) { - case RT_NOTHING: - /* check parameter separator */ - if (*eoc) - goto bad_param; /* extra parameter */ - - add_cid_event(cs, cid, rt->resp_code, NULL, 0); - break; - - case RT_RING: - /* check parameter separator */ - if (!*eoc) - eoc = NULL; /* no parameter */ - else if (*eoc++ != ',') - goto bad_param; - - add_cid_event(cs, 0, rt->resp_code, NULL, cid); - - /* process parameters as individual responses */ - while (eoc) { - /* look up parameter type */ - psep = NULL; - for (rt = resp_type; rt->response; ++rt) { - psep = skip_prefix(eoc, rt->response); - if (psep) - break; - } - - /* all legal parameters are of type RT_STRING */ - if (!psep || rt->type != RT_STRING) { - dev_warn(cs->dev, - "illegal RING parameter: '%s'\n", - eoc); - return; - } - - /* skip parameter value separator */ - if (*psep++ != '=') - goto bad_param; - - /* look up end of parameter */ - eoc = strchr(psep, ','); - if (eoc) - *eoc++ = 0; - - /* retrieve parameter value */ - ptr = kstrdup(psep, GFP_ATOMIC); - - /* queue event */ - add_cid_event(cs, cid, rt->resp_code, ptr, 0); - } - break; - - case RT_ZSAU: - /* check parameter separator */ - if (!*eoc) { - /* no parameter */ - add_cid_event(cs, cid, rt->resp_code, NULL, ZSAU_NONE); - break; - } - if (*eoc++ != '=') - goto bad_param; - - /* look up parameter value */ - for (zr = zsau_resp; zr->str; ++zr) - if (!strcmp(eoc, zr->str)) - break; - if (!zr->str) - goto bad_param; - - add_cid_event(cs, cid, rt->resp_code, NULL, zr->code); - break; - - case RT_STRING: - /* check parameter separator */ - if (*eoc++ != '=') - goto bad_param; - - /* retrieve parameter value */ - ptr = kstrdup(eoc, GFP_ATOMIC); - - /* queue event */ - add_cid_event(cs, cid, rt->resp_code, ptr, 0); - break; - - case RT_ZCAU: - /* check parameter separators */ - if (*eoc++ != '=') - goto bad_param; - psep = strchr(eoc, ','); - if (!psep) - goto bad_param; - *psep++ = 0; - - /* decode parameter values */ - if (kstrtou8(eoc, 16, &type) || kstrtou8(psep, 16, &value)) { - *--psep = ','; - goto bad_param; - } - parameter = (type << 8) | value; - - add_cid_event(cs, cid, rt->resp_code, NULL, parameter); - break; - - case RT_NUMBER: - /* check parameter separator */ - if (*eoc++ != '=') - goto bad_param; - - /* decode parameter value */ - if (kstrtoint(eoc, 10, ¶meter)) - goto bad_param; - - /* special case ZDLE: set flag before queueing event */ - if (rt->resp_code == RSP_ZDLE) - cs->dle = parameter; - - add_cid_event(cs, cid, rt->resp_code, NULL, parameter); - break; - -bad_param: - /* parameter unexpected, incomplete or malformed */ - dev_warn(cs->dev, "bad parameter in response '%s'\n", - cs->respdata); - add_cid_event(cs, cid, rt->resp_code, NULL, -1); - break; - - default: - dev_err(cs->dev, "%s: internal error on '%s'\n", - __func__, cs->respdata); - } -} -EXPORT_SYMBOL_GPL(gigaset_handle_modem_response); - -/* disconnect_nobc - * process closing of connection associated with given AT state structure - * without B channel - */ -static void disconnect_nobc(struct at_state_t **at_state_p, - struct cardstate *cs) -{ - unsigned long flags; - - spin_lock_irqsave(&cs->lock, flags); - ++(*at_state_p)->seq_index; - - /* revert to selected idle mode */ - if (!cs->cidmode) { - cs->at_state.pending_commands |= PC_UMMODE; - gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE"); - cs->commands_pending = 1; - } - - /* check for and deallocate temporary AT state */ - if (!list_empty(&(*at_state_p)->list)) { - list_del(&(*at_state_p)->list); - kfree(*at_state_p); - *at_state_p = NULL; - } - - spin_unlock_irqrestore(&cs->lock, flags); -} - -/* disconnect_bc - * process closing of connection associated with given AT state structure - * and B channel - */ -static void disconnect_bc(struct at_state_t *at_state, - struct cardstate *cs, struct bc_state *bcs) -{ - unsigned long flags; - - spin_lock_irqsave(&cs->lock, flags); - ++at_state->seq_index; - - /* revert to selected idle mode */ - if (!cs->cidmode) { - cs->at_state.pending_commands |= PC_UMMODE; - gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE"); - cs->commands_pending = 1; - } - spin_unlock_irqrestore(&cs->lock, flags); - - /* invoke hardware specific handler */ - cs->ops->close_bchannel(bcs); - - /* notify LL */ - if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) { - bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL); - gigaset_isdn_hupD(bcs); - } -} - -/* get_free_channel - * get a free AT state structure: either one of those associated with the - * B channels of the Gigaset device, or if none of those is available, - * a newly allocated one with bcs=NULL - * The structure should be freed by calling disconnect_nobc() after use. - */ -static inline struct at_state_t *get_free_channel(struct cardstate *cs, - int cid) -/* cids: >0: siemens-cid - * 0: without cid - * -1: no cid assigned yet - */ -{ - unsigned long flags; - int i; - struct at_state_t *ret; - - for (i = 0; i < cs->channels; ++i) - if (gigaset_get_channel(cs->bcs + i) >= 0) { - ret = &cs->bcs[i].at_state; - ret->cid = cid; - return ret; - } - - spin_lock_irqsave(&cs->lock, flags); - ret = kmalloc(sizeof(struct at_state_t), GFP_ATOMIC); - if (ret) { - gigaset_at_init(ret, NULL, cs, cid); - list_add(&ret->list, &cs->temp_at_states); - } - spin_unlock_irqrestore(&cs->lock, flags); - return ret; -} - -static void init_failed(struct cardstate *cs, int mode) -{ - int i; - struct at_state_t *at_state; - - cs->at_state.pending_commands &= ~PC_INIT; - cs->mode = mode; - cs->mstate = MS_UNINITIALIZED; - gigaset_free_channels(cs); - for (i = 0; i < cs->channels; ++i) { - at_state = &cs->bcs[i].at_state; - if (at_state->pending_commands & PC_CID) { - at_state->pending_commands &= ~PC_CID; - at_state->pending_commands |= PC_NOCID; - cs->commands_pending = 1; - } - } -} - -static void schedule_init(struct cardstate *cs, int state) -{ - if (cs->at_state.pending_commands & PC_INIT) { - gig_dbg(DEBUG_EVENT, "not scheduling PC_INIT again"); - return; - } - cs->mstate = state; - cs->mode = M_UNKNOWN; - gigaset_block_channels(cs); - cs->at_state.pending_commands |= PC_INIT; - gig_dbg(DEBUG_EVENT, "Scheduling PC_INIT"); - cs->commands_pending = 1; -} - -/* send an AT command - * adding the "AT" prefix, cid and DLE encapsulation as appropriate - */ -static void send_command(struct cardstate *cs, const char *cmd, - struct at_state_t *at_state) -{ - int cid = at_state->cid; - struct cmdbuf_t *cb; - size_t buflen; - - buflen = strlen(cmd) + 12; /* DLE ( A T 1 2 3 4 5 <cmd> DLE ) \0 */ - cb = kmalloc(sizeof(struct cmdbuf_t) + buflen, GFP_ATOMIC); - if (!cb) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return; - } - if (cid > 0 && cid <= 65535) - cb->len = snprintf(cb->buf, buflen, - cs->dle ? "\020(AT%d%s\020)" : "AT%d%s", - cid, cmd); - else - cb->len = snprintf(cb->buf, buflen, - cs->dle ? "\020(AT%s\020)" : "AT%s", - cmd); - cb->offset = 0; - cb->next = NULL; - cb->wake_tasklet = NULL; - cs->ops->write_cmd(cs, cb); -} - -static struct at_state_t *at_state_from_cid(struct cardstate *cs, int cid) -{ - struct at_state_t *at_state; - int i; - unsigned long flags; - - if (cid == 0) - return &cs->at_state; - - for (i = 0; i < cs->channels; ++i) - if (cid == cs->bcs[i].at_state.cid) - return &cs->bcs[i].at_state; - - spin_lock_irqsave(&cs->lock, flags); - - list_for_each_entry(at_state, &cs->temp_at_states, list) - if (cid == at_state->cid) { - spin_unlock_irqrestore(&cs->lock, flags); - return at_state; - } - - spin_unlock_irqrestore(&cs->lock, flags); - - return NULL; -} - -static void bchannel_down(struct bc_state *bcs) -{ - if (bcs->chstate & CHS_B_UP) { - bcs->chstate &= ~CHS_B_UP; - gigaset_isdn_hupB(bcs); - } - - if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) { - bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL); - gigaset_isdn_hupD(bcs); - } - - gigaset_free_channel(bcs); - - gigaset_bcs_reinit(bcs); -} - -static void bchannel_up(struct bc_state *bcs) -{ - if (bcs->chstate & CHS_B_UP) { - dev_notice(bcs->cs->dev, "%s: B channel already up\n", - __func__); - return; - } - - bcs->chstate |= CHS_B_UP; - gigaset_isdn_connB(bcs); -} - -static void start_dial(struct at_state_t *at_state, void *data, - unsigned seq_index) -{ - struct bc_state *bcs = at_state->bcs; - struct cardstate *cs = at_state->cs; - char **commands = data; - unsigned long flags; - int i; - - bcs->chstate |= CHS_NOTIFY_LL; - - spin_lock_irqsave(&cs->lock, flags); - if (at_state->seq_index != seq_index) { - spin_unlock_irqrestore(&cs->lock, flags); - goto error; - } - spin_unlock_irqrestore(&cs->lock, flags); - - for (i = 0; i < AT_NUM; ++i) { - kfree(bcs->commands[i]); - bcs->commands[i] = commands[i]; - } - - at_state->pending_commands |= PC_CID; - gig_dbg(DEBUG_EVENT, "Scheduling PC_CID"); - cs->commands_pending = 1; - return; - -error: - for (i = 0; i < AT_NUM; ++i) { - kfree(commands[i]); - commands[i] = NULL; - } - at_state->pending_commands |= PC_NOCID; - gig_dbg(DEBUG_EVENT, "Scheduling PC_NOCID"); - cs->commands_pending = 1; - return; -} - -static void start_accept(struct at_state_t *at_state) -{ - struct cardstate *cs = at_state->cs; - struct bc_state *bcs = at_state->bcs; - int i; - - for (i = 0; i < AT_NUM; ++i) { - kfree(bcs->commands[i]); - bcs->commands[i] = NULL; - } - - bcs->commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC); - bcs->commands[AT_ISO] = kmalloc(9, GFP_ATOMIC); - if (!bcs->commands[AT_PROTO] || !bcs->commands[AT_ISO]) { - dev_err(at_state->cs->dev, "out of memory\n"); - /* error reset */ - at_state->pending_commands |= PC_HUP; - gig_dbg(DEBUG_EVENT, "Scheduling PC_HUP"); - cs->commands_pending = 1; - return; - } - - snprintf(bcs->commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2); - snprintf(bcs->commands[AT_ISO], 9, "^SISO=%u\r", bcs->channel + 1); - - at_state->pending_commands |= PC_ACCEPT; - gig_dbg(DEBUG_EVENT, "Scheduling PC_ACCEPT"); - cs->commands_pending = 1; -} - -static void do_start(struct cardstate *cs) -{ - gigaset_free_channels(cs); - - if (cs->mstate != MS_LOCKED) - schedule_init(cs, MS_INIT); - - cs->isdn_up = 1; - gigaset_isdn_start(cs); - - cs->waiting = 0; - wake_up(&cs->waitqueue); -} - -static void finish_shutdown(struct cardstate *cs) -{ - if (cs->mstate != MS_LOCKED) { - cs->mstate = MS_UNINITIALIZED; - cs->mode = M_UNKNOWN; - } - - /* Tell the LL that the device is not available .. */ - if (cs->isdn_up) { - cs->isdn_up = 0; - gigaset_isdn_stop(cs); - } - - /* The rest is done by cleanup_cs() in process context. */ - - cs->cmd_result = -ENODEV; - cs->waiting = 0; - wake_up(&cs->waitqueue); -} - -static void do_shutdown(struct cardstate *cs) -{ - gigaset_block_channels(cs); - - if (cs->mstate == MS_READY) { - cs->mstate = MS_SHUTDOWN; - cs->at_state.pending_commands |= PC_SHUTDOWN; - gig_dbg(DEBUG_EVENT, "Scheduling PC_SHUTDOWN"); - cs->commands_pending = 1; - } else - finish_shutdown(cs); -} - -static void do_stop(struct cardstate *cs) -{ - unsigned long flags; - - spin_lock_irqsave(&cs->lock, flags); - cs->connected = 0; - spin_unlock_irqrestore(&cs->lock, flags); - - do_shutdown(cs); -} - -/* Entering cid mode or getting a cid failed: - * try to initialize the device and try again. - * - * channel >= 0: getting cid for the channel failed - * channel < 0: entering cid mode failed - * - * returns 0 on success, <0 on failure - */ -static int reinit_and_retry(struct cardstate *cs, int channel) -{ - int i; - - if (--cs->retry_count <= 0) - return -EFAULT; - - for (i = 0; i < cs->channels; ++i) - if (cs->bcs[i].at_state.cid > 0) - return -EBUSY; - - if (channel < 0) - dev_warn(cs->dev, - "Could not enter cid mode. Reinit device and try again.\n"); - else { - dev_warn(cs->dev, - "Could not get a call id. Reinit device and try again.\n"); - cs->bcs[channel].at_state.pending_commands |= PC_CID; - } - schedule_init(cs, MS_INIT); - return 0; -} - -static int at_state_invalid(struct cardstate *cs, - struct at_state_t *test_ptr) -{ - unsigned long flags; - unsigned channel; - struct at_state_t *at_state; - int retval = 0; - - spin_lock_irqsave(&cs->lock, flags); - - if (test_ptr == &cs->at_state) - goto exit; - - list_for_each_entry(at_state, &cs->temp_at_states, list) - if (at_state == test_ptr) - goto exit; - - for (channel = 0; channel < cs->channels; ++channel) - if (&cs->bcs[channel].at_state == test_ptr) - goto exit; - - retval = 1; -exit: - spin_unlock_irqrestore(&cs->lock, flags); - return retval; -} - -static void handle_icall(struct cardstate *cs, struct bc_state *bcs, - struct at_state_t *at_state) -{ - int retval; - - retval = gigaset_isdn_icall(at_state); - switch (retval) { - case ICALL_ACCEPT: - break; - default: - dev_err(cs->dev, "internal error: disposition=%d\n", retval); - /* fall through */ - case ICALL_IGNORE: - case ICALL_REJECT: - /* hang up actively - * Device doc says that would reject the call. - * In fact it doesn't. - */ - at_state->pending_commands |= PC_HUP; - cs->commands_pending = 1; - break; - } -} - -static int do_lock(struct cardstate *cs) -{ - int mode; - int i; - - switch (cs->mstate) { - case MS_UNINITIALIZED: - case MS_READY: - if (cs->cur_at_seq || !list_empty(&cs->temp_at_states) || - cs->at_state.pending_commands) - return -EBUSY; - - for (i = 0; i < cs->channels; ++i) - if (cs->bcs[i].at_state.pending_commands) - return -EBUSY; - - if (gigaset_get_channels(cs) < 0) - return -EBUSY; - - break; - case MS_LOCKED: - break; - default: - return -EBUSY; - } - - mode = cs->mode; - cs->mstate = MS_LOCKED; - cs->mode = M_UNKNOWN; - - return mode; -} - -static int do_unlock(struct cardstate *cs) -{ - if (cs->mstate != MS_LOCKED) - return -EINVAL; - - cs->mstate = MS_UNINITIALIZED; - cs->mode = M_UNKNOWN; - gigaset_free_channels(cs); - if (cs->connected) - schedule_init(cs, MS_INIT); - - return 0; -} - -static void do_action(int action, struct cardstate *cs, - struct bc_state *bcs, - struct at_state_t **p_at_state, char **pp_command, - int *p_genresp, int *p_resp_code, - struct event_t *ev) -{ - struct at_state_t *at_state = *p_at_state; - struct bc_state *bcs2; - unsigned long flags; - - int channel; - - unsigned char *s, *e; - int i; - unsigned long val; - - switch (action) { - case ACT_NOTHING: - break; - case ACT_TIMEOUT: - at_state->waiting = 1; - break; - case ACT_INIT: - cs->at_state.pending_commands &= ~PC_INIT; - cs->cur_at_seq = SEQ_NONE; - cs->mode = M_UNIMODEM; - spin_lock_irqsave(&cs->lock, flags); - if (!cs->cidmode) { - spin_unlock_irqrestore(&cs->lock, flags); - gigaset_free_channels(cs); - cs->mstate = MS_READY; - break; - } - spin_unlock_irqrestore(&cs->lock, flags); - cs->at_state.pending_commands |= PC_CIDMODE; - gig_dbg(DEBUG_EVENT, "Scheduling PC_CIDMODE"); - cs->commands_pending = 1; - break; - case ACT_FAILINIT: - dev_warn(cs->dev, "Could not initialize the device.\n"); - cs->dle = 0; - init_failed(cs, M_UNKNOWN); - cs->cur_at_seq = SEQ_NONE; - break; - case ACT_CONFIGMODE: - init_failed(cs, M_CONFIG); - cs->cur_at_seq = SEQ_NONE; - break; - case ACT_SETDLE1: - cs->dle = 1; - /* cs->inbuf[0].inputstate |= INS_command | INS_DLE_command; */ - cs->inbuf[0].inputstate &= - ~(INS_command | INS_DLE_command); - break; - case ACT_SETDLE0: - cs->dle = 0; - cs->inbuf[0].inputstate = - (cs->inbuf[0].inputstate & ~INS_DLE_command) - | INS_command; - break; - case ACT_CMODESET: - if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) { - gigaset_free_channels(cs); - cs->mstate = MS_READY; - } - cs->mode = M_CID; - cs->cur_at_seq = SEQ_NONE; - break; - case ACT_UMODESET: - cs->mode = M_UNIMODEM; - cs->cur_at_seq = SEQ_NONE; - break; - case ACT_FAILCMODE: - cs->cur_at_seq = SEQ_NONE; - if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) { - init_failed(cs, M_UNKNOWN); - break; - } - if (reinit_and_retry(cs, -1) < 0) - schedule_init(cs, MS_RECOVER); - break; - case ACT_FAILUMODE: - cs->cur_at_seq = SEQ_NONE; - schedule_init(cs, MS_RECOVER); - break; - case ACT_HUPMODEM: - /* send "+++" (hangup in unimodem mode) */ - if (cs->connected) { - struct cmdbuf_t *cb; - - cb = kmalloc(sizeof(struct cmdbuf_t) + 3, GFP_ATOMIC); - if (!cb) { - dev_err(cs->dev, "%s: out of memory\n", - __func__); - return; - } - memcpy(cb->buf, "+++", 3); - cb->len = 3; - cb->offset = 0; - cb->next = NULL; - cb->wake_tasklet = NULL; - cs->ops->write_cmd(cs, cb); - } - break; - case ACT_RING: - /* get fresh AT state structure for new CID */ - at_state = get_free_channel(cs, ev->parameter); - if (!at_state) { - dev_warn(cs->dev, - "RING ignored: could not allocate channel structure\n"); - break; - } - - /* initialize AT state structure - * note that bcs may be NULL if no B channel is free - */ - at_state->ConState = 700; - for (i = 0; i < STR_NUM; ++i) { - kfree(at_state->str_var[i]); - at_state->str_var[i] = NULL; - } - at_state->int_var[VAR_ZCTP] = -1; - - spin_lock_irqsave(&cs->lock, flags); - at_state->timer_expires = RING_TIMEOUT; - at_state->timer_active = 1; - spin_unlock_irqrestore(&cs->lock, flags); - break; - case ACT_ICALL: - handle_icall(cs, bcs, at_state); - break; - case ACT_FAILSDOWN: - dev_warn(cs->dev, "Could not shut down the device.\n"); - /* fall through */ - case ACT_FAKESDOWN: - case ACT_SDOWN: - cs->cur_at_seq = SEQ_NONE; - finish_shutdown(cs); - break; - case ACT_CONNECT: - if (cs->onechannel) { - at_state->pending_commands |= PC_DLE1; - cs->commands_pending = 1; - break; - } - bcs->chstate |= CHS_D_UP; - gigaset_isdn_connD(bcs); - cs->ops->init_bchannel(bcs); - break; - case ACT_DLE1: - cs->cur_at_seq = SEQ_NONE; - bcs = cs->bcs + cs->curchannel; - - bcs->chstate |= CHS_D_UP; - gigaset_isdn_connD(bcs); - cs->ops->init_bchannel(bcs); - break; - case ACT_FAKEHUP: - at_state->int_var[VAR_ZSAU] = ZSAU_NULL; - /* fall through */ - case ACT_DISCONNECT: - cs->cur_at_seq = SEQ_NONE; - at_state->cid = -1; - if (!bcs) { - disconnect_nobc(p_at_state, cs); - } else if (cs->onechannel && cs->dle) { - /* Check for other open channels not needed: - * DLE only used for M10x with one B channel. - */ - at_state->pending_commands |= PC_DLE0; - cs->commands_pending = 1; - } else { - disconnect_bc(at_state, cs, bcs); - } - break; - case ACT_FAKEDLE0: - at_state->int_var[VAR_ZDLE] = 0; - cs->dle = 0; - /* fall through */ - case ACT_DLE0: - cs->cur_at_seq = SEQ_NONE; - bcs2 = cs->bcs + cs->curchannel; - disconnect_bc(&bcs2->at_state, cs, bcs2); - break; - case ACT_ABORTHUP: - cs->cur_at_seq = SEQ_NONE; - dev_warn(cs->dev, "Could not hang up.\n"); - at_state->cid = -1; - if (!bcs) - disconnect_nobc(p_at_state, cs); - else if (cs->onechannel) - at_state->pending_commands |= PC_DLE0; - else - disconnect_bc(at_state, cs, bcs); - schedule_init(cs, MS_RECOVER); - break; - case ACT_FAILDLE0: - cs->cur_at_seq = SEQ_NONE; - dev_warn(cs->dev, "Error leaving DLE mode.\n"); - cs->dle = 0; - bcs2 = cs->bcs + cs->curchannel; - disconnect_bc(&bcs2->at_state, cs, bcs2); - schedule_init(cs, MS_RECOVER); - break; - case ACT_FAILDLE1: - cs->cur_at_seq = SEQ_NONE; - dev_warn(cs->dev, - "Could not enter DLE mode. Trying to hang up.\n"); - channel = cs->curchannel; - cs->bcs[channel].at_state.pending_commands |= PC_HUP; - cs->commands_pending = 1; - break; - - case ACT_CID: /* got cid; start dialing */ - cs->cur_at_seq = SEQ_NONE; - channel = cs->curchannel; - if (ev->parameter > 0 && ev->parameter <= 65535) { - cs->bcs[channel].at_state.cid = ev->parameter; - cs->bcs[channel].at_state.pending_commands |= - PC_DIAL; - cs->commands_pending = 1; - break; - } - /* fall through - bad cid */ - case ACT_FAILCID: - cs->cur_at_seq = SEQ_NONE; - channel = cs->curchannel; - if (reinit_and_retry(cs, channel) < 0) { - dev_warn(cs->dev, - "Could not get a call ID. Cannot dial.\n"); - bcs2 = cs->bcs + channel; - disconnect_bc(&bcs2->at_state, cs, bcs2); - } - break; - case ACT_ABORTCID: - cs->cur_at_seq = SEQ_NONE; - bcs2 = cs->bcs + cs->curchannel; - disconnect_bc(&bcs2->at_state, cs, bcs2); - break; - - case ACT_DIALING: - case ACT_ACCEPTED: - cs->cur_at_seq = SEQ_NONE; - break; - - case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL procssng */ - if (bcs) - disconnect_bc(at_state, cs, bcs); - else - disconnect_nobc(p_at_state, cs); - break; - - case ACT_ABORTDIAL: /* error/timeout during dial preparation */ - cs->cur_at_seq = SEQ_NONE; - at_state->pending_commands |= PC_HUP; - cs->commands_pending = 1; - break; - - case ACT_REMOTEREJECT: /* DISCONNECT_IND after dialling */ - case ACT_CONNTIMEOUT: /* timeout waiting for ZSAU=ACTIVE */ - case ACT_REMOTEHUP: /* DISCONNECT_IND with established connection */ - at_state->pending_commands |= PC_HUP; - cs->commands_pending = 1; - break; - case ACT_GETSTRING: /* warning: RING, ZDLE, ... - are not handled properly anymore */ - at_state->getstring = 1; - break; - case ACT_SETVER: - if (!ev->ptr) { - *p_genresp = 1; - *p_resp_code = RSP_ERROR; - break; - } - s = ev->ptr; - - if (!strcmp(s, "OK")) { - /* OK without version string: assume old response */ - *p_genresp = 1; - *p_resp_code = RSP_NONE; - break; - } - - for (i = 0; i < 4; ++i) { - val = simple_strtoul(s, (char **) &e, 10); - if (val > INT_MAX || e == s) - break; - if (i == 3) { - if (*e) - break; - } else if (*e != '.') - break; - else - s = e + 1; - cs->fwver[i] = val; - } - if (i != 4) { - *p_genresp = 1; - *p_resp_code = RSP_ERROR; - break; - } - cs->gotfwver = 0; - break; - case ACT_GOTVER: - if (cs->gotfwver == 0) { - cs->gotfwver = 1; - gig_dbg(DEBUG_EVENT, - "firmware version %02d.%03d.%02d.%02d", - cs->fwver[0], cs->fwver[1], - cs->fwver[2], cs->fwver[3]); - break; - } - /* fall through */ - case ACT_FAILVER: - cs->gotfwver = -1; - dev_err(cs->dev, "could not read firmware version.\n"); - break; - case ACT_ERROR: - gig_dbg(DEBUG_ANY, "%s: ERROR response in ConState %d", - __func__, at_state->ConState); - cs->cur_at_seq = SEQ_NONE; - break; - case ACT_DEBUG: - gig_dbg(DEBUG_ANY, "%s: resp_code %d in ConState %d", - __func__, ev->type, at_state->ConState); - break; - case ACT_WARN: - dev_warn(cs->dev, "%s: resp_code %d in ConState %d!\n", - __func__, ev->type, at_state->ConState); - break; - case ACT_ZCAU: - dev_warn(cs->dev, "cause code %04x in connection state %d.\n", - ev->parameter, at_state->ConState); - break; - - /* events from the LL */ - - case ACT_DIAL: - if (!ev->ptr) { - *p_genresp = 1; - *p_resp_code = RSP_ERROR; - break; - } - start_dial(at_state, ev->ptr, ev->parameter); - break; - case ACT_ACCEPT: - start_accept(at_state); - break; - case ACT_HUP: - at_state->pending_commands |= PC_HUP; - gig_dbg(DEBUG_EVENT, "Scheduling PC_HUP"); - cs->commands_pending = 1; - break; - - /* hotplug events */ - - case ACT_STOP: - do_stop(cs); - break; - case ACT_START: - do_start(cs); - break; - - /* events from the interface */ - - case ACT_IF_LOCK: - cs->cmd_result = ev->parameter ? do_lock(cs) : do_unlock(cs); - cs->waiting = 0; - wake_up(&cs->waitqueue); - break; - case ACT_IF_VER: - if (ev->parameter != 0) - cs->cmd_result = -EINVAL; - else if (cs->gotfwver != 1) { - cs->cmd_result = -ENOENT; - } else { - memcpy(ev->arg, cs->fwver, sizeof cs->fwver); - cs->cmd_result = 0; - } - cs->waiting = 0; - wake_up(&cs->waitqueue); - break; - - /* events from the proc file system */ - - case ACT_PROC_CIDMODE: - spin_lock_irqsave(&cs->lock, flags); - if (ev->parameter != cs->cidmode) { - cs->cidmode = ev->parameter; - if (ev->parameter) { - cs->at_state.pending_commands |= PC_CIDMODE; - gig_dbg(DEBUG_EVENT, "Scheduling PC_CIDMODE"); - } else { - cs->at_state.pending_commands |= PC_UMMODE; - gig_dbg(DEBUG_EVENT, "Scheduling PC_UMMODE"); - } - cs->commands_pending = 1; - } - spin_unlock_irqrestore(&cs->lock, flags); - cs->waiting = 0; - wake_up(&cs->waitqueue); - break; - - /* events from the hardware drivers */ - - case ACT_NOTIFY_BC_DOWN: - bchannel_down(bcs); - break; - case ACT_NOTIFY_BC_UP: - bchannel_up(bcs); - break; - case ACT_SHUTDOWN: - do_shutdown(cs); - break; - - - default: - if (action >= ACT_CMD && action < ACT_CMD + AT_NUM) { - *pp_command = at_state->bcs->commands[action - ACT_CMD]; - if (!*pp_command) { - *p_genresp = 1; - *p_resp_code = RSP_NULL; - } - } else - dev_err(cs->dev, "%s: action==%d!\n", __func__, action); - } -} - -/* State machine to do the calling and hangup procedure */ -static void process_event(struct cardstate *cs, struct event_t *ev) -{ - struct bc_state *bcs; - char *p_command = NULL; - struct reply_t *rep; - int rcode; - int genresp = 0; - int resp_code = RSP_ERROR; - struct at_state_t *at_state; - int index; - int curact; - unsigned long flags; - - if (ev->cid >= 0) { - at_state = at_state_from_cid(cs, ev->cid); - if (!at_state) { - gig_dbg(DEBUG_EVENT, "event %d for invalid cid %d", - ev->type, ev->cid); - gigaset_add_event(cs, &cs->at_state, RSP_WRONG_CID, - NULL, 0, NULL); - return; - } - } else { - at_state = ev->at_state; - if (at_state_invalid(cs, at_state)) { - gig_dbg(DEBUG_EVENT, "event for invalid at_state %p", - at_state); - return; - } - } - - gig_dbg(DEBUG_EVENT, "connection state %d, event %d", - at_state->ConState, ev->type); - - bcs = at_state->bcs; - - /* Setting the pointer to the dial array */ - rep = at_state->replystruct; - - spin_lock_irqsave(&cs->lock, flags); - if (ev->type == EV_TIMEOUT) { - if (ev->parameter != at_state->timer_index - || !at_state->timer_active) { - ev->type = RSP_NONE; /* old timeout */ - gig_dbg(DEBUG_EVENT, "old timeout"); - } else { - if (at_state->waiting) - gig_dbg(DEBUG_EVENT, "stopped waiting"); - else - gig_dbg(DEBUG_EVENT, "timeout occurred"); - } - } - spin_unlock_irqrestore(&cs->lock, flags); - - /* if the response belongs to a variable in at_state->int_var[VAR_XXXX] - or at_state->str_var[STR_XXXX], set it */ - if (ev->type >= RSP_VAR && ev->type < RSP_VAR + VAR_NUM) { - index = ev->type - RSP_VAR; - at_state->int_var[index] = ev->parameter; - } else if (ev->type >= RSP_STR && ev->type < RSP_STR + STR_NUM) { - index = ev->type - RSP_STR; - kfree(at_state->str_var[index]); - at_state->str_var[index] = ev->ptr; - ev->ptr = NULL; /* prevent process_events() from - deallocating ptr */ - } - - if (ev->type == EV_TIMEOUT || ev->type == RSP_STRING) - at_state->getstring = 0; - - /* Search row in dial array which matches modem response and current - constate */ - for (;; rep++) { - rcode = rep->resp_code; - if (rcode == RSP_LAST) { - /* found nothing...*/ - dev_warn(cs->dev, "%s: rcode=RSP_LAST: " - "resp_code %d in ConState %d!\n", - __func__, ev->type, at_state->ConState); - return; - } - if ((rcode == RSP_ANY || rcode == ev->type) - && ((int) at_state->ConState >= rep->min_ConState) - && (rep->max_ConState < 0 - || (int) at_state->ConState <= rep->max_ConState) - && (rep->parameter < 0 || rep->parameter == ev->parameter)) - break; - } - - p_command = rep->command; - - at_state->waiting = 0; - for (curact = 0; curact < MAXACT; ++curact) { - /* The row tells us what we should do .. - */ - do_action(rep->action[curact], cs, bcs, &at_state, &p_command, - &genresp, &resp_code, ev); - if (!at_state) - /* at_state destroyed by disconnect */ - return; - } - - /* Jump to the next con-state regarding the array */ - if (rep->new_ConState >= 0) - at_state->ConState = rep->new_ConState; - - if (genresp) { - spin_lock_irqsave(&cs->lock, flags); - at_state->timer_expires = 0; - at_state->timer_active = 0; - spin_unlock_irqrestore(&cs->lock, flags); - gigaset_add_event(cs, at_state, resp_code, NULL, 0, NULL); - } else { - /* Send command to modem if not NULL... */ - if (p_command) { - if (cs->connected) - send_command(cs, p_command, at_state); - else - gigaset_add_event(cs, at_state, RSP_NODEV, - NULL, 0, NULL); - } - - spin_lock_irqsave(&cs->lock, flags); - if (!rep->timeout) { - at_state->timer_expires = 0; - at_state->timer_active = 0; - } else if (rep->timeout > 0) { /* new timeout */ - at_state->timer_expires = rep->timeout * 10; - at_state->timer_active = 1; - ++at_state->timer_index; - } - spin_unlock_irqrestore(&cs->lock, flags); - } -} - -static void schedule_sequence(struct cardstate *cs, - struct at_state_t *at_state, int sequence) -{ - cs->cur_at_seq = sequence; - gigaset_add_event(cs, at_state, RSP_INIT, NULL, sequence, NULL); -} - -static void process_command_flags(struct cardstate *cs) -{ - struct at_state_t *at_state = NULL; - struct bc_state *bcs; - int i; - int sequence; - unsigned long flags; - - cs->commands_pending = 0; - - if (cs->cur_at_seq) { - gig_dbg(DEBUG_EVENT, "not searching scheduled commands: busy"); - return; - } - - gig_dbg(DEBUG_EVENT, "searching scheduled commands"); - - sequence = SEQ_NONE; - - /* clear pending_commands and hangup channels on shutdown */ - if (cs->at_state.pending_commands & PC_SHUTDOWN) { - cs->at_state.pending_commands &= ~PC_CIDMODE; - for (i = 0; i < cs->channels; ++i) { - bcs = cs->bcs + i; - at_state = &bcs->at_state; - at_state->pending_commands &= - ~(PC_DLE1 | PC_ACCEPT | PC_DIAL); - if (at_state->cid > 0) - at_state->pending_commands |= PC_HUP; - if (at_state->pending_commands & PC_CID) { - at_state->pending_commands |= PC_NOCID; - at_state->pending_commands &= ~PC_CID; - } - } - } - - /* clear pending_commands and hangup channels on reset */ - if (cs->at_state.pending_commands & PC_INIT) { - cs->at_state.pending_commands &= ~PC_CIDMODE; - for (i = 0; i < cs->channels; ++i) { - bcs = cs->bcs + i; - at_state = &bcs->at_state; - at_state->pending_commands &= - ~(PC_DLE1 | PC_ACCEPT | PC_DIAL); - if (at_state->cid > 0) - at_state->pending_commands |= PC_HUP; - if (cs->mstate == MS_RECOVER) { - if (at_state->pending_commands & PC_CID) { - at_state->pending_commands |= PC_NOCID; - at_state->pending_commands &= ~PC_CID; - } - } - } - } - - /* only switch back to unimodem mode if no commands are pending and - * no channels are up */ - spin_lock_irqsave(&cs->lock, flags); - if (cs->at_state.pending_commands == PC_UMMODE - && !cs->cidmode - && list_empty(&cs->temp_at_states) - && cs->mode == M_CID) { - sequence = SEQ_UMMODE; - at_state = &cs->at_state; - for (i = 0; i < cs->channels; ++i) { - bcs = cs->bcs + i; - if (bcs->at_state.pending_commands || - bcs->at_state.cid > 0) { - sequence = SEQ_NONE; - break; - } - } - } - spin_unlock_irqrestore(&cs->lock, flags); - cs->at_state.pending_commands &= ~PC_UMMODE; - if (sequence != SEQ_NONE) { - schedule_sequence(cs, at_state, sequence); - return; - } - - for (i = 0; i < cs->channels; ++i) { - bcs = cs->bcs + i; - if (bcs->at_state.pending_commands & PC_HUP) { - if (cs->dle) { - cs->curchannel = bcs->channel; - schedule_sequence(cs, &cs->at_state, SEQ_DLE0); - return; - } - bcs->at_state.pending_commands &= ~PC_HUP; - if (bcs->at_state.pending_commands & PC_CID) { - /* not yet dialing: PC_NOCID is sufficient */ - bcs->at_state.pending_commands |= PC_NOCID; - bcs->at_state.pending_commands &= ~PC_CID; - } else { - schedule_sequence(cs, &bcs->at_state, SEQ_HUP); - return; - } - } - if (bcs->at_state.pending_commands & PC_NOCID) { - bcs->at_state.pending_commands &= ~PC_NOCID; - cs->curchannel = bcs->channel; - schedule_sequence(cs, &cs->at_state, SEQ_NOCID); - return; - } else if (bcs->at_state.pending_commands & PC_DLE0) { - bcs->at_state.pending_commands &= ~PC_DLE0; - cs->curchannel = bcs->channel; - schedule_sequence(cs, &cs->at_state, SEQ_DLE0); - return; - } - } - - list_for_each_entry(at_state, &cs->temp_at_states, list) - if (at_state->pending_commands & PC_HUP) { - at_state->pending_commands &= ~PC_HUP; - schedule_sequence(cs, at_state, SEQ_HUP); - return; - } - - if (cs->at_state.pending_commands & PC_INIT) { - cs->at_state.pending_commands &= ~PC_INIT; - cs->dle = 0; - cs->inbuf->inputstate = INS_command; - schedule_sequence(cs, &cs->at_state, SEQ_INIT); - return; - } - if (cs->at_state.pending_commands & PC_SHUTDOWN) { - cs->at_state.pending_commands &= ~PC_SHUTDOWN; - schedule_sequence(cs, &cs->at_state, SEQ_SHUTDOWN); - return; - } - if (cs->at_state.pending_commands & PC_CIDMODE) { - cs->at_state.pending_commands &= ~PC_CIDMODE; - if (cs->mode == M_UNIMODEM) { - cs->retry_count = 1; - schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE); - return; - } - } - - for (i = 0; i < cs->channels; ++i) { - bcs = cs->bcs + i; - if (bcs->at_state.pending_commands & PC_DLE1) { - bcs->at_state.pending_commands &= ~PC_DLE1; - cs->curchannel = bcs->channel; - schedule_sequence(cs, &cs->at_state, SEQ_DLE1); - return; - } - if (bcs->at_state.pending_commands & PC_ACCEPT) { - bcs->at_state.pending_commands &= ~PC_ACCEPT; - schedule_sequence(cs, &bcs->at_state, SEQ_ACCEPT); - return; - } - if (bcs->at_state.pending_commands & PC_DIAL) { - bcs->at_state.pending_commands &= ~PC_DIAL; - schedule_sequence(cs, &bcs->at_state, SEQ_DIAL); - return; - } - if (bcs->at_state.pending_commands & PC_CID) { - switch (cs->mode) { - case M_UNIMODEM: - cs->at_state.pending_commands |= PC_CIDMODE; - gig_dbg(DEBUG_EVENT, "Scheduling PC_CIDMODE"); - cs->commands_pending = 1; - return; - case M_UNKNOWN: - schedule_init(cs, MS_INIT); - return; - } - bcs->at_state.pending_commands &= ~PC_CID; - cs->curchannel = bcs->channel; - cs->retry_count = 2; - schedule_sequence(cs, &cs->at_state, SEQ_CID); - return; - } - } -} - -static void process_events(struct cardstate *cs) -{ - struct event_t *ev; - unsigned head, tail; - int i; - int check_flags = 0; - int was_busy; - unsigned long flags; - - spin_lock_irqsave(&cs->ev_lock, flags); - head = cs->ev_head; - - for (i = 0; i < 2 * MAX_EVENTS; ++i) { - tail = cs->ev_tail; - if (tail == head) { - if (!check_flags && !cs->commands_pending) - break; - check_flags = 0; - spin_unlock_irqrestore(&cs->ev_lock, flags); - process_command_flags(cs); - spin_lock_irqsave(&cs->ev_lock, flags); - tail = cs->ev_tail; - if (tail == head) { - if (!cs->commands_pending) - break; - continue; - } - } - - ev = cs->events + head; - was_busy = cs->cur_at_seq != SEQ_NONE; - spin_unlock_irqrestore(&cs->ev_lock, flags); - process_event(cs, ev); - spin_lock_irqsave(&cs->ev_lock, flags); - kfree(ev->ptr); - ev->ptr = NULL; - if (was_busy && cs->cur_at_seq == SEQ_NONE) - check_flags = 1; - - head = (head + 1) % MAX_EVENTS; - cs->ev_head = head; - } - - spin_unlock_irqrestore(&cs->ev_lock, flags); - - if (i == 2 * MAX_EVENTS) { - dev_err(cs->dev, - "infinite loop in process_events; aborting.\n"); - } -} - -/* tasklet scheduled on any event received from the Gigaset device - * parameter: - * data ISDN controller state structure - */ -void gigaset_handle_event(unsigned long data) -{ - struct cardstate *cs = (struct cardstate *) data; - - /* handle incoming data on control/common channel */ - if (cs->inbuf->head != cs->inbuf->tail) { - gig_dbg(DEBUG_INTR, "processing new data"); - cs->ops->handle_input(cs->inbuf); - } - - process_events(cs); -} diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h deleted file mode 100644 index 0ecc2b5ea553..000000000000 --- a/drivers/isdn/gigaset/gigaset.h +++ /dev/null @@ -1,827 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Siemens Gigaset 307x driver - * Common header file for all connection variants - * - * Written by Stefan Eilers - * and Hansjoerg Lipp <hjlipp@web.de> - * - * ===================================================================== - * ===================================================================== - */ - -#ifndef GIGASET_H -#define GIGASET_H - -/* define global prefix for pr_ macros in linux/kernel.h */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/compiler.h> -#include <linux/types.h> -#include <linux/ctype.h> -#include <linux/slab.h> -#include <linux/spinlock.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/ppp_defs.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_driver.h> -#include <linux/list.h> -#include <linux/atomic.h> - -#define GIG_VERSION {0, 5, 0, 0} -#define GIG_COMPAT {0, 4, 0, 0} - -#define MAX_REC_PARAMS 10 /* Max. number of params in response string */ -#define MAX_RESP_SIZE 511 /* Max. size of a response string */ - -#define MAX_EVENTS 64 /* size of event queue */ - -#define RBUFSIZE 8192 - -#define GIG_TICK 100 /* in milliseconds */ - -/* timeout values (unit: 1 sec) */ -#define INIT_TIMEOUT 1 - -/* timeout values (unit: 0.1 sec) */ -#define RING_TIMEOUT 3 /* for additional parameters to RING */ -#define BAS_TIMEOUT 20 /* for response to Base USB ops */ -#define ATRDY_TIMEOUT 3 /* for HD_READY_SEND_ATDATA */ - -#define BAS_RETRY 3 /* max. retries for base USB ops */ - -#define MAXACT 3 - -extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */ - -/* debug flags, combine by adding/bitwise OR */ -enum debuglevel { - DEBUG_INTR = 0x00008, /* interrupt processing */ - DEBUG_CMD = 0x00020, /* sent/received LL commands */ - DEBUG_STREAM = 0x00040, /* application data stream I/O events */ - DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */ - DEBUG_LLDATA = 0x00100, /* sent/received LL data */ - DEBUG_EVENT = 0x00200, /* event processing */ - DEBUG_HDLC = 0x00800, /* M10x HDLC processing */ - DEBUG_CHANNEL = 0x01000, /* channel allocation/deallocation */ - DEBUG_TRANSCMD = 0x02000, /* AT-COMMANDS+RESPONSES */ - DEBUG_MCMD = 0x04000, /* COMMANDS THAT ARE SENT VERY OFTEN */ - DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data - structures */ - DEBUG_SUSPEND = 0x10000, /* suspend/resume processing */ - DEBUG_OUTPUT = 0x20000, /* output to device */ - DEBUG_ISO = 0x40000, /* isochronous transfers */ - DEBUG_IF = 0x80000, /* character device operations */ - DEBUG_USBREQ = 0x100000, /* USB communication (except payload - data) */ - DEBUG_LOCKCMD = 0x200000, /* AT commands and responses when - MS_LOCKED */ - - DEBUG_ANY = 0x3fffff, /* print message if any of the others is - activated */ -}; - -#ifdef CONFIG_GIGASET_DEBUG - -#define gig_dbg(level, format, arg...) \ - do { \ - if (unlikely(((enum debuglevel)gigaset_debuglevel) & (level))) \ - printk(KERN_DEBUG KBUILD_MODNAME ": " format "\n", \ - ## arg); \ - } while (0) -#define DEBUG_DEFAULT (DEBUG_TRANSCMD | DEBUG_CMD | DEBUG_USBREQ) - -#else - -#define gig_dbg(level, format, arg...) do {} while (0) -#define DEBUG_DEFAULT 0 - -#endif - -void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, - size_t len, const unsigned char *buf); - -/* connection state */ -#define ZSAU_NONE 0 -#define ZSAU_PROCEEDING 1 -#define ZSAU_CALL_DELIVERED 2 -#define ZSAU_ACTIVE 3 -#define ZSAU_DISCONNECT_IND 4 -#define ZSAU_NULL 5 -#define ZSAU_DISCONNECT_REQ 6 -#define ZSAU_UNKNOWN -1 - -/* USB control transfer requests */ -#define OUT_VENDOR_REQ (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT) -#define IN_VENDOR_REQ (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT) - -/* interrupt pipe messages */ -#define HD_B1_FLOW_CONTROL 0x80 -#define HD_B2_FLOW_CONTROL 0x81 -#define HD_RECEIVEATDATA_ACK (0x35) /* 3070 */ -#define HD_READY_SEND_ATDATA (0x36) /* 3070 */ -#define HD_OPEN_ATCHANNEL_ACK (0x37) /* 3070 */ -#define HD_CLOSE_ATCHANNEL_ACK (0x38) /* 3070 */ -#define HD_DEVICE_INIT_OK (0x11) /* ISurf USB + 3070 */ -#define HD_OPEN_B1CHANNEL_ACK (0x51) /* ISurf USB + 3070 */ -#define HD_OPEN_B2CHANNEL_ACK (0x52) /* ISurf USB + 3070 */ -#define HD_CLOSE_B1CHANNEL_ACK (0x53) /* ISurf USB + 3070 */ -#define HD_CLOSE_B2CHANNEL_ACK (0x54) /* ISurf USB + 3070 */ -#define HD_SUSPEND_END (0x61) /* ISurf USB */ -#define HD_RESET_INTERRUPT_PIPE_ACK (0xFF) /* ISurf USB + 3070 */ - -/* control requests */ -#define HD_OPEN_B1CHANNEL (0x23) /* ISurf USB + 3070 */ -#define HD_CLOSE_B1CHANNEL (0x24) /* ISurf USB + 3070 */ -#define HD_OPEN_B2CHANNEL (0x25) /* ISurf USB + 3070 */ -#define HD_CLOSE_B2CHANNEL (0x26) /* ISurf USB + 3070 */ -#define HD_RESET_INTERRUPT_PIPE (0x27) /* ISurf USB + 3070 */ -#define HD_DEVICE_INIT_ACK (0x34) /* ISurf USB + 3070 */ -#define HD_WRITE_ATMESSAGE (0x12) /* 3070 */ -#define HD_READ_ATMESSAGE (0x13) /* 3070 */ -#define HD_OPEN_ATCHANNEL (0x28) /* 3070 */ -#define HD_CLOSE_ATCHANNEL (0x29) /* 3070 */ - -/* number of B channels supported by base driver */ -#define BAS_CHANNELS 2 - -/* USB frames for isochronous transfer */ -#define BAS_FRAMETIME 1 /* number of milliseconds between frames */ -#define BAS_NUMFRAMES 8 /* number of frames per URB */ -#define BAS_MAXFRAME 16 /* allocated bytes per frame */ -#define BAS_NORMFRAME 8 /* send size without flow control */ -#define BAS_HIGHFRAME 10 /* " " with positive flow control */ -#define BAS_LOWFRAME 5 /* " " with negative flow control */ -#define BAS_CORRFRAMES 4 /* flow control multiplicator */ - -#define BAS_INBUFSIZE (BAS_MAXFRAME * BAS_NUMFRAMES) /* size of isoc in buf - * per URB */ -#define BAS_OUTBUFSIZE 4096 /* size of common isoc out buffer */ -#define BAS_OUTBUFPAD BAS_MAXFRAME /* size of pad area for isoc out buf */ - -#define BAS_INURBS 3 -#define BAS_OUTURBS 3 - -/* variable commands in struct bc_state */ -#define AT_ISO 0 -#define AT_DIAL 1 -#define AT_MSN 2 -#define AT_BC 3 -#define AT_PROTO 4 -#define AT_TYPE 5 -#define AT_CLIP 6 -/* total number */ -#define AT_NUM 7 - -/* variables in struct at_state_t */ -/* - numeric */ -#define VAR_ZSAU 0 -#define VAR_ZDLE 1 -#define VAR_ZCTP 2 -/* total number */ -#define VAR_NUM 3 -/* - string */ -#define STR_NMBR 0 -#define STR_ZCPN 1 -#define STR_ZCON 2 -#define STR_ZBC 3 -#define STR_ZHLC 4 -/* total number */ -#define STR_NUM 5 - -/* event types */ -#define EV_TIMEOUT -105 -#define EV_IF_VER -106 -#define EV_PROC_CIDMODE -107 -#define EV_SHUTDOWN -108 -#define EV_START -110 -#define EV_STOP -111 -#define EV_IF_LOCK -112 -#define EV_ACCEPT -114 -#define EV_DIAL -115 -#define EV_HUP -116 -#define EV_BC_OPEN -117 -#define EV_BC_CLOSED -118 - -/* input state */ -#define INS_command 0x0001 /* receiving messages (not payload data) */ -#define INS_DLE_char 0x0002 /* DLE flag received (in DLE mode) */ -#define INS_byte_stuff 0x0004 -#define INS_have_data 0x0008 -#define INS_DLE_command 0x0020 /* DLE message start (<DLE> X) received */ -#define INS_flag_hunt 0x0040 - -/* channel state */ -#define CHS_D_UP 0x01 -#define CHS_B_UP 0x02 -#define CHS_NOTIFY_LL 0x04 - -#define ICALL_REJECT 0 -#define ICALL_ACCEPT 1 -#define ICALL_IGNORE 2 - -/* device state */ -#define MS_UNINITIALIZED 0 -#define MS_INIT 1 -#define MS_LOCKED 2 -#define MS_SHUTDOWN 3 -#define MS_RECOVER 4 -#define MS_READY 5 - -/* mode */ -#define M_UNKNOWN 0 -#define M_CONFIG 1 -#define M_UNIMODEM 2 -#define M_CID 3 - -/* start mode */ -#define SM_LOCKED 0 -#define SM_ISDN 1 /* default */ - -/* layer 2 protocols (AT^SBPR=...) */ -#define L2_BITSYNC 0 -#define L2_HDLC 1 -#define L2_VOICE 2 - -struct gigaset_ops; -struct gigaset_driver; - -struct usb_cardstate; -struct ser_cardstate; -struct bas_cardstate; - -struct bc_state; -struct usb_bc_state; -struct ser_bc_state; -struct bas_bc_state; - -struct reply_t { - int resp_code; /* RSP_XXXX */ - int min_ConState; /* <0 => ignore */ - int max_ConState; /* <0 => ignore */ - int parameter; /* e.g. ZSAU_XXXX <0: ignore*/ - int new_ConState; /* <0 => ignore */ - int timeout; /* >0 => *HZ; <=0 => TOUT_XXXX*/ - int action[MAXACT]; /* ACT_XXXX */ - char *command; /* NULL==none */ -}; - -extern struct reply_t gigaset_tab_cid[]; -extern struct reply_t gigaset_tab_nocid[]; - -struct inbuf_t { - struct cardstate *cs; - int inputstate; - int head, tail; - unsigned char data[RBUFSIZE]; -}; - -/* isochronous write buffer structure - * circular buffer with pad area for extraction of complete USB frames - * - data[read..nextread-1] is valid data already submitted to the USB subsystem - * - data[nextread..write-1] is valid data yet to be sent - * - data[write] is the next byte to write to - * - in byte-oriented L2 procotols, it is completely free - * - in bit-oriented L2 procotols, it may contain a partial byte of valid data - * - data[write+1..read-1] is free - * - wbits is the number of valid data bits in data[write], starting at the LSB - * - writesem is the semaphore for writing to the buffer: - * if writesem <= 0, data[write..read-1] is currently being written to - * - idle contains the byte value to repeat when the end of valid data is - * reached; if nextread==write (buffer contains no data to send), either the - * BAS_OUTBUFPAD bytes immediately before data[write] (if - * write>=BAS_OUTBUFPAD) or those of the pad area (if write<BAS_OUTBUFPAD) - * are also filled with that value - */ -struct isowbuf_t { - int read; - int nextread; - int write; - atomic_t writesem; - int wbits; - unsigned char data[BAS_OUTBUFSIZE + BAS_OUTBUFPAD]; - unsigned char idle; -}; - -/* isochronous write URB context structure - * data to be stored along with the URB and retrieved when it is returned - * as completed by the USB subsystem - * - urb: pointer to the URB itself - * - bcs: pointer to the B Channel control structure - * - limit: end of write buffer area covered by this URB - * - status: URB completion status - */ -struct isow_urbctx_t { - struct urb *urb; - struct bc_state *bcs; - int limit; - int status; -}; - -/* AT state structure - * data associated with the state of an ISDN connection, whether or not - * it is currently assigned a B channel - */ -struct at_state_t { - struct list_head list; - int waiting; - int getstring; - unsigned timer_index; - unsigned long timer_expires; - int timer_active; - unsigned int ConState; /* State of connection */ - struct reply_t *replystruct; - int cid; - int int_var[VAR_NUM]; /* see VAR_XXXX */ - char *str_var[STR_NUM]; /* see STR_XXXX */ - unsigned pending_commands; /* see PC_XXXX */ - unsigned seq_index; - - struct cardstate *cs; - struct bc_state *bcs; -}; - -struct event_t { - int type; - void *ptr, *arg; - int parameter; - int cid; - struct at_state_t *at_state; -}; - -/* This buffer holds all information about the used B-Channel */ -struct bc_state { - struct sk_buff *tx_skb; /* Current transfer buffer to modem */ - struct sk_buff_head squeue; /* B-Channel send Queue */ - - /* Variables for debugging .. */ - int corrupted; /* Counter for corrupted packages */ - int trans_down; /* Counter of packages (downstream) */ - int trans_up; /* Counter of packages (upstream) */ - - struct at_state_t at_state; - - /* receive buffer */ - unsigned rx_bufsize; /* max size accepted by application */ - struct sk_buff *rx_skb; - __u16 rx_fcs; - int inputstate; /* see INS_XXXX */ - - int channel; - - struct cardstate *cs; - - unsigned chstate; /* bitmap (CHS_*) */ - int ignore; - unsigned proto2; /* layer 2 protocol (L2_*) */ - char *commands[AT_NUM]; /* see AT_XXXX */ - -#ifdef CONFIG_GIGASET_DEBUG - int emptycount; -#endif - int busy; - int use_count; - - /* private data of hardware drivers */ - union { - struct ser_bc_state *ser; /* serial hardware driver */ - struct usb_bc_state *usb; /* usb hardware driver (m105) */ - struct bas_bc_state *bas; /* usb hardware driver (base) */ - } hw; - - void *ap; /* associated LL application */ - int apconnstate; /* LL application connection state */ - spinlock_t aplock; -}; - -struct cardstate { - struct gigaset_driver *driver; - unsigned minor_index; - struct device *dev; - struct device *tty_dev; - unsigned flags; - - const struct gigaset_ops *ops; - - /* Stuff to handle communication */ - wait_queue_head_t waitqueue; - int waiting; - int mode; /* see M_XXXX */ - int mstate; /* Modem state: see MS_XXXX */ - /* only changed by the event layer */ - int cmd_result; - - int channels; - struct bc_state *bcs; /* Array of struct bc_state */ - - int onechannel; /* data and commands transmitted in one - stream (M10x) */ - - spinlock_t lock; - struct at_state_t at_state; /* at_state_t for cid == 0 */ - struct list_head temp_at_states;/* list of temporary "struct - at_state_t"s without B channel */ - - struct inbuf_t *inbuf; - - struct cmdbuf_t *cmdbuf, *lastcmdbuf; - spinlock_t cmdlock; - unsigned curlen, cmdbytes; - - struct tty_port port; - struct tasklet_struct if_wake_tasklet; - unsigned control_state; - - unsigned fwver[4]; - int gotfwver; - - unsigned running; /* !=0 if events are handled */ - unsigned connected; /* !=0 if hardware is connected */ - unsigned isdn_up; /* !=0 after gigaset_isdn_start() */ - - unsigned cidmode; - - int myid; /* id for communication with LL */ - void *iif; /* LL interface structure */ - unsigned short hw_hdr_len; /* headroom needed in data skbs */ - - struct reply_t *tabnocid; - struct reply_t *tabcid; - int cs_init; - int ignoreframes; /* frames to ignore after setting up the - B channel */ - struct mutex mutex; /* locks this structure: - * connected is not changed, - * hardware_up is not changed, - * MState is not changed to or from - * MS_LOCKED */ - - struct timer_list timer; - int retry_count; - int dle; /* !=0 if DLE mode is active - (ZDLE=1 received -- M10x only) */ - int cur_at_seq; /* sequence of AT commands being - processed */ - int curchannel; /* channel those commands are meant - for */ - int commands_pending; /* flag(s) in xxx.commands_pending have - been set */ - struct tasklet_struct - event_tasklet; /* tasklet for serializing AT commands. - * Scheduled - * -> for modem reponses (and - * incoming data for M10x) - * -> on timeout - * -> after setting bits in - * xxx.at_state.pending_command - * (e.g. command from LL) */ - struct tasklet_struct - write_tasklet; /* tasklet for serial output - * (not used in base driver) */ - - /* event queue */ - struct event_t events[MAX_EVENTS]; - unsigned ev_tail, ev_head; - spinlock_t ev_lock; - - /* current modem response */ - unsigned char respdata[MAX_RESP_SIZE + 1]; - unsigned cbytes; - - /* private data of hardware drivers */ - union { - struct usb_cardstate *usb; /* USB hardware driver (m105) */ - struct ser_cardstate *ser; /* serial hardware driver */ - struct bas_cardstate *bas; /* USB hardware driver (base) */ - } hw; -}; - -struct gigaset_driver { - struct list_head list; - spinlock_t lock; /* locks minor tables and blocked */ - struct tty_driver *tty; - unsigned have_tty; - unsigned minor; - unsigned minors; - struct cardstate *cs; - int blocked; - - const struct gigaset_ops *ops; - struct module *owner; -}; - -struct cmdbuf_t { - struct cmdbuf_t *next, *prev; - int len, offset; - struct tasklet_struct *wake_tasklet; - unsigned char buf[0]; -}; - -struct bas_bc_state { - /* isochronous output state */ - int running; - atomic_t corrbytes; - spinlock_t isooutlock; - struct isow_urbctx_t isoouturbs[BAS_OUTURBS]; - struct isow_urbctx_t *isooutdone, *isooutfree, *isooutovfl; - struct isowbuf_t *isooutbuf; - unsigned numsub; /* submitted URB counter - (for diagnostic messages only) */ - struct tasklet_struct sent_tasklet; - - /* isochronous input state */ - spinlock_t isoinlock; - struct urb *isoinurbs[BAS_INURBS]; - unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS]; - struct urb *isoindone; /* completed isoc read URB */ - int isoinstatus; /* status of completed URB */ - int loststatus; /* status of dropped URB */ - unsigned isoinlost; /* number of bytes lost */ - /* state of bit unstuffing algorithm - (in addition to BC_state.inputstate) */ - unsigned seqlen; /* number of '1' bits not yet - unstuffed */ - unsigned inbyte, inbits; /* collected bits for next byte */ - /* statistics */ - unsigned goodbytes; /* bytes correctly received */ - unsigned alignerrs; /* frames with incomplete byte at end */ - unsigned fcserrs; /* FCS errors */ - unsigned frameerrs; /* framing errors */ - unsigned giants; /* long frames */ - unsigned runts; /* short frames */ - unsigned aborts; /* HDLC aborts */ - unsigned shared0s; /* '0' bits shared between flags */ - unsigned stolen0s; /* '0' stuff bits also serving as - leading flag bits */ - struct tasklet_struct rcvd_tasklet; -}; - -struct gigaset_ops { - /* Called from ev-layer.c/interface.c for sending AT commands to the - device */ - int (*write_cmd)(struct cardstate *cs, struct cmdbuf_t *cb); - - /* Called from interface.c for additional device control */ - int (*write_room)(struct cardstate *cs); - int (*chars_in_buffer)(struct cardstate *cs); - int (*brkchars)(struct cardstate *cs, const unsigned char buf[6]); - - /* Called from ev-layer.c after setting up connection - * Should call gigaset_bchannel_up(), when finished. */ - int (*init_bchannel)(struct bc_state *bcs); - - /* Called from ev-layer.c after hanging up - * Should call gigaset_bchannel_down(), when finished. */ - int (*close_bchannel)(struct bc_state *bcs); - - /* Called by gigaset_initcs() for setting up bcs->hw.xxx */ - int (*initbcshw)(struct bc_state *bcs); - - /* Called by gigaset_freecs() for freeing bcs->hw.xxx */ - void (*freebcshw)(struct bc_state *bcs); - - /* Called by gigaset_bchannel_down() for resetting bcs->hw.xxx */ - void (*reinitbcshw)(struct bc_state *bcs); - - /* Called by gigaset_initcs() for setting up cs->hw.xxx */ - int (*initcshw)(struct cardstate *cs); - - /* Called by gigaset_freecs() for freeing cs->hw.xxx */ - void (*freecshw)(struct cardstate *cs); - - /* Called from common.c/interface.c for additional serial port - control */ - int (*set_modem_ctrl)(struct cardstate *cs, unsigned old_state, - unsigned new_state); - int (*baud_rate)(struct cardstate *cs, unsigned cflag); - int (*set_line_ctrl)(struct cardstate *cs, unsigned cflag); - - /* Called from LL interface to put an skb into the send-queue. - * After sending is completed, gigaset_skb_sent() must be called - * with the skb's link layer header preserved. */ - int (*send_skb)(struct bc_state *bcs, struct sk_buff *skb); - - /* Called from ev-layer.c to process a block of data - * received through the common/control channel. */ - void (*handle_input)(struct inbuf_t *inbuf); - -}; - -/* = Common structures and definitions ======================================= - */ - -/* Parser states for DLE-Event: - * <DLE-EVENT>: <DLE_FLAG> "X" <EVENT> <DLE_FLAG> "." - * <DLE_FLAG>: 0x10 - * <EVENT>: ((a-z)* | (A-Z)* | (0-10)*)+ - */ -#define DLE_FLAG 0x10 - -/* =========================================================================== - * Functions implemented in asyncdata.c - */ - -/* Called from LL interface to put an skb into the send queue. */ -int gigaset_m10x_send_skb(struct bc_state *bcs, struct sk_buff *skb); - -/* Called from ev-layer.c to process a block of data - * received through the common/control channel. */ -void gigaset_m10x_input(struct inbuf_t *inbuf); - -/* =========================================================================== - * Functions implemented in isocdata.c - */ - -/* Called from LL interface to put an skb into the send queue. */ -int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb); - -/* Called from ev-layer.c to process a block of data - * received through the common/control channel. */ -void gigaset_isoc_input(struct inbuf_t *inbuf); - -/* Called from bas-gigaset.c to process a block of data - * received through the isochronous channel */ -void gigaset_isoc_receive(unsigned char *src, unsigned count, - struct bc_state *bcs); - -/* Called from bas-gigaset.c to put a block of data - * into the isochronous output buffer */ -int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len); - -/* Called from bas-gigaset.c to initialize the isochronous output buffer */ -void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle); - -/* Called from bas-gigaset.c to retrieve a block of bytes for sending */ -int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size); - -/* =========================================================================== - * Functions implemented in LL interface - */ - -/* Called from common.c for setting up/shutting down with the ISDN subsystem */ -void gigaset_isdn_regdrv(void); -void gigaset_isdn_unregdrv(void); -int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid); -void gigaset_isdn_unregdev(struct cardstate *cs); - -/* Called from hardware module to indicate completion of an skb */ -void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); -void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb); -void gigaset_isdn_rcv_err(struct bc_state *bcs); - -/* Called from common.c/ev-layer.c to indicate events relevant to the LL */ -void gigaset_isdn_start(struct cardstate *cs); -void gigaset_isdn_stop(struct cardstate *cs); -int gigaset_isdn_icall(struct at_state_t *at_state); -void gigaset_isdn_connD(struct bc_state *bcs); -void gigaset_isdn_hupD(struct bc_state *bcs); -void gigaset_isdn_connB(struct bc_state *bcs); -void gigaset_isdn_hupB(struct bc_state *bcs); - -/* =========================================================================== - * Functions implemented in ev-layer.c - */ - -/* tasklet called from common.c to process queued events */ -void gigaset_handle_event(unsigned long data); - -/* called from isocdata.c / asyncdata.c - * when a complete modem response line has been received */ -void gigaset_handle_modem_response(struct cardstate *cs); - -/* =========================================================================== - * Functions implemented in proc.c - */ - -/* initialize sysfs for device */ -void gigaset_init_dev_sysfs(struct cardstate *cs); -void gigaset_free_dev_sysfs(struct cardstate *cs); - -/* =========================================================================== - * Functions implemented in common.c/gigaset.h - */ - -void gigaset_bcs_reinit(struct bc_state *bcs); -void gigaset_at_init(struct at_state_t *at_state, struct bc_state *bcs, - struct cardstate *cs, int cid); -int gigaset_get_channel(struct bc_state *bcs); -struct bc_state *gigaset_get_free_channel(struct cardstate *cs); -void gigaset_free_channel(struct bc_state *bcs); -int gigaset_get_channels(struct cardstate *cs); -void gigaset_free_channels(struct cardstate *cs); -void gigaset_block_channels(struct cardstate *cs); - -/* Allocate and initialize driver structure. */ -struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, - const char *procname, - const char *devname, - const struct gigaset_ops *ops, - struct module *owner); - -/* Deallocate driver structure. */ -void gigaset_freedriver(struct gigaset_driver *drv); - -struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty); -struct cardstate *gigaset_get_cs_by_id(int id); -void gigaset_blockdriver(struct gigaset_driver *drv); - -/* Allocate and initialize card state. Calls hardware dependent - gigaset_init[b]cs(). */ -struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, - int onechannel, int ignoreframes, - int cidmode, const char *modulename); - -/* Free card state. Calls hardware dependent gigaset_free[b]cs(). */ -void gigaset_freecs(struct cardstate *cs); - -/* Tell common.c that hardware and driver are ready. */ -int gigaset_start(struct cardstate *cs); - -/* Tell common.c that the device is not present any more. */ -void gigaset_stop(struct cardstate *cs); - -/* Tell common.c that the driver is being unloaded. */ -int gigaset_shutdown(struct cardstate *cs); - -/* Append event to the queue. - * Returns NULL on failure or a pointer to the event on success. - * ptr must be kmalloc()ed (and not be freed by the caller). - */ -struct event_t *gigaset_add_event(struct cardstate *cs, - struct at_state_t *at_state, int type, - void *ptr, int parameter, void *arg); - -/* Called on CONFIG1 command from frontend. */ -int gigaset_enterconfigmode(struct cardstate *cs); - -/* cs->lock must not be locked */ -static inline void gigaset_schedule_event(struct cardstate *cs) -{ - unsigned long flags; - spin_lock_irqsave(&cs->lock, flags); - if (cs->running) - tasklet_schedule(&cs->event_tasklet); - spin_unlock_irqrestore(&cs->lock, flags); -} - -/* Tell common.c that B channel has been closed. */ -/* cs->lock must not be locked */ -static inline void gigaset_bchannel_down(struct bc_state *bcs) -{ - gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_CLOSED, NULL, 0, NULL); - gigaset_schedule_event(bcs->cs); -} - -/* Tell common.c that B channel has been opened. */ -/* cs->lock must not be locked */ -static inline void gigaset_bchannel_up(struct bc_state *bcs) -{ - gigaset_add_event(bcs->cs, &bcs->at_state, EV_BC_OPEN, NULL, 0, NULL); - gigaset_schedule_event(bcs->cs); -} - -/* set up next receive skb for data mode */ -static inline struct sk_buff *gigaset_new_rx_skb(struct bc_state *bcs) -{ - struct cardstate *cs = bcs->cs; - unsigned short hw_hdr_len = cs->hw_hdr_len; - - if (bcs->ignore) { - bcs->rx_skb = NULL; - } else { - bcs->rx_skb = dev_alloc_skb(bcs->rx_bufsize + hw_hdr_len); - if (bcs->rx_skb == NULL) - dev_warn(cs->dev, "could not allocate skb\n"); - else - skb_reserve(bcs->rx_skb, hw_hdr_len); - } - return bcs->rx_skb; -} - -/* append received bytes to inbuf */ -int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, - unsigned numbytes); - -/* =========================================================================== - * Functions implemented in interface.c - */ - -/* initialize interface */ -void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, - const char *devname); -/* release interface */ -void gigaset_if_freedriver(struct gigaset_driver *drv); -/* add minor */ -void gigaset_if_init(struct cardstate *cs); -/* remove minor */ -void gigaset_if_free(struct cardstate *cs); -/* device received data */ -void gigaset_if_receive(struct cardstate *cs, - unsigned char *buffer, size_t len); - -#endif diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c deleted file mode 100644 index 335b8ce2bb06..000000000000 --- a/drivers/isdn/gigaset/i4l.c +++ /dev/null @@ -1,692 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Stuff used by all variants of the driver - * - * Copyright (c) 2001 by Stefan Eilers, - * Hansjoerg Lipp <hjlipp@web.de>, - * Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * ===================================================================== - */ - -#include "gigaset.h" -#include <linux/isdnif.h> -#include <linux/export.h> - -#define SBUFSIZE 4096 /* sk_buff payload size */ -#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ -#define HW_HDR_LEN 2 /* Header size used to store ack info */ -#define MAX_BUF_SIZE (SBUFSIZE - HW_HDR_LEN) /* max data packet from LL */ - -/* == Handling of I4L IO =====================================================*/ - -/* writebuf_from_LL - * called by LL to transmit data on an open channel - * inserts the buffer data into the send queue and starts the transmission - * Note that this operation must not sleep! - * When the buffer is processed completely, gigaset_skb_sent() should be called. - * parameters: - * driverID driver ID as assigned by LL - * channel channel number - * ack if != 0 LL wants to be notified on completion via - * statcallb(ISDN_STAT_BSENT) - * skb skb containing data to send - * return value: - * number of accepted bytes - * 0 if temporarily unable to accept data (out of buffer space) - * <0 on error (eg. -EINVAL) - */ -static int writebuf_from_LL(int driverID, int channel, int ack, - struct sk_buff *skb) -{ - struct cardstate *cs = gigaset_get_cs_by_id(driverID); - struct bc_state *bcs; - unsigned char *ack_header; - unsigned len; - - if (!cs) { - pr_err("%s: invalid driver ID (%d)\n", __func__, driverID); - return -ENODEV; - } - if (channel < 0 || channel >= cs->channels) { - dev_err(cs->dev, "%s: invalid channel ID (%d)\n", - __func__, channel); - return -ENODEV; - } - bcs = &cs->bcs[channel]; - - /* can only handle linear sk_buffs */ - if (skb_linearize(skb) < 0) { - dev_err(cs->dev, "%s: skb_linearize failed\n", __func__); - return -ENOMEM; - } - len = skb->len; - - gig_dbg(DEBUG_LLDATA, - "Receiving data from LL (id: %d, ch: %d, ack: %d, sz: %d)", - driverID, channel, ack, len); - - if (!len) { - if (ack) - dev_notice(cs->dev, "%s: not ACKing empty packet\n", - __func__); - return 0; - } - if (len > MAX_BUF_SIZE) { - dev_err(cs->dev, "%s: packet too large (%d bytes)\n", - __func__, len); - return -EINVAL; - } - - /* set up acknowledgement header */ - if (skb_headroom(skb) < HW_HDR_LEN) { - /* should never happen */ - dev_err(cs->dev, "%s: insufficient skb headroom\n", __func__); - return -ENOMEM; - } - skb_set_mac_header(skb, -HW_HDR_LEN); - skb->mac_len = HW_HDR_LEN; - ack_header = skb_mac_header(skb); - if (ack) { - ack_header[0] = len & 0xff; - ack_header[1] = len >> 8; - } else { - ack_header[0] = ack_header[1] = 0; - } - gig_dbg(DEBUG_MCMD, "skb: len=%u, ack=%d: %02x %02x", - len, ack, ack_header[0], ack_header[1]); - - /* pass to device-specific module */ - return cs->ops->send_skb(bcs, skb); -} - -/** - * gigaset_skb_sent() - acknowledge sending an skb - * @bcs: B channel descriptor structure. - * @skb: sent data. - * - * Called by hardware module {bas,ser,usb}_gigaset when the data in a - * skb has been successfully sent, for signalling completion to the LL. - */ -void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb) -{ - isdn_if *iif = bcs->cs->iif; - unsigned char *ack_header = skb_mac_header(skb); - unsigned len; - isdn_ctrl response; - - ++bcs->trans_up; - - if (skb->len) - dev_warn(bcs->cs->dev, "%s: skb->len==%d\n", - __func__, skb->len); - - len = ack_header[0] + ((unsigned) ack_header[1] << 8); - if (len) { - gig_dbg(DEBUG_MCMD, "ACKing to LL (id: %d, ch: %d, sz: %u)", - bcs->cs->myid, bcs->channel, len); - - response.driver = bcs->cs->myid; - response.command = ISDN_STAT_BSENT; - response.arg = bcs->channel; - response.parm.length = len; - iif->statcallb(&response); - } -} -EXPORT_SYMBOL_GPL(gigaset_skb_sent); - -/** - * gigaset_skb_rcvd() - pass received skb to LL - * @bcs: B channel descriptor structure. - * @skb: received data. - * - * Called by hardware module {bas,ser,usb}_gigaset when user data has - * been successfully received, for passing to the LL. - * Warning: skb must not be accessed anymore! - */ -void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb) -{ - isdn_if *iif = bcs->cs->iif; - - iif->rcvcallb_skb(bcs->cs->myid, bcs->channel, skb); - bcs->trans_down++; -} -EXPORT_SYMBOL_GPL(gigaset_skb_rcvd); - -/** - * gigaset_isdn_rcv_err() - signal receive error - * @bcs: B channel descriptor structure. - * - * Called by hardware module {bas,ser,usb}_gigaset when a receive error - * has occurred, for signalling to the LL. - */ -void gigaset_isdn_rcv_err(struct bc_state *bcs) -{ - isdn_if *iif = bcs->cs->iif; - isdn_ctrl response; - - /* if currently ignoring packets, just count down */ - if (bcs->ignore) { - bcs->ignore--; - return; - } - - /* update statistics */ - bcs->corrupted++; - - /* error -> LL */ - gig_dbg(DEBUG_CMD, "sending L1ERR"); - response.driver = bcs->cs->myid; - response.command = ISDN_STAT_L1ERR; - response.arg = bcs->channel; - response.parm.errcode = ISDN_STAT_L1ERR_RECV; - iif->statcallb(&response); -} -EXPORT_SYMBOL_GPL(gigaset_isdn_rcv_err); - -/* This function will be called by LL to send commands - * NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL, - * so don't put too much effort into it. - */ -static int command_from_LL(isdn_ctrl *cntrl) -{ - struct cardstate *cs; - struct bc_state *bcs; - int retval = 0; - char **commands; - int ch; - int i; - size_t l; - - gig_dbg(DEBUG_CMD, "driver: %d, command: %d, arg: 0x%lx", - cntrl->driver, cntrl->command, cntrl->arg); - - cs = gigaset_get_cs_by_id(cntrl->driver); - if (cs == NULL) { - pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver); - return -ENODEV; - } - ch = cntrl->arg & 0xff; - - switch (cntrl->command) { - case ISDN_CMD_IOCTL: - dev_warn(cs->dev, "ISDN_CMD_IOCTL not supported\n"); - return -EINVAL; - - case ISDN_CMD_DIAL: - gig_dbg(DEBUG_CMD, - "ISDN_CMD_DIAL (phone: %s, msn: %s, si1: %d, si2: %d)", - cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn, - cntrl->parm.setup.si1, cntrl->parm.setup.si2); - - if (ch >= cs->channels) { - dev_err(cs->dev, - "ISDN_CMD_DIAL: invalid channel (%d)\n", ch); - return -EINVAL; - } - bcs = cs->bcs + ch; - if (gigaset_get_channel(bcs) < 0) { - dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n"); - return -EBUSY; - } - switch (bcs->proto2) { - case L2_HDLC: - bcs->rx_bufsize = SBUFSIZE; - break; - default: /* assume transparent */ - bcs->rx_bufsize = TRANSBUFSIZE; - } - dev_kfree_skb(bcs->rx_skb); - gigaset_new_rx_skb(bcs); - - commands = kcalloc(AT_NUM, sizeof(*commands), GFP_ATOMIC); - if (!commands) { - gigaset_free_channel(bcs); - dev_err(cs->dev, "ISDN_CMD_DIAL: out of memory\n"); - return -ENOMEM; - } - - l = 3 + strlen(cntrl->parm.setup.phone); - commands[AT_DIAL] = kmalloc(l, GFP_ATOMIC); - if (!commands[AT_DIAL]) - goto oom; - if (cntrl->parm.setup.phone[0] == '*' && - cntrl->parm.setup.phone[1] == '*') { - /* internal call: translate ** prefix to CTP value */ - commands[AT_TYPE] = kstrdup("^SCTP=0\r", GFP_ATOMIC); - if (!commands[AT_TYPE]) - goto oom; - snprintf(commands[AT_DIAL], l, - "D%s\r", cntrl->parm.setup.phone + 2); - } else { - commands[AT_TYPE] = kstrdup("^SCTP=1\r", GFP_ATOMIC); - if (!commands[AT_TYPE]) - goto oom; - snprintf(commands[AT_DIAL], l, - "D%s\r", cntrl->parm.setup.phone); - } - - l = strlen(cntrl->parm.setup.eazmsn); - if (l) { - l += 8; - commands[AT_MSN] = kmalloc(l, GFP_ATOMIC); - if (!commands[AT_MSN]) - goto oom; - snprintf(commands[AT_MSN], l, "^SMSN=%s\r", - cntrl->parm.setup.eazmsn); - } - - switch (cntrl->parm.setup.si1) { - case 1: /* audio */ - /* BC = 9090A3: 3.1 kHz audio, A-law */ - commands[AT_BC] = kstrdup("^SBC=9090A3\r", GFP_ATOMIC); - if (!commands[AT_BC]) - goto oom; - break; - case 7: /* data */ - default: /* hope the app knows what it is doing */ - /* BC = 8890: unrestricted digital information */ - commands[AT_BC] = kstrdup("^SBC=8890\r", GFP_ATOMIC); - if (!commands[AT_BC]) - goto oom; - } - /* ToDo: other si1 values, inspect si2, set HLC/LLC */ - - commands[AT_PROTO] = kmalloc(9, GFP_ATOMIC); - if (!commands[AT_PROTO]) - goto oom; - snprintf(commands[AT_PROTO], 9, "^SBPR=%u\r", bcs->proto2); - - commands[AT_ISO] = kmalloc(9, GFP_ATOMIC); - if (!commands[AT_ISO]) - goto oom; - snprintf(commands[AT_ISO], 9, "^SISO=%u\r", - (unsigned) bcs->channel + 1); - - if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, commands, - bcs->at_state.seq_index, NULL)) { - for (i = 0; i < AT_NUM; ++i) - kfree(commands[i]); - kfree(commands); - gigaset_free_channel(bcs); - return -ENOMEM; - } - gigaset_schedule_event(cs); - break; - case ISDN_CMD_ACCEPTD: - gig_dbg(DEBUG_CMD, "ISDN_CMD_ACCEPTD"); - if (ch >= cs->channels) { - dev_err(cs->dev, - "ISDN_CMD_ACCEPTD: invalid channel (%d)\n", ch); - return -EINVAL; - } - bcs = cs->bcs + ch; - switch (bcs->proto2) { - case L2_HDLC: - bcs->rx_bufsize = SBUFSIZE; - break; - default: /* assume transparent */ - bcs->rx_bufsize = TRANSBUFSIZE; - } - dev_kfree_skb(bcs->rx_skb); - gigaset_new_rx_skb(bcs); - if (!gigaset_add_event(cs, &bcs->at_state, - EV_ACCEPT, NULL, 0, NULL)) - return -ENOMEM; - gigaset_schedule_event(cs); - - break; - case ISDN_CMD_HANGUP: - gig_dbg(DEBUG_CMD, "ISDN_CMD_HANGUP"); - if (ch >= cs->channels) { - dev_err(cs->dev, - "ISDN_CMD_HANGUP: invalid channel (%d)\n", ch); - return -EINVAL; - } - bcs = cs->bcs + ch; - if (!gigaset_add_event(cs, &bcs->at_state, - EV_HUP, NULL, 0, NULL)) - return -ENOMEM; - gigaset_schedule_event(cs); - - break; - case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ - dev_info(cs->dev, "ignoring ISDN_CMD_CLREAZ\n"); - break; - case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ - dev_info(cs->dev, "ignoring ISDN_CMD_SETEAZ (%s)\n", - cntrl->parm.num); - break; - case ISDN_CMD_SETL2: /* Set L2 to given protocol */ - if (ch >= cs->channels) { - dev_err(cs->dev, - "ISDN_CMD_SETL2: invalid channel (%d)\n", ch); - return -EINVAL; - } - bcs = cs->bcs + ch; - if (bcs->chstate & CHS_D_UP) { - dev_err(cs->dev, - "ISDN_CMD_SETL2: channel active (%d)\n", ch); - return -EINVAL; - } - switch (cntrl->arg >> 8) { - case ISDN_PROTO_L2_HDLC: - gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_HDLC"); - bcs->proto2 = L2_HDLC; - break; - case ISDN_PROTO_L2_TRANS: - gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL2: setting L2_VOICE"); - bcs->proto2 = L2_VOICE; - break; - default: - dev_err(cs->dev, - "ISDN_CMD_SETL2: unsupported protocol (%lu)\n", - cntrl->arg >> 8); - return -EINVAL; - } - break; - case ISDN_CMD_SETL3: /* Set L3 to given protocol */ - gig_dbg(DEBUG_CMD, "ISDN_CMD_SETL3"); - if (ch >= cs->channels) { - dev_err(cs->dev, - "ISDN_CMD_SETL3: invalid channel (%d)\n", ch); - return -EINVAL; - } - - if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) { - dev_err(cs->dev, - "ISDN_CMD_SETL3: unsupported protocol (%lu)\n", - cntrl->arg >> 8); - return -EINVAL; - } - - break; - - default: - gig_dbg(DEBUG_CMD, "unknown command %d from LL", - cntrl->command); - return -EINVAL; - } - - return retval; - -oom: - dev_err(bcs->cs->dev, "out of memory\n"); - for (i = 0; i < AT_NUM; ++i) - kfree(commands[i]); - kfree(commands); - gigaset_free_channel(bcs); - return -ENOMEM; -} - -static void gigaset_i4l_cmd(struct cardstate *cs, int cmd) -{ - isdn_if *iif = cs->iif; - isdn_ctrl command; - - command.driver = cs->myid; - command.command = cmd; - command.arg = 0; - iif->statcallb(&command); -} - -static void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd) -{ - isdn_if *iif = bcs->cs->iif; - isdn_ctrl command; - - command.driver = bcs->cs->myid; - command.command = cmd; - command.arg = bcs->channel; - iif->statcallb(&command); -} - -/** - * gigaset_isdn_icall() - signal incoming call - * @at_state: connection state structure. - * - * Called by main module to notify the LL that an incoming call has been - * received. @at_state contains the parameters of the call. - * - * Return value: call disposition (ICALL_*) - */ -int gigaset_isdn_icall(struct at_state_t *at_state) -{ - struct cardstate *cs = at_state->cs; - struct bc_state *bcs = at_state->bcs; - isdn_if *iif = cs->iif; - isdn_ctrl response; - int retval; - - /* fill ICALL structure */ - response.parm.setup.si1 = 0; /* default: unknown */ - response.parm.setup.si2 = 0; - response.parm.setup.screen = 0; - response.parm.setup.plan = 0; - if (!at_state->str_var[STR_ZBC]) { - /* no BC (internal call): assume speech, A-law */ - response.parm.setup.si1 = 1; - } else if (!strcmp(at_state->str_var[STR_ZBC], "8890")) { - /* unrestricted digital information */ - response.parm.setup.si1 = 7; - } else if (!strcmp(at_state->str_var[STR_ZBC], "8090A3")) { - /* speech, A-law */ - response.parm.setup.si1 = 1; - } else if (!strcmp(at_state->str_var[STR_ZBC], "9090A3")) { - /* 3,1 kHz audio, A-law */ - response.parm.setup.si1 = 1; - response.parm.setup.si2 = 2; - } else { - dev_warn(cs->dev, "RING ignored - unsupported BC %s\n", - at_state->str_var[STR_ZBC]); - return ICALL_IGNORE; - } - if (at_state->str_var[STR_NMBR]) { - strlcpy(response.parm.setup.phone, at_state->str_var[STR_NMBR], - sizeof response.parm.setup.phone); - } else - response.parm.setup.phone[0] = 0; - if (at_state->str_var[STR_ZCPN]) { - strlcpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN], - sizeof response.parm.setup.eazmsn); - } else - response.parm.setup.eazmsn[0] = 0; - - if (!bcs) { - dev_notice(cs->dev, "no channel for incoming call\n"); - response.command = ISDN_STAT_ICALLW; - response.arg = 0; - } else { - gig_dbg(DEBUG_CMD, "Sending ICALL"); - response.command = ISDN_STAT_ICALL; - response.arg = bcs->channel; - } - response.driver = cs->myid; - retval = iif->statcallb(&response); - gig_dbg(DEBUG_CMD, "Response: %d", retval); - switch (retval) { - case 0: /* no takers */ - return ICALL_IGNORE; - case 1: /* alerting */ - bcs->chstate |= CHS_NOTIFY_LL; - return ICALL_ACCEPT; - case 2: /* reject */ - return ICALL_REJECT; - case 3: /* incomplete */ - dev_warn(cs->dev, - "LL requested unsupported feature: Incomplete Number\n"); - return ICALL_IGNORE; - case 4: /* proceeding */ - /* Gigaset will send ALERTING anyway. - * There doesn't seem to be a way to avoid this. - */ - return ICALL_ACCEPT; - case 5: /* deflect */ - dev_warn(cs->dev, - "LL requested unsupported feature: Call Deflection\n"); - return ICALL_IGNORE; - default: - dev_err(cs->dev, "LL error %d on ICALL\n", retval); - return ICALL_IGNORE; - } -} - -/** - * gigaset_isdn_connD() - signal D channel connect - * @bcs: B channel descriptor structure. - * - * Called by main module to notify the LL that the D channel connection has - * been established. - */ -void gigaset_isdn_connD(struct bc_state *bcs) -{ - gig_dbg(DEBUG_CMD, "sending DCONN"); - gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN); -} - -/** - * gigaset_isdn_hupD() - signal D channel hangup - * @bcs: B channel descriptor structure. - * - * Called by main module to notify the LL that the D channel connection has - * been shut down. - */ -void gigaset_isdn_hupD(struct bc_state *bcs) -{ - gig_dbg(DEBUG_CMD, "sending DHUP"); - gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DHUP); -} - -/** - * gigaset_isdn_connB() - signal B channel connect - * @bcs: B channel descriptor structure. - * - * Called by main module to notify the LL that the B channel connection has - * been established. - */ -void gigaset_isdn_connB(struct bc_state *bcs) -{ - gig_dbg(DEBUG_CMD, "sending BCONN"); - gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BCONN); -} - -/** - * gigaset_isdn_hupB() - signal B channel hangup - * @bcs: B channel descriptor structure. - * - * Called by main module to notify the LL that the B channel connection has - * been shut down. - */ -void gigaset_isdn_hupB(struct bc_state *bcs) -{ - gig_dbg(DEBUG_CMD, "sending BHUP"); - gigaset_i4l_channel_cmd(bcs, ISDN_STAT_BHUP); -} - -/** - * gigaset_isdn_start() - signal device availability - * @cs: device descriptor structure. - * - * Called by main module to notify the LL that the device is available for - * use. - */ -void gigaset_isdn_start(struct cardstate *cs) -{ - gig_dbg(DEBUG_CMD, "sending RUN"); - gigaset_i4l_cmd(cs, ISDN_STAT_RUN); -} - -/** - * gigaset_isdn_stop() - signal device unavailability - * @cs: device descriptor structure. - * - * Called by main module to notify the LL that the device is no longer - * available for use. - */ -void gigaset_isdn_stop(struct cardstate *cs) -{ - gig_dbg(DEBUG_CMD, "sending STOP"); - gigaset_i4l_cmd(cs, ISDN_STAT_STOP); -} - -/** - * gigaset_isdn_regdev() - register to LL - * @cs: device descriptor structure. - * @isdnid: device name. - * - * Return value: 0 on success, error code < 0 on failure - */ -int gigaset_isdn_regdev(struct cardstate *cs, const char *isdnid) -{ - isdn_if *iif; - - iif = kmalloc(sizeof *iif, GFP_KERNEL); - if (!iif) { - pr_err("out of memory\n"); - return -ENOMEM; - } - - if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index) - >= sizeof iif->id) { - pr_err("ID too long: %s\n", isdnid); - kfree(iif); - return -EINVAL; - } - - iif->owner = THIS_MODULE; - iif->channels = cs->channels; - iif->maxbufsize = MAX_BUF_SIZE; - iif->features = ISDN_FEATURE_L2_TRANS | - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_X75I | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_P_EURO; - iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */ - iif->command = command_from_LL; - iif->writebuf_skb = writebuf_from_LL; - iif->writecmd = NULL; /* Don't support isdnctrl */ - iif->readstat = NULL; /* Don't support isdnctrl */ - iif->rcvcallb_skb = NULL; /* Will be set by LL */ - iif->statcallb = NULL; /* Will be set by LL */ - - if (!register_isdn(iif)) { - pr_err("register_isdn failed\n"); - kfree(iif); - return -EINVAL; - } - - cs->iif = iif; - cs->myid = iif->channels; /* Set my device id */ - cs->hw_hdr_len = HW_HDR_LEN; - return 0; -} - -/** - * gigaset_isdn_unregdev() - unregister device from LL - * @cs: device descriptor structure. - */ -void gigaset_isdn_unregdev(struct cardstate *cs) -{ - gig_dbg(DEBUG_CMD, "sending UNLOAD"); - gigaset_i4l_cmd(cs, ISDN_STAT_UNLOAD); - kfree(cs->iif); - cs->iif = NULL; -} - -/** - * gigaset_isdn_regdrv() - register driver to LL - */ -void gigaset_isdn_regdrv(void) -{ - pr_info("ISDN4Linux interface\n"); - /* nothing to do */ -} - -/** - * gigaset_isdn_unregdrv() - unregister driver from LL - */ -void gigaset_isdn_unregdrv(void) -{ - /* nothing to do */ -} diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c deleted file mode 100644 index 17fa615a8c68..000000000000 --- a/drivers/isdn/gigaset/interface.c +++ /dev/null @@ -1,613 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * interface to user space for the gigaset driver - * - * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de> - * - * ===================================================================== - * ===================================================================== - */ - -#include "gigaset.h" -#include <linux/gigaset_dev.h> -#include <linux/tty_flip.h> -#include <linux/module.h> - -/*** our ioctls ***/ - -static int if_lock(struct cardstate *cs, int *arg) -{ - int cmd = *arg; - - gig_dbg(DEBUG_IF, "%u: if_lock (%d)", cs->minor_index, cmd); - - if (cmd > 1) - return -EINVAL; - - if (cmd < 0) { - *arg = cs->mstate == MS_LOCKED; - return 0; - } - - if (!cmd && cs->mstate == MS_LOCKED && cs->connected) { - cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR | TIOCM_RTS); - cs->ops->baud_rate(cs, B115200); - cs->ops->set_line_ctrl(cs, CS8); - cs->control_state = TIOCM_DTR | TIOCM_RTS; - } - - cs->waiting = 1; - if (!gigaset_add_event(cs, &cs->at_state, EV_IF_LOCK, - NULL, cmd, NULL)) { - cs->waiting = 0; - return -ENOMEM; - } - gigaset_schedule_event(cs); - - wait_event(cs->waitqueue, !cs->waiting); - - if (cs->cmd_result >= 0) { - *arg = cs->cmd_result; - return 0; - } - - return cs->cmd_result; -} - -static int if_version(struct cardstate *cs, unsigned arg[4]) -{ - static const unsigned version[4] = GIG_VERSION; - static const unsigned compat[4] = GIG_COMPAT; - unsigned cmd = arg[0]; - - gig_dbg(DEBUG_IF, "%u: if_version (%d)", cs->minor_index, cmd); - - switch (cmd) { - case GIGVER_DRIVER: - memcpy(arg, version, sizeof version); - return 0; - case GIGVER_COMPAT: - memcpy(arg, compat, sizeof compat); - return 0; - case GIGVER_FWBASE: - cs->waiting = 1; - if (!gigaset_add_event(cs, &cs->at_state, EV_IF_VER, - NULL, 0, arg)) { - cs->waiting = 0; - return -ENOMEM; - } - gigaset_schedule_event(cs); - - wait_event(cs->waitqueue, !cs->waiting); - - if (cs->cmd_result >= 0) - return 0; - - return cs->cmd_result; - default: - return -EINVAL; - } -} - -static int if_config(struct cardstate *cs, int *arg) -{ - gig_dbg(DEBUG_IF, "%u: if_config (%d)", cs->minor_index, *arg); - - if (*arg != 1) - return -EINVAL; - - if (cs->mstate != MS_LOCKED) - return -EBUSY; - - if (!cs->connected) { - pr_err("%s: not connected\n", __func__); - return -ENODEV; - } - - *arg = 0; - return gigaset_enterconfigmode(cs); -} - -/*** the terminal driver ***/ - -static int if_open(struct tty_struct *tty, struct file *filp) -{ - struct cardstate *cs; - - gig_dbg(DEBUG_IF, "%d+%d: %s()", - tty->driver->minor_start, tty->index, __func__); - - cs = gigaset_get_cs_by_tty(tty); - if (!cs || !try_module_get(cs->driver->owner)) - return -ENODEV; - - if (mutex_lock_interruptible(&cs->mutex)) { - module_put(cs->driver->owner); - return -ERESTARTSYS; - } - tty->driver_data = cs; - - ++cs->port.count; - - if (cs->port.count == 1) { - tty_port_tty_set(&cs->port, tty); - cs->port.low_latency = 1; - } - - mutex_unlock(&cs->mutex); - return 0; -} - -static void if_close(struct tty_struct *tty, struct file *filp) -{ - struct cardstate *cs = tty->driver_data; - - if (!cs) { /* happens if we didn't find cs in open */ - gig_dbg(DEBUG_IF, "%s: no cardstate", __func__); - return; - } - - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - - mutex_lock(&cs->mutex); - - if (!cs->connected) - gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ - else if (!cs->port.count) - dev_warn(cs->dev, "%s: device not opened\n", __func__); - else if (!--cs->port.count) - tty_port_tty_set(&cs->port, NULL); - - mutex_unlock(&cs->mutex); - - module_put(cs->driver->owner); -} - -static int if_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - struct cardstate *cs = tty->driver_data; - int retval = -ENODEV; - int int_arg; - unsigned char buf[6]; - unsigned version[4]; - - gig_dbg(DEBUG_IF, "%u: %s(0x%x)", cs->minor_index, __func__, cmd); - - if (mutex_lock_interruptible(&cs->mutex)) - return -ERESTARTSYS; - - if (!cs->connected) { - gig_dbg(DEBUG_IF, "not connected"); - retval = -ENODEV; - } else { - retval = 0; - switch (cmd) { - case GIGASET_REDIR: - retval = get_user(int_arg, (int __user *) arg); - if (retval >= 0) - retval = if_lock(cs, &int_arg); - if (retval >= 0) - retval = put_user(int_arg, (int __user *) arg); - break; - case GIGASET_CONFIG: - retval = get_user(int_arg, (int __user *) arg); - if (retval >= 0) - retval = if_config(cs, &int_arg); - if (retval >= 0) - retval = put_user(int_arg, (int __user *) arg); - break; - case GIGASET_BRKCHARS: - retval = copy_from_user(&buf, - (const unsigned char __user *) arg, 6) - ? -EFAULT : 0; - if (retval >= 0) { - gigaset_dbg_buffer(DEBUG_IF, "GIGASET_BRKCHARS", - 6, buf); - retval = cs->ops->brkchars(cs, buf); - } - break; - case GIGASET_VERSION: - retval = copy_from_user(version, - (unsigned __user *) arg, sizeof version) - ? -EFAULT : 0; - if (retval >= 0) - retval = if_version(cs, version); - if (retval >= 0) - retval = copy_to_user((unsigned __user *) arg, - version, sizeof version) - ? -EFAULT : 0; - break; - default: - gig_dbg(DEBUG_IF, "%s: arg not supported - 0x%04x", - __func__, cmd); - retval = -ENOIOCTLCMD; - } - } - - mutex_unlock(&cs->mutex); - - return retval; -} - -#ifdef CONFIG_COMPAT -static long if_compat_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - return if_ioctl(tty, cmd, (unsigned long)compat_ptr(arg)); -} -#endif - -static int if_tiocmget(struct tty_struct *tty) -{ - struct cardstate *cs = tty->driver_data; - int retval; - - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - - if (mutex_lock_interruptible(&cs->mutex)) - return -ERESTARTSYS; - - retval = cs->control_state & (TIOCM_RTS | TIOCM_DTR); - - mutex_unlock(&cs->mutex); - - return retval; -} - -static int if_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct cardstate *cs = tty->driver_data; - int retval; - unsigned mc; - - gig_dbg(DEBUG_IF, "%u: %s(0x%x, 0x%x)", - cs->minor_index, __func__, set, clear); - - if (mutex_lock_interruptible(&cs->mutex)) - return -ERESTARTSYS; - - if (!cs->connected) { - gig_dbg(DEBUG_IF, "not connected"); - retval = -ENODEV; - } else { - mc = (cs->control_state | set) & ~clear & (TIOCM_RTS | TIOCM_DTR); - retval = cs->ops->set_modem_ctrl(cs, cs->control_state, mc); - cs->control_state = mc; - } - - mutex_unlock(&cs->mutex); - - return retval; -} - -static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - struct cardstate *cs = tty->driver_data; - struct cmdbuf_t *cb; - int retval; - - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - - if (mutex_lock_interruptible(&cs->mutex)) - return -ERESTARTSYS; - - if (!cs->connected) { - gig_dbg(DEBUG_IF, "not connected"); - retval = -ENODEV; - goto done; - } - if (cs->mstate != MS_LOCKED) { - dev_warn(cs->dev, "can't write to unlocked device\n"); - retval = -EBUSY; - goto done; - } - if (count <= 0) { - /* nothing to do */ - retval = 0; - goto done; - } - - cb = kmalloc(sizeof(struct cmdbuf_t) + count, GFP_KERNEL); - if (!cb) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - retval = -ENOMEM; - goto done; - } - - memcpy(cb->buf, buf, count); - cb->len = count; - cb->offset = 0; - cb->next = NULL; - cb->wake_tasklet = &cs->if_wake_tasklet; - retval = cs->ops->write_cmd(cs, cb); -done: - mutex_unlock(&cs->mutex); - return retval; -} - -static int if_write_room(struct tty_struct *tty) -{ - struct cardstate *cs = tty->driver_data; - int retval; - - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - - if (mutex_lock_interruptible(&cs->mutex)) - return -ERESTARTSYS; - - if (!cs->connected) { - gig_dbg(DEBUG_IF, "not connected"); - retval = -ENODEV; - } else if (cs->mstate != MS_LOCKED) { - dev_warn(cs->dev, "can't write to unlocked device\n"); - retval = -EBUSY; - } else - retval = cs->ops->write_room(cs); - - mutex_unlock(&cs->mutex); - - return retval; -} - -static int if_chars_in_buffer(struct tty_struct *tty) -{ - struct cardstate *cs = tty->driver_data; - int retval = 0; - - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - - mutex_lock(&cs->mutex); - - if (!cs->connected) - gig_dbg(DEBUG_IF, "not connected"); - else if (cs->mstate != MS_LOCKED) - dev_warn(cs->dev, "can't write to unlocked device\n"); - else - retval = cs->ops->chars_in_buffer(cs); - - mutex_unlock(&cs->mutex); - - return retval; -} - -static void if_throttle(struct tty_struct *tty) -{ - struct cardstate *cs = tty->driver_data; - - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - - mutex_lock(&cs->mutex); - - if (!cs->connected) - gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ - else - gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__); - - mutex_unlock(&cs->mutex); -} - -static void if_unthrottle(struct tty_struct *tty) -{ - struct cardstate *cs = tty->driver_data; - - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - - mutex_lock(&cs->mutex); - - if (!cs->connected) - gig_dbg(DEBUG_IF, "not connected"); /* nothing to do */ - else - gig_dbg(DEBUG_IF, "%s: not implemented\n", __func__); - - mutex_unlock(&cs->mutex); -} - -static void if_set_termios(struct tty_struct *tty, struct ktermios *old) -{ - struct cardstate *cs = tty->driver_data; - unsigned int iflag; - unsigned int cflag; - unsigned int old_cflag; - unsigned int control_state, new_state; - - gig_dbg(DEBUG_IF, "%u: %s()", cs->minor_index, __func__); - - mutex_lock(&cs->mutex); - - if (!cs->connected) { - gig_dbg(DEBUG_IF, "not connected"); - goto out; - } - - iflag = tty->termios.c_iflag; - cflag = tty->termios.c_cflag; - old_cflag = old ? old->c_cflag : cflag; - gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x", - cs->minor_index, iflag, cflag, old_cflag); - - /* get a local copy of the current port settings */ - control_state = cs->control_state; - - /* - * Update baud rate. - * Do not attempt to cache old rates and skip settings, - * disconnects screw such tricks up completely. - * Premature optimization is the root of all evil. - */ - - /* reassert DTR and (maybe) RTS on transition from B0 */ - if ((old_cflag & CBAUD) == B0) { - new_state = control_state | TIOCM_DTR; - /* don't set RTS if using hardware flow control */ - if (!(old_cflag & CRTSCTS)) - new_state |= TIOCM_RTS; - gig_dbg(DEBUG_IF, "%u: from B0 - set DTR%s", - cs->minor_index, - (new_state & TIOCM_RTS) ? " only" : "/RTS"); - cs->ops->set_modem_ctrl(cs, control_state, new_state); - control_state = new_state; - } - - cs->ops->baud_rate(cs, cflag & CBAUD); - - if ((cflag & CBAUD) == B0) { - /* Drop RTS and DTR */ - gig_dbg(DEBUG_IF, "%u: to B0 - drop DTR/RTS", cs->minor_index); - new_state = control_state & ~(TIOCM_DTR | TIOCM_RTS); - cs->ops->set_modem_ctrl(cs, control_state, new_state); - control_state = new_state; - } - - /* - * Update line control register (LCR) - */ - - cs->ops->set_line_ctrl(cs, cflag); - - /* save off the modified port settings */ - cs->control_state = control_state; - -out: - mutex_unlock(&cs->mutex); -} - -static const struct tty_operations if_ops = { - .open = if_open, - .close = if_close, - .ioctl = if_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = if_compat_ioctl, -#endif - .write = if_write, - .write_room = if_write_room, - .chars_in_buffer = if_chars_in_buffer, - .set_termios = if_set_termios, - .throttle = if_throttle, - .unthrottle = if_unthrottle, - .tiocmget = if_tiocmget, - .tiocmset = if_tiocmset, -}; - - -/* wakeup tasklet for the write operation */ -static void if_wake(unsigned long data) -{ - struct cardstate *cs = (struct cardstate *)data; - - tty_port_tty_wakeup(&cs->port); -} - -/*** interface to common ***/ - -void gigaset_if_init(struct cardstate *cs) -{ - struct gigaset_driver *drv; - - drv = cs->driver; - if (!drv->have_tty) - return; - - tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs); - - mutex_lock(&cs->mutex); - cs->tty_dev = tty_port_register_device(&cs->port, drv->tty, - cs->minor_index, NULL); - - if (!IS_ERR(cs->tty_dev)) - dev_set_drvdata(cs->tty_dev, cs); - else { - pr_warning("could not register device to the tty subsystem\n"); - cs->tty_dev = NULL; - } - mutex_unlock(&cs->mutex); -} - -void gigaset_if_free(struct cardstate *cs) -{ - struct gigaset_driver *drv; - - drv = cs->driver; - if (!drv->have_tty) - return; - - tasklet_disable(&cs->if_wake_tasklet); - tasklet_kill(&cs->if_wake_tasklet); - cs->tty_dev = NULL; - tty_unregister_device(drv->tty, cs->minor_index); -} - -/** - * gigaset_if_receive() - pass a received block of data to the tty device - * @cs: device descriptor structure. - * @buffer: received data. - * @len: number of bytes received. - * - * Called by asyncdata/isocdata if a block of data received from the - * device must be sent to userspace through the ttyG* device. - */ -void gigaset_if_receive(struct cardstate *cs, - unsigned char *buffer, size_t len) -{ - tty_insert_flip_string(&cs->port, buffer, len); - tty_flip_buffer_push(&cs->port); -} -EXPORT_SYMBOL_GPL(gigaset_if_receive); - -/* gigaset_if_initdriver - * Initialize tty interface. - * parameters: - * drv Driver - * procname Name of the driver (e.g. for /proc/tty/drivers) - * devname Name of the device files (prefix without minor number) - */ -void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, - const char *devname) -{ - int ret; - struct tty_driver *tty; - - drv->have_tty = 0; - - drv->tty = tty = alloc_tty_driver(drv->minors); - if (tty == NULL) - goto enomem; - - tty->type = TTY_DRIVER_TYPE_SERIAL; - tty->subtype = SERIAL_TYPE_NORMAL; - tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - - tty->driver_name = procname; - tty->name = devname; - tty->minor_start = drv->minor; - - tty->init_termios = tty_std_termios; - tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - tty_set_operations(tty, &if_ops); - - ret = tty_register_driver(tty); - if (ret < 0) { - pr_err("error %d registering tty driver\n", ret); - goto error; - } - gig_dbg(DEBUG_IF, "tty driver initialized"); - drv->have_tty = 1; - return; - -enomem: - pr_err("out of memory\n"); -error: - if (drv->tty) - put_tty_driver(drv->tty); -} - -void gigaset_if_freedriver(struct gigaset_driver *drv) -{ - if (!drv->have_tty) - return; - - drv->have_tty = 0; - tty_unregister_driver(drv->tty); - put_tty_driver(drv->tty); -} diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c deleted file mode 100644 index 3ecf6e33ed15..000000000000 --- a/drivers/isdn/gigaset/isocdata.c +++ /dev/null @@ -1,1006 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Common data handling layer for bas_gigaset - * - * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>, - * Hansjoerg Lipp <hjlipp@web.de>. - * - * ===================================================================== - * ===================================================================== - */ - -#include "gigaset.h" -#include <linux/crc-ccitt.h> -#include <linux/bitrev.h> - -/* access methods for isowbuf_t */ -/* ============================ */ - -/* initialize buffer structure - */ -void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle) -{ - iwb->read = 0; - iwb->nextread = 0; - iwb->write = 0; - atomic_set(&iwb->writesem, 1); - iwb->wbits = 0; - iwb->idle = idle; - memset(iwb->data + BAS_OUTBUFSIZE, idle, BAS_OUTBUFPAD); -} - -/* compute number of bytes which can be appended to buffer - * so that there is still room to append a maximum frame of flags - */ -static inline int isowbuf_freebytes(struct isowbuf_t *iwb) -{ - int read, write, freebytes; - - read = iwb->read; - write = iwb->write; - freebytes = read - write; - if (freebytes > 0) { - /* no wraparound: need padding space within regular area */ - return freebytes - BAS_OUTBUFPAD; - } else if (read < BAS_OUTBUFPAD) { - /* wraparound: can use space up to end of regular area */ - return BAS_OUTBUFSIZE - write; - } else { - /* following the wraparound yields more space */ - return freebytes + BAS_OUTBUFSIZE - BAS_OUTBUFPAD; - } -} - -/* start writing - * acquire the write semaphore - * return 0 if acquired, <0 if busy - */ -static inline int isowbuf_startwrite(struct isowbuf_t *iwb) -{ - if (!atomic_dec_and_test(&iwb->writesem)) { - atomic_inc(&iwb->writesem); - gig_dbg(DEBUG_ISO, "%s: couldn't acquire iso write semaphore", - __func__); - return -EBUSY; - } - gig_dbg(DEBUG_ISO, - "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d", - __func__, iwb->data[iwb->write], iwb->wbits); - return 0; -} - -/* finish writing - * release the write semaphore - * returns the current write position - */ -static inline int isowbuf_donewrite(struct isowbuf_t *iwb) -{ - int write = iwb->write; - atomic_inc(&iwb->writesem); - return write; -} - -/* append bits to buffer without any checks - * - data contains bits to append, starting at LSB - * - nbits is number of bits to append (0..24) - * must be called with the write semaphore held - * If more than nbits bits are set in data, the extraneous bits are set in the - * buffer too, but the write position is only advanced by nbits. - */ -static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits) -{ - int write = iwb->write; - data <<= iwb->wbits; - data |= iwb->data[write]; - nbits += iwb->wbits; - while (nbits >= 8) { - iwb->data[write++] = data & 0xff; - write %= BAS_OUTBUFSIZE; - data >>= 8; - nbits -= 8; - } - iwb->wbits = nbits; - iwb->data[write] = data & 0xff; - iwb->write = write; -} - -/* put final flag on HDLC bitstream - * also sets the idle fill byte to the correspondingly shifted flag pattern - * must be called with the write semaphore held - */ -static inline void isowbuf_putflag(struct isowbuf_t *iwb) -{ - int write; - - /* add two flags, thus reliably covering one byte */ - isowbuf_putbits(iwb, 0x7e7e, 8); - /* recover the idle flag byte */ - write = iwb->write; - iwb->idle = iwb->data[write]; - gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle); - /* mask extraneous bits in buffer */ - iwb->data[write] &= (1 << iwb->wbits) - 1; -} - -/* retrieve a block of bytes for sending - * The requested number of bytes is provided as a contiguous block. - * If necessary, the frame is filled to the requested number of bytes - * with the idle value. - * returns offset to frame, < 0 on busy or error - */ -int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) -{ - int read, write, limit, src, dst; - unsigned char pbyte; - - read = iwb->nextread; - write = iwb->write; - if (likely(read == write)) { - /* return idle frame */ - return read < BAS_OUTBUFPAD ? - BAS_OUTBUFSIZE : read - BAS_OUTBUFPAD; - } - - limit = read + size; - gig_dbg(DEBUG_STREAM, "%s: read=%d write=%d limit=%d", - __func__, read, write, limit); -#ifdef CONFIG_GIGASET_DEBUG - if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) { - pr_err("invalid size %d\n", size); - return -EINVAL; - } -#endif - - if (read < write) { - /* no wraparound in valid data */ - if (limit >= write) { - /* append idle frame */ - if (isowbuf_startwrite(iwb) < 0) - return -EBUSY; - /* write position could have changed */ - write = iwb->write; - if (limit >= write) { - pbyte = iwb->data[write]; /* save - partial byte */ - limit = write + BAS_OUTBUFPAD; - gig_dbg(DEBUG_STREAM, - "%s: filling %d->%d with %02x", - __func__, write, limit, iwb->idle); - if (write + BAS_OUTBUFPAD < BAS_OUTBUFSIZE) - memset(iwb->data + write, iwb->idle, - BAS_OUTBUFPAD); - else { - /* wraparound, fill entire pad area */ - memset(iwb->data + write, iwb->idle, - BAS_OUTBUFSIZE + BAS_OUTBUFPAD - - write); - limit = 0; - } - gig_dbg(DEBUG_STREAM, - "%s: restoring %02x at %d", - __func__, pbyte, limit); - iwb->data[limit] = pbyte; /* restore - partial byte */ - iwb->write = limit; - } - isowbuf_donewrite(iwb); - } - } else { - /* valid data wraparound */ - if (limit >= BAS_OUTBUFSIZE) { - /* copy wrapped part into pad area */ - src = 0; - dst = BAS_OUTBUFSIZE; - while (dst < limit && src < write) - iwb->data[dst++] = iwb->data[src++]; - if (dst <= limit) { - /* fill pad area with idle byte */ - memset(iwb->data + dst, iwb->idle, - BAS_OUTBUFSIZE + BAS_OUTBUFPAD - dst); - } - limit = src; - } - } - iwb->nextread = limit; - return read; -} - -/* dump_bytes - * write hex bytes to syslog for debugging - */ -static inline void dump_bytes(enum debuglevel level, const char *tag, - unsigned char *bytes, int count) -{ -#ifdef CONFIG_GIGASET_DEBUG - unsigned char c; - static char dbgline[3 * 32 + 1]; - int i = 0; - - if (!(gigaset_debuglevel & level)) - return; - - while (count-- > 0) { - if (i > sizeof(dbgline) - 4) { - dbgline[i] = '\0'; - gig_dbg(level, "%s:%s", tag, dbgline); - i = 0; - } - c = *bytes++; - dbgline[i] = (i && !(i % 12)) ? '-' : ' '; - i++; - dbgline[i++] = hex_asc_hi(c); - dbgline[i++] = hex_asc_lo(c); - } - dbgline[i] = '\0'; - gig_dbg(level, "%s:%s", tag, dbgline); -#endif -} - -/*============================================================================*/ - -/* bytewise HDLC bitstuffing via table lookup - * lookup table: 5 subtables for 0..4 preceding consecutive '1' bits - * index: 256*(number of preceding '1' bits) + (next byte to stuff) - * value: bit 9.. 0 = result bits - * bit 12..10 = number of trailing '1' bits in result - * bit 14..13 = number of bits added by stuffing - */ -static const u16 stufftab[5 * 256] = { -/* previous 1s = 0: */ - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x201f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x205f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x209f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20df, - 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f, - 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x251f, - 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af, - 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x255f, - 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x08cf, - 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x299f, - 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x0cef, - 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x2ddf, - -/* previous 1s = 1: */ - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x200f, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x202f, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x204f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x206f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x208f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20af, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20cf, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20ef, - 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x250f, - 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x252f, - 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x254f, - 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x256f, - 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x08c7, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x298f, - 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x08d7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29af, - 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x0ce7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dcf, - 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x10f7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x31ef, - -/* previous 1s = 2: */ - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x2007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x2017, - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x2027, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x2037, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x2047, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x2057, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x2067, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x203e, 0x2077, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x2087, 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x2097, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x20a7, 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x20b7, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x20c7, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x20d7, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x20e7, 0x0078, 0x0079, 0x007a, 0x007b, 0x207c, 0x207d, 0x20be, 0x20f7, - 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x2507, 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x2517, - 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x2527, 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x2537, - 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x2547, 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x2557, - 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x2567, 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x253e, 0x2577, - 0x08c0, 0x08c1, 0x08c2, 0x08c3, 0x08c4, 0x08c5, 0x08c6, 0x2987, 0x08c8, 0x08c9, 0x08ca, 0x08cb, 0x08cc, 0x08cd, 0x08ce, 0x2997, - 0x08d0, 0x08d1, 0x08d2, 0x08d3, 0x08d4, 0x08d5, 0x08d6, 0x29a7, 0x08d8, 0x08d9, 0x08da, 0x08db, 0x08dc, 0x08dd, 0x08de, 0x29b7, - 0x0ce0, 0x0ce1, 0x0ce2, 0x0ce3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dc7, 0x0ce8, 0x0ce9, 0x0cea, 0x0ceb, 0x0cec, 0x0ced, 0x0cee, 0x2dd7, - 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0x10f6, 0x31e7, 0x20f8, 0x20f9, 0x20fa, 0x20fb, 0x257c, 0x257d, 0x29be, 0x41f7, - -/* previous 1s = 3: */ - 0x0000, 0x0001, 0x0002, 0x2003, 0x0004, 0x0005, 0x0006, 0x200b, 0x0008, 0x0009, 0x000a, 0x2013, 0x000c, 0x000d, 0x000e, 0x201b, - 0x0010, 0x0011, 0x0012, 0x2023, 0x0014, 0x0015, 0x0016, 0x202b, 0x0018, 0x0019, 0x001a, 0x2033, 0x001c, 0x001d, 0x001e, 0x203b, - 0x0020, 0x0021, 0x0022, 0x2043, 0x0024, 0x0025, 0x0026, 0x204b, 0x0028, 0x0029, 0x002a, 0x2053, 0x002c, 0x002d, 0x002e, 0x205b, - 0x0030, 0x0031, 0x0032, 0x2063, 0x0034, 0x0035, 0x0036, 0x206b, 0x0038, 0x0039, 0x003a, 0x2073, 0x003c, 0x003d, 0x203e, 0x207b, - 0x0040, 0x0041, 0x0042, 0x2083, 0x0044, 0x0045, 0x0046, 0x208b, 0x0048, 0x0049, 0x004a, 0x2093, 0x004c, 0x004d, 0x004e, 0x209b, - 0x0050, 0x0051, 0x0052, 0x20a3, 0x0054, 0x0055, 0x0056, 0x20ab, 0x0058, 0x0059, 0x005a, 0x20b3, 0x005c, 0x005d, 0x005e, 0x20bb, - 0x0060, 0x0061, 0x0062, 0x20c3, 0x0064, 0x0065, 0x0066, 0x20cb, 0x0068, 0x0069, 0x006a, 0x20d3, 0x006c, 0x006d, 0x006e, 0x20db, - 0x0070, 0x0071, 0x0072, 0x20e3, 0x0074, 0x0075, 0x0076, 0x20eb, 0x0078, 0x0079, 0x007a, 0x20f3, 0x207c, 0x207d, 0x20be, 0x40fb, - 0x0480, 0x0481, 0x0482, 0x2503, 0x0484, 0x0485, 0x0486, 0x250b, 0x0488, 0x0489, 0x048a, 0x2513, 0x048c, 0x048d, 0x048e, 0x251b, - 0x0490, 0x0491, 0x0492, 0x2523, 0x0494, 0x0495, 0x0496, 0x252b, 0x0498, 0x0499, 0x049a, 0x2533, 0x049c, 0x049d, 0x049e, 0x253b, - 0x04a0, 0x04a1, 0x04a2, 0x2543, 0x04a4, 0x04a5, 0x04a6, 0x254b, 0x04a8, 0x04a9, 0x04aa, 0x2553, 0x04ac, 0x04ad, 0x04ae, 0x255b, - 0x04b0, 0x04b1, 0x04b2, 0x2563, 0x04b4, 0x04b5, 0x04b6, 0x256b, 0x04b8, 0x04b9, 0x04ba, 0x2573, 0x04bc, 0x04bd, 0x253e, 0x257b, - 0x08c0, 0x08c1, 0x08c2, 0x2983, 0x08c4, 0x08c5, 0x08c6, 0x298b, 0x08c8, 0x08c9, 0x08ca, 0x2993, 0x08cc, 0x08cd, 0x08ce, 0x299b, - 0x08d0, 0x08d1, 0x08d2, 0x29a3, 0x08d4, 0x08d5, 0x08d6, 0x29ab, 0x08d8, 0x08d9, 0x08da, 0x29b3, 0x08dc, 0x08dd, 0x08de, 0x29bb, - 0x0ce0, 0x0ce1, 0x0ce2, 0x2dc3, 0x0ce4, 0x0ce5, 0x0ce6, 0x2dcb, 0x0ce8, 0x0ce9, 0x0cea, 0x2dd3, 0x0cec, 0x0ced, 0x0cee, 0x2ddb, - 0x10f0, 0x10f1, 0x10f2, 0x31e3, 0x10f4, 0x10f5, 0x10f6, 0x31eb, 0x20f8, 0x20f9, 0x20fa, 0x41f3, 0x257c, 0x257d, 0x29be, 0x46fb, - -/* previous 1s = 4: */ - 0x0000, 0x2001, 0x0002, 0x2005, 0x0004, 0x2009, 0x0006, 0x200d, 0x0008, 0x2011, 0x000a, 0x2015, 0x000c, 0x2019, 0x000e, 0x201d, - 0x0010, 0x2021, 0x0012, 0x2025, 0x0014, 0x2029, 0x0016, 0x202d, 0x0018, 0x2031, 0x001a, 0x2035, 0x001c, 0x2039, 0x001e, 0x203d, - 0x0020, 0x2041, 0x0022, 0x2045, 0x0024, 0x2049, 0x0026, 0x204d, 0x0028, 0x2051, 0x002a, 0x2055, 0x002c, 0x2059, 0x002e, 0x205d, - 0x0030, 0x2061, 0x0032, 0x2065, 0x0034, 0x2069, 0x0036, 0x206d, 0x0038, 0x2071, 0x003a, 0x2075, 0x003c, 0x2079, 0x203e, 0x407d, - 0x0040, 0x2081, 0x0042, 0x2085, 0x0044, 0x2089, 0x0046, 0x208d, 0x0048, 0x2091, 0x004a, 0x2095, 0x004c, 0x2099, 0x004e, 0x209d, - 0x0050, 0x20a1, 0x0052, 0x20a5, 0x0054, 0x20a9, 0x0056, 0x20ad, 0x0058, 0x20b1, 0x005a, 0x20b5, 0x005c, 0x20b9, 0x005e, 0x20bd, - 0x0060, 0x20c1, 0x0062, 0x20c5, 0x0064, 0x20c9, 0x0066, 0x20cd, 0x0068, 0x20d1, 0x006a, 0x20d5, 0x006c, 0x20d9, 0x006e, 0x20dd, - 0x0070, 0x20e1, 0x0072, 0x20e5, 0x0074, 0x20e9, 0x0076, 0x20ed, 0x0078, 0x20f1, 0x007a, 0x20f5, 0x207c, 0x40f9, 0x20be, 0x417d, - 0x0480, 0x2501, 0x0482, 0x2505, 0x0484, 0x2509, 0x0486, 0x250d, 0x0488, 0x2511, 0x048a, 0x2515, 0x048c, 0x2519, 0x048e, 0x251d, - 0x0490, 0x2521, 0x0492, 0x2525, 0x0494, 0x2529, 0x0496, 0x252d, 0x0498, 0x2531, 0x049a, 0x2535, 0x049c, 0x2539, 0x049e, 0x253d, - 0x04a0, 0x2541, 0x04a2, 0x2545, 0x04a4, 0x2549, 0x04a6, 0x254d, 0x04a8, 0x2551, 0x04aa, 0x2555, 0x04ac, 0x2559, 0x04ae, 0x255d, - 0x04b0, 0x2561, 0x04b2, 0x2565, 0x04b4, 0x2569, 0x04b6, 0x256d, 0x04b8, 0x2571, 0x04ba, 0x2575, 0x04bc, 0x2579, 0x253e, 0x467d, - 0x08c0, 0x2981, 0x08c2, 0x2985, 0x08c4, 0x2989, 0x08c6, 0x298d, 0x08c8, 0x2991, 0x08ca, 0x2995, 0x08cc, 0x2999, 0x08ce, 0x299d, - 0x08d0, 0x29a1, 0x08d2, 0x29a5, 0x08d4, 0x29a9, 0x08d6, 0x29ad, 0x08d8, 0x29b1, 0x08da, 0x29b5, 0x08dc, 0x29b9, 0x08de, 0x29bd, - 0x0ce0, 0x2dc1, 0x0ce2, 0x2dc5, 0x0ce4, 0x2dc9, 0x0ce6, 0x2dcd, 0x0ce8, 0x2dd1, 0x0cea, 0x2dd5, 0x0cec, 0x2dd9, 0x0cee, 0x2ddd, - 0x10f0, 0x31e1, 0x10f2, 0x31e5, 0x10f4, 0x31e9, 0x10f6, 0x31ed, 0x20f8, 0x41f1, 0x20fa, 0x41f5, 0x257c, 0x46f9, 0x29be, 0x4b7d -}; - -/* hdlc_bitstuff_byte - * perform HDLC bitstuffing for one input byte (8 bits, LSB first) - * parameters: - * cin input byte - * ones number of trailing '1' bits in result before this step - * iwb pointer to output buffer structure - * (write semaphore must be held) - * return value: - * number of trailing '1' bits in result after this step - */ - -static inline int hdlc_bitstuff_byte(struct isowbuf_t *iwb, unsigned char cin, - int ones) -{ - u16 stuff; - int shiftinc, newones; - - /* get stuffing information for input byte - * value: bit 9.. 0 = result bits - * bit 12..10 = number of trailing '1' bits in result - * bit 14..13 = number of bits added by stuffing - */ - stuff = stufftab[256 * ones + cin]; - shiftinc = (stuff >> 13) & 3; - newones = (stuff >> 10) & 7; - stuff &= 0x3ff; - - /* append stuffed byte to output stream */ - isowbuf_putbits(iwb, stuff, 8 + shiftinc); - return newones; -} - -/* hdlc_buildframe - * Perform HDLC framing with bitstuffing on a byte buffer - * The input buffer is regarded as a sequence of bits, starting with the least - * significant bit of the first byte and ending with the most significant bit - * of the last byte. A 16 bit FCS is appended as defined by RFC 1662. - * Whenever five consecutive '1' bits appear in the resulting bit sequence, a - * '0' bit is inserted after them. - * The resulting bit string and a closing flag pattern (PPP_FLAG, '01111110') - * are appended to the output buffer starting at the given bit position, which - * is assumed to already contain a leading flag. - * The output buffer must have sufficient length; count + count/5 + 6 bytes - * starting at *out are safe and are verified to be present. - * parameters: - * in input buffer - * count number of bytes in input buffer - * iwb pointer to output buffer structure - * (write semaphore must be held) - * return value: - * position of end of packet in output buffer on success, - * -EAGAIN if write semaphore busy or buffer full - */ - -static inline int hdlc_buildframe(struct isowbuf_t *iwb, - unsigned char *in, int count) -{ - int ones; - u16 fcs; - int end; - unsigned char c; - - if (isowbuf_freebytes(iwb) < count + count / 5 + 6 || - isowbuf_startwrite(iwb) < 0) { - gig_dbg(DEBUG_ISO, "%s: %d bytes free -> -EAGAIN", - __func__, isowbuf_freebytes(iwb)); - return -EAGAIN; - } - - dump_bytes(DEBUG_STREAM_DUMP, "snd data", in, count); - - /* bitstuff and checksum input data */ - fcs = PPP_INITFCS; - ones = 0; - while (count-- > 0) { - c = *in++; - ones = hdlc_bitstuff_byte(iwb, c, ones); - fcs = crc_ccitt_byte(fcs, c); - } - - /* bitstuff and append FCS - * (complemented, least significant byte first) */ - fcs ^= 0xffff; - ones = hdlc_bitstuff_byte(iwb, fcs & 0x00ff, ones); - ones = hdlc_bitstuff_byte(iwb, (fcs >> 8) & 0x00ff, ones); - - /* put closing flag and repeat byte for flag idle */ - isowbuf_putflag(iwb); - end = isowbuf_donewrite(iwb); - return end; -} - -/* trans_buildframe - * Append a block of 'transparent' data to the output buffer, - * inverting the bytes. - * The output buffer must have sufficient length; count bytes - * starting at *out are safe and are verified to be present. - * parameters: - * in input buffer - * count number of bytes in input buffer - * iwb pointer to output buffer structure - * (write semaphore must be held) - * return value: - * position of end of packet in output buffer on success, - * -EAGAIN if write semaphore busy or buffer full - */ - -static inline int trans_buildframe(struct isowbuf_t *iwb, - unsigned char *in, int count) -{ - int write; - unsigned char c; - - if (unlikely(count <= 0)) - return iwb->write; - - if (isowbuf_freebytes(iwb) < count || - isowbuf_startwrite(iwb) < 0) { - gig_dbg(DEBUG_ISO, "can't put %d bytes", count); - return -EAGAIN; - } - - gig_dbg(DEBUG_STREAM, "put %d bytes", count); - dump_bytes(DEBUG_STREAM_DUMP, "snd data", in, count); - - write = iwb->write; - do { - c = bitrev8(*in++); - iwb->data[write++] = c; - write %= BAS_OUTBUFSIZE; - } while (--count > 0); - iwb->write = write; - iwb->idle = c; - - return isowbuf_donewrite(iwb); -} - -int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len) -{ - int result; - - switch (bcs->proto2) { - case L2_HDLC: - result = hdlc_buildframe(bcs->hw.bas->isooutbuf, in, len); - gig_dbg(DEBUG_ISO, "%s: %d bytes HDLC -> %d", - __func__, len, result); - break; - default: /* assume transparent */ - result = trans_buildframe(bcs->hw.bas->isooutbuf, in, len); - gig_dbg(DEBUG_ISO, "%s: %d bytes trans -> %d", - __func__, len, result); - } - return result; -} - -/* hdlc_putbyte - * append byte c to current skb of B channel structure *bcs, updating fcs - */ -static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs) -{ - bcs->rx_fcs = crc_ccitt_byte(bcs->rx_fcs, c); - if (bcs->rx_skb == NULL) - /* skipping */ - return; - if (bcs->rx_skb->len >= bcs->rx_bufsize) { - dev_warn(bcs->cs->dev, "received oversized packet discarded\n"); - bcs->hw.bas->giants++; - dev_kfree_skb_any(bcs->rx_skb); - bcs->rx_skb = NULL; - return; - } - __skb_put_u8(bcs->rx_skb, c); -} - -/* hdlc_flush - * drop partial HDLC data packet - */ -static inline void hdlc_flush(struct bc_state *bcs) -{ - /* clear skb or allocate new if not skipping */ - if (bcs->rx_skb != NULL) - skb_trim(bcs->rx_skb, 0); - else - gigaset_new_rx_skb(bcs); - - /* reset packet state */ - bcs->rx_fcs = PPP_INITFCS; -} - -/* hdlc_done - * process completed HDLC data packet - */ -static inline void hdlc_done(struct bc_state *bcs) -{ - struct cardstate *cs = bcs->cs; - struct sk_buff *procskb; - unsigned int len; - - if (unlikely(bcs->ignore)) { - bcs->ignore--; - hdlc_flush(bcs); - return; - } - procskb = bcs->rx_skb; - if (procskb == NULL) { - /* previous error */ - gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__); - gigaset_isdn_rcv_err(bcs); - } else if (procskb->len < 2) { - dev_notice(cs->dev, "received short frame (%d octets)\n", - procskb->len); - bcs->hw.bas->runts++; - dev_kfree_skb_any(procskb); - gigaset_isdn_rcv_err(bcs); - } else if (bcs->rx_fcs != PPP_GOODFCS) { - dev_notice(cs->dev, "frame check error\n"); - bcs->hw.bas->fcserrs++; - dev_kfree_skb_any(procskb); - gigaset_isdn_rcv_err(bcs); - } else { - len = procskb->len; - __skb_trim(procskb, len -= 2); /* subtract FCS */ - gig_dbg(DEBUG_ISO, "%s: good frame (%d octets)", __func__, len); - dump_bytes(DEBUG_STREAM_DUMP, - "rcv data", procskb->data, len); - bcs->hw.bas->goodbytes += len; - gigaset_skb_rcvd(bcs, procskb); - } - gigaset_new_rx_skb(bcs); - bcs->rx_fcs = PPP_INITFCS; -} - -/* hdlc_frag - * drop HDLC data packet with non-integral last byte - */ -static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits) -{ - if (unlikely(bcs->ignore)) { - bcs->ignore--; - hdlc_flush(bcs); - return; - } - - dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits); - bcs->hw.bas->alignerrs++; - gigaset_isdn_rcv_err(bcs); - __skb_trim(bcs->rx_skb, 0); - bcs->rx_fcs = PPP_INITFCS; -} - -/* bit counts lookup table for HDLC bit unstuffing - * index: input byte - * value: bit 0..3 = number of consecutive '1' bits starting from LSB - * bit 4..6 = number of consecutive '1' bits starting from MSB - * (replacing 8 by 7 to make it fit; the algorithm won't care) - * bit 7 set if there are 5 or more "interior" consecutive '1' bits - */ -static const unsigned char bitcounts[256] = { - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x80, 0x06, - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x05, - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x04, - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x80, 0x81, 0x80, 0x07, - 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14, - 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x15, - 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x14, - 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x10, 0x13, 0x10, 0x11, 0x10, 0x12, 0x10, 0x11, 0x90, 0x16, - 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x24, - 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x23, 0x20, 0x21, 0x20, 0x22, 0x20, 0x21, 0x20, 0x25, - 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x33, 0x30, 0x31, 0x30, 0x32, 0x30, 0x31, 0x30, 0x34, - 0x40, 0x41, 0x40, 0x42, 0x40, 0x41, 0x40, 0x43, 0x50, 0x51, 0x50, 0x52, 0x60, 0x61, 0x70, 0x78 -}; - -/* hdlc_unpack - * perform HDLC frame processing (bit unstuffing, flag detection, FCS - * calculation) on a sequence of received data bytes (8 bits each, LSB first) - * pass on successfully received, complete frames as SKBs via gigaset_skb_rcvd - * notify of errors via gigaset_isdn_rcv_err - * tally frames, errors etc. in BC structure counters - * parameters: - * src received data - * count number of received bytes - * bcs receiving B channel structure - */ -static inline void hdlc_unpack(unsigned char *src, unsigned count, - struct bc_state *bcs) -{ - struct bas_bc_state *ubc = bcs->hw.bas; - int inputstate; - unsigned seqlen, inbyte, inbits; - - /* load previous state: - * inputstate = set of flag bits: - * - INS_flag_hunt: no complete opening flag received since connection - * setup or last abort - * - INS_have_data: at least one complete data byte received since last - * flag - * seqlen = number of consecutive '1' bits in last 7 input stream bits - * (0..7) - * inbyte = accumulated partial data byte (if !INS_flag_hunt) - * inbits = number of valid bits in inbyte, starting at LSB (0..6) - */ - inputstate = bcs->inputstate; - seqlen = ubc->seqlen; - inbyte = ubc->inbyte; - inbits = ubc->inbits; - - /* bit unstuffing a byte a time - * Take your time to understand this; it's straightforward but tedious. - * The "bitcounts" lookup table is used to speed up the counting of - * leading and trailing '1' bits. - */ - while (count--) { - unsigned char c = *src++; - unsigned char tabentry = bitcounts[c]; - unsigned lead1 = tabentry & 0x0f; - unsigned trail1 = (tabentry >> 4) & 0x0f; - - seqlen += lead1; - - if (unlikely(inputstate & INS_flag_hunt)) { - if (c == PPP_FLAG) { - /* flag-in-one */ - inputstate &= ~(INS_flag_hunt | INS_have_data); - inbyte = 0; - inbits = 0; - } else if (seqlen == 6 && trail1 != 7) { - /* flag completed & not followed by abort */ - inputstate &= ~(INS_flag_hunt | INS_have_data); - inbyte = c >> (lead1 + 1); - inbits = 7 - lead1; - if (trail1 >= 8) { - /* interior stuffing: - * omitting the MSB handles most cases, - * correct the incorrectly handled - * cases individually */ - inbits--; - switch (c) { - case 0xbe: - inbyte = 0x3f; - break; - } - } - } - /* else: continue flag-hunting */ - } else if (likely(seqlen < 5 && trail1 < 7)) { - /* streamlined case: 8 data bits, no stuffing */ - inbyte |= c << inbits; - hdlc_putbyte(inbyte & 0xff, bcs); - inputstate |= INS_have_data; - inbyte >>= 8; - /* inbits unchanged */ - } else if (likely(seqlen == 6 && inbits == 7 - lead1 && - trail1 + 1 == inbits && - !(inputstate & INS_have_data))) { - /* streamlined case: flag idle - state unchanged */ - } else if (unlikely(seqlen > 6)) { - /* abort sequence */ - ubc->aborts++; - hdlc_flush(bcs); - inputstate |= INS_flag_hunt; - } else if (seqlen == 6) { - /* closing flag, including (6 - lead1) '1's - * and one '0' from inbits */ - if (inbits > 7 - lead1) { - hdlc_frag(bcs, inbits + lead1 - 7); - inputstate &= ~INS_have_data; - } else { - if (inbits < 7 - lead1) - ubc->stolen0s++; - if (inputstate & INS_have_data) { - hdlc_done(bcs); - inputstate &= ~INS_have_data; - } - } - - if (c == PPP_FLAG) { - /* complete flag, LSB overlaps preceding flag */ - ubc->shared0s++; - inbits = 0; - inbyte = 0; - } else if (trail1 != 7) { - /* remaining bits */ - inbyte = c >> (lead1 + 1); - inbits = 7 - lead1; - if (trail1 >= 8) { - /* interior stuffing: - * omitting the MSB handles most cases, - * correct the incorrectly handled - * cases individually */ - inbits--; - switch (c) { - case 0xbe: - inbyte = 0x3f; - break; - } - } - } else { - /* abort sequence follows, - * skb already empty anyway */ - ubc->aborts++; - inputstate |= INS_flag_hunt; - } - } else { /* (seqlen < 6) && (seqlen == 5 || trail1 >= 7) */ - - if (c == PPP_FLAG) { - /* complete flag */ - if (seqlen == 5) - ubc->stolen0s++; - if (inbits) { - hdlc_frag(bcs, inbits); - inbits = 0; - inbyte = 0; - } else if (inputstate & INS_have_data) - hdlc_done(bcs); - inputstate &= ~INS_have_data; - } else if (trail1 == 7) { - /* abort sequence */ - ubc->aborts++; - hdlc_flush(bcs); - inputstate |= INS_flag_hunt; - } else { - /* stuffed data */ - if (trail1 < 7) { /* => seqlen == 5 */ - /* stuff bit at position lead1, - * no interior stuffing */ - unsigned char mask = (1 << lead1) - 1; - c = (c & mask) | ((c & ~mask) >> 1); - inbyte |= c << inbits; - inbits += 7; - } else if (seqlen < 5) { /* trail1 >= 8 */ - /* interior stuffing: - * omitting the MSB handles most cases, - * correct the incorrectly handled - * cases individually */ - switch (c) { - case 0xbe: - c = 0x7e; - break; - } - inbyte |= c << inbits; - inbits += 7; - } else { /* seqlen == 5 && trail1 >= 8 */ - - /* stuff bit at lead1 *and* interior - * stuffing -- unstuff individually */ - switch (c) { - case 0x7d: - c = 0x3f; - break; - case 0xbe: - c = 0x3f; - break; - case 0x3e: - c = 0x1f; - break; - case 0x7c: - c = 0x3e; - break; - } - inbyte |= c << inbits; - inbits += 6; - } - if (inbits >= 8) { - inbits -= 8; - hdlc_putbyte(inbyte & 0xff, bcs); - inputstate |= INS_have_data; - inbyte >>= 8; - } - } - } - seqlen = trail1 & 7; - } - - /* save new state */ - bcs->inputstate = inputstate; - ubc->seqlen = seqlen; - ubc->inbyte = inbyte; - ubc->inbits = inbits; -} - -/* trans_receive - * pass on received USB frame transparently as SKB via gigaset_skb_rcvd - * invert bytes - * tally frames, errors etc. in BC structure counters - * parameters: - * src received data - * count number of received bytes - * bcs receiving B channel structure - */ -static inline void trans_receive(unsigned char *src, unsigned count, - struct bc_state *bcs) -{ - struct sk_buff *skb; - int dobytes; - unsigned char *dst; - - if (unlikely(bcs->ignore)) { - bcs->ignore--; - return; - } - skb = bcs->rx_skb; - if (skb == NULL) { - skb = gigaset_new_rx_skb(bcs); - if (skb == NULL) - return; - } - dobytes = bcs->rx_bufsize - skb->len; - while (count > 0) { - dst = skb_put(skb, count < dobytes ? count : dobytes); - while (count > 0 && dobytes > 0) { - *dst++ = bitrev8(*src++); - count--; - dobytes--; - } - if (dobytes == 0) { - dump_bytes(DEBUG_STREAM_DUMP, - "rcv data", skb->data, skb->len); - bcs->hw.bas->goodbytes += skb->len; - gigaset_skb_rcvd(bcs, skb); - skb = gigaset_new_rx_skb(bcs); - if (skb == NULL) - return; - dobytes = bcs->rx_bufsize; - } - } -} - -void gigaset_isoc_receive(unsigned char *src, unsigned count, - struct bc_state *bcs) -{ - switch (bcs->proto2) { - case L2_HDLC: - hdlc_unpack(src, count, bcs); - break; - default: /* assume transparent */ - trans_receive(src, count, bcs); - } -} - -/* == data input =========================================================== */ - -/* process a block of received bytes in command mode (mstate != MS_LOCKED) - * Append received bytes to the command response buffer and forward them - * line by line to the response handler. - * Note: Received lines may be terminated by CR, LF, or CR LF, which will be - * removed before passing the line to the response handler. - */ -static void cmd_loop(unsigned char *src, int numbytes, struct inbuf_t *inbuf) -{ - struct cardstate *cs = inbuf->cs; - unsigned cbytes = cs->cbytes; - unsigned char c; - - while (numbytes--) { - c = *src++; - switch (c) { - case '\n': - if (cbytes == 0 && cs->respdata[0] == '\r') { - /* collapse LF with preceding CR */ - cs->respdata[0] = 0; - break; - } - /* fall through */ - case '\r': - /* end of message line, pass to response handler */ - if (cbytes >= MAX_RESP_SIZE) { - dev_warn(cs->dev, "response too large (%d)\n", - cbytes); - cbytes = MAX_RESP_SIZE; - } - cs->cbytes = cbytes; - gigaset_dbg_buffer(DEBUG_TRANSCMD, "received response", - cbytes, cs->respdata); - gigaset_handle_modem_response(cs); - cbytes = 0; - - /* store EOL byte for CRLF collapsing */ - cs->respdata[0] = c; - break; - default: - /* append to line buffer if possible */ - if (cbytes < MAX_RESP_SIZE) - cs->respdata[cbytes] = c; - cbytes++; - } - } - - /* save state */ - cs->cbytes = cbytes; -} - - -/* process a block of data received through the control channel - */ -void gigaset_isoc_input(struct inbuf_t *inbuf) -{ - struct cardstate *cs = inbuf->cs; - unsigned tail, head, numbytes; - unsigned char *src; - - head = inbuf->head; - while (head != (tail = inbuf->tail)) { - gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); - if (head > tail) - tail = RBUFSIZE; - src = inbuf->data + head; - numbytes = tail - head; - gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes); - - if (cs->mstate == MS_LOCKED) { - gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", - numbytes, src); - gigaset_if_receive(inbuf->cs, src, numbytes); - } else { - cmd_loop(src, numbytes, inbuf); - } - - head += numbytes; - if (head == RBUFSIZE) - head = 0; - gig_dbg(DEBUG_INTR, "setting head to %u", head); - inbuf->head = head; - } -} - - -/* == data output ========================================================== */ - -/** - * gigaset_isoc_send_skb() - queue an skb for sending - * @bcs: B channel descriptor structure. - * @skb: data to send. - * - * Called by LL to queue an skb for sending, and start transmission if - * necessary. - * Once the payload data has been transmitted completely, gigaset_skb_sent() - * will be called with the skb's link layer header preserved. - * - * Return value: - * number of bytes accepted for sending (skb->len) if ok, - * error code < 0 (eg. -ENODEV) on error - */ -int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb) -{ - int len = skb->len; - unsigned long flags; - - spin_lock_irqsave(&bcs->cs->lock, flags); - if (!bcs->cs->connected) { - spin_unlock_irqrestore(&bcs->cs->lock, flags); - return -ENODEV; - } - - skb_queue_tail(&bcs->squeue, skb); - gig_dbg(DEBUG_ISO, "%s: skb queued, qlen=%d", - __func__, skb_queue_len(&bcs->squeue)); - - /* tasklet submits URB if necessary */ - tasklet_schedule(&bcs->hw.bas->sent_tasklet); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - - return len; /* ok so far */ -} diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c deleted file mode 100644 index 8914439a4237..000000000000 --- a/drivers/isdn/gigaset/proc.c +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Stuff used by all variants of the driver - * - * Copyright (c) 2001 by Stefan Eilers, - * Hansjoerg Lipp <hjlipp@web.de>, - * Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * ===================================================================== - */ - -#include "gigaset.h" - -static ssize_t show_cidmode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cardstate *cs = dev_get_drvdata(dev); - - return sprintf(buf, "%u\n", cs->cidmode); -} - -static ssize_t set_cidmode(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct cardstate *cs = dev_get_drvdata(dev); - long int value; - char *end; - - value = simple_strtol(buf, &end, 0); - while (*end) - if (!isspace(*end++)) - return -EINVAL; - if (value < 0 || value > 1) - return -EINVAL; - - if (mutex_lock_interruptible(&cs->mutex)) - return -ERESTARTSYS; - - cs->waiting = 1; - if (!gigaset_add_event(cs, &cs->at_state, EV_PROC_CIDMODE, - NULL, value, NULL)) { - cs->waiting = 0; - mutex_unlock(&cs->mutex); - return -ENOMEM; - } - gigaset_schedule_event(cs); - - wait_event(cs->waitqueue, !cs->waiting); - - mutex_unlock(&cs->mutex); - - return count; -} - -static DEVICE_ATTR(cidmode, S_IRUGO | S_IWUSR, show_cidmode, set_cidmode); - -/* free sysfs for device */ -void gigaset_free_dev_sysfs(struct cardstate *cs) -{ - if (!cs->tty_dev) - return; - - gig_dbg(DEBUG_INIT, "removing sysfs entries"); - device_remove_file(cs->tty_dev, &dev_attr_cidmode); -} - -/* initialize sysfs for device */ -void gigaset_init_dev_sysfs(struct cardstate *cs) -{ - if (!cs->tty_dev) - return; - - gig_dbg(DEBUG_INIT, "setting up sysfs"); - if (device_create_file(cs->tty_dev, &dev_attr_cidmode)) - pr_err("could not create sysfs attribute\n"); -} diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c deleted file mode 100644 index 5587e9e7fc73..000000000000 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ /dev/null @@ -1,796 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* This is the serial hardware link layer (HLL) for the Gigaset 307x isdn - * DECT base (aka Sinus 45 isdn) using the RS232 DECT data module M101, - * written as a line discipline. - * - * ===================================================================== - * ===================================================================== - */ - -#include "gigaset.h" -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/platform_device.h> -#include <linux/completion.h> - -/* Version Information */ -#define DRIVER_AUTHOR "Tilman Schmidt" -#define DRIVER_DESC "Serial Driver for Gigaset 307x using Siemens M101" - -#define GIGASET_MINORS 1 -#define GIGASET_MINOR 0 -#define GIGASET_MODULENAME "ser_gigaset" -#define GIGASET_DEVNAME "ttyGS" - -/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */ -#define IF_WRITEBUF 264 - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_LDISC(N_GIGASET_M101); - -static int startmode = SM_ISDN; -module_param(startmode, int, S_IRUGO); -MODULE_PARM_DESC(startmode, "initial operation mode"); -static int cidmode = 1; -module_param(cidmode, int, S_IRUGO); -MODULE_PARM_DESC(cidmode, "stay in CID mode when idle"); - -static struct gigaset_driver *driver; - -struct ser_cardstate { - struct platform_device dev; - struct tty_struct *tty; - atomic_t refcnt; - struct completion dead_cmp; -}; - -static struct platform_driver device_driver = { - .driver = { - .name = GIGASET_MODULENAME, - }, -}; - -static void flush_send_queue(struct cardstate *); - -/* transmit data from current open skb - * result: number of bytes sent or error code < 0 - */ -static int write_modem(struct cardstate *cs) -{ - struct tty_struct *tty = cs->hw.ser->tty; - struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ - struct sk_buff *skb = bcs->tx_skb; - int sent = -EOPNOTSUPP; - - WARN_ON(!tty || !tty->ops || !skb); - - if (!skb->len) { - dev_kfree_skb_any(skb); - bcs->tx_skb = NULL; - return -EINVAL; - } - - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - if (tty->ops->write) - sent = tty->ops->write(tty, skb->data, skb->len); - gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent); - if (sent < 0) { - /* error */ - flush_send_queue(cs); - return sent; - } - skb_pull(skb, sent); - if (!skb->len) { - /* skb sent completely */ - gigaset_skb_sent(bcs, skb); - - gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!", - (unsigned long) skb); - dev_kfree_skb_any(skb); - bcs->tx_skb = NULL; - } - return sent; -} - -/* - * transmit first queued command buffer - * result: number of bytes sent or error code < 0 - */ -static int send_cb(struct cardstate *cs) -{ - struct tty_struct *tty = cs->hw.ser->tty; - struct cmdbuf_t *cb, *tcb; - unsigned long flags; - int sent = 0; - - WARN_ON(!tty || !tty->ops); - - cb = cs->cmdbuf; - if (!cb) - return 0; /* nothing to do */ - - if (cb->len) { - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - sent = tty->ops->write(tty, cb->buf + cb->offset, cb->len); - if (sent < 0) { - /* error */ - gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent); - flush_send_queue(cs); - return sent; - } - cb->offset += sent; - cb->len -= sent; - gig_dbg(DEBUG_OUTPUT, "send_cb: sent %d, left %u, queued %u", - sent, cb->len, cs->cmdbytes); - } - - while (cb && !cb->len) { - spin_lock_irqsave(&cs->cmdlock, flags); - cs->cmdbytes -= cs->curlen; - tcb = cb; - cs->cmdbuf = cb = cb->next; - if (cb) { - cb->prev = NULL; - cs->curlen = cb->len; - } else { - cs->lastcmdbuf = NULL; - cs->curlen = 0; - } - spin_unlock_irqrestore(&cs->cmdlock, flags); - - if (tcb->wake_tasklet) - tasklet_schedule(tcb->wake_tasklet); - kfree(tcb); - } - return sent; -} - -/* - * send queue tasklet - * If there is already a skb opened, put data to the transfer buffer - * by calling "write_modem". - * Otherwise take a new skb out of the queue. - */ -static void gigaset_modem_fill(unsigned long data) -{ - struct cardstate *cs = (struct cardstate *) data; - struct bc_state *bcs; - struct sk_buff *nextskb; - int sent = 0; - - if (!cs) { - gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__); - return; - } - bcs = cs->bcs; - if (!bcs) { - gig_dbg(DEBUG_OUTPUT, "%s: no cardstate", __func__); - return; - } - if (!bcs->tx_skb) { - /* no skb is being sent; send command if any */ - sent = send_cb(cs); - gig_dbg(DEBUG_OUTPUT, "%s: send_cb -> %d", __func__, sent); - if (sent) - /* something sent or error */ - return; - - /* no command to send; get skb */ - nextskb = skb_dequeue(&bcs->squeue); - if (!nextskb) - /* no skb either, nothing to do */ - return; - bcs->tx_skb = nextskb; - - gig_dbg(DEBUG_INTR, "Dequeued skb (Adr: %lx)", - (unsigned long) bcs->tx_skb); - } - - /* send skb */ - gig_dbg(DEBUG_OUTPUT, "%s: tx_skb", __func__); - if (write_modem(cs) < 0) - gig_dbg(DEBUG_OUTPUT, "%s: write_modem failed", __func__); -} - -/* - * throw away all data queued for sending - */ -static void flush_send_queue(struct cardstate *cs) -{ - struct sk_buff *skb; - struct cmdbuf_t *cb; - unsigned long flags; - - /* command queue */ - spin_lock_irqsave(&cs->cmdlock, flags); - while ((cb = cs->cmdbuf) != NULL) { - cs->cmdbuf = cb->next; - if (cb->wake_tasklet) - tasklet_schedule(cb->wake_tasklet); - kfree(cb); - } - cs->cmdbuf = cs->lastcmdbuf = NULL; - cs->cmdbytes = cs->curlen = 0; - spin_unlock_irqrestore(&cs->cmdlock, flags); - - /* data queue */ - if (cs->bcs->tx_skb) - dev_kfree_skb_any(cs->bcs->tx_skb); - while ((skb = skb_dequeue(&cs->bcs->squeue)) != NULL) - dev_kfree_skb_any(skb); -} - - -/* Gigaset Driver Interface */ -/* ======================== */ - -/* - * queue an AT command string for transmission to the Gigaset device - * parameters: - * cs controller state structure - * buf buffer containing the string to send - * len number of characters to send - * wake_tasklet tasklet to run when transmission is complete, or NULL - * return value: - * number of bytes queued, or error code < 0 - */ -static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb) -{ - unsigned long flags; - - gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? - DEBUG_TRANSCMD : DEBUG_LOCKCMD, - "CMD Transmit", cb->len, cb->buf); - - spin_lock_irqsave(&cs->cmdlock, flags); - cb->prev = cs->lastcmdbuf; - if (cs->lastcmdbuf) - cs->lastcmdbuf->next = cb; - else { - cs->cmdbuf = cb; - cs->curlen = cb->len; - } - cs->cmdbytes += cb->len; - cs->lastcmdbuf = cb; - spin_unlock_irqrestore(&cs->cmdlock, flags); - - spin_lock_irqsave(&cs->lock, flags); - if (cs->connected) - tasklet_schedule(&cs->write_tasklet); - spin_unlock_irqrestore(&cs->lock, flags); - return cb->len; -} - -/* - * tty_driver.write_room interface routine - * return number of characters the driver will accept to be written - * parameter: - * controller state structure - * return value: - * number of characters - */ -static int gigaset_write_room(struct cardstate *cs) -{ - unsigned bytes; - - bytes = cs->cmdbytes; - return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0; -} - -/* - * tty_driver.chars_in_buffer interface routine - * return number of characters waiting to be sent - * parameter: - * controller state structure - * return value: - * number of characters - */ -static int gigaset_chars_in_buffer(struct cardstate *cs) -{ - return cs->cmdbytes; -} - -/* - * implementation of ioctl(GIGASET_BRKCHARS) - * parameter: - * controller state structure - * return value: - * -EINVAL (unimplemented function) - */ -static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) -{ - /* not implemented */ - return -EINVAL; -} - -/* - * Open B channel - * Called by "do_action" in ev-layer.c - */ -static int gigaset_init_bchannel(struct bc_state *bcs) -{ - /* nothing to do for M10x */ - gigaset_bchannel_up(bcs); - return 0; -} - -/* - * Close B channel - * Called by "do_action" in ev-layer.c - */ -static int gigaset_close_bchannel(struct bc_state *bcs) -{ - /* nothing to do for M10x */ - gigaset_bchannel_down(bcs); - return 0; -} - -/* - * Set up B channel structure - * This is called by "gigaset_initcs" in common.c - */ -static int gigaset_initbcshw(struct bc_state *bcs) -{ - /* unused */ - bcs->hw.ser = NULL; - return 0; -} - -/* - * Free B channel structure - * Called by "gigaset_freebcs" in common.c - */ -static void gigaset_freebcshw(struct bc_state *bcs) -{ - /* unused */ -} - -/* - * Reinitialize B channel structure - * This is called by "bcs_reinit" in common.c - */ -static void gigaset_reinitbcshw(struct bc_state *bcs) -{ - /* nothing to do for M10x */ -} - -/* - * Free hardware specific device data - * This will be called by "gigaset_freecs" in common.c - */ -static void gigaset_freecshw(struct cardstate *cs) -{ - tasklet_kill(&cs->write_tasklet); - if (!cs->hw.ser) - return; - platform_device_unregister(&cs->hw.ser->dev); -} - -static void gigaset_device_release(struct device *dev) -{ - kfree(container_of(dev, struct ser_cardstate, dev.dev)); -} - -/* - * Set up hardware specific device data - * This is called by "gigaset_initcs" in common.c - */ -static int gigaset_initcshw(struct cardstate *cs) -{ - int rc; - struct ser_cardstate *scs; - - scs = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL); - if (!scs) { - pr_err("out of memory\n"); - return -ENOMEM; - } - cs->hw.ser = scs; - - cs->hw.ser->dev.name = GIGASET_MODULENAME; - cs->hw.ser->dev.id = cs->minor_index; - cs->hw.ser->dev.dev.release = gigaset_device_release; - rc = platform_device_register(&cs->hw.ser->dev); - if (rc != 0) { - pr_err("error %d registering platform device\n", rc); - kfree(cs->hw.ser); - cs->hw.ser = NULL; - return rc; - } - - tasklet_init(&cs->write_tasklet, - gigaset_modem_fill, (unsigned long) cs); - return 0; -} - -/* - * set modem control lines - * Parameters: - * card state structure - * modem control line state ([TIOCM_DTR]|[TIOCM_RTS]) - * Called by "gigaset_start" and "gigaset_enterconfigmode" in common.c - * and by "if_lock" and "if_termios" in interface.c - */ -static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, - unsigned new_state) -{ - struct tty_struct *tty = cs->hw.ser->tty; - unsigned int set, clear; - - WARN_ON(!tty || !tty->ops); - /* tiocmset is an optional tty driver method */ - if (!tty->ops->tiocmset) - return -EINVAL; - set = new_state & ~old_state; - clear = old_state & ~new_state; - if (!set && !clear) - return 0; - gig_dbg(DEBUG_IF, "tiocmset set %x clear %x", set, clear); - return tty->ops->tiocmset(tty, set, clear); -} - -static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) -{ - return -EINVAL; -} - -static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) -{ - return -EINVAL; -} - -static const struct gigaset_ops ops = { - .write_cmd = gigaset_write_cmd, - .write_room = gigaset_write_room, - .chars_in_buffer = gigaset_chars_in_buffer, - .brkchars = gigaset_brkchars, - .init_bchannel = gigaset_init_bchannel, - .close_bchannel = gigaset_close_bchannel, - .initbcshw = gigaset_initbcshw, - .freebcshw = gigaset_freebcshw, - .reinitbcshw = gigaset_reinitbcshw, - .initcshw = gigaset_initcshw, - .freecshw = gigaset_freecshw, - .set_modem_ctrl = gigaset_set_modem_ctrl, - .baud_rate = gigaset_baud_rate, - .set_line_ctrl = gigaset_set_line_ctrl, - .send_skb = gigaset_m10x_send_skb, /* asyncdata.c */ - .handle_input = gigaset_m10x_input, /* asyncdata.c */ -}; - - -/* Line Discipline Interface */ -/* ========================= */ - -/* helper functions for cardstate refcounting */ -static struct cardstate *cs_get(struct tty_struct *tty) -{ - struct cardstate *cs = tty->disc_data; - - if (!cs || !cs->hw.ser) { - gig_dbg(DEBUG_ANY, "%s: no cardstate", __func__); - return NULL; - } - atomic_inc(&cs->hw.ser->refcnt); - return cs; -} - -static void cs_put(struct cardstate *cs) -{ - if (atomic_dec_and_test(&cs->hw.ser->refcnt)) - complete(&cs->hw.ser->dead_cmp); -} - -/* - * Called by the tty driver when the line discipline is pushed onto the tty. - * Called in process context. - */ -static int -gigaset_tty_open(struct tty_struct *tty) -{ - struct cardstate *cs; - int rc; - - gig_dbg(DEBUG_INIT, "Starting HLL for Gigaset M101"); - - pr_info(DRIVER_DESC "\n"); - - if (!driver) { - pr_err("%s: no driver structure\n", __func__); - return -ENODEV; - } - - /* allocate memory for our device state and initialize it */ - cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); - if (!cs) { - rc = -ENODEV; - goto error; - } - - cs->dev = &cs->hw.ser->dev.dev; - cs->hw.ser->tty = tty; - atomic_set(&cs->hw.ser->refcnt, 1); - init_completion(&cs->hw.ser->dead_cmp); - tty->disc_data = cs; - - /* Set the amount of data we're willing to receive per call - * from the hardware driver to half of the input buffer size - * to leave some reserve. - * Note: We don't do flow control towards the hardware driver. - * If more data is received than will fit into the input buffer, - * it will be dropped and an error will be logged. This should - * never happen as the device is slow and the buffer size ample. - */ - tty->receive_room = RBUFSIZE/2; - - /* OK.. Initialization of the datastructures and the HW is done.. Now - * startup system and notify the LL that we are ready to run - */ - if (startmode == SM_LOCKED) - cs->mstate = MS_LOCKED; - rc = gigaset_start(cs); - if (rc < 0) { - tasklet_kill(&cs->write_tasklet); - goto error; - } - - gig_dbg(DEBUG_INIT, "Startup of HLL done"); - return 0; - -error: - gig_dbg(DEBUG_INIT, "Startup of HLL failed"); - tty->disc_data = NULL; - gigaset_freecs(cs); - return rc; -} - -/* - * Called by the tty driver when the line discipline is removed. - * Called from process context. - */ -static void -gigaset_tty_close(struct tty_struct *tty) -{ - struct cardstate *cs = tty->disc_data; - - gig_dbg(DEBUG_INIT, "Stopping HLL for Gigaset M101"); - - if (!cs) { - gig_dbg(DEBUG_INIT, "%s: no cardstate", __func__); - return; - } - - /* prevent other callers from entering ldisc methods */ - tty->disc_data = NULL; - - if (!cs->hw.ser) - pr_err("%s: no hw cardstate\n", __func__); - else { - /* wait for running methods to finish */ - if (!atomic_dec_and_test(&cs->hw.ser->refcnt)) - wait_for_completion(&cs->hw.ser->dead_cmp); - } - - /* stop operations */ - gigaset_stop(cs); - tasklet_kill(&cs->write_tasklet); - flush_send_queue(cs); - cs->dev = NULL; - gigaset_freecs(cs); - - gig_dbg(DEBUG_INIT, "Shutdown of HLL done"); -} - -/* - * Called by the tty driver when the tty line is hung up. - * Wait for I/O to driver to complete and unregister ISDN device. - * This is already done by the close routine, so just call that. - * Called from process context. - */ -static int gigaset_tty_hangup(struct tty_struct *tty) -{ - gigaset_tty_close(tty); - return 0; -} - -/* - * Ioctl on the tty. - * Called in process context only. - * May be re-entered by multiple ioctl calling threads. - */ -static int -gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct cardstate *cs = cs_get(tty); - int rc, val; - int __user *p = (int __user *)arg; - - if (!cs) - return -ENXIO; - - switch (cmd) { - - case FIONREAD: - /* unused, always return zero */ - val = 0; - rc = put_user(val, p); - break; - - case TCFLSH: - /* flush our buffers and the serial port's buffer */ - switch (arg) { - case TCIFLUSH: - /* no own input buffer to flush */ - break; - case TCIOFLUSH: - case TCOFLUSH: - flush_send_queue(cs); - break; - } - /* fall through */ - - default: - /* pass through to underlying serial device */ - rc = n_tty_ioctl_helper(tty, file, cmd, arg); - break; - } - cs_put(cs); - return rc; -} - -/* - * Called by the tty driver when a block of data has been received. - * Will not be re-entered while running but other ldisc functions - * may be called in parallel. - * Can be called from hard interrupt level as well as soft interrupt - * level or mainline. - * Parameters: - * tty tty structure - * buf buffer containing received characters - * cflags buffer containing error flags for received characters (ignored) - * count number of received characters - */ -static void -gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf, - char *cflags, int count) -{ - struct cardstate *cs = cs_get(tty); - unsigned tail, head, n; - struct inbuf_t *inbuf; - - if (!cs) - return; - inbuf = cs->inbuf; - if (!inbuf) { - dev_err(cs->dev, "%s: no inbuf\n", __func__); - cs_put(cs); - return; - } - - tail = inbuf->tail; - head = inbuf->head; - gig_dbg(DEBUG_INTR, "buffer state: %u -> %u, receive %u bytes", - head, tail, count); - - if (head <= tail) { - /* possible buffer wraparound */ - n = min_t(unsigned, count, RBUFSIZE - tail); - memcpy(inbuf->data + tail, buf, n); - tail = (tail + n) % RBUFSIZE; - buf += n; - count -= n; - } - - if (count > 0) { - /* tail < head and some data left */ - n = head - tail - 1; - if (count > n) { - dev_err(cs->dev, - "inbuf overflow, discarding %d bytes\n", - count - n); - count = n; - } - memcpy(inbuf->data + tail, buf, count); - tail += count; - } - - gig_dbg(DEBUG_INTR, "setting tail to %u", tail); - inbuf->tail = tail; - - /* Everything was received .. Push data into handler */ - gig_dbg(DEBUG_INTR, "%s-->BH", __func__); - gigaset_schedule_event(cs); - cs_put(cs); -} - -/* - * Called by the tty driver when there's room for more data to send. - */ -static void -gigaset_tty_wakeup(struct tty_struct *tty) -{ - struct cardstate *cs = cs_get(tty); - - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - if (!cs) - return; - tasklet_schedule(&cs->write_tasklet); - cs_put(cs); -} - -static struct tty_ldisc_ops gigaset_ldisc = { - .owner = THIS_MODULE, - .magic = TTY_LDISC_MAGIC, - .name = "ser_gigaset", - .open = gigaset_tty_open, - .close = gigaset_tty_close, - .hangup = gigaset_tty_hangup, - .ioctl = gigaset_tty_ioctl, - .receive_buf = gigaset_tty_receive, - .write_wakeup = gigaset_tty_wakeup, -}; - - -/* Initialization / Shutdown */ -/* ========================= */ - -static int __init ser_gigaset_init(void) -{ - int rc; - - gig_dbg(DEBUG_INIT, "%s", __func__); - rc = platform_driver_register(&device_driver); - if (rc != 0) { - pr_err("error %d registering platform driver\n", rc); - return rc; - } - - /* allocate memory for our driver state and initialize it */ - driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, - GIGASET_MODULENAME, GIGASET_DEVNAME, - &ops, THIS_MODULE); - if (!driver) { - rc = -ENOMEM; - goto error; - } - - rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc); - if (rc != 0) { - pr_err("error %d registering line discipline\n", rc); - goto error; - } - - return 0; - -error: - if (driver) { - gigaset_freedriver(driver); - driver = NULL; - } - platform_driver_unregister(&device_driver); - return rc; -} - -static void __exit ser_gigaset_exit(void) -{ - int rc; - - gig_dbg(DEBUG_INIT, "%s", __func__); - - if (driver) { - gigaset_freedriver(driver); - driver = NULL; - } - - rc = tty_unregister_ldisc(N_GIGASET_M101); - if (rc != 0) - pr_err("error %d unregistering line discipline\n", rc); - - platform_driver_unregister(&device_driver); -} - -module_init(ser_gigaset_init); -module_exit(ser_gigaset_exit); diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c deleted file mode 100644 index 1b9b43659bdf..000000000000 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ /dev/null @@ -1,946 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * USB driver for Gigaset 307x directly or using M105 Data. - * - * Copyright (c) 2001 by Stefan Eilers - * and Hansjoerg Lipp <hjlipp@web.de>. - * - * This driver was derived from the USB skeleton driver by - * Greg Kroah-Hartman <greg@kroah.com> - * - * ===================================================================== - * ===================================================================== - */ - -#include "gigaset.h" -#include <linux/usb.h> -#include <linux/module.h> -#include <linux/moduleparam.h> - -/* Version Information */ -#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Stefan Eilers" -#define DRIVER_DESC "USB Driver for Gigaset 307x using M105" - -/* Module parameters */ - -static int startmode = SM_ISDN; -static int cidmode = 1; - -module_param(startmode, int, S_IRUGO); -module_param(cidmode, int, S_IRUGO); -MODULE_PARM_DESC(startmode, "start in isdn4linux mode"); -MODULE_PARM_DESC(cidmode, "Call-ID mode"); - -#define GIGASET_MINORS 1 -#define GIGASET_MINOR 8 -#define GIGASET_MODULENAME "usb_gigaset" -#define GIGASET_DEVNAME "ttyGU" - -/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */ -#define IF_WRITEBUF 264 - -/* Values for the Gigaset M105 Data */ -#define USB_M105_VENDOR_ID 0x0681 -#define USB_M105_PRODUCT_ID 0x0009 - -/* table of devices that work with this driver */ -static const struct usb_device_id gigaset_table[] = { - { USB_DEVICE(USB_M105_VENDOR_ID, USB_M105_PRODUCT_ID) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, gigaset_table); - -/* - * Control requests (empty fields: 00) - * - * RT|RQ|VALUE|INDEX|LEN |DATA - * In: - * C1 08 01 - * Get flags (1 byte). Bits: 0=dtr,1=rts,3-7:? - * C1 0F ll ll - * Get device information/status (llll: 0x200 and 0x40 seen). - * Real size: I only saw MIN(llll,0x64). - * Contents: seems to be always the same... - * offset 0x00: Length of this structure (0x64) (len: 1,2,3 bytes) - * offset 0x3c: String (16 bit chars): "MCCI USB Serial V2.0" - * rest: ? - * Out: - * 41 11 - * Initialize/reset device ? - * 41 00 xx 00 - * ? (xx=00 or 01; 01 on start, 00 on close) - * 41 07 vv mm - * Set/clear flags vv=value, mm=mask (see RQ 08) - * 41 12 xx - * Used before the following configuration requests are issued - * (with xx=0x0f). I've seen other values<0xf, though. - * 41 01 xx xx - * Set baud rate. xxxx=ceil(0x384000/rate)=trunc(0x383fff/rate)+1. - * 41 03 ps bb - * Set byte size and parity. p: 0x20=even,0x10=odd,0x00=no parity - * [ 0x30: m, 0x40: s ] - * [s: 0: 1 stop bit; 1: 1.5; 2: 2] - * bb: bits/byte (seen 7 and 8) - * 41 13 -- -- -- -- 10 00 ww 00 00 00 xx 00 00 00 yy 00 00 00 zz 00 00 00 - * ?? - * Initialization: 01, 40, 00, 00 - * Open device: 00 40, 00, 00 - * yy and zz seem to be equal, either 0x00 or 0x0a - * (ww,xx) pairs seen: (00,00), (00,40), (01,40), (09,80), (19,80) - * 41 19 -- -- -- -- 06 00 00 00 00 xx 11 13 - * Used after every "configuration sequence" (RQ 12, RQs 01/03/13). - * xx is usually 0x00 but was 0x7e before starting data transfer - * in unimodem mode. So, this might be an array of characters that - * need special treatment ("commit all bufferd data"?), 11=^Q, 13=^S. - * - * Unimodem mode: use "modprobe ppp_async flag_time=0" as the device _needs_ two - * flags per packet. - */ - -/* functions called if a device of this driver is connected/disconnected */ -static int gigaset_probe(struct usb_interface *interface, - const struct usb_device_id *id); -static void gigaset_disconnect(struct usb_interface *interface); - -/* functions called before/after suspend */ -static int gigaset_suspend(struct usb_interface *intf, pm_message_t message); -static int gigaset_resume(struct usb_interface *intf); -static int gigaset_pre_reset(struct usb_interface *intf); - -static struct gigaset_driver *driver; - -/* usb specific object needed to register this driver with the usb subsystem */ -static struct usb_driver gigaset_usb_driver = { - .name = GIGASET_MODULENAME, - .probe = gigaset_probe, - .disconnect = gigaset_disconnect, - .id_table = gigaset_table, - .suspend = gigaset_suspend, - .resume = gigaset_resume, - .reset_resume = gigaset_resume, - .pre_reset = gigaset_pre_reset, - .post_reset = gigaset_resume, - .disable_hub_initiated_lpm = 1, -}; - -struct usb_cardstate { - struct usb_device *udev; /* usb device pointer */ - struct usb_interface *interface; /* interface for this device */ - int busy; /* bulk output in progress */ - - /* Output buffer */ - unsigned char *bulk_out_buffer; - int bulk_out_size; - int bulk_out_epnum; - struct urb *bulk_out_urb; - - /* Input buffer */ - unsigned char *rcvbuf; - int rcvbuf_size; - struct urb *read_urb; - - char bchars[6]; /* for request 0x19 */ -}; - -static inline unsigned tiocm_to_gigaset(unsigned state) -{ - return ((state & TIOCM_DTR) ? 1 : 0) | ((state & TIOCM_RTS) ? 2 : 0); -} - -static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, - unsigned new_state) -{ - struct usb_device *udev = cs->hw.usb->udev; - unsigned mask, val; - int r; - - mask = tiocm_to_gigaset(old_state ^ new_state); - val = tiocm_to_gigaset(new_state); - - gig_dbg(DEBUG_USBREQ, "set flags 0x%02x with mask 0x%02x", val, mask); - r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 7, 0x41, - (val & 0xff) | ((mask & 0xff) << 8), 0, - NULL, 0, 2000 /* timeout? */); - if (r < 0) - return r; - return 0; -} - -/* - * Set M105 configuration value - * using undocumented device commands reverse engineered from USB traces - * of the Siemens Windows driver - */ -static int set_value(struct cardstate *cs, u8 req, u16 val) -{ - struct usb_device *udev = cs->hw.usb->udev; - int r, r2; - - gig_dbg(DEBUG_USBREQ, "request %02x (%04x)", - (unsigned)req, (unsigned)val); - r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x12, 0x41, - 0xf /*?*/, 0, NULL, 0, 2000 /*?*/); - /* no idea what this does */ - if (r < 0) { - dev_err(&udev->dev, "error %d on request 0x12\n", -r); - return r; - } - - r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), req, 0x41, - val, 0, NULL, 0, 2000 /*?*/); - if (r < 0) - dev_err(&udev->dev, "error %d on request 0x%02x\n", - -r, (unsigned)req); - - r2 = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, - 0, 0, cs->hw.usb->bchars, 6, 2000 /*?*/); - if (r2 < 0) - dev_err(&udev->dev, "error %d on request 0x19\n", -r2); - - return r < 0 ? r : (r2 < 0 ? r2 : 0); -} - -/* - * set the baud rate on the internal serial adapter - * using the undocumented parameter setting command - */ -static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) -{ - u16 val; - u32 rate; - - cflag &= CBAUD; - - switch (cflag) { - case B300: rate = 300; break; - case B600: rate = 600; break; - case B1200: rate = 1200; break; - case B2400: rate = 2400; break; - case B4800: rate = 4800; break; - case B9600: rate = 9600; break; - case B19200: rate = 19200; break; - case B38400: rate = 38400; break; - case B57600: rate = 57600; break; - case B115200: rate = 115200; break; - default: - rate = 9600; - dev_err(cs->dev, "unsupported baudrate request 0x%x," - " using default of B9600\n", cflag); - } - - val = 0x383fff / rate + 1; - - return set_value(cs, 1, val); -} - -/* - * set the line format on the internal serial adapter - * using the undocumented parameter setting command - */ -static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) -{ - u16 val = 0; - - /* set the parity */ - if (cflag & PARENB) - val |= (cflag & PARODD) ? 0x10 : 0x20; - - /* set the number of data bits */ - switch (cflag & CSIZE) { - case CS5: - val |= 5 << 8; break; - case CS6: - val |= 6 << 8; break; - case CS7: - val |= 7 << 8; break; - case CS8: - val |= 8 << 8; break; - default: - dev_err(cs->dev, "CSIZE was not CS5-CS8, using default of 8\n"); - val |= 8 << 8; - break; - } - - /* set the number of stop bits */ - if (cflag & CSTOPB) { - if ((cflag & CSIZE) == CS5) - val |= 1; /* 1.5 stop bits */ - else - val |= 2; /* 2 stop bits */ - } - - return set_value(cs, 3, val); -} - - -/*============================================================================*/ -static int gigaset_init_bchannel(struct bc_state *bcs) -{ - /* nothing to do for M10x */ - gigaset_bchannel_up(bcs); - return 0; -} - -static int gigaset_close_bchannel(struct bc_state *bcs) -{ - /* nothing to do for M10x */ - gigaset_bchannel_down(bcs); - return 0; -} - -static int write_modem(struct cardstate *cs); -static int send_cb(struct cardstate *cs); - - -/* Write tasklet handler: Continue sending current skb, or send command, or - * start sending an skb from the send queue. - */ -static void gigaset_modem_fill(unsigned long data) -{ - struct cardstate *cs = (struct cardstate *) data; - struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ - - gig_dbg(DEBUG_OUTPUT, "modem_fill"); - - if (cs->hw.usb->busy) { - gig_dbg(DEBUG_OUTPUT, "modem_fill: busy"); - return; - } - -again: - if (!bcs->tx_skb) { /* no skb is being sent */ - if (cs->cmdbuf) { /* commands to send? */ - gig_dbg(DEBUG_OUTPUT, "modem_fill: cb"); - if (send_cb(cs) < 0) { - gig_dbg(DEBUG_OUTPUT, - "modem_fill: send_cb failed"); - goto again; /* no callback will be called! */ - } - return; - } - - /* skbs to send? */ - bcs->tx_skb = skb_dequeue(&bcs->squeue); - if (!bcs->tx_skb) - return; - - gig_dbg(DEBUG_INTR, "Dequeued skb (Adr: %lx)!", - (unsigned long) bcs->tx_skb); - } - - gig_dbg(DEBUG_OUTPUT, "modem_fill: tx_skb"); - if (write_modem(cs) < 0) { - gig_dbg(DEBUG_OUTPUT, "modem_fill: write_modem failed"); - goto again; /* no callback will be called! */ - } -} - -/* - * Interrupt Input URB completion routine - */ -static void gigaset_read_int_callback(struct urb *urb) -{ - struct cardstate *cs = urb->context; - struct inbuf_t *inbuf = cs->inbuf; - int status = urb->status; - int r; - unsigned numbytes; - unsigned char *src; - unsigned long flags; - - if (!status) { - numbytes = urb->actual_length; - - if (numbytes) { - src = cs->hw.usb->rcvbuf; - if (unlikely(*src)) - dev_warn(cs->dev, - "%s: There was no leading 0, but 0x%02x!\n", - __func__, (unsigned) *src); - ++src; /* skip leading 0x00 */ - --numbytes; - if (gigaset_fill_inbuf(inbuf, src, numbytes)) { - gig_dbg(DEBUG_INTR, "%s-->BH", __func__); - gigaset_schedule_event(inbuf->cs); - } - } else - gig_dbg(DEBUG_INTR, "Received zero block length"); - } else { - /* The urb might have been killed. */ - gig_dbg(DEBUG_ANY, "%s - nonzero status received: %d", - __func__, status); - if (status == -ENOENT || status == -ESHUTDOWN) - /* killed or endpoint shutdown: don't resubmit */ - return; - } - - /* resubmit URB */ - spin_lock_irqsave(&cs->lock, flags); - if (!cs->connected) { - spin_unlock_irqrestore(&cs->lock, flags); - pr_err("%s: disconnected\n", __func__); - return; - } - r = usb_submit_urb(urb, GFP_ATOMIC); - spin_unlock_irqrestore(&cs->lock, flags); - if (r) - dev_err(cs->dev, "error %d resubmitting URB\n", -r); -} - - -/* This callback routine is called when data was transmitted to the device. */ -static void gigaset_write_bulk_callback(struct urb *urb) -{ - struct cardstate *cs = urb->context; - int status = urb->status; - unsigned long flags; - - switch (status) { - case 0: /* normal completion */ - break; - case -ENOENT: /* killed */ - gig_dbg(DEBUG_ANY, "%s: killed", __func__); - cs->hw.usb->busy = 0; - return; - default: - dev_err(cs->dev, "bulk transfer failed (status %d)\n", - -status); - /* That's all we can do. Communication problems - are handled by timeouts or network protocols. */ - } - - spin_lock_irqsave(&cs->lock, flags); - if (!cs->connected) { - pr_err("%s: disconnected\n", __func__); - } else { - cs->hw.usb->busy = 0; - tasklet_schedule(&cs->write_tasklet); - } - spin_unlock_irqrestore(&cs->lock, flags); -} - -static int send_cb(struct cardstate *cs) -{ - struct cmdbuf_t *cb = cs->cmdbuf; - unsigned long flags; - int count; - int status = -ENOENT; - struct usb_cardstate *ucs = cs->hw.usb; - - do { - if (!cb->len) { - spin_lock_irqsave(&cs->cmdlock, flags); - cs->cmdbytes -= cs->curlen; - gig_dbg(DEBUG_OUTPUT, "send_cb: sent %u bytes, %u left", - cs->curlen, cs->cmdbytes); - cs->cmdbuf = cb->next; - if (cs->cmdbuf) { - cs->cmdbuf->prev = NULL; - cs->curlen = cs->cmdbuf->len; - } else { - cs->lastcmdbuf = NULL; - cs->curlen = 0; - } - spin_unlock_irqrestore(&cs->cmdlock, flags); - - if (cb->wake_tasklet) - tasklet_schedule(cb->wake_tasklet); - kfree(cb); - - cb = cs->cmdbuf; - } - - if (cb) { - count = min(cb->len, ucs->bulk_out_size); - gig_dbg(DEBUG_OUTPUT, "send_cb: send %d bytes", count); - - usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, - usb_sndbulkpipe(ucs->udev, - ucs->bulk_out_epnum), - cb->buf + cb->offset, count, - gigaset_write_bulk_callback, cs); - - cb->offset += count; - cb->len -= count; - ucs->busy = 1; - - spin_lock_irqsave(&cs->lock, flags); - status = cs->connected ? - usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : - -ENODEV; - spin_unlock_irqrestore(&cs->lock, flags); - - if (status) { - ucs->busy = 0; - dev_err(cs->dev, - "could not submit urb (error %d)\n", - -status); - cb->len = 0; /* skip urb => remove cb+wakeup - in next loop cycle */ - } - } - } while (cb && status); /* next command on error */ - - return status; -} - -/* Send command to device. */ -static int gigaset_write_cmd(struct cardstate *cs, struct cmdbuf_t *cb) -{ - unsigned long flags; - int len; - - gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? - DEBUG_TRANSCMD : DEBUG_LOCKCMD, - "CMD Transmit", cb->len, cb->buf); - - spin_lock_irqsave(&cs->cmdlock, flags); - cb->prev = cs->lastcmdbuf; - if (cs->lastcmdbuf) - cs->lastcmdbuf->next = cb; - else { - cs->cmdbuf = cb; - cs->curlen = cb->len; - } - cs->cmdbytes += cb->len; - cs->lastcmdbuf = cb; - spin_unlock_irqrestore(&cs->cmdlock, flags); - - spin_lock_irqsave(&cs->lock, flags); - len = cb->len; - if (cs->connected) - tasklet_schedule(&cs->write_tasklet); - spin_unlock_irqrestore(&cs->lock, flags); - return len; -} - -static int gigaset_write_room(struct cardstate *cs) -{ - unsigned bytes; - - bytes = cs->cmdbytes; - return bytes < IF_WRITEBUF ? IF_WRITEBUF - bytes : 0; -} - -static int gigaset_chars_in_buffer(struct cardstate *cs) -{ - return cs->cmdbytes; -} - -/* - * set the break characters on the internal serial adapter - * using undocumented device commands reverse engineered from USB traces - * of the Siemens Windows driver - */ -static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6]) -{ - struct usb_device *udev = cs->hw.usb->udev; - - gigaset_dbg_buffer(DEBUG_USBREQ, "brkchars", 6, buf); - memcpy(cs->hw.usb->bchars, buf, 6); - return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41, - 0, 0, &buf, 6, 2000); -} - -static void gigaset_freebcshw(struct bc_state *bcs) -{ - /* unused */ -} - -/* Initialize the b-channel structure */ -static int gigaset_initbcshw(struct bc_state *bcs) -{ - /* unused */ - bcs->hw.usb = NULL; - return 0; -} - -static void gigaset_reinitbcshw(struct bc_state *bcs) -{ - /* nothing to do for M10x */ -} - -static void gigaset_freecshw(struct cardstate *cs) -{ - tasklet_kill(&cs->write_tasklet); - kfree(cs->hw.usb); -} - -static int gigaset_initcshw(struct cardstate *cs) -{ - struct usb_cardstate *ucs; - - cs->hw.usb = ucs = - kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL); - if (!ucs) { - pr_err("out of memory\n"); - return -ENOMEM; - } - - ucs->bchars[0] = 0; - ucs->bchars[1] = 0; - ucs->bchars[2] = 0; - ucs->bchars[3] = 0; - ucs->bchars[4] = 0x11; - ucs->bchars[5] = 0x13; - ucs->bulk_out_buffer = NULL; - ucs->bulk_out_urb = NULL; - ucs->read_urb = NULL; - tasklet_init(&cs->write_tasklet, - gigaset_modem_fill, (unsigned long) cs); - - return 0; -} - -/* Send data from current skb to the device. */ -static int write_modem(struct cardstate *cs) -{ - int ret = 0; - int count; - struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ - struct usb_cardstate *ucs = cs->hw.usb; - unsigned long flags; - - gig_dbg(DEBUG_OUTPUT, "len: %d...", bcs->tx_skb->len); - - if (!bcs->tx_skb->len) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - return -EINVAL; - } - - /* Copy data to bulk out buffer and transmit data */ - count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); - skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count); - skb_pull(bcs->tx_skb, count); - ucs->busy = 1; - gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count); - - spin_lock_irqsave(&cs->lock, flags); - if (cs->connected) { - usb_fill_bulk_urb(ucs->bulk_out_urb, ucs->udev, - usb_sndbulkpipe(ucs->udev, - ucs->bulk_out_epnum), - ucs->bulk_out_buffer, count, - gigaset_write_bulk_callback, cs); - ret = usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC); - } else { - ret = -ENODEV; - } - spin_unlock_irqrestore(&cs->lock, flags); - - if (ret) { - dev_err(cs->dev, "could not submit urb (error %d)\n", -ret); - ucs->busy = 0; - } - - if (!bcs->tx_skb->len) { - /* skb sent completely */ - gigaset_skb_sent(bcs, bcs->tx_skb); - - gig_dbg(DEBUG_INTR, "kfree skb (Adr: %lx)!", - (unsigned long) bcs->tx_skb); - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - } - - return ret; -} - -static int gigaset_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - int retval; - struct usb_device *udev = interface_to_usbdev(interface); - struct usb_host_interface *hostif = interface->cur_altsetting; - struct cardstate *cs = NULL; - struct usb_cardstate *ucs = NULL; - struct usb_endpoint_descriptor *endpoint; - int buffer_size; - - gig_dbg(DEBUG_ANY, "%s: Check if device matches ...", __func__); - - /* See if the device offered us matches what we can accept */ - if ((le16_to_cpu(udev->descriptor.idVendor) != USB_M105_VENDOR_ID) || - (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) { - gig_dbg(DEBUG_ANY, "device ID (0x%x, 0x%x) not for me - skip", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - return -ENODEV; - } - if (hostif->desc.bInterfaceNumber != 0) { - gig_dbg(DEBUG_ANY, "interface %d not for me - skip", - hostif->desc.bInterfaceNumber); - return -ENODEV; - } - if (hostif->desc.bAlternateSetting != 0) { - dev_notice(&udev->dev, "unsupported altsetting %d - skip", - hostif->desc.bAlternateSetting); - return -ENODEV; - } - if (hostif->desc.bInterfaceClass != 255) { - dev_notice(&udev->dev, "unsupported interface class %d - skip", - hostif->desc.bInterfaceClass); - return -ENODEV; - } - - dev_info(&udev->dev, "%s: Device matched ... !\n", __func__); - - /* allocate memory for our device state and initialize it */ - cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); - if (!cs) - return -ENODEV; - ucs = cs->hw.usb; - - /* save off device structure ptrs for later use */ - usb_get_dev(udev); - ucs->udev = udev; - ucs->interface = interface; - cs->dev = &interface->dev; - - /* save address of controller structure */ - usb_set_intfdata(interface, cs); - - endpoint = &hostif->endpoint[0].desc; - - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - ucs->bulk_out_size = buffer_size; - ucs->bulk_out_epnum = usb_endpoint_num(endpoint); - ucs->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL); - if (!ucs->bulk_out_buffer) { - dev_err(cs->dev, "Couldn't allocate bulk_out_buffer\n"); - retval = -ENOMEM; - goto error; - } - - ucs->bulk_out_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ucs->bulk_out_urb) { - dev_err(cs->dev, "Couldn't allocate bulk_out_urb\n"); - retval = -ENOMEM; - goto error; - } - - endpoint = &hostif->endpoint[1].desc; - - ucs->busy = 0; - - ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ucs->read_urb) { - dev_err(cs->dev, "No free urbs available\n"); - retval = -ENOMEM; - goto error; - } - buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); - ucs->rcvbuf_size = buffer_size; - ucs->rcvbuf = kmalloc(buffer_size, GFP_KERNEL); - if (!ucs->rcvbuf) { - dev_err(cs->dev, "Couldn't allocate rcvbuf\n"); - retval = -ENOMEM; - goto error; - } - /* Fill the interrupt urb and send it to the core */ - usb_fill_int_urb(ucs->read_urb, udev, - usb_rcvintpipe(udev, usb_endpoint_num(endpoint)), - ucs->rcvbuf, buffer_size, - gigaset_read_int_callback, - cs, endpoint->bInterval); - - retval = usb_submit_urb(ucs->read_urb, GFP_KERNEL); - if (retval) { - dev_err(cs->dev, "Could not submit URB (error %d)\n", -retval); - goto error; - } - - /* tell common part that the device is ready */ - if (startmode == SM_LOCKED) - cs->mstate = MS_LOCKED; - - retval = gigaset_start(cs); - if (retval < 0) { - tasklet_kill(&cs->write_tasklet); - goto error; - } - return 0; - -error: - usb_kill_urb(ucs->read_urb); - kfree(ucs->bulk_out_buffer); - usb_free_urb(ucs->bulk_out_urb); - kfree(ucs->rcvbuf); - usb_free_urb(ucs->read_urb); - usb_set_intfdata(interface, NULL); - ucs->read_urb = ucs->bulk_out_urb = NULL; - ucs->rcvbuf = ucs->bulk_out_buffer = NULL; - usb_put_dev(ucs->udev); - ucs->udev = NULL; - ucs->interface = NULL; - gigaset_freecs(cs); - return retval; -} - -static void gigaset_disconnect(struct usb_interface *interface) -{ - struct cardstate *cs; - struct usb_cardstate *ucs; - - cs = usb_get_intfdata(interface); - ucs = cs->hw.usb; - - dev_info(cs->dev, "disconnecting Gigaset USB adapter\n"); - - usb_kill_urb(ucs->read_urb); - - gigaset_stop(cs); - - usb_set_intfdata(interface, NULL); - tasklet_kill(&cs->write_tasklet); - - usb_kill_urb(ucs->bulk_out_urb); - - kfree(ucs->bulk_out_buffer); - usb_free_urb(ucs->bulk_out_urb); - kfree(ucs->rcvbuf); - usb_free_urb(ucs->read_urb); - ucs->read_urb = ucs->bulk_out_urb = NULL; - ucs->rcvbuf = ucs->bulk_out_buffer = NULL; - - usb_put_dev(ucs->udev); - ucs->interface = NULL; - ucs->udev = NULL; - cs->dev = NULL; - gigaset_freecs(cs); -} - -/* gigaset_suspend - * This function is called before the USB connection is suspended or reset. - */ -static int gigaset_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct cardstate *cs = usb_get_intfdata(intf); - - /* stop activity */ - cs->connected = 0; /* prevent rescheduling */ - usb_kill_urb(cs->hw.usb->read_urb); - tasklet_kill(&cs->write_tasklet); - usb_kill_urb(cs->hw.usb->bulk_out_urb); - - gig_dbg(DEBUG_SUSPEND, "suspend complete"); - return 0; -} - -/* gigaset_resume - * This function is called after the USB connection has been resumed or reset. - */ -static int gigaset_resume(struct usb_interface *intf) -{ - struct cardstate *cs = usb_get_intfdata(intf); - int rc; - - /* resubmit interrupt URB */ - cs->connected = 1; - rc = usb_submit_urb(cs->hw.usb->read_urb, GFP_KERNEL); - if (rc) { - dev_err(cs->dev, "Could not submit read URB (error %d)\n", -rc); - return rc; - } - - gig_dbg(DEBUG_SUSPEND, "resume complete"); - return 0; -} - -/* gigaset_pre_reset - * This function is called before the USB connection is reset. - */ -static int gigaset_pre_reset(struct usb_interface *intf) -{ - /* same as suspend */ - return gigaset_suspend(intf, PMSG_ON); -} - -static const struct gigaset_ops ops = { - .write_cmd = gigaset_write_cmd, - .write_room = gigaset_write_room, - .chars_in_buffer = gigaset_chars_in_buffer, - .brkchars = gigaset_brkchars, - .init_bchannel = gigaset_init_bchannel, - .close_bchannel = gigaset_close_bchannel, - .initbcshw = gigaset_initbcshw, - .freebcshw = gigaset_freebcshw, - .reinitbcshw = gigaset_reinitbcshw, - .initcshw = gigaset_initcshw, - .freecshw = gigaset_freecshw, - .set_modem_ctrl = gigaset_set_modem_ctrl, - .baud_rate = gigaset_baud_rate, - .set_line_ctrl = gigaset_set_line_ctrl, - .send_skb = gigaset_m10x_send_skb, - .handle_input = gigaset_m10x_input, -}; - -/* - * This function is called while kernel-module is loaded - */ -static int __init usb_gigaset_init(void) -{ - int result; - - /* allocate memory for our driver state and initialize it */ - driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS, - GIGASET_MODULENAME, GIGASET_DEVNAME, - &ops, THIS_MODULE); - if (driver == NULL) { - result = -ENOMEM; - goto error; - } - - /* register this driver with the USB subsystem */ - result = usb_register(&gigaset_usb_driver); - if (result < 0) { - pr_err("error %d registering USB driver\n", -result); - goto error; - } - - pr_info(DRIVER_DESC "\n"); - return 0; - -error: - if (driver) - gigaset_freedriver(driver); - driver = NULL; - return result; -} - -/* - * This function is called while unloading the kernel-module - */ -static void __exit usb_gigaset_exit(void) -{ - int i; - - gigaset_blockdriver(driver); /* => probe will fail - * => no gigaset_start any more - */ - - /* stop all connected devices */ - for (i = 0; i < driver->minors; i++) - gigaset_shutdown(driver->cs + i); - - /* from now on, no isdn callback should be possible */ - - /* deregister this driver with the USB subsystem */ - usb_deregister(&gigaset_usb_driver); - /* this will call the disconnect-callback */ - /* from now on, no disconnect/probe callback should be running */ - - gigaset_freedriver(driver); - driver = NULL; -} - - -module_init(usb_gigaset_init); -module_exit(usb_gigaset_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); - -MODULE_LICENSE("GPL"); diff --git a/drivers/isdn/hardware/Kconfig b/drivers/isdn/hardware/Kconfig deleted file mode 100644 index 0d609b5fcf01..000000000000 --- a/drivers/isdn/hardware/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# ISDN hardware drivers -# -comment "CAPI hardware drivers" - -source "drivers/isdn/hardware/avm/Kconfig" - diff --git a/drivers/isdn/hardware/Makefile b/drivers/isdn/hardware/Makefile index a43760a0a4f5..96f9eb2e46ba 100644 --- a/drivers/isdn/hardware/Makefile +++ b/drivers/isdn/hardware/Makefile @@ -3,5 +3,4 @@ # Object files in subdirectories -obj-$(CONFIG_CAPI_AVM) += avm/ obj-$(CONFIG_MISDN) += mISDN/ diff --git a/drivers/isdn/hardware/avm/Kconfig b/drivers/isdn/hardware/avm/Kconfig deleted file mode 100644 index 81483db067bb..000000000000 --- a/drivers/isdn/hardware/avm/Kconfig +++ /dev/null @@ -1,65 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# ISDN AVM drivers -# - -menuconfig CAPI_AVM - bool "Active AVM cards" - help - Enable support for AVM active ISDN cards. - -if CAPI_AVM - -config ISDN_DRV_AVMB1_B1ISA - tristate "AVM B1 ISA support" - depends on ISA - help - Enable support for the ISA version of the AVM B1 card. - -config ISDN_DRV_AVMB1_B1PCI - tristate "AVM B1 PCI support" - depends on PCI - help - Enable support for the PCI version of the AVM B1 card. - -config ISDN_DRV_AVMB1_B1PCIV4 - bool "AVM B1 PCI V4 support" - depends on ISDN_DRV_AVMB1_B1PCI - help - Enable support for the V4 version of AVM B1 PCI card. - -config ISDN_DRV_AVMB1_T1ISA - tristate "AVM T1/T1-B ISA support" - depends on ISA - help - Enable support for the AVM T1 T1B card. - Note: This is a PRI card and handle 30 B-channels. - -config ISDN_DRV_AVMB1_B1PCMCIA - tristate "AVM B1/M1/M2 PCMCIA support" - depends on PCMCIA - help - Enable support for the PCMCIA version of the AVM B1 card. - -config ISDN_DRV_AVMB1_AVM_CS - tristate "AVM B1/M1/M2 PCMCIA cs module" - depends on ISDN_DRV_AVMB1_B1PCMCIA - help - Enable the PCMCIA client driver for the AVM B1/M1/M2 - PCMCIA cards. - -config ISDN_DRV_AVMB1_T1PCI - tristate "AVM T1/T1-B PCI support" - depends on PCI - help - Enable support for the AVM T1 T1B card. - Note: This is a PRI card and handle 30 B-channels. - -config ISDN_DRV_AVMB1_C4 - tristate "AVM C4/C2 support" - depends on PCI - help - Enable support for the AVM C4/C2 PCI cards. - These cards handle 4/2 BRI ISDN lines (8/4 channels). - -endif # CAPI_AVM diff --git a/drivers/isdn/hardware/avm/Makefile b/drivers/isdn/hardware/avm/Makefile deleted file mode 100644 index 3830a0573fcc..000000000000 --- a/drivers/isdn/hardware/avm/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Makefile for the AVM ISDN device drivers - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN_DRV_AVMB1_B1ISA) += b1isa.o b1.o -obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCI) += b1pci.o b1.o b1dma.o -obj-$(CONFIG_ISDN_DRV_AVMB1_B1PCMCIA) += b1pcmcia.o b1.o -obj-$(CONFIG_ISDN_DRV_AVMB1_AVM_CS) += avm_cs.o -obj-$(CONFIG_ISDN_DRV_AVMB1_T1ISA) += t1isa.o b1.o -obj-$(CONFIG_ISDN_DRV_AVMB1_T1PCI) += t1pci.o b1.o b1dma.o -obj-$(CONFIG_ISDN_DRV_AVMB1_C4) += c4.o b1.o diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c deleted file mode 100644 index 62b8030ee331..000000000000 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ /dev/null @@ -1,166 +0,0 @@ -/* $Id: avm_cs.c,v 1.4.6.3 2001/09/23 22:24:33 kai Exp $ - * - * A PCMCIA client driver for AVM B1/M1/M2 - * - * Copyright 1999 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/string.h> -#include <linux/tty.h> -#include <linux/serial.h> -#include <linux/major.h> -#include <asm/io.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/ciscode.h> -#include <pcmcia/ds.h> -#include <pcmcia/cisreg.h> - -#include <linux/skbuff.h> -#include <linux/capi.h> -#include <linux/b1lli.h> -#include <linux/b1pcmcia.h> - -/*====================================================================*/ - -MODULE_DESCRIPTION("CAPI4Linux: PCMCIA client driver for AVM B1/M1/M2"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/*====================================================================*/ - -static int avmcs_config(struct pcmcia_device *link); -static void avmcs_release(struct pcmcia_device *link); -static void avmcs_detach(struct pcmcia_device *p_dev); - -static int avmcs_probe(struct pcmcia_device *p_dev) -{ - /* General socket configuration */ - p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - p_dev->config_index = 1; - p_dev->config_regs = PRESENT_OPTION; - - return avmcs_config(p_dev); -} /* avmcs_attach */ - - -static void avmcs_detach(struct pcmcia_device *link) -{ - avmcs_release(link); -} /* avmcs_detach */ - -static int avmcs_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - - return pcmcia_request_io(p_dev); -} - -static int avmcs_config(struct pcmcia_device *link) -{ - int i = -1; - char devname[128]; - int cardtype; - int (*addcard)(unsigned int port, unsigned irq); - - devname[0] = 0; - if (link->prod_id[1]) - strlcpy(devname, link->prod_id[1], sizeof(devname)); - - /* - * find IO port - */ - if (pcmcia_loop_config(link, avmcs_configcheck, NULL)) - return -ENODEV; - - do { - if (!link->irq) { - /* undo */ - pcmcia_disable_device(link); - break; - } - - /* - * configure the PCMCIA socket - */ - i = pcmcia_enable_device(link); - if (i != 0) { - pcmcia_disable_device(link); - break; - } - - } while (0); - - if (devname[0]) { - char *s = strrchr(devname, ' '); - if (!s) - s = devname; - else s++; - if (strcmp("M1", s) == 0) { - cardtype = AVM_CARDTYPE_M1; - } else if (strcmp("M2", s) == 0) { - cardtype = AVM_CARDTYPE_M2; - } else { - cardtype = AVM_CARDTYPE_B1; - } - } else - cardtype = AVM_CARDTYPE_B1; - - /* If any step failed, release any partially configured state */ - if (i != 0) { - avmcs_release(link); - return -ENODEV; - } - - - switch (cardtype) { - case AVM_CARDTYPE_M1: addcard = b1pcmcia_addcard_m1; break; - case AVM_CARDTYPE_M2: addcard = b1pcmcia_addcard_m2; break; - default: - case AVM_CARDTYPE_B1: addcard = b1pcmcia_addcard_b1; break; - } - if ((i = (*addcard)(link->resource[0]->start, link->irq)) < 0) { - dev_err(&link->dev, - "avm_cs: failed to add AVM-Controller at i/o %#x, irq %d\n", - (unsigned int) link->resource[0]->start, link->irq); - avmcs_release(link); - return -ENODEV; - } - return 0; - -} /* avmcs_config */ - - -static void avmcs_release(struct pcmcia_device *link) -{ - b1pcmcia_delcard(link->resource[0]->start, link->irq); - pcmcia_disable_device(link); -} /* avmcs_release */ - - -static const struct pcmcia_device_id avmcs_ids[] = { - PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335), - PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430), - PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, avmcs_ids); - -static struct pcmcia_driver avmcs_driver = { - .owner = THIS_MODULE, - .name = "avm_cs", - .probe = avmcs_probe, - .remove = avmcs_detach, - .id_table = avmcs_ids, -}; -module_pcmcia_driver(avmcs_driver); diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h deleted file mode 100644 index cdfa89c71997..000000000000 --- a/drivers/isdn/hardware/avm/avmcard.h +++ /dev/null @@ -1,581 +0,0 @@ -/* $Id: avmcard.h,v 1.1.4.1.2.1 2001/12/21 15:00:17 kai Exp $ - * - * Copyright 1999 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef _AVMCARD_H_ -#define _AVMCARD_H_ - -#include <linux/spinlock.h> -#include <linux/list.h> -#include <linux/interrupt.h> - -#define AVMB1_PORTLEN 0x1f -#define AVM_MAXVERSION 8 -#define AVM_NCCI_PER_CHANNEL 4 - -/* - * Versions - */ - -#define VER_DRIVER 0 -#define VER_CARDTYPE 1 -#define VER_HWID 2 -#define VER_SERIAL 3 -#define VER_OPTION 4 -#define VER_PROTO 5 -#define VER_PROFILE 6 -#define VER_CAPI 7 - -enum avmcardtype { - avm_b1isa, - avm_b1pci, - avm_b1pcmcia, - avm_m1, - avm_m2, - avm_t1isa, - avm_t1pci, - avm_c4, - avm_c2 -}; - -typedef struct avmcard_dmabuf { - long size; - u8 *dmabuf; - dma_addr_t dmaaddr; -} avmcard_dmabuf; - -typedef struct avmcard_dmainfo { - u32 recvlen; - avmcard_dmabuf recvbuf; - - avmcard_dmabuf sendbuf; - struct sk_buff_head send_queue; - - struct pci_dev *pcidev; -} avmcard_dmainfo; - -typedef struct avmctrl_info { - char cardname[32]; - - int versionlen; - char versionbuf[1024]; - char *version[AVM_MAXVERSION]; - - char infobuf[128]; /* for function procinfo */ - - struct avmcard *card; - struct capi_ctr capi_ctrl; - - struct list_head ncci_head; -} avmctrl_info; - -typedef struct avmcard { - char name[32]; - - spinlock_t lock; - unsigned int port; - unsigned irq; - unsigned long membase; - enum avmcardtype cardtype; - unsigned char revision; - unsigned char class; - int cardnr; /* for t1isa */ - - char msgbuf[128]; /* capimsg msg part */ - char databuf[2048]; /* capimsg data part */ - - void __iomem *mbase; - volatile u32 csr; - avmcard_dmainfo *dma; - - struct avmctrl_info *ctrlinfo; - - u_int nr_controllers; - u_int nlogcontr; - struct list_head list; -} avmcard; - -extern int b1_irq_table[16]; - -/* - * LLI Messages to the ISDN-ControllerISDN Controller - */ - -#define SEND_POLL 0x72 /* - * after load <- RECEIVE_POLL - */ -#define SEND_INIT 0x11 /* - * first message <- RECEIVE_INIT - * int32 NumApplications int32 - * NumNCCIs int32 BoardNumber - */ -#define SEND_REGISTER 0x12 /* - * register an application int32 - * ApplIDId int32 NumMessages - * int32 NumB3Connections int32 - * NumB3Blocks int32 B3Size - * - * AnzB3Connection != 0 && - * AnzB3Blocks >= 1 && B3Size >= 1 - */ -#define SEND_RELEASE 0x14 /* - * deregister an application int32 - * ApplID - */ -#define SEND_MESSAGE 0x15 /* - * send capi-message int32 length - * capi-data ... - */ -#define SEND_DATA_B3_REQ 0x13 /* - * send capi-data-message int32 - * MsgLength capi-data ... int32 - * B3Length data .... - */ - -#define SEND_CONFIG 0x21 /* - */ - -#define SEND_POLLACK 0x73 /* T1 Watchdog */ - -/* - * LLI Messages from the ISDN-ControllerISDN Controller - */ - -#define RECEIVE_POLL 0x32 /* - * <- after SEND_POLL - */ -#define RECEIVE_INIT 0x27 /* - * <- after SEND_INIT int32 length - * byte total length b1struct board - * driver revision b1struct card - * type b1struct reserved b1struct - * serial number b1struct driver - * capability b1struct d-channel - * protocol b1struct CAPI-2.0 - * profile b1struct capi version - */ -#define RECEIVE_MESSAGE 0x21 /* - * <- after SEND_MESSAGE int32 - * AppllID int32 Length capi-data - * .... - */ -#define RECEIVE_DATA_B3_IND 0x22 /* - * received data int32 AppllID - * int32 Length capi-data ... - * int32 B3Length data ... - */ -#define RECEIVE_START 0x23 /* - * Handshake - */ -#define RECEIVE_STOP 0x24 /* - * Handshake - */ -#define RECEIVE_NEW_NCCI 0x25 /* - * int32 AppllID int32 NCCI int32 - * WindowSize - */ -#define RECEIVE_FREE_NCCI 0x26 /* - * int32 AppllID int32 NCCI - */ -#define RECEIVE_RELEASE 0x26 /* - * int32 AppllID int32 0xffffffff - */ -#define RECEIVE_TASK_READY 0x31 /* - * int32 tasknr - * int32 Length Taskname ... - */ -#define RECEIVE_DEBUGMSG 0x71 /* - * int32 Length message - * - */ -#define RECEIVE_POLLDWORD 0x75 /* t1pci in dword mode */ - -#define WRITE_REGISTER 0x00 -#define READ_REGISTER 0x01 - -/* - * port offsets - */ - -#define B1_READ 0x00 -#define B1_WRITE 0x01 -#define B1_INSTAT 0x02 -#define B1_OUTSTAT 0x03 -#define B1_ANALYSE 0x04 -#define B1_REVISION 0x05 -#define B1_RESET 0x10 - - -#define B1_STAT0(cardtype) ((cardtype) == avm_m1 ? 0x81200000l : 0x80A00000l) -#define B1_STAT1(cardtype) (0x80E00000l) - -/* ---------------------------------------------------------------- */ - -static inline unsigned char b1outp(unsigned int base, - unsigned short offset, - unsigned char value) -{ - outb(value, base + offset); - return inb(base + B1_ANALYSE); -} - - -static inline int b1_rx_full(unsigned int base) -{ - return inb(base + B1_INSTAT) & 0x1; -} - -static inline unsigned char b1_get_byte(unsigned int base) -{ - unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ - while (!b1_rx_full(base) && time_before(jiffies, stop)); - if (b1_rx_full(base)) - return inb(base + B1_READ); - printk(KERN_CRIT "b1lli(0x%x): rx not full after 1 second\n", base); - return 0; -} - -static inline unsigned int b1_get_word(unsigned int base) -{ - unsigned int val = 0; - val |= b1_get_byte(base); - val |= (b1_get_byte(base) << 8); - val |= (b1_get_byte(base) << 16); - val |= (b1_get_byte(base) << 24); - return val; -} - -static inline int b1_tx_empty(unsigned int base) -{ - return inb(base + B1_OUTSTAT) & 0x1; -} - -static inline void b1_put_byte(unsigned int base, unsigned char val) -{ - while (!b1_tx_empty(base)); - b1outp(base, B1_WRITE, val); -} - -static inline int b1_save_put_byte(unsigned int base, unsigned char val) -{ - unsigned long stop = jiffies + 2 * HZ; - while (!b1_tx_empty(base) && time_before(jiffies, stop)); - if (!b1_tx_empty(base)) return -1; - b1outp(base, B1_WRITE, val); - return 0; -} - -static inline void b1_put_word(unsigned int base, unsigned int val) -{ - b1_put_byte(base, val & 0xff); - b1_put_byte(base, (val >> 8) & 0xff); - b1_put_byte(base, (val >> 16) & 0xff); - b1_put_byte(base, (val >> 24) & 0xff); -} - -static inline unsigned int b1_get_slice(unsigned int base, - unsigned char *dp) -{ - unsigned int len, i; - - len = i = b1_get_word(base); - while (i-- > 0) *dp++ = b1_get_byte(base); - return len; -} - -static inline void b1_put_slice(unsigned int base, - unsigned char *dp, unsigned int len) -{ - unsigned i = len; - b1_put_word(base, i); - while (i-- > 0) - b1_put_byte(base, *dp++); -} - -static void b1_wr_reg(unsigned int base, - unsigned int reg, - unsigned int value) -{ - b1_put_byte(base, WRITE_REGISTER); - b1_put_word(base, reg); - b1_put_word(base, value); -} - -static inline unsigned int b1_rd_reg(unsigned int base, - unsigned int reg) -{ - b1_put_byte(base, READ_REGISTER); - b1_put_word(base, reg); - return b1_get_word(base); - -} - -static inline void b1_reset(unsigned int base) -{ - b1outp(base, B1_RESET, 0); - mdelay(55 * 2); /* 2 TIC's */ - - b1outp(base, B1_RESET, 1); - mdelay(55 * 2); /* 2 TIC's */ - - b1outp(base, B1_RESET, 0); - mdelay(55 * 2); /* 2 TIC's */ -} - -static inline unsigned char b1_disable_irq(unsigned int base) -{ - return b1outp(base, B1_INSTAT, 0x00); -} - -/* ---------------------------------------------------------------- */ - -static inline void b1_set_test_bit(unsigned int base, - enum avmcardtype cardtype, - int onoff) -{ - b1_wr_reg(base, B1_STAT0(cardtype), onoff ? 0x21 : 0x20); -} - -static inline int b1_get_test_bit(unsigned int base, - enum avmcardtype cardtype) -{ - return (b1_rd_reg(base, B1_STAT0(cardtype)) & 0x01) != 0; -} - -/* ---------------------------------------------------------------- */ - -#define T1_FASTLINK 0x00 -#define T1_SLOWLINK 0x08 - -#define T1_READ B1_READ -#define T1_WRITE B1_WRITE -#define T1_INSTAT B1_INSTAT -#define T1_OUTSTAT B1_OUTSTAT -#define T1_IRQENABLE 0x05 -#define T1_FIFOSTAT 0x06 -#define T1_RESETLINK 0x10 -#define T1_ANALYSE 0x11 -#define T1_IRQMASTER 0x12 -#define T1_IDENT 0x17 -#define T1_RESETBOARD 0x1f - -#define T1F_IREADY 0x01 -#define T1F_IHALF 0x02 -#define T1F_IFULL 0x04 -#define T1F_IEMPTY 0x08 -#define T1F_IFLAGS 0xF0 - -#define T1F_OREADY 0x10 -#define T1F_OHALF 0x20 -#define T1F_OEMPTY 0x40 -#define T1F_OFULL 0x80 -#define T1F_OFLAGS 0xF0 - -/* there are HEMA cards with 1k and 4k FIFO out */ -#define FIFO_OUTBSIZE 256 -#define FIFO_INPBSIZE 512 - -#define HEMA_VERSION_ID 0 -#define HEMA_PAL_ID 0 - -static inline void t1outp(unsigned int base, - unsigned short offset, - unsigned char value) -{ - outb(value, base + offset); -} - -static inline unsigned char t1inp(unsigned int base, - unsigned short offset) -{ - return inb(base + offset); -} - -static inline int t1_isfastlink(unsigned int base) -{ - return (inb(base + T1_IDENT) & ~0x82) == 1; -} - -static inline unsigned char t1_fifostatus(unsigned int base) -{ - return inb(base + T1_FIFOSTAT); -} - -static inline unsigned int t1_get_slice(unsigned int base, - unsigned char *dp) -{ - unsigned int len, i; -#ifdef FASTLINK_DEBUG - unsigned wcnt = 0, bcnt = 0; -#endif - - len = i = b1_get_word(base); - if (t1_isfastlink(base)) { - int status; - while (i > 0) { - status = t1_fifostatus(base) & (T1F_IREADY | T1F_IHALF); - if (i >= FIFO_INPBSIZE) status |= T1F_IFULL; - - switch (status) { - case T1F_IREADY | T1F_IHALF | T1F_IFULL: - insb(base + B1_READ, dp, FIFO_INPBSIZE); - dp += FIFO_INPBSIZE; - i -= FIFO_INPBSIZE; -#ifdef FASTLINK_DEBUG - wcnt += FIFO_INPBSIZE; -#endif - break; - case T1F_IREADY | T1F_IHALF: - insb(base + B1_READ, dp, i); -#ifdef FASTLINK_DEBUG - wcnt += i; -#endif - dp += i; - i = 0; - break; - default: - *dp++ = b1_get_byte(base); - i--; -#ifdef FASTLINK_DEBUG - bcnt++; -#endif - break; - } - } -#ifdef FASTLINK_DEBUG - if (wcnt) - printk(KERN_DEBUG "b1lli(0x%x): get_slice l=%d w=%d b=%d\n", - base, len, wcnt, bcnt); -#endif - } else { - while (i-- > 0) - *dp++ = b1_get_byte(base); - } - return len; -} - -static inline void t1_put_slice(unsigned int base, - unsigned char *dp, unsigned int len) -{ - unsigned i = len; - b1_put_word(base, i); - if (t1_isfastlink(base)) { - int status; - while (i > 0) { - status = t1_fifostatus(base) & (T1F_OREADY | T1F_OHALF); - if (i >= FIFO_OUTBSIZE) status |= T1F_OEMPTY; - switch (status) { - case T1F_OREADY | T1F_OHALF | T1F_OEMPTY: - outsb(base + B1_WRITE, dp, FIFO_OUTBSIZE); - dp += FIFO_OUTBSIZE; - i -= FIFO_OUTBSIZE; - break; - case T1F_OREADY | T1F_OHALF: - outsb(base + B1_WRITE, dp, i); - dp += i; - i = 0; - break; - default: - b1_put_byte(base, *dp++); - i--; - break; - } - } - } else { - while (i-- > 0) - b1_put_byte(base, *dp++); - } -} - -static inline void t1_disable_irq(unsigned int base) -{ - t1outp(base, T1_IRQMASTER, 0x00); -} - -static inline void t1_reset(unsigned int base) -{ - /* reset T1 Controller */ - b1_reset(base); - /* disable irq on HEMA */ - t1outp(base, B1_INSTAT, 0x00); - t1outp(base, B1_OUTSTAT, 0x00); - t1outp(base, T1_IRQMASTER, 0x00); - /* reset HEMA board configuration */ - t1outp(base, T1_RESETBOARD, 0xf); -} - -static inline void b1_setinterrupt(unsigned int base, unsigned irq, - enum avmcardtype cardtype) -{ - switch (cardtype) { - case avm_t1isa: - t1outp(base, B1_INSTAT, 0x00); - t1outp(base, B1_INSTAT, 0x02); - t1outp(base, T1_IRQMASTER, 0x08); - break; - case avm_b1isa: - b1outp(base, B1_INSTAT, 0x00); - b1outp(base, B1_RESET, b1_irq_table[irq]); - b1outp(base, B1_INSTAT, 0x02); - break; - default: - case avm_m1: - case avm_m2: - case avm_b1pci: - b1outp(base, B1_INSTAT, 0x00); - b1outp(base, B1_RESET, 0xf0); - b1outp(base, B1_INSTAT, 0x02); - break; - case avm_c4: - case avm_t1pci: - b1outp(base, B1_RESET, 0xf0); - break; - } -} - -/* b1.c */ -avmcard *b1_alloc_card(int nr_controllers); -void b1_free_card(avmcard *card); -int b1_detect(unsigned int base, enum avmcardtype cardtype); -void b1_getrevision(avmcard *card); -int b1_load_t4file(avmcard *card, capiloaddatapart *t4file); -int b1_load_config(avmcard *card, capiloaddatapart *config); -int b1_loaded(avmcard *card); - -int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data); -void b1_reset_ctr(struct capi_ctr *ctrl); -void b1_register_appl(struct capi_ctr *ctrl, u16 appl, - capi_register_params *rp); -void b1_release_appl(struct capi_ctr *ctrl, u16 appl); -u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); -void b1_parse_version(avmctrl_info *card); -irqreturn_t b1_interrupt(int interrupt, void *devptr); - -int b1_proc_show(struct seq_file *m, void *v); - -avmcard_dmainfo *avmcard_dma_alloc(char *name, struct pci_dev *, - long rsize, long ssize); -void avmcard_dma_free(avmcard_dmainfo *); - -/* b1dma.c */ -int b1pciv4_detect(avmcard *card); -int t1pci_detect(avmcard *card); -void b1dma_reset(avmcard *card); -irqreturn_t b1dma_interrupt(int interrupt, void *devptr); - -int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data); -void b1dma_reset_ctr(struct capi_ctr *ctrl); -void b1dma_remove_ctr(struct capi_ctr *ctrl); -void b1dma_register_appl(struct capi_ctr *ctrl, - u16 appl, - capi_register_params *rp); -void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl); -u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); -int b1dma_proc_show(struct seq_file *m, void *v); - -#endif /* _AVMCARD_H_ */ diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c deleted file mode 100644 index 40ca1e8fa09f..000000000000 --- a/drivers/isdn/hardware/avm/b1.c +++ /dev/null @@ -1,804 +0,0 @@ -/* $Id: b1.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ - * - * Common module for AVM B1 cards. - * - * Copyright 1999 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/capi.h> -#include <linux/kernelcapi.h> -#include <linux/slab.h> -#include <asm/io.h> -#include <linux/init.h> -#include <linux/uaccess.h> -#include <linux/netdevice.h> -#include <linux/isdn/capilli.h> -#include "avmcard.h" -#include <linux/isdn/capicmd.h> -#include <linux/isdn/capiutil.h> - -static char *revision = "$Revision: 1.1.2.2 $"; - -/* ------------------------------------------------------------- */ - -MODULE_DESCRIPTION("CAPI4Linux: Common support for active AVM cards"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------- */ - -int b1_irq_table[16] = -{0, - 0, - 0, - 192, /* irq 3 */ - 32, /* irq 4 */ - 160, /* irq 5 */ - 96, /* irq 6 */ - 224, /* irq 7 */ - 0, - 64, /* irq 9 */ - 80, /* irq 10 */ - 208, /* irq 11 */ - 48, /* irq 12 */ - 0, - 0, - 112, /* irq 15 */ -}; - -/* ------------------------------------------------------------- */ - -avmcard *b1_alloc_card(int nr_controllers) -{ - avmcard *card; - avmctrl_info *cinfo; - int i; - - card = kzalloc(sizeof(*card), GFP_KERNEL); - if (!card) - return NULL; - - cinfo = kcalloc(nr_controllers, sizeof(*cinfo), GFP_KERNEL); - if (!cinfo) { - kfree(card); - return NULL; - } - - card->ctrlinfo = cinfo; - for (i = 0; i < nr_controllers; i++) { - INIT_LIST_HEAD(&cinfo[i].ncci_head); - cinfo[i].card = card; - } - spin_lock_init(&card->lock); - card->nr_controllers = nr_controllers; - - return card; -} - -/* ------------------------------------------------------------- */ - -void b1_free_card(avmcard *card) -{ - kfree(card->ctrlinfo); - kfree(card); -} - -/* ------------------------------------------------------------- */ - -int b1_detect(unsigned int base, enum avmcardtype cardtype) -{ - int onoff, i; - - /* - * Statusregister 0000 00xx - */ - if ((inb(base + B1_INSTAT) & 0xfc) - || (inb(base + B1_OUTSTAT) & 0xfc)) - return 1; - /* - * Statusregister 0000 001x - */ - b1outp(base, B1_INSTAT, 0x2); /* enable irq */ - /* b1outp(base, B1_OUTSTAT, 0x2); */ - if ((inb(base + B1_INSTAT) & 0xfe) != 0x2 - /* || (inb(base + B1_OUTSTAT) & 0xfe) != 0x2 */) - return 2; - /* - * Statusregister 0000 000x - */ - b1outp(base, B1_INSTAT, 0x0); /* disable irq */ - b1outp(base, B1_OUTSTAT, 0x0); - if ((inb(base + B1_INSTAT) & 0xfe) - || (inb(base + B1_OUTSTAT) & 0xfe)) - return 3; - - for (onoff = !0, i = 0; i < 10; i++) { - b1_set_test_bit(base, cardtype, onoff); - if (b1_get_test_bit(base, cardtype) != onoff) - return 4; - onoff = !onoff; - } - - if (cardtype == avm_m1) - return 0; - - if ((b1_rd_reg(base, B1_STAT1(cardtype)) & 0x0f) != 0x01) - return 5; - - return 0; -} - -void b1_getrevision(avmcard *card) -{ - card->class = inb(card->port + B1_ANALYSE); - card->revision = inb(card->port + B1_REVISION); -} - -#define FWBUF_SIZE 256 -int b1_load_t4file(avmcard *card, capiloaddatapart *t4file) -{ - unsigned char buf[FWBUF_SIZE]; - unsigned char *dp; - int i, left; - unsigned int base = card->port; - - dp = t4file->data; - left = t4file->len; - while (left > FWBUF_SIZE) { - if (t4file->user) { - if (copy_from_user(buf, dp, FWBUF_SIZE)) - return -EFAULT; - } else { - memcpy(buf, dp, FWBUF_SIZE); - } - for (i = 0; i < FWBUF_SIZE; i++) - if (b1_save_put_byte(base, buf[i]) < 0) { - printk(KERN_ERR "%s: corrupted firmware file ?\n", - card->name); - return -EIO; - } - left -= FWBUF_SIZE; - dp += FWBUF_SIZE; - } - if (left) { - if (t4file->user) { - if (copy_from_user(buf, dp, left)) - return -EFAULT; - } else { - memcpy(buf, dp, left); - } - for (i = 0; i < left; i++) - if (b1_save_put_byte(base, buf[i]) < 0) { - printk(KERN_ERR "%s: corrupted firmware file ?\n", - card->name); - return -EIO; - } - } - return 0; -} - -int b1_load_config(avmcard *card, capiloaddatapart *config) -{ - unsigned char buf[FWBUF_SIZE]; - unsigned char *dp; - unsigned int base = card->port; - int i, j, left; - - dp = config->data; - left = config->len; - if (left) { - b1_put_byte(base, SEND_CONFIG); - b1_put_word(base, 1); - b1_put_byte(base, SEND_CONFIG); - b1_put_word(base, left); - } - while (left > FWBUF_SIZE) { - if (config->user) { - if (copy_from_user(buf, dp, FWBUF_SIZE)) - return -EFAULT; - } else { - memcpy(buf, dp, FWBUF_SIZE); - } - for (i = 0; i < FWBUF_SIZE; ) { - b1_put_byte(base, SEND_CONFIG); - for (j = 0; j < 4; j++) { - b1_put_byte(base, buf[i++]); - } - } - left -= FWBUF_SIZE; - dp += FWBUF_SIZE; - } - if (left) { - if (config->user) { - if (copy_from_user(buf, dp, left)) - return -EFAULT; - } else { - memcpy(buf, dp, left); - } - for (i = 0; i < left; ) { - b1_put_byte(base, SEND_CONFIG); - for (j = 0; j < 4; j++) { - if (i < left) - b1_put_byte(base, buf[i++]); - else - b1_put_byte(base, 0); - } - } - } - return 0; -} - -int b1_loaded(avmcard *card) -{ - unsigned int base = card->port; - unsigned long stop; - unsigned char ans; - unsigned long tout = 2; - - for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { - if (b1_tx_empty(base)) - break; - } - if (!b1_tx_empty(base)) { - printk(KERN_ERR "%s: b1_loaded: tx err, corrupted t4 file ?\n", - card->name); - return 0; - } - b1_put_byte(base, SEND_POLL); - for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { - if (b1_rx_full(base)) { - if ((ans = b1_get_byte(base)) == RECEIVE_POLL) { - return 1; - } - printk(KERN_ERR "%s: b1_loaded: got 0x%x, firmware not running\n", - card->name, ans); - return 0; - } - } - printk(KERN_ERR "%s: b1_loaded: firmware not running\n", card->name); - return 0; -} - -/* ------------------------------------------------------------- */ - -int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned int port = card->port; - unsigned long flags; - int retval; - - b1_reset(port); - - if ((retval = b1_load_t4file(card, &data->firmware))) { - b1_reset(port); - printk(KERN_ERR "%s: failed to load t4file!!\n", - card->name); - return retval; - } - - b1_disable_irq(port); - - if (data->configuration.len > 0 && data->configuration.data) { - if ((retval = b1_load_config(card, &data->configuration))) { - b1_reset(port); - printk(KERN_ERR "%s: failed to load config!!\n", - card->name); - return retval; - } - } - - if (!b1_loaded(card)) { - printk(KERN_ERR "%s: failed to load t4file.\n", card->name); - return -EIO; - } - - spin_lock_irqsave(&card->lock, flags); - b1_setinterrupt(port, card->irq, card->cardtype); - b1_put_byte(port, SEND_INIT); - b1_put_word(port, CAPI_MAXAPPL); - b1_put_word(port, AVM_NCCI_PER_CHANNEL * 2); - b1_put_word(port, ctrl->cnr - 1); - spin_unlock_irqrestore(&card->lock, flags); - - return 0; -} - -void b1_reset_ctr(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned int port = card->port; - unsigned long flags; - - b1_reset(port); - b1_reset(port); - - memset(cinfo->version, 0, sizeof(cinfo->version)); - spin_lock_irqsave(&card->lock, flags); - capilib_release(&cinfo->ncci_head); - spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_down(ctrl); -} - -void b1_register_appl(struct capi_ctr *ctrl, - u16 appl, - capi_register_params *rp) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned int port = card->port; - unsigned long flags; - int nconn, want = rp->level3cnt; - - if (want > 0) nconn = want; - else nconn = ctrl->profile.nbchannel * -want; - if (nconn == 0) nconn = ctrl->profile.nbchannel; - - spin_lock_irqsave(&card->lock, flags); - b1_put_byte(port, SEND_REGISTER); - b1_put_word(port, appl); - b1_put_word(port, 1024 * (nconn + 1)); - b1_put_word(port, nconn); - b1_put_word(port, rp->datablkcnt); - b1_put_word(port, rp->datablklen); - spin_unlock_irqrestore(&card->lock, flags); -} - -void b1_release_appl(struct capi_ctr *ctrl, u16 appl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned int port = card->port; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - capilib_release_appl(&cinfo->ncci_head, appl); - b1_put_byte(port, SEND_RELEASE); - b1_put_word(port, appl); - spin_unlock_irqrestore(&card->lock, flags); -} - -u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned int port = card->port; - unsigned long flags; - u16 len = CAPIMSG_LEN(skb->data); - u8 cmd = CAPIMSG_COMMAND(skb->data); - u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data); - u16 dlen, retval; - - spin_lock_irqsave(&card->lock, flags); - if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { - retval = capilib_data_b3_req(&cinfo->ncci_head, - CAPIMSG_APPID(skb->data), - CAPIMSG_NCCI(skb->data), - CAPIMSG_MSGID(skb->data)); - if (retval != CAPI_NOERROR) { - spin_unlock_irqrestore(&card->lock, flags); - return retval; - } - - dlen = CAPIMSG_DATALEN(skb->data); - - b1_put_byte(port, SEND_DATA_B3_REQ); - b1_put_slice(port, skb->data, len); - b1_put_slice(port, skb->data + len, dlen); - } else { - b1_put_byte(port, SEND_MESSAGE); - b1_put_slice(port, skb->data, len); - } - spin_unlock_irqrestore(&card->lock, flags); - - dev_kfree_skb_any(skb); - return CAPI_NOERROR; -} - -/* ------------------------------------------------------------- */ - -void b1_parse_version(avmctrl_info *cinfo) -{ - struct capi_ctr *ctrl = &cinfo->capi_ctrl; - avmcard *card = cinfo->card; - capi_profile *profp; - u8 *dversion; - u8 flag; - int i, j; - - for (j = 0; j < AVM_MAXVERSION; j++) - cinfo->version[j] = ""; - for (i = 0, j = 0; - j < AVM_MAXVERSION && i < cinfo->versionlen; - j++, i += cinfo->versionbuf[i] + 1) - cinfo->version[j] = &cinfo->versionbuf[i + 1]; - - strlcpy(ctrl->serial, cinfo->version[VER_SERIAL], sizeof(ctrl->serial)); - memcpy(&ctrl->profile, cinfo->version[VER_PROFILE], sizeof(capi_profile)); - strlcpy(ctrl->manu, "AVM GmbH", sizeof(ctrl->manu)); - dversion = cinfo->version[VER_DRIVER]; - ctrl->version.majorversion = 2; - ctrl->version.minorversion = 0; - ctrl->version.majormanuversion = (((dversion[0] - '0') & 0xf) << 4); - ctrl->version.majormanuversion |= ((dversion[2] - '0') & 0xf); - ctrl->version.minormanuversion = (dversion[3] - '0') << 4; - ctrl->version.minormanuversion |= - (dversion[5] - '0') * 10 + ((dversion[6] - '0') & 0xf); - - profp = &ctrl->profile; - - flag = ((u8 *)(profp->manu))[1]; - switch (flag) { - case 0: if (cinfo->version[VER_CARDTYPE]) - strcpy(cinfo->cardname, cinfo->version[VER_CARDTYPE]); - else strcpy(cinfo->cardname, "B1"); - break; - case 3: strcpy(cinfo->cardname, "PCMCIA B"); break; - case 4: strcpy(cinfo->cardname, "PCMCIA M1"); break; - case 5: strcpy(cinfo->cardname, "PCMCIA M2"); break; - case 6: strcpy(cinfo->cardname, "B1 V3.0"); break; - case 7: strcpy(cinfo->cardname, "B1 PCI"); break; - default: sprintf(cinfo->cardname, "AVM?%u", (unsigned int)flag); break; - } - printk(KERN_NOTICE "%s: card %d \"%s\" ready.\n", - card->name, ctrl->cnr, cinfo->cardname); - - flag = ((u8 *)(profp->manu))[3]; - if (flag) - printk(KERN_NOTICE "%s: card %d Protocol:%s%s%s%s%s%s%s\n", - card->name, - ctrl->cnr, - (flag & 0x01) ? " DSS1" : "", - (flag & 0x02) ? " CT1" : "", - (flag & 0x04) ? " VN3" : "", - (flag & 0x08) ? " NI1" : "", - (flag & 0x10) ? " AUSTEL" : "", - (flag & 0x20) ? " ESS" : "", - (flag & 0x40) ? " 1TR6" : "" - ); - - flag = ((u8 *)(profp->manu))[5]; - if (flag) - printk(KERN_NOTICE "%s: card %d Linetype:%s%s%s%s\n", - card->name, - ctrl->cnr, - (flag & 0x01) ? " point to point" : "", - (flag & 0x02) ? " point to multipoint" : "", - (flag & 0x08) ? " leased line without D-channel" : "", - (flag & 0x04) ? " leased line with D-channel" : "" - ); -} - -/* ------------------------------------------------------------- */ - -irqreturn_t b1_interrupt(int interrupt, void *devptr) -{ - avmcard *card = devptr; - avmctrl_info *cinfo = &card->ctrlinfo[0]; - struct capi_ctr *ctrl = &cinfo->capi_ctrl; - unsigned char b1cmd; - struct sk_buff *skb; - - unsigned ApplId; - unsigned MsgLen; - unsigned DataB3Len; - unsigned NCCI; - unsigned WindowSize; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - - if (!b1_rx_full(card->port)) { - spin_unlock_irqrestore(&card->lock, flags); - return IRQ_NONE; - } - - b1cmd = b1_get_byte(card->port); - - switch (b1cmd) { - - case RECEIVE_DATA_B3_IND: - - ApplId = (unsigned) b1_get_word(card->port); - MsgLen = b1_get_slice(card->port, card->msgbuf); - DataB3Len = b1_get_slice(card->port, card->databuf); - spin_unlock_irqrestore(&card->lock, flags); - - if (MsgLen < 30) { /* not CAPI 64Bit */ - memset(card->msgbuf + MsgLen, 0, 30-MsgLen); - MsgLen = 30; - CAPIMSG_SETLEN(card->msgbuf, 30); - } - if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) { - printk(KERN_ERR "%s: incoming packet dropped\n", - card->name); - } else { - skb_put_data(skb, card->msgbuf, MsgLen); - skb_put_data(skb, card->databuf, DataB3Len); - capi_ctr_handle_message(ctrl, ApplId, skb); - } - break; - - case RECEIVE_MESSAGE: - - ApplId = (unsigned) b1_get_word(card->port); - MsgLen = b1_get_slice(card->port, card->msgbuf); - if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { - printk(KERN_ERR "%s: incoming packet dropped\n", - card->name); - spin_unlock_irqrestore(&card->lock, flags); - } else { - skb_put_data(skb, card->msgbuf, MsgLen); - if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) - capilib_data_b3_conf(&cinfo->ncci_head, ApplId, - CAPIMSG_NCCI(skb->data), - CAPIMSG_MSGID(skb->data)); - spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_handle_message(ctrl, ApplId, skb); - } - break; - - case RECEIVE_NEW_NCCI: - - ApplId = b1_get_word(card->port); - NCCI = b1_get_word(card->port); - WindowSize = b1_get_word(card->port); - capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); - spin_unlock_irqrestore(&card->lock, flags); - break; - - case RECEIVE_FREE_NCCI: - - ApplId = b1_get_word(card->port); - NCCI = b1_get_word(card->port); - if (NCCI != 0xffffffff) - capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); - spin_unlock_irqrestore(&card->lock, flags); - break; - - case RECEIVE_START: - /* b1_put_byte(card->port, SEND_POLLACK); */ - spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_resume_output(ctrl); - break; - - case RECEIVE_STOP: - spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_suspend_output(ctrl); - break; - - case RECEIVE_INIT: - - cinfo->versionlen = b1_get_slice(card->port, cinfo->versionbuf); - spin_unlock_irqrestore(&card->lock, flags); - b1_parse_version(cinfo); - printk(KERN_INFO "%s: %s-card (%s) now active\n", - card->name, - cinfo->version[VER_CARDTYPE], - cinfo->version[VER_DRIVER]); - capi_ctr_ready(ctrl); - break; - - case RECEIVE_TASK_READY: - ApplId = (unsigned) b1_get_word(card->port); - MsgLen = b1_get_slice(card->port, card->msgbuf); - spin_unlock_irqrestore(&card->lock, flags); - card->msgbuf[MsgLen] = 0; - while (MsgLen > 0 - && (card->msgbuf[MsgLen - 1] == '\n' - || card->msgbuf[MsgLen - 1] == '\r')) { - card->msgbuf[MsgLen - 1] = 0; - MsgLen--; - } - printk(KERN_INFO "%s: task %d \"%s\" ready.\n", - card->name, ApplId, card->msgbuf); - break; - - case RECEIVE_DEBUGMSG: - MsgLen = b1_get_slice(card->port, card->msgbuf); - spin_unlock_irqrestore(&card->lock, flags); - card->msgbuf[MsgLen] = 0; - while (MsgLen > 0 - && (card->msgbuf[MsgLen - 1] == '\n' - || card->msgbuf[MsgLen - 1] == '\r')) { - card->msgbuf[MsgLen - 1] = 0; - MsgLen--; - } - printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); - break; - - case 0xff: - spin_unlock_irqrestore(&card->lock, flags); - printk(KERN_ERR "%s: card removed ?\n", card->name); - return IRQ_NONE; - default: - spin_unlock_irqrestore(&card->lock, flags); - printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n", - card->name, b1cmd); - return IRQ_HANDLED; - } - return IRQ_HANDLED; -} - -/* ------------------------------------------------------------- */ -int b1_proc_show(struct seq_file *m, void *v) -{ - struct capi_ctr *ctrl = m->private; - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - u8 flag; - char *s; - - seq_printf(m, "%-16s %s\n", "name", card->name); - seq_printf(m, "%-16s 0x%x\n", "io", card->port); - seq_printf(m, "%-16s %d\n", "irq", card->irq); - switch (card->cardtype) { - case avm_b1isa: s = "B1 ISA"; break; - case avm_b1pci: s = "B1 PCI"; break; - case avm_b1pcmcia: s = "B1 PCMCIA"; break; - case avm_m1: s = "M1"; break; - case avm_m2: s = "M2"; break; - case avm_t1isa: s = "T1 ISA (HEMA)"; break; - case avm_t1pci: s = "T1 PCI"; break; - case avm_c4: s = "C4"; break; - case avm_c2: s = "C2"; break; - default: s = "???"; break; - } - seq_printf(m, "%-16s %s\n", "type", s); - if (card->cardtype == avm_t1isa) - seq_printf(m, "%-16s %d\n", "cardnr", card->cardnr); - if ((s = cinfo->version[VER_DRIVER]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_serial", s); - - if (card->cardtype != avm_m1) { - flag = ((u8 *)(ctrl->profile.manu))[3]; - if (flag) - seq_printf(m, "%-16s%s%s%s%s%s%s%s\n", - "protocol", - (flag & 0x01) ? " DSS1" : "", - (flag & 0x02) ? " CT1" : "", - (flag & 0x04) ? " VN3" : "", - (flag & 0x08) ? " NI1" : "", - (flag & 0x10) ? " AUSTEL" : "", - (flag & 0x20) ? " ESS" : "", - (flag & 0x40) ? " 1TR6" : "" - ); - } - if (card->cardtype != avm_m1) { - flag = ((u8 *)(ctrl->profile.manu))[5]; - if (flag) - seq_printf(m, "%-16s%s%s%s%s\n", - "linetype", - (flag & 0x01) ? " point to point" : "", - (flag & 0x02) ? " point to multipoint" : "", - (flag & 0x08) ? " leased line without D-channel" : "", - (flag & 0x04) ? " leased line with D-channel" : "" - ); - } - seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname); - - return 0; -} -EXPORT_SYMBOL(b1_proc_show); - -/* ------------------------------------------------------------- */ - -#ifdef CONFIG_PCI - -avmcard_dmainfo * -avmcard_dma_alloc(char *name, struct pci_dev *pdev, long rsize, long ssize) -{ - avmcard_dmainfo *p; - void *buf; - - p = kzalloc(sizeof(avmcard_dmainfo), GFP_KERNEL); - if (!p) { - printk(KERN_WARNING "%s: no memory.\n", name); - goto err; - } - - p->recvbuf.size = rsize; - buf = pci_alloc_consistent(pdev, rsize, &p->recvbuf.dmaaddr); - if (!buf) { - printk(KERN_WARNING "%s: allocation of receive dma buffer failed.\n", name); - goto err_kfree; - } - p->recvbuf.dmabuf = buf; - - p->sendbuf.size = ssize; - buf = pci_alloc_consistent(pdev, ssize, &p->sendbuf.dmaaddr); - if (!buf) { - printk(KERN_WARNING "%s: allocation of send dma buffer failed.\n", name); - goto err_free_consistent; - } - - p->sendbuf.dmabuf = buf; - skb_queue_head_init(&p->send_queue); - - return p; - -err_free_consistent: - pci_free_consistent(p->pcidev, p->recvbuf.size, - p->recvbuf.dmabuf, p->recvbuf.dmaaddr); -err_kfree: - kfree(p); -err: - return NULL; -} - -void avmcard_dma_free(avmcard_dmainfo *p) -{ - pci_free_consistent(p->pcidev, p->recvbuf.size, - p->recvbuf.dmabuf, p->recvbuf.dmaaddr); - pci_free_consistent(p->pcidev, p->sendbuf.size, - p->sendbuf.dmabuf, p->sendbuf.dmaaddr); - skb_queue_purge(&p->send_queue); - kfree(p); -} - -EXPORT_SYMBOL(avmcard_dma_alloc); -EXPORT_SYMBOL(avmcard_dma_free); - -#endif - -EXPORT_SYMBOL(b1_irq_table); - -EXPORT_SYMBOL(b1_alloc_card); -EXPORT_SYMBOL(b1_free_card); -EXPORT_SYMBOL(b1_detect); -EXPORT_SYMBOL(b1_getrevision); -EXPORT_SYMBOL(b1_load_t4file); -EXPORT_SYMBOL(b1_load_config); -EXPORT_SYMBOL(b1_loaded); -EXPORT_SYMBOL(b1_load_firmware); -EXPORT_SYMBOL(b1_reset_ctr); -EXPORT_SYMBOL(b1_register_appl); -EXPORT_SYMBOL(b1_release_appl); -EXPORT_SYMBOL(b1_send_message); - -EXPORT_SYMBOL(b1_parse_version); -EXPORT_SYMBOL(b1_interrupt); - -static int __init b1_init(void) -{ - char *p; - char rev[32]; - - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p - 1) = 0; - } else - strcpy(rev, "1.0"); - - printk(KERN_INFO "b1: revision %s\n", rev); - - return 0; -} - -static void __exit b1_exit(void) -{ -} - -module_init(b1_init); -module_exit(b1_exit); diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c deleted file mode 100644 index 6a3dc9937ce5..000000000000 --- a/drivers/isdn/hardware/avm/b1dma.c +++ /dev/null @@ -1,981 +0,0 @@ -/* $Id: b1dma.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ - * - * Common module for AVM B1 cards that support dma with AMCC - * - * Copyright 2000 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/capi.h> -#include <linux/kernelcapi.h> -#include <linux/gfp.h> -#include <asm/io.h> -#include <linux/init.h> -#include <linux/uaccess.h> -#include <linux/netdevice.h> -#include <linux/isdn/capilli.h> -#include "avmcard.h" -#include <linux/isdn/capicmd.h> -#include <linux/isdn/capiutil.h> - -static char *revision = "$Revision: 1.1.2.3 $"; - -#undef AVM_B1DMA_DEBUG - -/* ------------------------------------------------------------- */ - -MODULE_DESCRIPTION("CAPI4Linux: DMA support for active AVM cards"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -static bool suppress_pollack = 0; -module_param(suppress_pollack, bool, 0); - -/* ------------------------------------------------------------- */ - -static void b1dma_dispatch_tx(avmcard *card); - -/* ------------------------------------------------------------- */ - -/* S5933 */ - -#define AMCC_RXPTR 0x24 -#define AMCC_RXLEN 0x28 -#define AMCC_TXPTR 0x2c -#define AMCC_TXLEN 0x30 - -#define AMCC_INTCSR 0x38 -# define EN_READ_TC_INT 0x00008000L -# define EN_WRITE_TC_INT 0x00004000L -# define EN_TX_TC_INT EN_READ_TC_INT -# define EN_RX_TC_INT EN_WRITE_TC_INT -# define AVM_FLAG 0x30000000L - -# define ANY_S5933_INT 0x00800000L -# define READ_TC_INT 0x00080000L -# define WRITE_TC_INT 0x00040000L -# define TX_TC_INT READ_TC_INT -# define RX_TC_INT WRITE_TC_INT -# define MASTER_ABORT_INT 0x00100000L -# define TARGET_ABORT_INT 0x00200000L -# define BUS_MASTER_INT 0x00200000L -# define ALL_INT 0x000C0000L - -#define AMCC_MCSR 0x3c -# define A2P_HI_PRIORITY 0x00000100L -# define EN_A2P_TRANSFERS 0x00000400L -# define P2A_HI_PRIORITY 0x00001000L -# define EN_P2A_TRANSFERS 0x00004000L -# define RESET_A2P_FLAGS 0x04000000L -# define RESET_P2A_FLAGS 0x02000000L - -/* ------------------------------------------------------------- */ - -static inline void b1dma_writel(avmcard *card, u32 value, int off) -{ - writel(value, card->mbase + off); -} - -static inline u32 b1dma_readl(avmcard *card, int off) -{ - return readl(card->mbase + off); -} - -/* ------------------------------------------------------------- */ - -static inline int b1dma_tx_empty(unsigned int port) -{ - return inb(port + 0x03) & 0x1; -} - -static inline int b1dma_rx_full(unsigned int port) -{ - return inb(port + 0x02) & 0x1; -} - -static int b1dma_tolink(avmcard *card, void *buf, unsigned int len) -{ - unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ - unsigned char *s = (unsigned char *)buf; - while (len--) { - while (!b1dma_tx_empty(card->port) - && time_before(jiffies, stop)); - if (!b1dma_tx_empty(card->port)) - return -1; - t1outp(card->port, 0x01, *s++); - } - return 0; -} - -static int b1dma_fromlink(avmcard *card, void *buf, unsigned int len) -{ - unsigned long stop = jiffies + 1 * HZ; /* maximum wait time 1 sec */ - unsigned char *s = (unsigned char *)buf; - while (len--) { - while (!b1dma_rx_full(card->port) - && time_before(jiffies, stop)); - if (!b1dma_rx_full(card->port)) - return -1; - *s++ = t1inp(card->port, 0x00); - } - return 0; -} - -static int WriteReg(avmcard *card, u32 reg, u8 val) -{ - u8 cmd = 0x00; - if (b1dma_tolink(card, &cmd, 1) == 0 - && b1dma_tolink(card, ®, 4) == 0) { - u32 tmp = val; - return b1dma_tolink(card, &tmp, 4); - } - return -1; -} - -static u8 ReadReg(avmcard *card, u32 reg) -{ - u8 cmd = 0x01; - if (b1dma_tolink(card, &cmd, 1) == 0 - && b1dma_tolink(card, ®, 4) == 0) { - u32 tmp; - if (b1dma_fromlink(card, &tmp, 4) == 0) - return (u8)tmp; - } - return 0xff; -} - -/* ------------------------------------------------------------- */ - -static inline void _put_byte(void **pp, u8 val) -{ - u8 *s = *pp; - *s++ = val; - *pp = s; -} - -static inline void _put_word(void **pp, u32 val) -{ - u8 *s = *pp; - *s++ = val & 0xff; - *s++ = (val >> 8) & 0xff; - *s++ = (val >> 16) & 0xff; - *s++ = (val >> 24) & 0xff; - *pp = s; -} - -static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len) -{ - unsigned i = len; - _put_word(pp, i); - while (i-- > 0) - _put_byte(pp, *dp++); -} - -static inline u8 _get_byte(void **pp) -{ - u8 *s = *pp; - u8 val; - val = *s++; - *pp = s; - return val; -} - -static inline u32 _get_word(void **pp) -{ - u8 *s = *pp; - u32 val; - val = *s++; - val |= (*s++ << 8); - val |= (*s++ << 16); - val |= (*s++ << 24); - *pp = s; - return val; -} - -static inline u32 _get_slice(void **pp, unsigned char *dp) -{ - unsigned int len, i; - - len = i = _get_word(pp); - while (i-- > 0) *dp++ = _get_byte(pp); - return len; -} - -/* ------------------------------------------------------------- */ - -void b1dma_reset(avmcard *card) -{ - card->csr = 0x0; - b1dma_writel(card, card->csr, AMCC_INTCSR); - b1dma_writel(card, 0, AMCC_MCSR); - b1dma_writel(card, 0, AMCC_RXLEN); - b1dma_writel(card, 0, AMCC_TXLEN); - - t1outp(card->port, 0x10, 0x00); - t1outp(card->port, 0x07, 0x00); - - b1dma_writel(card, 0, AMCC_MCSR); - mdelay(10); - b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */ - mdelay(10); - b1dma_writel(card, 0, AMCC_MCSR); - if (card->cardtype == avm_t1pci) - mdelay(42); - else - mdelay(10); -} - -/* ------------------------------------------------------------- */ - -static int b1dma_detect(avmcard *card) -{ - b1dma_writel(card, 0, AMCC_MCSR); - mdelay(10); - b1dma_writel(card, 0x0f000000, AMCC_MCSR); /* reset all */ - mdelay(10); - b1dma_writel(card, 0, AMCC_MCSR); - mdelay(42); - - b1dma_writel(card, 0, AMCC_RXLEN); - b1dma_writel(card, 0, AMCC_TXLEN); - card->csr = 0x0; - b1dma_writel(card, card->csr, AMCC_INTCSR); - - if (b1dma_readl(card, AMCC_MCSR) != 0x000000E6) - return 1; - - b1dma_writel(card, 0xffffffff, AMCC_RXPTR); - b1dma_writel(card, 0xffffffff, AMCC_TXPTR); - if (b1dma_readl(card, AMCC_RXPTR) != 0xfffffffc - || b1dma_readl(card, AMCC_TXPTR) != 0xfffffffc) - return 2; - - b1dma_writel(card, 0x0, AMCC_RXPTR); - b1dma_writel(card, 0x0, AMCC_TXPTR); - if (b1dma_readl(card, AMCC_RXPTR) != 0x0 - || b1dma_readl(card, AMCC_TXPTR) != 0x0) - return 3; - - t1outp(card->port, 0x10, 0x00); - t1outp(card->port, 0x07, 0x00); - - t1outp(card->port, 0x02, 0x02); - t1outp(card->port, 0x03, 0x02); - - if ((t1inp(card->port, 0x02) & 0xFE) != 0x02 - || t1inp(card->port, 0x3) != 0x03) - return 4; - - t1outp(card->port, 0x02, 0x00); - t1outp(card->port, 0x03, 0x00); - - if ((t1inp(card->port, 0x02) & 0xFE) != 0x00 - || t1inp(card->port, 0x3) != 0x01) - return 5; - - return 0; -} - -int t1pci_detect(avmcard *card) -{ - int ret; - - if ((ret = b1dma_detect(card)) != 0) - return ret; - - /* Transputer test */ - - if (WriteReg(card, 0x80001000, 0x11) != 0 - || WriteReg(card, 0x80101000, 0x22) != 0 - || WriteReg(card, 0x80201000, 0x33) != 0 - || WriteReg(card, 0x80301000, 0x44) != 0) - return 6; - - if (ReadReg(card, 0x80001000) != 0x11 - || ReadReg(card, 0x80101000) != 0x22 - || ReadReg(card, 0x80201000) != 0x33 - || ReadReg(card, 0x80301000) != 0x44) - return 7; - - if (WriteReg(card, 0x80001000, 0x55) != 0 - || WriteReg(card, 0x80101000, 0x66) != 0 - || WriteReg(card, 0x80201000, 0x77) != 0 - || WriteReg(card, 0x80301000, 0x88) != 0) - return 8; - - if (ReadReg(card, 0x80001000) != 0x55 - || ReadReg(card, 0x80101000) != 0x66 - || ReadReg(card, 0x80201000) != 0x77 - || ReadReg(card, 0x80301000) != 0x88) - return 9; - - return 0; -} - -int b1pciv4_detect(avmcard *card) -{ - int ret, i; - - if ((ret = b1dma_detect(card)) != 0) - return ret; - - for (i = 0; i < 5; i++) { - if (WriteReg(card, 0x80A00000, 0x21) != 0) - return 6; - if ((ReadReg(card, 0x80A00000) & 0x01) != 0x01) - return 7; - } - for (i = 0; i < 5; i++) { - if (WriteReg(card, 0x80A00000, 0x20) != 0) - return 8; - if ((ReadReg(card, 0x80A00000) & 0x01) != 0x00) - return 9; - } - - return 0; -} - -static void b1dma_queue_tx(avmcard *card, struct sk_buff *skb) -{ - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - - skb_queue_tail(&card->dma->send_queue, skb); - - if (!(card->csr & EN_TX_TC_INT)) { - b1dma_dispatch_tx(card); - b1dma_writel(card, card->csr, AMCC_INTCSR); - } - - spin_unlock_irqrestore(&card->lock, flags); -} - -/* ------------------------------------------------------------- */ - -static void b1dma_dispatch_tx(avmcard *card) -{ - avmcard_dmainfo *dma = card->dma; - struct sk_buff *skb; - u8 cmd, subcmd; - u16 len; - u32 txlen; - void *p; - - skb = skb_dequeue(&dma->send_queue); - - len = CAPIMSG_LEN(skb->data); - - if (len) { - cmd = CAPIMSG_COMMAND(skb->data); - subcmd = CAPIMSG_SUBCOMMAND(skb->data); - - p = dma->sendbuf.dmabuf; - - if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { - u16 dlen = CAPIMSG_DATALEN(skb->data); - _put_byte(&p, SEND_DATA_B3_REQ); - _put_slice(&p, skb->data, len); - _put_slice(&p, skb->data + len, dlen); - } else { - _put_byte(&p, SEND_MESSAGE); - _put_slice(&p, skb->data, len); - } - txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf; -#ifdef AVM_B1DMA_DEBUG - printk(KERN_DEBUG "tx: put msg len=%d\n", txlen); -#endif - } else { - txlen = skb->len - 2; -#ifdef AVM_B1DMA_POLLDEBUG - if (skb->data[2] == SEND_POLLACK) - printk(KERN_INFO "%s: send ack\n", card->name); -#endif -#ifdef AVM_B1DMA_DEBUG - printk(KERN_DEBUG "tx: put 0x%x len=%d\n", - skb->data[2], txlen); -#endif - skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf, - skb->len - 2); - } - txlen = (txlen + 3) & ~3; - - b1dma_writel(card, dma->sendbuf.dmaaddr, AMCC_TXPTR); - b1dma_writel(card, txlen, AMCC_TXLEN); - - card->csr |= EN_TX_TC_INT; - - dev_kfree_skb_any(skb); -} - -/* ------------------------------------------------------------- */ - -static void queue_pollack(avmcard *card) -{ - struct sk_buff *skb; - void *p; - - skb = alloc_skb(3, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost poll ack\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_POLLACK); - skb_put(skb, (u8 *)p - (u8 *)skb->data); - - b1dma_queue_tx(card, skb); -} - -/* ------------------------------------------------------------- */ - -static void b1dma_handle_rx(avmcard *card) -{ - avmctrl_info *cinfo = &card->ctrlinfo[0]; - avmcard_dmainfo *dma = card->dma; - struct capi_ctr *ctrl = &cinfo->capi_ctrl; - struct sk_buff *skb; - void *p = dma->recvbuf.dmabuf + 4; - u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; - u8 b1cmd = _get_byte(&p); - -#ifdef AVM_B1DMA_DEBUG - printk(KERN_DEBUG "rx: 0x%x %lu\n", b1cmd, (unsigned long)dma->recvlen); -#endif - - switch (b1cmd) { - case RECEIVE_DATA_B3_IND: - - ApplId = (unsigned) _get_word(&p); - MsgLen = _get_slice(&p, card->msgbuf); - DataB3Len = _get_slice(&p, card->databuf); - - if (MsgLen < 30) { /* not CAPI 64Bit */ - memset(card->msgbuf + MsgLen, 0, 30 - MsgLen); - MsgLen = 30; - CAPIMSG_SETLEN(card->msgbuf, 30); - } - if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) { - printk(KERN_ERR "%s: incoming packet dropped\n", - card->name); - } else { - skb_put_data(skb, card->msgbuf, MsgLen); - skb_put_data(skb, card->databuf, DataB3Len); - capi_ctr_handle_message(ctrl, ApplId, skb); - } - break; - - case RECEIVE_MESSAGE: - - ApplId = (unsigned) _get_word(&p); - MsgLen = _get_slice(&p, card->msgbuf); - if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { - printk(KERN_ERR "%s: incoming packet dropped\n", - card->name); - } else { - skb_put_data(skb, card->msgbuf, MsgLen); - if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) { - spin_lock(&card->lock); - capilib_data_b3_conf(&cinfo->ncci_head, ApplId, - CAPIMSG_NCCI(skb->data), - CAPIMSG_MSGID(skb->data)); - spin_unlock(&card->lock); - } - capi_ctr_handle_message(ctrl, ApplId, skb); - } - break; - - case RECEIVE_NEW_NCCI: - - ApplId = _get_word(&p); - NCCI = _get_word(&p); - WindowSize = _get_word(&p); - spin_lock(&card->lock); - capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); - spin_unlock(&card->lock); - break; - - case RECEIVE_FREE_NCCI: - - ApplId = _get_word(&p); - NCCI = _get_word(&p); - - if (NCCI != 0xffffffff) { - spin_lock(&card->lock); - capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); - spin_unlock(&card->lock); - } - break; - - case RECEIVE_START: -#ifdef AVM_B1DMA_POLLDEBUG - printk(KERN_INFO "%s: receive poll\n", card->name); -#endif - if (!suppress_pollack) - queue_pollack(card); - capi_ctr_resume_output(ctrl); - break; - - case RECEIVE_STOP: - capi_ctr_suspend_output(ctrl); - break; - - case RECEIVE_INIT: - - cinfo->versionlen = _get_slice(&p, cinfo->versionbuf); - b1_parse_version(cinfo); - printk(KERN_INFO "%s: %s-card (%s) now active\n", - card->name, - cinfo->version[VER_CARDTYPE], - cinfo->version[VER_DRIVER]); - capi_ctr_ready(ctrl); - break; - - case RECEIVE_TASK_READY: - ApplId = (unsigned) _get_word(&p); - MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen] = 0; - while (MsgLen > 0 - && (card->msgbuf[MsgLen - 1] == '\n' - || card->msgbuf[MsgLen - 1] == '\r')) { - card->msgbuf[MsgLen - 1] = 0; - MsgLen--; - } - printk(KERN_INFO "%s: task %d \"%s\" ready.\n", - card->name, ApplId, card->msgbuf); - break; - - case RECEIVE_DEBUGMSG: - MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen] = 0; - while (MsgLen > 0 - && (card->msgbuf[MsgLen - 1] == '\n' - || card->msgbuf[MsgLen - 1] == '\r')) { - card->msgbuf[MsgLen - 1] = 0; - MsgLen--; - } - printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); - break; - - default: - printk(KERN_ERR "%s: b1dma_interrupt: 0x%x ???\n", - card->name, b1cmd); - return; - } -} - -/* ------------------------------------------------------------- */ - -static void b1dma_handle_interrupt(avmcard *card) -{ - u32 status; - u32 newcsr; - - spin_lock(&card->lock); - - status = b1dma_readl(card, AMCC_INTCSR); - if ((status & ANY_S5933_INT) == 0) { - spin_unlock(&card->lock); - return; - } - - newcsr = card->csr | (status & ALL_INT); - if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT; - if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT; - b1dma_writel(card, newcsr, AMCC_INTCSR); - - if ((status & RX_TC_INT) != 0) { - struct avmcard_dmainfo *dma = card->dma; - u32 rxlen; - if (card->dma->recvlen == 0) { - rxlen = b1dma_readl(card, AMCC_RXLEN); - if (rxlen == 0) { - dma->recvlen = *((u32 *)dma->recvbuf.dmabuf); - rxlen = (dma->recvlen + 3) & ~3; - b1dma_writel(card, dma->recvbuf.dmaaddr + 4, AMCC_RXPTR); - b1dma_writel(card, rxlen, AMCC_RXLEN); -#ifdef AVM_B1DMA_DEBUG - } else { - printk(KERN_ERR "%s: rx not complete (%d).\n", - card->name, rxlen); -#endif - } - } else { - spin_unlock(&card->lock); - b1dma_handle_rx(card); - dma->recvlen = 0; - spin_lock(&card->lock); - b1dma_writel(card, dma->recvbuf.dmaaddr, AMCC_RXPTR); - b1dma_writel(card, 4, AMCC_RXLEN); - } - } - - if ((status & TX_TC_INT) != 0) { - if (skb_queue_empty(&card->dma->send_queue)) - card->csr &= ~EN_TX_TC_INT; - else - b1dma_dispatch_tx(card); - } - b1dma_writel(card, card->csr, AMCC_INTCSR); - - spin_unlock(&card->lock); -} - -irqreturn_t b1dma_interrupt(int interrupt, void *devptr) -{ - avmcard *card = devptr; - - b1dma_handle_interrupt(card); - return IRQ_HANDLED; -} - -/* ------------------------------------------------------------- */ - -static int b1dma_loaded(avmcard *card) -{ - unsigned long stop; - unsigned char ans; - unsigned long tout = 2; - unsigned int base = card->port; - - for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { - if (b1_tx_empty(base)) - break; - } - if (!b1_tx_empty(base)) { - printk(KERN_ERR "%s: b1dma_loaded: tx err, corrupted t4 file ?\n", - card->name); - return 0; - } - b1_put_byte(base, SEND_POLLACK); - for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { - if (b1_rx_full(base)) { - if ((ans = b1_get_byte(base)) == RECEIVE_POLLDWORD) { - return 1; - } - printk(KERN_ERR "%s: b1dma_loaded: got 0x%x, firmware not running in dword mode\n", card->name, ans); - return 0; - } - } - printk(KERN_ERR "%s: b1dma_loaded: firmware not running\n", card->name); - return 0; -} - -/* ------------------------------------------------------------- */ - -static void b1dma_send_init(avmcard *card) -{ - struct sk_buff *skb; - void *p; - - skb = alloc_skb(15, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost register appl.\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_INIT); - _put_word(&p, CAPI_MAXAPPL); - _put_word(&p, AVM_NCCI_PER_CHANNEL * 30); - _put_word(&p, card->cardnr - 1); - skb_put(skb, (u8 *)p - (u8 *)skb->data); - - b1dma_queue_tx(card, skb); -} - -int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - int retval; - - b1dma_reset(card); - - if ((retval = b1_load_t4file(card, &data->firmware))) { - b1dma_reset(card); - printk(KERN_ERR "%s: failed to load t4file!!\n", - card->name); - return retval; - } - - if (data->configuration.len > 0 && data->configuration.data) { - if ((retval = b1_load_config(card, &data->configuration))) { - b1dma_reset(card); - printk(KERN_ERR "%s: failed to load config!!\n", - card->name); - return retval; - } - } - - if (!b1dma_loaded(card)) { - b1dma_reset(card); - printk(KERN_ERR "%s: failed to load t4file.\n", card->name); - return -EIO; - } - - card->csr = AVM_FLAG; - b1dma_writel(card, card->csr, AMCC_INTCSR); - b1dma_writel(card, EN_A2P_TRANSFERS | EN_P2A_TRANSFERS | A2P_HI_PRIORITY | - P2A_HI_PRIORITY | RESET_A2P_FLAGS | RESET_P2A_FLAGS, - AMCC_MCSR); - t1outp(card->port, 0x07, 0x30); - t1outp(card->port, 0x10, 0xF0); - - card->dma->recvlen = 0; - b1dma_writel(card, card->dma->recvbuf.dmaaddr, AMCC_RXPTR); - b1dma_writel(card, 4, AMCC_RXLEN); - card->csr |= EN_RX_TC_INT; - b1dma_writel(card, card->csr, AMCC_INTCSR); - - b1dma_send_init(card); - - return 0; -} - -void b1dma_reset_ctr(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - b1dma_reset(card); - - memset(cinfo->version, 0, sizeof(cinfo->version)); - capilib_release(&cinfo->ncci_head); - spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_down(ctrl); -} - -/* ------------------------------------------------------------- */ - -void b1dma_register_appl(struct capi_ctr *ctrl, - u16 appl, - capi_register_params *rp) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - struct sk_buff *skb; - int want = rp->level3cnt; - int nconn; - void *p; - - if (want > 0) nconn = want; - else nconn = ctrl->profile.nbchannel * -want; - if (nconn == 0) nconn = ctrl->profile.nbchannel; - - skb = alloc_skb(23, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost register appl.\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_REGISTER); - _put_word(&p, appl); - _put_word(&p, 1024 * (nconn + 1)); - _put_word(&p, nconn); - _put_word(&p, rp->datablkcnt); - _put_word(&p, rp->datablklen); - skb_put(skb, (u8 *)p - (u8 *)skb->data); - - b1dma_queue_tx(card, skb); -} - -/* ------------------------------------------------------------- */ - -void b1dma_release_appl(struct capi_ctr *ctrl, u16 appl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - struct sk_buff *skb; - void *p; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - capilib_release_appl(&cinfo->ncci_head, appl); - spin_unlock_irqrestore(&card->lock, flags); - - skb = alloc_skb(7, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost release appl.\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_RELEASE); - _put_word(&p, appl); - - skb_put(skb, (u8 *)p - (u8 *)skb->data); - - b1dma_queue_tx(card, skb); -} - -/* ------------------------------------------------------------- */ - -u16 b1dma_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - u16 retval = CAPI_NOERROR; - - if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { - unsigned long flags; - spin_lock_irqsave(&card->lock, flags); - retval = capilib_data_b3_req(&cinfo->ncci_head, - CAPIMSG_APPID(skb->data), - CAPIMSG_NCCI(skb->data), - CAPIMSG_MSGID(skb->data)); - spin_unlock_irqrestore(&card->lock, flags); - } - if (retval == CAPI_NOERROR) - b1dma_queue_tx(card, skb); - - return retval; -} - -/* ------------------------------------------------------------- */ - -int b1dma_proc_show(struct seq_file *m, void *v) -{ - struct capi_ctr *ctrl = m->private; - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - u8 flag; - char *s; - u32 txoff, txlen, rxoff, rxlen, csr; - unsigned long flags; - - seq_printf(m, "%-16s %s\n", "name", card->name); - seq_printf(m, "%-16s 0x%x\n", "io", card->port); - seq_printf(m, "%-16s %d\n", "irq", card->irq); - seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase); - switch (card->cardtype) { - case avm_b1isa: s = "B1 ISA"; break; - case avm_b1pci: s = "B1 PCI"; break; - case avm_b1pcmcia: s = "B1 PCMCIA"; break; - case avm_m1: s = "M1"; break; - case avm_m2: s = "M2"; break; - case avm_t1isa: s = "T1 ISA (HEMA)"; break; - case avm_t1pci: s = "T1 PCI"; break; - case avm_c4: s = "C4"; break; - case avm_c2: s = "C2"; break; - default: s = "???"; break; - } - seq_printf(m, "%-16s %s\n", "type", s); - if ((s = cinfo->version[VER_DRIVER]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_serial", s); - - if (card->cardtype != avm_m1) { - flag = ((u8 *)(ctrl->profile.manu))[3]; - if (flag) - seq_printf(m, "%-16s%s%s%s%s%s%s%s\n", - "protocol", - (flag & 0x01) ? " DSS1" : "", - (flag & 0x02) ? " CT1" : "", - (flag & 0x04) ? " VN3" : "", - (flag & 0x08) ? " NI1" : "", - (flag & 0x10) ? " AUSTEL" : "", - (flag & 0x20) ? " ESS" : "", - (flag & 0x40) ? " 1TR6" : "" - ); - } - if (card->cardtype != avm_m1) { - flag = ((u8 *)(ctrl->profile.manu))[5]; - if (flag) - seq_printf(m, "%-16s%s%s%s%s\n", - "linetype", - (flag & 0x01) ? " point to point" : "", - (flag & 0x02) ? " point to multipoint" : "", - (flag & 0x08) ? " leased line without D-channel" : "", - (flag & 0x04) ? " leased line with D-channel" : "" - ); - } - seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname); - - - spin_lock_irqsave(&card->lock, flags); - - txoff = (dma_addr_t)b1dma_readl(card, AMCC_TXPTR)-card->dma->sendbuf.dmaaddr; - txlen = b1dma_readl(card, AMCC_TXLEN); - - rxoff = (dma_addr_t)b1dma_readl(card, AMCC_RXPTR)-card->dma->recvbuf.dmaaddr; - rxlen = b1dma_readl(card, AMCC_RXLEN); - - csr = b1dma_readl(card, AMCC_INTCSR); - - spin_unlock_irqrestore(&card->lock, flags); - - seq_printf(m, "%-16s 0x%lx\n", "csr (cached)", (unsigned long)card->csr); - seq_printf(m, "%-16s 0x%lx\n", "csr", (unsigned long)csr); - seq_printf(m, "%-16s %lu\n", "txoff", (unsigned long)txoff); - seq_printf(m, "%-16s %lu\n", "txlen", (unsigned long)txlen); - seq_printf(m, "%-16s %lu\n", "rxoff", (unsigned long)rxoff); - seq_printf(m, "%-16s %lu\n", "rxlen", (unsigned long)rxlen); - - return 0; -} -EXPORT_SYMBOL(b1dma_proc_show); - -/* ------------------------------------------------------------- */ - -EXPORT_SYMBOL(b1dma_reset); -EXPORT_SYMBOL(t1pci_detect); -EXPORT_SYMBOL(b1pciv4_detect); -EXPORT_SYMBOL(b1dma_interrupt); - -EXPORT_SYMBOL(b1dma_load_firmware); -EXPORT_SYMBOL(b1dma_reset_ctr); -EXPORT_SYMBOL(b1dma_register_appl); -EXPORT_SYMBOL(b1dma_release_appl); -EXPORT_SYMBOL(b1dma_send_message); - -static int __init b1dma_init(void) -{ - char *p; - char rev[32]; - - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, sizeof(rev)); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p - 1) = 0; - } else - strcpy(rev, "1.0"); - - printk(KERN_INFO "b1dma: revision %s\n", rev); - - return 0; -} - -static void __exit b1dma_exit(void) -{ -} - -module_init(b1dma_init); -module_exit(b1dma_exit); diff --git a/drivers/isdn/hardware/avm/b1isa.c b/drivers/isdn/hardware/avm/b1isa.c deleted file mode 100644 index cdfea72e0ef6..000000000000 --- a/drivers/isdn/hardware/avm/b1isa.c +++ /dev/null @@ -1,243 +0,0 @@ -/* $Id: b1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ - * - * Module for AVM B1 ISA-card. - * - * Copyright 1999 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/capi.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <asm/io.h> -#include <linux/isdn/capicmd.h> -#include <linux/isdn/capiutil.h> -#include <linux/isdn/capilli.h> -#include "avmcard.h" - -/* ------------------------------------------------------------- */ - -static char *revision = "$Revision: 1.1.2.3 $"; - -/* ------------------------------------------------------------- */ - -MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 ISA card"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------- */ - -static void b1isa_remove(struct pci_dev *pdev) -{ - avmctrl_info *cinfo = pci_get_drvdata(pdev); - avmcard *card; - - if (!cinfo) - return; - - card = cinfo->card; - - b1_reset(card->port); - b1_reset(card->port); - - detach_capi_ctr(&cinfo->capi_ctrl); - free_irq(card->irq, card); - release_region(card->port, AVMB1_PORTLEN); - b1_free_card(card); -} - -/* ------------------------------------------------------------- */ - -static char *b1isa_procinfo(struct capi_ctr *ctrl); - -static int b1isa_probe(struct pci_dev *pdev) -{ - avmctrl_info *cinfo; - avmcard *card; - int retval; - - card = b1_alloc_card(1); - if (!card) { - printk(KERN_WARNING "b1isa: no memory.\n"); - retval = -ENOMEM; - goto err; - } - - cinfo = card->ctrlinfo; - - card->port = pci_resource_start(pdev, 0); - card->irq = pdev->irq; - card->cardtype = avm_b1isa; - sprintf(card->name, "b1isa-%x", card->port); - - if (card->port != 0x150 && card->port != 0x250 - && card->port != 0x300 && card->port != 0x340) { - printk(KERN_WARNING "b1isa: invalid port 0x%x.\n", card->port); - retval = -EINVAL; - goto err_free; - } - if (b1_irq_table[card->irq & 0xf] == 0) { - printk(KERN_WARNING "b1isa: irq %d not valid.\n", card->irq); - retval = -EINVAL; - goto err_free; - } - if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { - printk(KERN_WARNING "b1isa: ports 0x%03x-0x%03x in use.\n", - card->port, card->port + AVMB1_PORTLEN); - retval = -EBUSY; - goto err_free; - } - retval = request_irq(card->irq, b1_interrupt, 0, card->name, card); - if (retval) { - printk(KERN_ERR "b1isa: unable to get IRQ %d.\n", card->irq); - goto err_release_region; - } - b1_reset(card->port); - if ((retval = b1_detect(card->port, card->cardtype)) != 0) { - printk(KERN_NOTICE "b1isa: NO card at 0x%x (%d)\n", - card->port, retval); - retval = -ENODEV; - goto err_free_irq; - } - b1_reset(card->port); - b1_getrevision(card); - - cinfo->capi_ctrl.owner = THIS_MODULE; - cinfo->capi_ctrl.driver_name = "b1isa"; - cinfo->capi_ctrl.driverdata = cinfo; - cinfo->capi_ctrl.register_appl = b1_register_appl; - cinfo->capi_ctrl.release_appl = b1_release_appl; - cinfo->capi_ctrl.send_message = b1_send_message; - cinfo->capi_ctrl.load_firmware = b1_load_firmware; - cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; - cinfo->capi_ctrl.procinfo = b1isa_procinfo; - cinfo->capi_ctrl.proc_show = b1_proc_show; - strcpy(cinfo->capi_ctrl.name, card->name); - - retval = attach_capi_ctr(&cinfo->capi_ctrl); - if (retval) { - printk(KERN_ERR "b1isa: attach controller failed.\n"); - goto err_free_irq; - } - - printk(KERN_INFO "b1isa: AVM B1 ISA at i/o %#x, irq %d, revision %d\n", - card->port, card->irq, card->revision); - - pci_set_drvdata(pdev, cinfo); - return 0; - -err_free_irq: - free_irq(card->irq, card); -err_release_region: - release_region(card->port, AVMB1_PORTLEN); -err_free: - b1_free_card(card); -err: - return retval; -} - -static char *b1isa_procinfo(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - - if (!cinfo) - return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", - cinfo->cardname[0] ? cinfo->cardname : "-", - cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", - cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0, - cinfo->card ? cinfo->card->revision : 0 - ); - return cinfo->infobuf; -} - -/* ------------------------------------------------------------- */ - -#define MAX_CARDS 4 -static struct pci_dev isa_dev[MAX_CARDS]; -static int io[MAX_CARDS]; -static int irq[MAX_CARDS]; - -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -MODULE_PARM_DESC(io, "I/O base address(es)"); -MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); - -static int b1isa_add_card(struct capi_driver *driver, capicardparams *data) -{ - int i; - - for (i = 0; i < MAX_CARDS; i++) { - if (isa_dev[i].resource[0].start) - continue; - - isa_dev[i].resource[0].start = data->port; - isa_dev[i].irq = data->irq; - - if (b1isa_probe(&isa_dev[i]) == 0) - return 0; - } - return -ENODEV; -} - -static struct capi_driver capi_driver_b1isa = { - .name = "b1isa", - .revision = "1.0", - .add_card = b1isa_add_card, -}; - -static int __init b1isa_init(void) -{ - char *p; - char rev[32]; - int i; - - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p - 1) = 0; - } else - strcpy(rev, "1.0"); - - for (i = 0; i < MAX_CARDS; i++) { - if (!io[i]) - break; - - isa_dev[i].resource[0].start = io[i]; - isa_dev[i].irq = irq[i]; - - if (b1isa_probe(&isa_dev[i]) != 0) - return -ENODEV; - } - - strlcpy(capi_driver_b1isa.revision, rev, 32); - register_capi_driver(&capi_driver_b1isa); - printk(KERN_INFO "b1isa: revision %s\n", rev); - - return 0; -} - -static void __exit b1isa_exit(void) -{ - int i; - - for (i = 0; i < MAX_CARDS; i++) { - if (isa_dev[i].resource[0].start) - b1isa_remove(&isa_dev[i]); - } - unregister_capi_driver(&capi_driver_b1isa); -} - -module_init(b1isa_init); -module_exit(b1isa_exit); diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c deleted file mode 100644 index b76b57a82c02..000000000000 --- a/drivers/isdn/hardware/avm/b1pci.c +++ /dev/null @@ -1,416 +0,0 @@ -/* $Id: b1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ - * - * Module for AVM B1 PCI-card. - * - * Copyright 1999 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/capi.h> -#include <asm/io.h> -#include <linux/init.h> -#include <linux/isdn/capicmd.h> -#include <linux/isdn/capiutil.h> -#include <linux/isdn/capilli.h> -#include "avmcard.h" - -/* ------------------------------------------------------------- */ - -static char *revision = "$Revision: 1.1.2.2 $"; - -/* ------------------------------------------------------------- */ - -static struct pci_device_id b1pci_pci_tbl[] = { - { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_B1, PCI_ANY_ID, PCI_ANY_ID }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(pci, b1pci_pci_tbl); -MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM B1 PCI card"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------- */ - -static char *b1pci_procinfo(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - - if (!cinfo) - return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", - cinfo->cardname[0] ? cinfo->cardname : "-", - cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", - cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0, - cinfo->card ? cinfo->card->revision : 0 - ); - return cinfo->infobuf; -} - -/* ------------------------------------------------------------- */ - -static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev) -{ - avmcard *card; - avmctrl_info *cinfo; - int retval; - - card = b1_alloc_card(1); - if (!card) { - printk(KERN_WARNING "b1pci: no memory.\n"); - retval = -ENOMEM; - goto err; - } - - cinfo = card->ctrlinfo; - sprintf(card->name, "b1pci-%x", p->port); - card->port = p->port; - card->irq = p->irq; - card->cardtype = avm_b1pci; - - if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { - printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n", - card->port, card->port + AVMB1_PORTLEN); - retval = -EBUSY; - goto err_free; - } - b1_reset(card->port); - retval = b1_detect(card->port, card->cardtype); - if (retval) { - printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n", - card->port, retval); - retval = -ENODEV; - goto err_release_region; - } - b1_reset(card->port); - b1_getrevision(card); - - retval = request_irq(card->irq, b1_interrupt, IRQF_SHARED, card->name, card); - if (retval) { - printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq); - retval = -EBUSY; - goto err_release_region; - } - - cinfo->capi_ctrl.driver_name = "b1pci"; - cinfo->capi_ctrl.driverdata = cinfo; - cinfo->capi_ctrl.register_appl = b1_register_appl; - cinfo->capi_ctrl.release_appl = b1_release_appl; - cinfo->capi_ctrl.send_message = b1_send_message; - cinfo->capi_ctrl.load_firmware = b1_load_firmware; - cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; - cinfo->capi_ctrl.procinfo = b1pci_procinfo; - cinfo->capi_ctrl.proc_show = b1_proc_show; - strcpy(cinfo->capi_ctrl.name, card->name); - cinfo->capi_ctrl.owner = THIS_MODULE; - - retval = attach_capi_ctr(&cinfo->capi_ctrl); - if (retval) { - printk(KERN_ERR "b1pci: attach controller failed.\n"); - goto err_free_irq; - } - - if (card->revision >= 4) { - printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, revision %d (no dma)\n", - card->port, card->irq, card->revision); - } else { - printk(KERN_INFO "b1pci: AVM B1 PCI at i/o %#x, irq %d, revision %d\n", - card->port, card->irq, card->revision); - } - - pci_set_drvdata(pdev, card); - return 0; - -err_free_irq: - free_irq(card->irq, card); -err_release_region: - release_region(card->port, AVMB1_PORTLEN); -err_free: - b1_free_card(card); -err: - return retval; -} - -static void b1pci_remove(struct pci_dev *pdev) -{ - avmcard *card = pci_get_drvdata(pdev); - avmctrl_info *cinfo = card->ctrlinfo; - unsigned int port = card->port; - - b1_reset(port); - b1_reset(port); - - detach_capi_ctr(&cinfo->capi_ctrl); - free_irq(card->irq, card); - release_region(card->port, AVMB1_PORTLEN); - b1_free_card(card); -} - -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 -/* ------------------------------------------------------------- */ - -static char *b1pciv4_procinfo(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - - if (!cinfo) - return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx r%d", - cinfo->cardname[0] ? cinfo->cardname : "-", - cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", - cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0, - cinfo->card ? cinfo->card->membase : 0, - cinfo->card ? cinfo->card->revision : 0 - ); - return cinfo->infobuf; -} - -/* ------------------------------------------------------------- */ - -static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev) -{ - avmcard *card; - avmctrl_info *cinfo; - int retval; - - card = b1_alloc_card(1); - if (!card) { - printk(KERN_WARNING "b1pci: no memory.\n"); - retval = -ENOMEM; - goto err; - } - - card->dma = avmcard_dma_alloc("b1pci", pdev, 2048 + 128, 2048 + 128); - if (!card->dma) { - printk(KERN_WARNING "b1pci: dma alloc.\n"); - retval = -ENOMEM; - goto err_free; - } - - cinfo = card->ctrlinfo; - sprintf(card->name, "b1pciv4-%x", p->port); - card->port = p->port; - card->irq = p->irq; - card->membase = p->membase; - card->cardtype = avm_b1pci; - - if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { - printk(KERN_WARNING "b1pci: ports 0x%03x-0x%03x in use.\n", - card->port, card->port + AVMB1_PORTLEN); - retval = -EBUSY; - goto err_free_dma; - } - - card->mbase = ioremap(card->membase, 64); - if (!card->mbase) { - printk(KERN_NOTICE "b1pci: can't remap memory at 0x%lx\n", - card->membase); - retval = -ENOMEM; - goto err_release_region; - } - - b1dma_reset(card); - - retval = b1pciv4_detect(card); - if (retval) { - printk(KERN_NOTICE "b1pci: NO card at 0x%x (%d)\n", - card->port, retval); - retval = -ENODEV; - goto err_unmap; - } - b1dma_reset(card); - b1_getrevision(card); - - retval = request_irq(card->irq, b1dma_interrupt, IRQF_SHARED, card->name, card); - if (retval) { - printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", - card->irq); - retval = -EBUSY; - goto err_unmap; - } - - cinfo->capi_ctrl.owner = THIS_MODULE; - cinfo->capi_ctrl.driver_name = "b1pciv4"; - cinfo->capi_ctrl.driverdata = cinfo; - cinfo->capi_ctrl.register_appl = b1dma_register_appl; - cinfo->capi_ctrl.release_appl = b1dma_release_appl; - cinfo->capi_ctrl.send_message = b1dma_send_message; - cinfo->capi_ctrl.load_firmware = b1dma_load_firmware; - cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr; - cinfo->capi_ctrl.procinfo = b1pciv4_procinfo; - cinfo->capi_ctrl.proc_show = b1dma_proc_show; - strcpy(cinfo->capi_ctrl.name, card->name); - - retval = attach_capi_ctr(&cinfo->capi_ctrl); - if (retval) { - printk(KERN_ERR "b1pci: attach controller failed.\n"); - goto err_free_irq; - } - card->cardnr = cinfo->capi_ctrl.cnr; - - printk(KERN_INFO "b1pci: AVM B1 PCI V4 at i/o %#x, irq %d, mem %#lx, revision %d (dma)\n", - card->port, card->irq, card->membase, card->revision); - - pci_set_drvdata(pdev, card); - return 0; - -err_free_irq: - free_irq(card->irq, card); -err_unmap: - iounmap(card->mbase); -err_release_region: - release_region(card->port, AVMB1_PORTLEN); -err_free_dma: - avmcard_dma_free(card->dma); -err_free: - b1_free_card(card); -err: - return retval; - -} - -static void b1pciv4_remove(struct pci_dev *pdev) -{ - avmcard *card = pci_get_drvdata(pdev); - avmctrl_info *cinfo = card->ctrlinfo; - - b1dma_reset(card); - - detach_capi_ctr(&cinfo->capi_ctrl); - free_irq(card->irq, card); - iounmap(card->mbase); - release_region(card->port, AVMB1_PORTLEN); - avmcard_dma_free(card->dma); - b1_free_card(card); -} - -#endif /* CONFIG_ISDN_DRV_AVMB1_B1PCIV4 */ - -static int b1pci_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct capicardparams param; - int retval; - - if (pci_enable_device(pdev) < 0) { - printk(KERN_ERR "b1pci: failed to enable AVM-B1\n"); - return -ENODEV; - } - param.irq = pdev->irq; - - if (pci_resource_start(pdev, 2)) { /* B1 PCI V4 */ -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 - pci_set_master(pdev); -#endif - param.membase = pci_resource_start(pdev, 0); - param.port = pci_resource_start(pdev, 2); - - printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 V4 at i/o %#x, irq %d, mem %#x\n", - param.port, param.irq, param.membase); -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 - retval = b1pciv4_probe(¶m, pdev); -#else - retval = b1pci_probe(¶m, pdev); -#endif - if (retval != 0) { - printk(KERN_ERR "b1pci: no AVM-B1 V4 at i/o %#x, irq %d, mem %#x detected\n", - param.port, param.irq, param.membase); - } - } else { - param.membase = 0; - param.port = pci_resource_start(pdev, 1); - - printk(KERN_INFO "b1pci: PCI BIOS reports AVM-B1 at i/o %#x, irq %d\n", - param.port, param.irq); - retval = b1pci_probe(¶m, pdev); - if (retval != 0) { - printk(KERN_ERR "b1pci: no AVM-B1 at i/o %#x, irq %d detected\n", - param.port, param.irq); - } - } - return retval; -} - -static void b1pci_pci_remove(struct pci_dev *pdev) -{ -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 - avmcard *card = pci_get_drvdata(pdev); - - if (card->dma) - b1pciv4_remove(pdev); - else - b1pci_remove(pdev); -#else - b1pci_remove(pdev); -#endif -} - -static struct pci_driver b1pci_pci_driver = { - .name = "b1pci", - .id_table = b1pci_pci_tbl, - .probe = b1pci_pci_probe, - .remove = b1pci_pci_remove, -}; - -static struct capi_driver capi_driver_b1pci = { - .name = "b1pci", - .revision = "1.0", -}; -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 -static struct capi_driver capi_driver_b1pciv4 = { - .name = "b1pciv4", - .revision = "1.0", -}; -#endif - -static int __init b1pci_init(void) -{ - char *p; - char rev[32]; - int err; - - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p - 1) = 0; - } else - strcpy(rev, "1.0"); - - - err = pci_register_driver(&b1pci_pci_driver); - if (!err) { - strlcpy(capi_driver_b1pci.revision, rev, 32); - register_capi_driver(&capi_driver_b1pci); -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 - strlcpy(capi_driver_b1pciv4.revision, rev, 32); - register_capi_driver(&capi_driver_b1pciv4); -#endif - printk(KERN_INFO "b1pci: revision %s\n", rev); - } - return err; -} - -static void __exit b1pci_exit(void) -{ - unregister_capi_driver(&capi_driver_b1pci); -#ifdef CONFIG_ISDN_DRV_AVMB1_B1PCIV4 - unregister_capi_driver(&capi_driver_b1pciv4); -#endif - pci_unregister_driver(&b1pci_pci_driver); -} - -module_init(b1pci_init); -module_exit(b1pci_exit); diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c deleted file mode 100644 index 3aca16e62902..000000000000 --- a/drivers/isdn/hardware/avm/b1pcmcia.c +++ /dev/null @@ -1,224 +0,0 @@ -/* $Id: b1pcmcia.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ - * - * Module for AVM B1/M1/M2 PCMCIA-card. - * - * Copyright 1999 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <asm/io.h> -#include <linux/capi.h> -#include <linux/b1pcmcia.h> -#include <linux/isdn/capicmd.h> -#include <linux/isdn/capiutil.h> -#include <linux/isdn/capilli.h> -#include "avmcard.h" - -/* ------------------------------------------------------------- */ - -static char *revision = "$Revision: 1.1.2.2 $"; - -/* ------------------------------------------------------------- */ - -MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM PCMCIA cards"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------- */ - -static void b1pcmcia_remove_ctr(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned int port = card->port; - - b1_reset(port); - b1_reset(port); - - detach_capi_ctr(ctrl); - free_irq(card->irq, card); - b1_free_card(card); -} - -/* ------------------------------------------------------------- */ - -static LIST_HEAD(cards); - -static char *b1pcmcia_procinfo(struct capi_ctr *ctrl); - -static int b1pcmcia_add_card(unsigned int port, unsigned irq, - enum avmcardtype cardtype) -{ - avmctrl_info *cinfo; - avmcard *card; - char *cardname; - int retval; - - card = b1_alloc_card(1); - if (!card) { - printk(KERN_WARNING "b1pcmcia: no memory.\n"); - retval = -ENOMEM; - goto err; - } - cinfo = card->ctrlinfo; - - switch (cardtype) { - case avm_m1: sprintf(card->name, "m1-%x", port); break; - case avm_m2: sprintf(card->name, "m2-%x", port); break; - default: sprintf(card->name, "b1pcmcia-%x", port); break; - } - card->port = port; - card->irq = irq; - card->cardtype = cardtype; - - retval = request_irq(card->irq, b1_interrupt, IRQF_SHARED, card->name, card); - if (retval) { - printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n", - card->irq); - retval = -EBUSY; - goto err_free; - } - b1_reset(card->port); - if ((retval = b1_detect(card->port, card->cardtype)) != 0) { - printk(KERN_NOTICE "b1pcmcia: NO card at 0x%x (%d)\n", - card->port, retval); - retval = -ENODEV; - goto err_free_irq; - } - b1_reset(card->port); - b1_getrevision(card); - - cinfo->capi_ctrl.owner = THIS_MODULE; - cinfo->capi_ctrl.driver_name = "b1pcmcia"; - cinfo->capi_ctrl.driverdata = cinfo; - cinfo->capi_ctrl.register_appl = b1_register_appl; - cinfo->capi_ctrl.release_appl = b1_release_appl; - cinfo->capi_ctrl.send_message = b1_send_message; - cinfo->capi_ctrl.load_firmware = b1_load_firmware; - cinfo->capi_ctrl.reset_ctr = b1_reset_ctr; - cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo; - cinfo->capi_ctrl.proc_show = b1_proc_show; - strcpy(cinfo->capi_ctrl.name, card->name); - - retval = attach_capi_ctr(&cinfo->capi_ctrl); - if (retval) { - printk(KERN_ERR "b1pcmcia: attach controller failed.\n"); - goto err_free_irq; - } - switch (cardtype) { - case avm_m1: cardname = "M1"; break; - case avm_m2: cardname = "M2"; break; - default: cardname = "B1 PCMCIA"; break; - } - - printk(KERN_INFO "b1pcmcia: AVM %s at i/o %#x, irq %d, revision %d\n", - cardname, card->port, card->irq, card->revision); - - list_add(&card->list, &cards); - return cinfo->capi_ctrl.cnr; - -err_free_irq: - free_irq(card->irq, card); -err_free: - b1_free_card(card); -err: - return retval; -} - -/* ------------------------------------------------------------- */ - -static char *b1pcmcia_procinfo(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - - if (!cinfo) - return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d r%d", - cinfo->cardname[0] ? cinfo->cardname : "-", - cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", - cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0, - cinfo->card ? cinfo->card->revision : 0 - ); - return cinfo->infobuf; -} - -/* ------------------------------------------------------------- */ - -int b1pcmcia_addcard_b1(unsigned int port, unsigned irq) -{ - return b1pcmcia_add_card(port, irq, avm_b1pcmcia); -} - -int b1pcmcia_addcard_m1(unsigned int port, unsigned irq) -{ - return b1pcmcia_add_card(port, irq, avm_m1); -} - -int b1pcmcia_addcard_m2(unsigned int port, unsigned irq) -{ - return b1pcmcia_add_card(port, irq, avm_m2); -} - -int b1pcmcia_delcard(unsigned int port, unsigned irq) -{ - struct list_head *l; - avmcard *card; - - list_for_each(l, &cards) { - card = list_entry(l, avmcard, list); - if (card->port == port && card->irq == irq) { - b1pcmcia_remove_ctr(&card->ctrlinfo[0].capi_ctrl); - return 0; - } - } - return -ESRCH; -} - -EXPORT_SYMBOL(b1pcmcia_addcard_b1); -EXPORT_SYMBOL(b1pcmcia_addcard_m1); -EXPORT_SYMBOL(b1pcmcia_addcard_m2); -EXPORT_SYMBOL(b1pcmcia_delcard); - -static struct capi_driver capi_driver_b1pcmcia = { - .name = "b1pcmcia", - .revision = "1.0", -}; - -static int __init b1pcmcia_init(void) -{ - char *p; - char rev[32]; - - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p - 1) = 0; - } else - strcpy(rev, "1.0"); - - strlcpy(capi_driver_b1pcmcia.revision, rev, 32); - register_capi_driver(&capi_driver_b1pcmcia); - printk(KERN_INFO "b1pci: revision %s\n", rev); - - return 0; -} - -static void __exit b1pcmcia_exit(void) -{ - unregister_capi_driver(&capi_driver_b1pcmcia); -} - -module_init(b1pcmcia_init); -module_exit(b1pcmcia_exit); diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c deleted file mode 100644 index ac72cd204c4d..000000000000 --- a/drivers/isdn/hardware/avm/c4.c +++ /dev/null @@ -1,1317 +0,0 @@ -/* $Id: c4.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ - * - * Module for AVM C4 & C2 card. - * - * Copyright 1999 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/capi.h> -#include <linux/kernelcapi.h> -#include <linux/init.h> -#include <linux/gfp.h> -#include <asm/io.h> -#include <linux/uaccess.h> -#include <linux/netdevice.h> -#include <linux/isdn/capicmd.h> -#include <linux/isdn/capiutil.h> -#include <linux/isdn/capilli.h> -#include "avmcard.h" - -#undef AVM_C4_DEBUG -#undef AVM_C4_POLLDEBUG - -/* ------------------------------------------------------------- */ - -static char *revision = "$Revision: 1.1.2.2 $"; - -/* ------------------------------------------------------------- */ - -static bool suppress_pollack; - -static const struct pci_device_id c4_pci_tbl[] = { - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C4, 0, 0, (unsigned long)4 }, - { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21285, PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_C2, 0, 0, (unsigned long)2 }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(pci, c4_pci_tbl); -MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM C2/C4 cards"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); -module_param(suppress_pollack, bool, 0); - -/* ------------------------------------------------------------- */ - -static void c4_dispatch_tx(avmcard *card); - -/* ------------------------------------------------------------- */ - -#define DC21285_DRAM_A0MR 0x40000000 -#define DC21285_DRAM_A1MR 0x40004000 -#define DC21285_DRAM_A2MR 0x40008000 -#define DC21285_DRAM_A3MR 0x4000C000 - -#define CAS_OFFSET 0x88 - -#define DC21285_ARMCSR_BASE 0x42000000 - -#define PCI_OUT_INT_STATUS 0x30 -#define PCI_OUT_INT_MASK 0x34 -#define MAILBOX_0 0x50 -#define MAILBOX_1 0x54 -#define MAILBOX_2 0x58 -#define MAILBOX_3 0x5C -#define DOORBELL 0x60 -#define DOORBELL_SETUP 0x64 - -#define CHAN_1_CONTROL 0x90 -#define CHAN_2_CONTROL 0xB0 -#define DRAM_TIMING 0x10C -#define DRAM_ADDR_SIZE_0 0x110 -#define DRAM_ADDR_SIZE_1 0x114 -#define DRAM_ADDR_SIZE_2 0x118 -#define DRAM_ADDR_SIZE_3 0x11C -#define SA_CONTROL 0x13C -#define XBUS_CYCLE 0x148 -#define XBUS_STROBE 0x14C -#define DBELL_PCI_MASK 0x150 -#define DBELL_SA_MASK 0x154 - -#define SDRAM_SIZE 0x1000000 - -/* ------------------------------------------------------------- */ - -#define MBOX_PEEK_POKE MAILBOX_0 - -#define DBELL_ADDR 0x01 -#define DBELL_DATA 0x02 -#define DBELL_RNWR 0x40 -#define DBELL_INIT 0x80 - -/* ------------------------------------------------------------- */ - -#define MBOX_UP_ADDR MAILBOX_0 -#define MBOX_UP_LEN MAILBOX_1 -#define MBOX_DOWN_ADDR MAILBOX_2 -#define MBOX_DOWN_LEN MAILBOX_3 - -#define DBELL_UP_HOST 0x00000100 -#define DBELL_UP_ARM 0x00000200 -#define DBELL_DOWN_HOST 0x00000400 -#define DBELL_DOWN_ARM 0x00000800 -#define DBELL_RESET_HOST 0x40000000 -#define DBELL_RESET_ARM 0x80000000 - -/* ------------------------------------------------------------- */ - -#define DRAM_TIMING_DEF 0x001A01A5 -#define DRAM_AD_SZ_DEF0 0x00000045 -#define DRAM_AD_SZ_NULL 0x00000000 - -#define SA_CTL_ALLRIGHT 0x64AA0271 - -#define INIT_XBUS_CYCLE 0x100016DB -#define INIT_XBUS_STROBE 0xF1F1F1F1 - -/* ------------------------------------------------------------- */ - -#define RESET_TIMEOUT (15 * HZ) /* 15 sec */ -#define PEEK_POKE_TIMEOUT (HZ / 10) /* 0.1 sec */ - -/* ------------------------------------------------------------- */ - -#define c4outmeml(addr, value) writel(value, addr) -#define c4inmeml(addr) readl(addr) -#define c4outmemw(addr, value) writew(value, addr) -#define c4inmemw(addr) readw(addr) -#define c4outmemb(addr, value) writeb(value, addr) -#define c4inmemb(addr) readb(addr) - -/* ------------------------------------------------------------- */ - -static inline int wait_for_doorbell(avmcard *card, unsigned long t) -{ - unsigned long stop; - - stop = jiffies + t; - while (c4inmeml(card->mbase + DOORBELL) != 0xffffffff) { - if (!time_before(jiffies, stop)) - return -1; - mb(); - } - return 0; -} - -static int c4_poke(avmcard *card, unsigned long off, unsigned long value) -{ - - if (wait_for_doorbell(card, HZ / 10) < 0) - return -1; - - c4outmeml(card->mbase + MBOX_PEEK_POKE, off); - c4outmeml(card->mbase + DOORBELL, DBELL_ADDR); - - if (wait_for_doorbell(card, HZ / 10) < 0) - return -1; - - c4outmeml(card->mbase + MBOX_PEEK_POKE, value); - c4outmeml(card->mbase + DOORBELL, DBELL_DATA | DBELL_ADDR); - - return 0; -} - -static int c4_peek(avmcard *card, unsigned long off, unsigned long *valuep) -{ - if (wait_for_doorbell(card, HZ / 10) < 0) - return -1; - - c4outmeml(card->mbase + MBOX_PEEK_POKE, off); - c4outmeml(card->mbase + DOORBELL, DBELL_RNWR | DBELL_ADDR); - - if (wait_for_doorbell(card, HZ / 10) < 0) - return -1; - - *valuep = c4inmeml(card->mbase + MBOX_PEEK_POKE); - - return 0; -} - -/* ------------------------------------------------------------- */ - -static int c4_load_t4file(avmcard *card, capiloaddatapart *t4file) -{ - u32 val; - unsigned char *dp; - u_int left; - u32 loadoff = 0; - - dp = t4file->data; - left = t4file->len; - while (left >= sizeof(u32)) { - if (t4file->user) { - if (copy_from_user(&val, dp, sizeof(val))) - return -EFAULT; - } else { - memcpy(&val, dp, sizeof(val)); - } - if (c4_poke(card, loadoff, val)) { - printk(KERN_ERR "%s: corrupted firmware file ?\n", - card->name); - return -EIO; - } - left -= sizeof(u32); - dp += sizeof(u32); - loadoff += sizeof(u32); - } - if (left) { - val = 0; - if (t4file->user) { - if (copy_from_user(&val, dp, left)) - return -EFAULT; - } else { - memcpy(&val, dp, left); - } - if (c4_poke(card, loadoff, val)) { - printk(KERN_ERR "%s: corrupted firmware file ?\n", - card->name); - return -EIO; - } - } - return 0; -} - -/* ------------------------------------------------------------- */ - -static inline void _put_byte(void **pp, u8 val) -{ - u8 *s = *pp; - *s++ = val; - *pp = s; -} - -static inline void _put_word(void **pp, u32 val) -{ - u8 *s = *pp; - *s++ = val & 0xff; - *s++ = (val >> 8) & 0xff; - *s++ = (val >> 16) & 0xff; - *s++ = (val >> 24) & 0xff; - *pp = s; -} - -static inline void _put_slice(void **pp, unsigned char *dp, unsigned int len) -{ - unsigned i = len; - _put_word(pp, i); - while (i-- > 0) - _put_byte(pp, *dp++); -} - -static inline u8 _get_byte(void **pp) -{ - u8 *s = *pp; - u8 val; - val = *s++; - *pp = s; - return val; -} - -static inline u32 _get_word(void **pp) -{ - u8 *s = *pp; - u32 val; - val = *s++; - val |= (*s++ << 8); - val |= (*s++ << 16); - val |= (*s++ << 24); - *pp = s; - return val; -} - -static inline u32 _get_slice(void **pp, unsigned char *dp) -{ - unsigned int len, i; - - len = i = _get_word(pp); - while (i-- > 0) *dp++ = _get_byte(pp); - return len; -} - -/* ------------------------------------------------------------- */ - -static void c4_reset(avmcard *card) -{ - unsigned long stop; - - c4outmeml(card->mbase + DOORBELL, DBELL_RESET_ARM); - - stop = jiffies + HZ * 10; - while (c4inmeml(card->mbase + DOORBELL) != 0xffffffff) { - if (!time_before(jiffies, stop)) - return; - c4outmeml(card->mbase + DOORBELL, DBELL_ADDR); - mb(); - } - - c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0); - c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0); -} - -/* ------------------------------------------------------------- */ - -static int c4_detect(avmcard *card) -{ - unsigned long stop, dummy; - - c4outmeml(card->mbase + PCI_OUT_INT_MASK, 0x0c); - if (c4inmeml(card->mbase + PCI_OUT_INT_MASK) != 0x0c) - return 1; - - c4outmeml(card->mbase + DOORBELL, DBELL_RESET_ARM); - - stop = jiffies + HZ * 10; - while (c4inmeml(card->mbase + DOORBELL) != 0xffffffff) { - if (!time_before(jiffies, stop)) - return 2; - c4outmeml(card->mbase + DOORBELL, DBELL_ADDR); - mb(); - } - - c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0); - c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0); - - c4outmeml(card->mbase + MAILBOX_0, 0x55aa55aa); - if (c4inmeml(card->mbase + MAILBOX_0) != 0x55aa55aa) return 3; - - c4outmeml(card->mbase + MAILBOX_0, 0xaa55aa55); - if (c4inmeml(card->mbase + MAILBOX_0) != 0xaa55aa55) return 4; - - if (c4_poke(card, DC21285_ARMCSR_BASE + DBELL_SA_MASK, 0)) return 5; - if (c4_poke(card, DC21285_ARMCSR_BASE + DBELL_PCI_MASK, 0)) return 6; - if (c4_poke(card, DC21285_ARMCSR_BASE + SA_CONTROL, SA_CTL_ALLRIGHT)) - return 7; - if (c4_poke(card, DC21285_ARMCSR_BASE + XBUS_CYCLE, INIT_XBUS_CYCLE)) - return 8; - if (c4_poke(card, DC21285_ARMCSR_BASE + XBUS_STROBE, INIT_XBUS_STROBE)) - return 8; - if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_TIMING, 0)) return 9; - - mdelay(1); - - if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10; - if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11; - if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12; - if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13; - - if (c4_poke(card, DC21285_DRAM_A0MR + CAS_OFFSET, 0)) return 14; - if (c4_poke(card, DC21285_DRAM_A1MR + CAS_OFFSET, 0)) return 15; - if (c4_poke(card, DC21285_DRAM_A2MR + CAS_OFFSET, 0)) return 16; - if (c4_poke(card, DC21285_DRAM_A3MR + CAS_OFFSET, 0)) return 17; - - mdelay(1); - - if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_TIMING, DRAM_TIMING_DEF)) - return 18; - - if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_ADDR_SIZE_0, DRAM_AD_SZ_DEF0)) - return 19; - if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_ADDR_SIZE_1, DRAM_AD_SZ_NULL)) - return 20; - if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_ADDR_SIZE_2, DRAM_AD_SZ_NULL)) - return 21; - if (c4_poke(card, DC21285_ARMCSR_BASE + DRAM_ADDR_SIZE_3, DRAM_AD_SZ_NULL)) - return 22; - - /* Transputer test */ - - if (c4_poke(card, 0x000000, 0x11111111) - || c4_poke(card, 0x400000, 0x22222222) - || c4_poke(card, 0x800000, 0x33333333) - || c4_poke(card, 0xC00000, 0x44444444)) - return 23; - - if (c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111 - || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222 - || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333 - || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444) - return 24; - - if (c4_poke(card, 0x000000, 0x55555555) - || c4_poke(card, 0x400000, 0x66666666) - || c4_poke(card, 0x800000, 0x77777777) - || c4_poke(card, 0xC00000, 0x88888888)) - return 25; - - if (c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555 - || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666 - || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777 - || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888) - return 26; - - return 0; -} - -/* ------------------------------------------------------------- */ - -static void c4_dispatch_tx(avmcard *card) -{ - avmcard_dmainfo *dma = card->dma; - struct sk_buff *skb; - u8 cmd, subcmd; - u16 len; - u32 txlen; - void *p; - - - if (card->csr & DBELL_DOWN_ARM) { /* tx busy */ - return; - } - - skb = skb_dequeue(&dma->send_queue); - if (!skb) { -#ifdef AVM_C4_DEBUG - printk(KERN_DEBUG "%s: tx underrun\n", card->name); -#endif - return; - } - - len = CAPIMSG_LEN(skb->data); - - if (len) { - cmd = CAPIMSG_COMMAND(skb->data); - subcmd = CAPIMSG_SUBCOMMAND(skb->data); - - p = dma->sendbuf.dmabuf; - - if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { - u16 dlen = CAPIMSG_DATALEN(skb->data); - _put_byte(&p, SEND_DATA_B3_REQ); - _put_slice(&p, skb->data, len); - _put_slice(&p, skb->data + len, dlen); - } else { - _put_byte(&p, SEND_MESSAGE); - _put_slice(&p, skb->data, len); - } - txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf; -#ifdef AVM_C4_DEBUG - printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen); -#endif - } else { - txlen = skb->len - 2; -#ifdef AVM_C4_POLLDEBUG - if (skb->data[2] == SEND_POLLACK) - printk(KERN_INFO "%s: ack to c4\n", card->name); -#endif -#ifdef AVM_C4_DEBUG - printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n", - card->name, skb->data[2], txlen); -#endif - skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf, - skb->len - 2); - } - txlen = (txlen + 3) & ~3; - - c4outmeml(card->mbase + MBOX_DOWN_ADDR, dma->sendbuf.dmaaddr); - c4outmeml(card->mbase + MBOX_DOWN_LEN, txlen); - - card->csr |= DBELL_DOWN_ARM; - - c4outmeml(card->mbase + DOORBELL, DBELL_DOWN_ARM); - - dev_kfree_skb_any(skb); -} - -/* ------------------------------------------------------------- */ - -static void queue_pollack(avmcard *card) -{ - struct sk_buff *skb; - void *p; - - skb = alloc_skb(3, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost poll ack\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_POLLACK); - skb_put(skb, (u8 *)p - (u8 *)skb->data); - - skb_queue_tail(&card->dma->send_queue, skb); - c4_dispatch_tx(card); -} - -/* ------------------------------------------------------------- */ - -static void c4_handle_rx(avmcard *card) -{ - avmcard_dmainfo *dma = card->dma; - struct capi_ctr *ctrl; - avmctrl_info *cinfo; - struct sk_buff *skb; - void *p = dma->recvbuf.dmabuf; - u32 ApplId, MsgLen, DataB3Len, NCCI, WindowSize; - u8 b1cmd = _get_byte(&p); - u32 cidx; - - -#ifdef AVM_C4_DEBUG - printk(KERN_DEBUG "%s: rx 0x%x len=%lu\n", card->name, - b1cmd, (unsigned long)dma->recvlen); -#endif - - switch (b1cmd) { - case RECEIVE_DATA_B3_IND: - - ApplId = (unsigned) _get_word(&p); - MsgLen = _get_slice(&p, card->msgbuf); - DataB3Len = _get_slice(&p, card->databuf); - cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr; - if (cidx >= card->nlogcontr) cidx = 0; - ctrl = &card->ctrlinfo[cidx].capi_ctrl; - - if (MsgLen < 30) { /* not CAPI 64Bit */ - memset(card->msgbuf + MsgLen, 0, 30 - MsgLen); - MsgLen = 30; - CAPIMSG_SETLEN(card->msgbuf, 30); - } - if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) { - printk(KERN_ERR "%s: incoming packet dropped\n", - card->name); - } else { - skb_put_data(skb, card->msgbuf, MsgLen); - skb_put_data(skb, card->databuf, DataB3Len); - capi_ctr_handle_message(ctrl, ApplId, skb); - } - break; - - case RECEIVE_MESSAGE: - - ApplId = (unsigned) _get_word(&p); - MsgLen = _get_slice(&p, card->msgbuf); - cidx = CAPIMSG_CONTROLLER(card->msgbuf)-card->cardnr; - if (cidx >= card->nlogcontr) cidx = 0; - cinfo = &card->ctrlinfo[cidx]; - ctrl = &card->ctrlinfo[cidx].capi_ctrl; - - if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { - printk(KERN_ERR "%s: incoming packet dropped\n", - card->name); - } else { - skb_put_data(skb, card->msgbuf, MsgLen); - if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_CONF) - capilib_data_b3_conf(&cinfo->ncci_head, ApplId, - CAPIMSG_NCCI(skb->data), - CAPIMSG_MSGID(skb->data)); - - capi_ctr_handle_message(ctrl, ApplId, skb); - } - break; - - case RECEIVE_NEW_NCCI: - - ApplId = _get_word(&p); - NCCI = _get_word(&p); - WindowSize = _get_word(&p); - cidx = (NCCI & 0x7f) - card->cardnr; - if (cidx >= card->nlogcontr) cidx = 0; - - capilib_new_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI, WindowSize); - - break; - - case RECEIVE_FREE_NCCI: - - ApplId = _get_word(&p); - NCCI = _get_word(&p); - - if (NCCI != 0xffffffff) { - cidx = (NCCI & 0x7f) - card->cardnr; - if (cidx >= card->nlogcontr) cidx = 0; - capilib_free_ncci(&card->ctrlinfo[cidx].ncci_head, ApplId, NCCI); - } - break; - - case RECEIVE_START: -#ifdef AVM_C4_POLLDEBUG - printk(KERN_INFO "%s: poll from c4\n", card->name); -#endif - if (!suppress_pollack) - queue_pollack(card); - for (cidx = 0; cidx < card->nr_controllers; cidx++) { - ctrl = &card->ctrlinfo[cidx].capi_ctrl; - capi_ctr_resume_output(ctrl); - } - break; - - case RECEIVE_STOP: - for (cidx = 0; cidx < card->nr_controllers; cidx++) { - ctrl = &card->ctrlinfo[cidx].capi_ctrl; - capi_ctr_suspend_output(ctrl); - } - break; - - case RECEIVE_INIT: - - cidx = card->nlogcontr; - if (cidx >= card->nr_controllers) { - printk(KERN_ERR "%s: card with %d controllers ??\n", - card->name, cidx + 1); - break; - } - card->nlogcontr++; - cinfo = &card->ctrlinfo[cidx]; - ctrl = &cinfo->capi_ctrl; - cinfo->versionlen = _get_slice(&p, cinfo->versionbuf); - b1_parse_version(cinfo); - printk(KERN_INFO "%s: %s-card (%s) now active\n", - card->name, - cinfo->version[VER_CARDTYPE], - cinfo->version[VER_DRIVER]); - capi_ctr_ready(&cinfo->capi_ctrl); - break; - - case RECEIVE_TASK_READY: - ApplId = (unsigned) _get_word(&p); - MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen] = 0; - while (MsgLen > 0 - && (card->msgbuf[MsgLen - 1] == '\n' - || card->msgbuf[MsgLen - 1] == '\r')) { - card->msgbuf[MsgLen - 1] = 0; - MsgLen--; - } - printk(KERN_INFO "%s: task %d \"%s\" ready.\n", - card->name, ApplId, card->msgbuf); - break; - - case RECEIVE_DEBUGMSG: - MsgLen = _get_slice(&p, card->msgbuf); - card->msgbuf[MsgLen] = 0; - while (MsgLen > 0 - && (card->msgbuf[MsgLen - 1] == '\n' - || card->msgbuf[MsgLen - 1] == '\r')) { - card->msgbuf[MsgLen - 1] = 0; - MsgLen--; - } - printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); - break; - - default: - printk(KERN_ERR "%s: c4_interrupt: 0x%x ???\n", - card->name, b1cmd); - return; - } -} - -/* ------------------------------------------------------------- */ - -static irqreturn_t c4_handle_interrupt(avmcard *card) -{ - unsigned long flags; - u32 status; - - spin_lock_irqsave(&card->lock, flags); - status = c4inmeml(card->mbase + DOORBELL); - - if (status & DBELL_RESET_HOST) { - u_int i; - c4outmeml(card->mbase + PCI_OUT_INT_MASK, 0x0c); - spin_unlock_irqrestore(&card->lock, flags); - if (card->nlogcontr == 0) - return IRQ_HANDLED; - printk(KERN_ERR "%s: unexpected reset\n", card->name); - for (i = 0; i < card->nr_controllers; i++) { - avmctrl_info *cinfo = &card->ctrlinfo[i]; - memset(cinfo->version, 0, sizeof(cinfo->version)); - spin_lock_irqsave(&card->lock, flags); - capilib_release(&cinfo->ncci_head); - spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_down(&cinfo->capi_ctrl); - } - card->nlogcontr = 0; - return IRQ_HANDLED; - } - - status &= (DBELL_UP_HOST | DBELL_DOWN_HOST); - if (!status) { - spin_unlock_irqrestore(&card->lock, flags); - return IRQ_HANDLED; - } - c4outmeml(card->mbase + DOORBELL, status); - - if ((status & DBELL_UP_HOST) != 0) { - card->dma->recvlen = c4inmeml(card->mbase + MBOX_UP_LEN); - c4outmeml(card->mbase + MBOX_UP_LEN, 0); - c4_handle_rx(card); - card->dma->recvlen = 0; - c4outmeml(card->mbase + MBOX_UP_LEN, card->dma->recvbuf.size); - c4outmeml(card->mbase + DOORBELL, DBELL_UP_ARM); - } - - if ((status & DBELL_DOWN_HOST) != 0) { - card->csr &= ~DBELL_DOWN_ARM; - c4_dispatch_tx(card); - } else if (card->csr & DBELL_DOWN_HOST) { - if (c4inmeml(card->mbase + MBOX_DOWN_LEN) == 0) { - card->csr &= ~DBELL_DOWN_ARM; - c4_dispatch_tx(card); - } - } - spin_unlock_irqrestore(&card->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t c4_interrupt(int interrupt, void *devptr) -{ - avmcard *card = devptr; - - return c4_handle_interrupt(card); -} - -/* ------------------------------------------------------------- */ - -static void c4_send_init(avmcard *card) -{ - struct sk_buff *skb; - void *p; - unsigned long flags; - - skb = alloc_skb(15, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost register appl.\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_INIT); - _put_word(&p, CAPI_MAXAPPL); - _put_word(&p, AVM_NCCI_PER_CHANNEL * 30); - _put_word(&p, card->cardnr - 1); - skb_put(skb, (u8 *)p - (u8 *)skb->data); - - skb_queue_tail(&card->dma->send_queue, skb); - spin_lock_irqsave(&card->lock, flags); - c4_dispatch_tx(card); - spin_unlock_irqrestore(&card->lock, flags); -} - -static int queue_sendconfigword(avmcard *card, u32 val) -{ - struct sk_buff *skb; - unsigned long flags; - void *p; - - skb = alloc_skb(3 + 4, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, send config\n", - card->name); - return -ENOMEM; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_CONFIG); - _put_word(&p, val); - skb_put(skb, (u8 *)p - (u8 *)skb->data); - - skb_queue_tail(&card->dma->send_queue, skb); - spin_lock_irqsave(&card->lock, flags); - c4_dispatch_tx(card); - spin_unlock_irqrestore(&card->lock, flags); - return 0; -} - -static int queue_sendconfig(avmcard *card, char cval[4]) -{ - struct sk_buff *skb; - unsigned long flags; - void *p; - - skb = alloc_skb(3 + 4, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, send config\n", - card->name); - return -ENOMEM; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_CONFIG); - _put_byte(&p, cval[0]); - _put_byte(&p, cval[1]); - _put_byte(&p, cval[2]); - _put_byte(&p, cval[3]); - skb_put(skb, (u8 *)p - (u8 *)skb->data); - - skb_queue_tail(&card->dma->send_queue, skb); - - spin_lock_irqsave(&card->lock, flags); - c4_dispatch_tx(card); - spin_unlock_irqrestore(&card->lock, flags); - return 0; -} - -static int c4_send_config(avmcard *card, capiloaddatapart *config) -{ - u8 val[4]; - unsigned char *dp; - u_int left; - int retval; - - if ((retval = queue_sendconfigword(card, 1)) != 0) - return retval; - if ((retval = queue_sendconfigword(card, config->len)) != 0) - return retval; - - dp = config->data; - left = config->len; - while (left >= sizeof(u32)) { - if (config->user) { - if (copy_from_user(val, dp, sizeof(val))) - return -EFAULT; - } else { - memcpy(val, dp, sizeof(val)); - } - if ((retval = queue_sendconfig(card, val)) != 0) - return retval; - left -= sizeof(val); - dp += sizeof(val); - } - if (left) { - memset(val, 0, sizeof(val)); - if (config->user) { - if (copy_from_user(&val, dp, left)) - return -EFAULT; - } else { - memcpy(&val, dp, left); - } - if ((retval = queue_sendconfig(card, val)) != 0) - return retval; - } - - return 0; -} - -static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - int retval; - - if ((retval = c4_load_t4file(card, &data->firmware))) { - printk(KERN_ERR "%s: failed to load t4file!!\n", - card->name); - c4_reset(card); - return retval; - } - - card->csr = 0; - c4outmeml(card->mbase + MBOX_UP_LEN, 0); - c4outmeml(card->mbase + MBOX_DOWN_LEN, 0); - c4outmeml(card->mbase + DOORBELL, DBELL_INIT); - mdelay(1); - c4outmeml(card->mbase + DOORBELL, - DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST); - - c4outmeml(card->mbase + PCI_OUT_INT_MASK, 0x08); - - card->dma->recvlen = 0; - c4outmeml(card->mbase + MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr); - c4outmeml(card->mbase + MBOX_UP_LEN, card->dma->recvbuf.size); - c4outmeml(card->mbase + DOORBELL, DBELL_UP_ARM); - - if (data->configuration.len > 0 && data->configuration.data) { - retval = c4_send_config(card, &data->configuration); - if (retval) { - printk(KERN_ERR "%s: failed to set config!!\n", - card->name); - c4_reset(card); - return retval; - } - } - - c4_send_init(card); - - return 0; -} - - -static void c4_reset_ctr(struct capi_ctr *ctrl) -{ - avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card; - avmctrl_info *cinfo; - u_int i; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - - c4_reset(card); - - spin_unlock_irqrestore(&card->lock, flags); - - for (i = 0; i < card->nr_controllers; i++) { - cinfo = &card->ctrlinfo[i]; - memset(cinfo->version, 0, sizeof(cinfo->version)); - capi_ctr_down(&cinfo->capi_ctrl); - } - card->nlogcontr = 0; -} - -static void c4_remove(struct pci_dev *pdev) -{ - avmcard *card = pci_get_drvdata(pdev); - avmctrl_info *cinfo; - u_int i; - - if (!card) - return; - - c4_reset(card); - - for (i = 0; i < card->nr_controllers; i++) { - cinfo = &card->ctrlinfo[i]; - detach_capi_ctr(&cinfo->capi_ctrl); - } - - free_irq(card->irq, card); - iounmap(card->mbase); - release_region(card->port, AVMB1_PORTLEN); - avmcard_dma_free(card->dma); - pci_set_drvdata(pdev, NULL); - b1_free_card(card); -} - -/* ------------------------------------------------------------- */ - - -static void c4_register_appl(struct capi_ctr *ctrl, - u16 appl, - capi_register_params *rp) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - struct sk_buff *skb; - int want = rp->level3cnt; - unsigned long flags; - int nconn; - void *p; - - if (ctrl->cnr == card->cardnr) { - - if (want > 0) nconn = want; - else nconn = ctrl->profile.nbchannel * 4 * -want; - if (nconn == 0) nconn = ctrl->profile.nbchannel * 4; - - skb = alloc_skb(23, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost register appl.\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_REGISTER); - _put_word(&p, appl); - _put_word(&p, 1024 * (nconn + 1)); - _put_word(&p, nconn); - _put_word(&p, rp->datablkcnt); - _put_word(&p, rp->datablklen); - skb_put(skb, (u8 *)p - (u8 *)skb->data); - - skb_queue_tail(&card->dma->send_queue, skb); - - spin_lock_irqsave(&card->lock, flags); - c4_dispatch_tx(card); - spin_unlock_irqrestore(&card->lock, flags); - } -} - -/* ------------------------------------------------------------- */ - -static void c4_release_appl(struct capi_ctr *ctrl, u16 appl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned long flags; - struct sk_buff *skb; - void *p; - - spin_lock_irqsave(&card->lock, flags); - capilib_release_appl(&cinfo->ncci_head, appl); - spin_unlock_irqrestore(&card->lock, flags); - - if (ctrl->cnr == card->cardnr) { - skb = alloc_skb(7, GFP_ATOMIC); - if (!skb) { - printk(KERN_CRIT "%s: no memory, lost release appl.\n", - card->name); - return; - } - p = skb->data; - _put_byte(&p, 0); - _put_byte(&p, 0); - _put_byte(&p, SEND_RELEASE); - _put_word(&p, appl); - - skb_put(skb, (u8 *)p - (u8 *)skb->data); - skb_queue_tail(&card->dma->send_queue, skb); - spin_lock_irqsave(&card->lock, flags); - c4_dispatch_tx(card); - spin_unlock_irqrestore(&card->lock, flags); - } -} - -/* ------------------------------------------------------------- */ - - -static u16 c4_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - u16 retval = CAPI_NOERROR; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3_REQ) { - retval = capilib_data_b3_req(&cinfo->ncci_head, - CAPIMSG_APPID(skb->data), - CAPIMSG_NCCI(skb->data), - CAPIMSG_MSGID(skb->data)); - } - if (retval == CAPI_NOERROR) { - skb_queue_tail(&card->dma->send_queue, skb); - c4_dispatch_tx(card); - } - spin_unlock_irqrestore(&card->lock, flags); - return retval; -} - -/* ------------------------------------------------------------- */ - -static char *c4_procinfo(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - - if (!cinfo) - return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx", - cinfo->cardname[0] ? cinfo->cardname : "-", - cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", - cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0, - cinfo->card ? cinfo->card->membase : 0 - ); - return cinfo->infobuf; -} - -static int c4_proc_show(struct seq_file *m, void *v) -{ - struct capi_ctr *ctrl = m->private; - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - u8 flag; - char *s; - - seq_printf(m, "%-16s %s\n", "name", card->name); - seq_printf(m, "%-16s 0x%x\n", "io", card->port); - seq_printf(m, "%-16s %d\n", "irq", card->irq); - seq_printf(m, "%-16s 0x%lx\n", "membase", card->membase); - switch (card->cardtype) { - case avm_b1isa: s = "B1 ISA"; break; - case avm_b1pci: s = "B1 PCI"; break; - case avm_b1pcmcia: s = "B1 PCMCIA"; break; - case avm_m1: s = "M1"; break; - case avm_m2: s = "M2"; break; - case avm_t1isa: s = "T1 ISA (HEMA)"; break; - case avm_t1pci: s = "T1 PCI"; break; - case avm_c4: s = "C4"; break; - case avm_c2: s = "C2"; break; - default: s = "???"; break; - } - seq_printf(m, "%-16s %s\n", "type", s); - if ((s = cinfo->version[VER_DRIVER]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_serial", s); - - if (card->cardtype != avm_m1) { - flag = ((u8 *)(ctrl->profile.manu))[3]; - if (flag) - seq_printf(m, "%-16s%s%s%s%s%s%s%s\n", - "protocol", - (flag & 0x01) ? " DSS1" : "", - (flag & 0x02) ? " CT1" : "", - (flag & 0x04) ? " VN3" : "", - (flag & 0x08) ? " NI1" : "", - (flag & 0x10) ? " AUSTEL" : "", - (flag & 0x20) ? " ESS" : "", - (flag & 0x40) ? " 1TR6" : "" - ); - } - if (card->cardtype != avm_m1) { - flag = ((u8 *)(ctrl->profile.manu))[5]; - if (flag) - seq_printf(m, "%-16s%s%s%s%s\n", - "linetype", - (flag & 0x01) ? " point to point" : "", - (flag & 0x02) ? " point to multipoint" : "", - (flag & 0x08) ? " leased line without D-channel" : "", - (flag & 0x04) ? " leased line with D-channel" : "" - ); - } - seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname); - - return 0; -} - -/* ------------------------------------------------------------- */ - -static int c4_add_card(struct capicardparams *p, struct pci_dev *dev, - int nr_controllers) -{ - avmcard *card; - avmctrl_info *cinfo; - int retval; - int i; - - card = b1_alloc_card(nr_controllers); - if (!card) { - printk(KERN_WARNING "c4: no memory.\n"); - retval = -ENOMEM; - goto err; - } - card->dma = avmcard_dma_alloc("c4", dev, 2048 + 128, 2048 + 128); - if (!card->dma) { - printk(KERN_WARNING "c4: no memory.\n"); - retval = -ENOMEM; - goto err_free; - } - - sprintf(card->name, "c%d-%x", nr_controllers, p->port); - card->port = p->port; - card->irq = p->irq; - card->membase = p->membase; - card->cardtype = (nr_controllers == 4) ? avm_c4 : avm_c2; - - if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { - printk(KERN_WARNING "c4: ports 0x%03x-0x%03x in use.\n", - card->port, card->port + AVMB1_PORTLEN); - retval = -EBUSY; - goto err_free_dma; - } - - card->mbase = ioremap(card->membase, 128); - if (card->mbase == NULL) { - printk(KERN_NOTICE "c4: can't remap memory at 0x%lx\n", - card->membase); - retval = -EIO; - goto err_release_region; - } - - retval = c4_detect(card); - if (retval != 0) { - printk(KERN_NOTICE "c4: NO card at 0x%x error(%d)\n", - card->port, retval); - retval = -EIO; - goto err_unmap; - } - c4_reset(card); - - retval = request_irq(card->irq, c4_interrupt, IRQF_SHARED, card->name, card); - if (retval) { - printk(KERN_ERR "c4: unable to get IRQ %d.\n", card->irq); - retval = -EBUSY; - goto err_unmap; - } - - for (i = 0; i < nr_controllers; i++) { - cinfo = &card->ctrlinfo[i]; - cinfo->capi_ctrl.owner = THIS_MODULE; - cinfo->capi_ctrl.driver_name = "c4"; - cinfo->capi_ctrl.driverdata = cinfo; - cinfo->capi_ctrl.register_appl = c4_register_appl; - cinfo->capi_ctrl.release_appl = c4_release_appl; - cinfo->capi_ctrl.send_message = c4_send_message; - cinfo->capi_ctrl.load_firmware = c4_load_firmware; - cinfo->capi_ctrl.reset_ctr = c4_reset_ctr; - cinfo->capi_ctrl.procinfo = c4_procinfo; - cinfo->capi_ctrl.proc_show = c4_proc_show; - strcpy(cinfo->capi_ctrl.name, card->name); - - retval = attach_capi_ctr(&cinfo->capi_ctrl); - if (retval) { - printk(KERN_ERR "c4: attach controller failed (%d).\n", i); - for (i--; i >= 0; i--) { - cinfo = &card->ctrlinfo[i]; - detach_capi_ctr(&cinfo->capi_ctrl); - } - goto err_free_irq; - } - if (i == 0) - card->cardnr = cinfo->capi_ctrl.cnr; - } - - printk(KERN_INFO "c4: AVM C%d at i/o %#x, irq %d, mem %#lx\n", - nr_controllers, card->port, card->irq, - card->membase); - pci_set_drvdata(dev, card); - return 0; - -err_free_irq: - free_irq(card->irq, card); -err_unmap: - iounmap(card->mbase); -err_release_region: - release_region(card->port, AVMB1_PORTLEN); -err_free_dma: - avmcard_dma_free(card->dma); -err_free: - b1_free_card(card); -err: - return retval; -} - -/* ------------------------------------------------------------- */ - -static int c4_probe(struct pci_dev *dev, const struct pci_device_id *ent) -{ - int nr = ent->driver_data; - int retval = 0; - struct capicardparams param; - - if (pci_enable_device(dev) < 0) { - printk(KERN_ERR "c4: failed to enable AVM-C%d\n", nr); - return -ENODEV; - } - pci_set_master(dev); - - param.port = pci_resource_start(dev, 1); - param.irq = dev->irq; - param.membase = pci_resource_start(dev, 0); - - printk(KERN_INFO "c4: PCI BIOS reports AVM-C%d at i/o %#x, irq %d, mem %#x\n", - nr, param.port, param.irq, param.membase); - - retval = c4_add_card(¶m, dev, nr); - if (retval != 0) { - printk(KERN_ERR "c4: no AVM-C%d at i/o %#x, irq %d detected, mem %#x\n", - nr, param.port, param.irq, param.membase); - pci_disable_device(dev); - return -ENODEV; - } - return 0; -} - -static struct pci_driver c4_pci_driver = { - .name = "c4", - .id_table = c4_pci_tbl, - .probe = c4_probe, - .remove = c4_remove, -}; - -static struct capi_driver capi_driver_c2 = { - .name = "c2", - .revision = "1.0", -}; - -static struct capi_driver capi_driver_c4 = { - .name = "c4", - .revision = "1.0", -}; - -static int __init c4_init(void) -{ - char *p; - char rev[32]; - int err; - - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p - 1) = 0; - } else - strcpy(rev, "1.0"); - - err = pci_register_driver(&c4_pci_driver); - if (!err) { - strlcpy(capi_driver_c2.revision, rev, 32); - register_capi_driver(&capi_driver_c2); - strlcpy(capi_driver_c4.revision, rev, 32); - register_capi_driver(&capi_driver_c4); - printk(KERN_INFO "c4: revision %s\n", rev); - } - return err; -} - -static void __exit c4_exit(void) -{ - unregister_capi_driver(&capi_driver_c2); - unregister_capi_driver(&capi_driver_c4); - pci_unregister_driver(&c4_pci_driver); -} - -module_init(c4_init); -module_exit(c4_exit); diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c deleted file mode 100644 index 2153619c5b31..000000000000 --- a/drivers/isdn/hardware/avm/t1isa.c +++ /dev/null @@ -1,594 +0,0 @@ -/* $Id: t1isa.c,v 1.1.2.3 2004/02/10 01:07:12 keil Exp $ - * - * Module for AVM T1 HEMA-card. - * - * Copyright 1999 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/capi.h> -#include <linux/netdevice.h> -#include <linux/kernelcapi.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/gfp.h> -#include <asm/io.h> -#include <linux/isdn/capicmd.h> -#include <linux/isdn/capiutil.h> -#include <linux/isdn/capilli.h> -#include "avmcard.h" - -/* ------------------------------------------------------------- */ - -static char *revision = "$Revision: 1.1.2.3 $"; - -/* ------------------------------------------------------------- */ - -MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 HEMA ISA card"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------- */ - -static int hema_irq_table[16] = -{0, - 0, - 0, - 0x80, /* irq 3 */ - 0, - 0x90, /* irq 5 */ - 0, - 0xA0, /* irq 7 */ - 0, - 0xB0, /* irq 9 */ - 0xC0, /* irq 10 */ - 0xD0, /* irq 11 */ - 0xE0, /* irq 12 */ - 0, - 0, - 0xF0, /* irq 15 */ -}; - -static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr) -{ - unsigned char cregs[8]; - unsigned char reverse_cardnr; - unsigned char dummy; - int i; - - reverse_cardnr = ((cardnr & 0x01) << 3) | ((cardnr & 0x02) << 1) - | ((cardnr & 0x04) >> 1) | ((cardnr & 0x08) >> 3); - cregs[0] = (HEMA_VERSION_ID << 4) | (reverse_cardnr & 0xf); - cregs[1] = 0x00; /* fast & slow link connected to CON1 */ - cregs[2] = 0x05; /* fast link 20MBit, slow link 20 MBit */ - cregs[3] = 0; - cregs[4] = 0x11; /* zero wait state */ - cregs[5] = hema_irq_table[irq & 0xf]; - cregs[6] = 0; - cregs[7] = 0; - - /* - * no one else should use the ISA bus in this moment, - * but no function there to prevent this :-( - * save_flags(flags); cli(); - */ - - /* board reset */ - t1outp(base, T1_RESETBOARD, 0xf); - mdelay(100); - dummy = t1inp(base, T1_FASTLINK + T1_OUTSTAT); /* first read */ - - /* write config */ - dummy = (base >> 4) & 0xff; - for (i = 1; i <= 0xf; i++) t1outp(base, i, dummy); - t1outp(base, HEMA_PAL_ID & 0xf, dummy); - t1outp(base, HEMA_PAL_ID >> 4, cregs[0]); - for (i = 1; i < 7; i++) t1outp(base, 0, cregs[i]); - t1outp(base, ((base >> 4)) & 0x3, cregs[7]); - /* restore_flags(flags); */ - - mdelay(100); - t1outp(base, T1_FASTLINK + T1_RESETLINK, 0); - t1outp(base, T1_SLOWLINK + T1_RESETLINK, 0); - mdelay(10); - t1outp(base, T1_FASTLINK + T1_RESETLINK, 1); - t1outp(base, T1_SLOWLINK + T1_RESETLINK, 1); - mdelay(100); - t1outp(base, T1_FASTLINK + T1_RESETLINK, 0); - t1outp(base, T1_SLOWLINK + T1_RESETLINK, 0); - mdelay(10); - t1outp(base, T1_FASTLINK + T1_ANALYSE, 0); - mdelay(5); - t1outp(base, T1_SLOWLINK + T1_ANALYSE, 0); - - if (t1inp(base, T1_FASTLINK + T1_OUTSTAT) != 0x1) /* tx empty */ - return 1; - if (t1inp(base, T1_FASTLINK + T1_INSTAT) != 0x0) /* rx empty */ - return 2; - if (t1inp(base, T1_FASTLINK + T1_IRQENABLE) != 0x0) - return 3; - if ((t1inp(base, T1_FASTLINK + T1_FIFOSTAT) & 0xf0) != 0x70) - return 4; - if ((t1inp(base, T1_FASTLINK + T1_IRQMASTER) & 0x0e) != 0) - return 5; - if ((t1inp(base, T1_FASTLINK + T1_IDENT) & 0x7d) != 1) - return 6; - if (t1inp(base, T1_SLOWLINK + T1_OUTSTAT) != 0x1) /* tx empty */ - return 7; - if ((t1inp(base, T1_SLOWLINK + T1_IRQMASTER) & 0x0e) != 0) - return 8; - if ((t1inp(base, T1_SLOWLINK + T1_IDENT) & 0x7d) != 0) - return 9; - return 0; -} - -static irqreturn_t t1isa_interrupt(int interrupt, void *devptr) -{ - avmcard *card = devptr; - avmctrl_info *cinfo = &card->ctrlinfo[0]; - struct capi_ctr *ctrl = &cinfo->capi_ctrl; - unsigned char b1cmd; - struct sk_buff *skb; - - unsigned ApplId; - unsigned MsgLen; - unsigned DataB3Len; - unsigned NCCI; - unsigned WindowSize; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - - while (b1_rx_full(card->port)) { - - b1cmd = b1_get_byte(card->port); - - switch (b1cmd) { - - case RECEIVE_DATA_B3_IND: - - ApplId = (unsigned) b1_get_word(card->port); - MsgLen = t1_get_slice(card->port, card->msgbuf); - DataB3Len = t1_get_slice(card->port, card->databuf); - spin_unlock_irqrestore(&card->lock, flags); - - if (MsgLen < 30) { /* not CAPI 64Bit */ - memset(card->msgbuf + MsgLen, 0, 30 - MsgLen); - MsgLen = 30; - CAPIMSG_SETLEN(card->msgbuf, 30); - } - if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) { - printk(KERN_ERR "%s: incoming packet dropped\n", - card->name); - } else { - skb_put_data(skb, card->msgbuf, MsgLen); - skb_put_data(skb, card->databuf, DataB3Len); - capi_ctr_handle_message(ctrl, ApplId, skb); - } - break; - - case RECEIVE_MESSAGE: - - ApplId = (unsigned) b1_get_word(card->port); - MsgLen = t1_get_slice(card->port, card->msgbuf); - if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { - spin_unlock_irqrestore(&card->lock, flags); - printk(KERN_ERR "%s: incoming packet dropped\n", - card->name); - } else { - skb_put_data(skb, card->msgbuf, MsgLen); - if (CAPIMSG_CMD(skb->data) == CAPI_DATA_B3) - capilib_data_b3_conf(&cinfo->ncci_head, ApplId, - CAPIMSG_NCCI(skb->data), - CAPIMSG_MSGID(skb->data)); - spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_handle_message(ctrl, ApplId, skb); - } - break; - - case RECEIVE_NEW_NCCI: - - ApplId = b1_get_word(card->port); - NCCI = b1_get_word(card->port); - WindowSize = b1_get_word(card->port); - capilib_new_ncci(&cinfo->ncci_head, ApplId, NCCI, WindowSize); - spin_unlock_irqrestore(&card->lock, flags); - break; - - case RECEIVE_FREE_NCCI: - - ApplId = b1_get_word(card->port); - NCCI = b1_get_word(card->port); - if (NCCI != 0xffffffff) - capilib_free_ncci(&cinfo->ncci_head, ApplId, NCCI); - spin_unlock_irqrestore(&card->lock, flags); - break; - - case RECEIVE_START: - b1_put_byte(card->port, SEND_POLLACK); - spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_resume_output(ctrl); - break; - - case RECEIVE_STOP: - spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_suspend_output(ctrl); - break; - - case RECEIVE_INIT: - - cinfo->versionlen = t1_get_slice(card->port, cinfo->versionbuf); - spin_unlock_irqrestore(&card->lock, flags); - b1_parse_version(cinfo); - printk(KERN_INFO "%s: %s-card (%s) now active\n", - card->name, - cinfo->version[VER_CARDTYPE], - cinfo->version[VER_DRIVER]); - capi_ctr_ready(ctrl); - break; - - case RECEIVE_TASK_READY: - ApplId = (unsigned) b1_get_word(card->port); - MsgLen = t1_get_slice(card->port, card->msgbuf); - spin_unlock_irqrestore(&card->lock, flags); - card->msgbuf[MsgLen] = 0; - while (MsgLen > 0 - && (card->msgbuf[MsgLen - 1] == '\n' - || card->msgbuf[MsgLen - 1] == '\r')) { - card->msgbuf[MsgLen - 1] = 0; - MsgLen--; - } - printk(KERN_INFO "%s: task %d \"%s\" ready.\n", - card->name, ApplId, card->msgbuf); - break; - - case RECEIVE_DEBUGMSG: - MsgLen = t1_get_slice(card->port, card->msgbuf); - spin_unlock_irqrestore(&card->lock, flags); - card->msgbuf[MsgLen] = 0; - while (MsgLen > 0 - && (card->msgbuf[MsgLen - 1] == '\n' - || card->msgbuf[MsgLen - 1] == '\r')) { - card->msgbuf[MsgLen - 1] = 0; - MsgLen--; - } - printk(KERN_INFO "%s: DEBUG: %s\n", card->name, card->msgbuf); - break; - - - case 0xff: - spin_unlock_irqrestore(&card->lock, flags); - printk(KERN_ERR "%s: card reseted ?\n", card->name); - return IRQ_HANDLED; - default: - spin_unlock_irqrestore(&card->lock, flags); - printk(KERN_ERR "%s: b1_interrupt: 0x%x ???\n", - card->name, b1cmd); - return IRQ_NONE; - } - } - return IRQ_HANDLED; -} - -/* ------------------------------------------------------------- */ - -static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned int port = card->port; - unsigned long flags; - int retval; - - t1_disable_irq(port); - b1_reset(port); - - if ((retval = b1_load_t4file(card, &data->firmware))) { - b1_reset(port); - printk(KERN_ERR "%s: failed to load t4file!!\n", - card->name); - return retval; - } - - if (data->configuration.len > 0 && data->configuration.data) { - if ((retval = b1_load_config(card, &data->configuration))) { - b1_reset(port); - printk(KERN_ERR "%s: failed to load config!!\n", - card->name); - return retval; - } - } - - if (!b1_loaded(card)) { - printk(KERN_ERR "%s: failed to load t4file.\n", card->name); - return -EIO; - } - - spin_lock_irqsave(&card->lock, flags); - b1_setinterrupt(port, card->irq, card->cardtype); - b1_put_byte(port, SEND_INIT); - b1_put_word(port, CAPI_MAXAPPL); - b1_put_word(port, AVM_NCCI_PER_CHANNEL * 30); - b1_put_word(port, ctrl->cnr - 1); - spin_unlock_irqrestore(&card->lock, flags); - - return 0; -} - -static void t1isa_reset_ctr(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned int port = card->port; - unsigned long flags; - - t1_disable_irq(port); - b1_reset(port); - b1_reset(port); - - memset(cinfo->version, 0, sizeof(cinfo->version)); - spin_lock_irqsave(&card->lock, flags); - capilib_release(&cinfo->ncci_head); - spin_unlock_irqrestore(&card->lock, flags); - capi_ctr_down(ctrl); -} - -static void t1isa_remove(struct pci_dev *pdev) -{ - avmctrl_info *cinfo = pci_get_drvdata(pdev); - avmcard *card; - - if (!cinfo) - return; - - card = cinfo->card; - - t1_disable_irq(card->port); - b1_reset(card->port); - b1_reset(card->port); - t1_reset(card->port); - - detach_capi_ctr(&cinfo->capi_ctrl); - free_irq(card->irq, card); - release_region(card->port, AVMB1_PORTLEN); - b1_free_card(card); -} - -/* ------------------------------------------------------------- */ - -static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); -static char *t1isa_procinfo(struct capi_ctr *ctrl); - -static int t1isa_probe(struct pci_dev *pdev, int cardnr) -{ - avmctrl_info *cinfo; - avmcard *card; - int retval; - - card = b1_alloc_card(1); - if (!card) { - printk(KERN_WARNING "t1isa: no memory.\n"); - retval = -ENOMEM; - goto err; - } - - cinfo = card->ctrlinfo; - card->port = pci_resource_start(pdev, 0); - card->irq = pdev->irq; - card->cardtype = avm_t1isa; - card->cardnr = cardnr; - sprintf(card->name, "t1isa-%x", card->port); - - if (!(((card->port & 0x7) == 0) && ((card->port & 0x30) != 0x30))) { - printk(KERN_WARNING "t1isa: invalid port 0x%x.\n", card->port); - retval = -EINVAL; - goto err_free; - } - if (hema_irq_table[card->irq & 0xf] == 0) { - printk(KERN_WARNING "t1isa: irq %d not valid.\n", card->irq); - retval = -EINVAL; - goto err_free; - } - if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { - printk(KERN_INFO "t1isa: ports 0x%03x-0x%03x in use.\n", - card->port, card->port + AVMB1_PORTLEN); - retval = -EBUSY; - goto err_free; - } - retval = request_irq(card->irq, t1isa_interrupt, 0, card->name, card); - if (retval) { - printk(KERN_INFO "t1isa: unable to get IRQ %d.\n", card->irq); - retval = -EBUSY; - goto err_release_region; - } - - if ((retval = t1_detectandinit(card->port, card->irq, card->cardnr)) != 0) { - printk(KERN_INFO "t1isa: NO card at 0x%x (%d)\n", - card->port, retval); - retval = -ENODEV; - goto err_free_irq; - } - t1_disable_irq(card->port); - b1_reset(card->port); - - cinfo->capi_ctrl.owner = THIS_MODULE; - cinfo->capi_ctrl.driver_name = "t1isa"; - cinfo->capi_ctrl.driverdata = cinfo; - cinfo->capi_ctrl.register_appl = b1_register_appl; - cinfo->capi_ctrl.release_appl = b1_release_appl; - cinfo->capi_ctrl.send_message = t1isa_send_message; - cinfo->capi_ctrl.load_firmware = t1isa_load_firmware; - cinfo->capi_ctrl.reset_ctr = t1isa_reset_ctr; - cinfo->capi_ctrl.procinfo = t1isa_procinfo; - cinfo->capi_ctrl.proc_show = b1_proc_show; - strcpy(cinfo->capi_ctrl.name, card->name); - - retval = attach_capi_ctr(&cinfo->capi_ctrl); - if (retval) { - printk(KERN_INFO "t1isa: attach controller failed.\n"); - goto err_free_irq; - } - - printk(KERN_INFO "t1isa: AVM T1 ISA at i/o %#x, irq %d, card %d\n", - card->port, card->irq, card->cardnr); - - pci_set_drvdata(pdev, cinfo); - return 0; - -err_free_irq: - free_irq(card->irq, card); -err_release_region: - release_region(card->port, AVMB1_PORTLEN); -err_free: - b1_free_card(card); -err: - return retval; -} - -static u16 t1isa_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - avmcard *card = cinfo->card; - unsigned int port = card->port; - unsigned long flags; - u16 len = CAPIMSG_LEN(skb->data); - u8 cmd = CAPIMSG_COMMAND(skb->data); - u8 subcmd = CAPIMSG_SUBCOMMAND(skb->data); - u16 dlen, retval; - - spin_lock_irqsave(&card->lock, flags); - if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { - retval = capilib_data_b3_req(&cinfo->ncci_head, - CAPIMSG_APPID(skb->data), - CAPIMSG_NCCI(skb->data), - CAPIMSG_MSGID(skb->data)); - if (retval != CAPI_NOERROR) { - spin_unlock_irqrestore(&card->lock, flags); - return retval; - } - dlen = CAPIMSG_DATALEN(skb->data); - - b1_put_byte(port, SEND_DATA_B3_REQ); - t1_put_slice(port, skb->data, len); - t1_put_slice(port, skb->data + len, dlen); - } else { - b1_put_byte(port, SEND_MESSAGE); - t1_put_slice(port, skb->data, len); - } - spin_unlock_irqrestore(&card->lock, flags); - dev_kfree_skb_any(skb); - return CAPI_NOERROR; -} -/* ------------------------------------------------------------- */ - -static char *t1isa_procinfo(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - - if (!cinfo) - return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d %d", - cinfo->cardname[0] ? cinfo->cardname : "-", - cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", - cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0, - cinfo->card ? cinfo->card->cardnr : 0 - ); - return cinfo->infobuf; -} - - -/* ------------------------------------------------------------- */ - -#define MAX_CARDS 4 -static struct pci_dev isa_dev[MAX_CARDS]; -static int io[MAX_CARDS]; -static int irq[MAX_CARDS]; -static int cardnr[MAX_CARDS]; - -module_param_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param_array(cardnr, int, NULL, 0); -MODULE_PARM_DESC(io, "I/O base address(es)"); -MODULE_PARM_DESC(irq, "IRQ number(s) (assigned)"); -MODULE_PARM_DESC(cardnr, "Card number(s) (as jumpered)"); - -static int t1isa_add_card(struct capi_driver *driver, capicardparams *data) -{ - int i; - - for (i = 0; i < MAX_CARDS; i++) { - if (isa_dev[i].resource[0].start) - continue; - - isa_dev[i].resource[0].start = data->port; - isa_dev[i].irq = data->irq; - - if (t1isa_probe(&isa_dev[i], data->cardnr) == 0) - return 0; - } - return -ENODEV; -} - -static struct capi_driver capi_driver_t1isa = { - .name = "t1isa", - .revision = "1.0", - .add_card = t1isa_add_card, -}; - -static int __init t1isa_init(void) -{ - char rev[32]; - char *p; - int i; - - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p - 1) = 0; - } else - strcpy(rev, "1.0"); - - for (i = 0; i < MAX_CARDS; i++) { - if (!io[i]) - break; - - isa_dev[i].resource[0].start = io[i]; - isa_dev[i].irq = irq[i]; - - if (t1isa_probe(&isa_dev[i], cardnr[i]) != 0) - return -ENODEV; - } - - strlcpy(capi_driver_t1isa.revision, rev, 32); - register_capi_driver(&capi_driver_t1isa); - printk(KERN_INFO "t1isa: revision %s\n", rev); - - return 0; -} - -static void __exit t1isa_exit(void) -{ - int i; - - unregister_capi_driver(&capi_driver_t1isa); - for (i = 0; i < MAX_CARDS; i++) { - if (!io[i]) - break; - - t1isa_remove(&isa_dev[i]); - } -} - -module_init(t1isa_init); -module_exit(t1isa_exit); diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c deleted file mode 100644 index f5ed1d5004c9..000000000000 --- a/drivers/isdn/hardware/avm/t1pci.c +++ /dev/null @@ -1,259 +0,0 @@ -/* $Id: t1pci.c,v 1.1.2.2 2004/01/16 21:09:27 keil Exp $ - * - * Module for AVM T1 PCI-card. - * - * Copyright 1999 by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/skbuff.h> -#include <linux/delay.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/capi.h> -#include <linux/init.h> -#include <asm/io.h> -#include <linux/isdn/capicmd.h> -#include <linux/isdn/capiutil.h> -#include <linux/isdn/capilli.h> -#include "avmcard.h" - -#undef CONFIG_T1PCI_DEBUG -#undef CONFIG_T1PCI_POLLDEBUG - -/* ------------------------------------------------------------- */ -static char *revision = "$Revision: 1.1.2.2 $"; -/* ------------------------------------------------------------- */ - -static struct pci_device_id t1pci_pci_tbl[] = { - { PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_T1, PCI_ANY_ID, PCI_ANY_ID }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(pci, t1pci_pci_tbl); -MODULE_DESCRIPTION("CAPI4Linux: Driver for AVM T1 PCI card"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - -/* ------------------------------------------------------------- */ - -static char *t1pci_procinfo(struct capi_ctr *ctrl); - -static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev) -{ - avmcard *card; - avmctrl_info *cinfo; - int retval; - - card = b1_alloc_card(1); - if (!card) { - printk(KERN_WARNING "t1pci: no memory.\n"); - retval = -ENOMEM; - goto err; - } - - card->dma = avmcard_dma_alloc("t1pci", pdev, 2048 + 128, 2048 + 128); - if (!card->dma) { - printk(KERN_WARNING "t1pci: no memory.\n"); - retval = -ENOMEM; - goto err_free; - } - - cinfo = card->ctrlinfo; - sprintf(card->name, "t1pci-%x", p->port); - card->port = p->port; - card->irq = p->irq; - card->membase = p->membase; - card->cardtype = avm_t1pci; - - if (!request_region(card->port, AVMB1_PORTLEN, card->name)) { - printk(KERN_WARNING "t1pci: ports 0x%03x-0x%03x in use.\n", - card->port, card->port + AVMB1_PORTLEN); - retval = -EBUSY; - goto err_free_dma; - } - - card->mbase = ioremap(card->membase, 64); - if (!card->mbase) { - printk(KERN_NOTICE "t1pci: can't remap memory at 0x%lx\n", - card->membase); - retval = -EIO; - goto err_release_region; - } - - b1dma_reset(card); - - retval = t1pci_detect(card); - if (retval != 0) { - if (retval < 6) - printk(KERN_NOTICE "t1pci: NO card at 0x%x (%d)\n", - card->port, retval); - else - printk(KERN_NOTICE "t1pci: card at 0x%x, but cable not connected or T1 has no power (%d)\n", - card->port, retval); - retval = -EIO; - goto err_unmap; - } - b1dma_reset(card); - - retval = request_irq(card->irq, b1dma_interrupt, IRQF_SHARED, card->name, card); - if (retval) { - printk(KERN_ERR "t1pci: unable to get IRQ %d.\n", card->irq); - retval = -EBUSY; - goto err_unmap; - } - - cinfo->capi_ctrl.owner = THIS_MODULE; - cinfo->capi_ctrl.driver_name = "t1pci"; - cinfo->capi_ctrl.driverdata = cinfo; - cinfo->capi_ctrl.register_appl = b1dma_register_appl; - cinfo->capi_ctrl.release_appl = b1dma_release_appl; - cinfo->capi_ctrl.send_message = b1dma_send_message; - cinfo->capi_ctrl.load_firmware = b1dma_load_firmware; - cinfo->capi_ctrl.reset_ctr = b1dma_reset_ctr; - cinfo->capi_ctrl.procinfo = t1pci_procinfo; - cinfo->capi_ctrl.proc_show = b1dma_proc_show; - strcpy(cinfo->capi_ctrl.name, card->name); - - retval = attach_capi_ctr(&cinfo->capi_ctrl); - if (retval) { - printk(KERN_ERR "t1pci: attach controller failed.\n"); - retval = -EBUSY; - goto err_free_irq; - } - card->cardnr = cinfo->capi_ctrl.cnr; - - printk(KERN_INFO "t1pci: AVM T1 PCI at i/o %#x, irq %d, mem %#lx\n", - card->port, card->irq, card->membase); - - pci_set_drvdata(pdev, card); - return 0; - -err_free_irq: - free_irq(card->irq, card); -err_unmap: - iounmap(card->mbase); -err_release_region: - release_region(card->port, AVMB1_PORTLEN); -err_free_dma: - avmcard_dma_free(card->dma); -err_free: - b1_free_card(card); -err: - return retval; -} - -/* ------------------------------------------------------------- */ - -static void t1pci_remove(struct pci_dev *pdev) -{ - avmcard *card = pci_get_drvdata(pdev); - avmctrl_info *cinfo = card->ctrlinfo; - - b1dma_reset(card); - - detach_capi_ctr(&cinfo->capi_ctrl); - free_irq(card->irq, card); - iounmap(card->mbase); - release_region(card->port, AVMB1_PORTLEN); - avmcard_dma_free(card->dma); - b1_free_card(card); -} - -/* ------------------------------------------------------------- */ - -static char *t1pci_procinfo(struct capi_ctr *ctrl) -{ - avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); - - if (!cinfo) - return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d 0x%lx", - cinfo->cardname[0] ? cinfo->cardname : "-", - cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", - cinfo->card ? cinfo->card->port : 0x0, - cinfo->card ? cinfo->card->irq : 0, - cinfo->card ? cinfo->card->membase : 0 - ); - return cinfo->infobuf; -} - -/* ------------------------------------------------------------- */ - -static int t1pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) -{ - struct capicardparams param; - int retval; - - if (pci_enable_device(dev) < 0) { - printk(KERN_ERR "t1pci: failed to enable AVM-T1-PCI\n"); - return -ENODEV; - } - pci_set_master(dev); - - param.port = pci_resource_start(dev, 1); - param.irq = dev->irq; - param.membase = pci_resource_start(dev, 0); - - printk(KERN_INFO "t1pci: PCI BIOS reports AVM-T1-PCI at i/o %#x, irq %d, mem %#x\n", - param.port, param.irq, param.membase); - - retval = t1pci_add_card(¶m, dev); - if (retval != 0) { - printk(KERN_ERR "t1pci: no AVM-T1-PCI at i/o %#x, irq %d detected, mem %#x\n", - param.port, param.irq, param.membase); - pci_disable_device(dev); - return -ENODEV; - } - return 0; -} - -static struct pci_driver t1pci_pci_driver = { - .name = "t1pci", - .id_table = t1pci_pci_tbl, - .probe = t1pci_probe, - .remove = t1pci_remove, -}; - -static struct capi_driver capi_driver_t1pci = { - .name = "t1pci", - .revision = "1.0", -}; - -static int __init t1pci_init(void) -{ - char *p; - char rev[32]; - int err; - - if ((p = strchr(revision, ':')) != NULL && p[1]) { - strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != NULL && p > rev) - *(p - 1) = 0; - } else - strcpy(rev, "1.0"); - - err = pci_register_driver(&t1pci_pci_driver); - if (!err) { - strlcpy(capi_driver_t1pci.revision, rev, 32); - register_capi_driver(&capi_driver_t1pci); - printk(KERN_INFO "t1pci: revision %s\n", rev); - } - return err; -} - -static void __exit t1pci_exit(void) -{ - unregister_capi_driver(&capi_driver_t1pci); - pci_unregister_driver(&t1pci_pci_driver); -} - -module_init(t1pci_init); -module_exit(t1pci_exit); diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index a7a34a85b970..304f50c08da2 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -79,11 +79,14 @@ config MISDN_NETJET depends on PCI depends on TTY select MISDN_IPAC - select ISDN_HDLC - select ISDN_I4L + select MISDN_HDLC help Enable support for Traverse Technologies NETJet PCI cards. +config MISDN_HDLC + tristate + select CRC_CCITT + select BITREVERSE config MISDN_IPAC tristate diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 422f9fd8ab9a..3f50f8c4753f 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -15,3 +15,5 @@ obj-$(CONFIG_MISDN_NETJET) += netjet.o # chip modules obj-$(CONFIG_MISDN_IPAC) += mISDNipac.o obj-$(CONFIG_MISDN_ISAR) += mISDNisar.o + +obj-$(CONFIG_MISDN_HDLC) += isdnhdlc.o diff --git a/drivers/isdn/i4l/isdnhdlc.c b/drivers/isdn/hardware/mISDN/isdnhdlc.c index 382a6b24e6a3..9fea16ed3dd8 100644 --- a/drivers/isdn/i4l/isdnhdlc.c +++ b/drivers/isdn/hardware/mISDN/isdnhdlc.c @@ -12,8 +12,8 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/crc-ccitt.h> -#include <linux/isdn/hdlc.h> #include <linux/bitrev.h> +#include "isdnhdlc.h" /*-------------------------------------------------------------------*/ diff --git a/drivers/isdn/hardware/mISDN/isdnhdlc.h b/drivers/isdn/hardware/mISDN/isdnhdlc.h new file mode 100644 index 000000000000..fe2c1279c139 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/isdnhdlc.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * hdlc.h -- General purpose ISDN HDLC decoder. + * + * Implementation of a HDLC decoder/encoder in software. + * Necessary because some ISDN devices don't have HDLC + * controllers. + * + * Copyright (C) + * 2009 Karsten Keil <keil@b1-systems.de> + * 2002 Wolfgang Mües <wolfgang@iksw-muees.de> + * 2001 Frode Isaksen <fisaksen@bewan.com> + * 2001 Kai Germaschewski <kai.germaschewski@gmx.de> + */ + +#ifndef __ISDNHDLC_H__ +#define __ISDNHDLC_H__ + +struct isdnhdlc_vars { + int bit_shift; + int hdlc_bits1; + int data_bits; + int ffbit_shift; /* encoding only */ + int state; + int dstpos; + + u16 crc; + + u8 cbin; + u8 shift_reg; + u8 ffvalue; + + /* set if transferring data */ + u32 data_received:1; + /* set if D channel (send idle instead of flags) */ + u32 dchannel:1; + /* set if 56K adaptation */ + u32 do_adapt56:1; + /* set if in closing phase (need to send CRC + flag) */ + u32 do_closing:1; + /* set if data is bitreverse */ + u32 do_bitreverse:1; +}; + +/* Feature Flags */ +#define HDLC_56KBIT 0x01 +#define HDLC_DCHANNEL 0x02 +#define HDLC_BITREVERSE 0x04 + +/* + The return value from isdnhdlc_decode is + the frame length, 0 if no complete frame was decoded, + or a negative error number +*/ +#define HDLC_FRAMING_ERROR 1 +#define HDLC_CRC_ERROR 2 +#define HDLC_LENGTH_ERROR 3 + +extern void isdnhdlc_rcv_init(struct isdnhdlc_vars *hdlc, u32 features); + +extern int isdnhdlc_decode(struct isdnhdlc_vars *hdlc, const u8 *src, + int slen, int *count, u8 *dst, int dsize); + +extern void isdnhdlc_out_init(struct isdnhdlc_vars *hdlc, u32 features); + +extern int isdnhdlc_encode(struct isdnhdlc_vars *hdlc, const u8 *src, + u16 slen, int *count, u8 *dst, int dsize); + +#endif /* __ISDNHDLC_H__ */ diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index 5c9e38ba52ea..4e30affd1a7c 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -16,7 +16,7 @@ #include "ipac.h" #include "iohelper.h" #include "netjet.h" -#include <linux/isdn/hdlc.h> +#include "isdnhdlc.h" #define NETJET_REV "2.0" diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig deleted file mode 100644 index 43d98ccf5ff6..000000000000 --- a/drivers/isdn/hisax/Kconfig +++ /dev/null @@ -1,423 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only - -menu "Passive cards" - -config ISDN_DRV_HISAX - tristate "HiSax SiemensChipSet driver support" - select CRC_CCITT - ---help--- - This is a driver supporting the Siemens chipset on various - ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles - S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many - compatibles). - - HiSax is just the name of this driver, not the name of any hardware. - - If you have a card with such a chipset, you should say Y here and - also to the configuration option of the driver for your particular - card, below. - -if ISDN_DRV_HISAX - -comment "D-channel protocol features" - -config HISAX_EURO - bool "HiSax Support for EURO/DSS1" - help - Say Y or N according to the D-channel protocol which your local - telephone service company provides. - - The call control protocol E-DSS1 is used in most European countries. - If unsure, say Y. - -config DE_AOC - bool "Support for german chargeinfo" - depends on HISAX_EURO - help - If you want that the HiSax hardware driver sends messages to the - upper level of the isdn code on each AOCD (Advice Of Charge, During - the call -- transmission of the fee information during a call) and - on each AOCE (Advice Of Charge, at the End of the call -- - transmission of fee information at the end of the call), say Y here. - This works only in Germany. - -config HISAX_NO_SENDCOMPLETE - bool "Disable sending complete" - depends on HISAX_EURO - help - If you have trouble with some ugly exchanges or you live in - Australia select this option. - -config HISAX_NO_LLC - bool "Disable sending low layer compatibility" - depends on HISAX_EURO - help - If you have trouble with some ugly exchanges try to select this - option. - -config HISAX_NO_KEYPAD - bool "Disable keypad protocol option" - depends on HISAX_EURO - help - If you like to send special dial strings including * or # without - using the keypad protocol, select this option. - -config HISAX_1TR6 - bool "HiSax Support for german 1TR6" - help - Say Y or N according to the D-channel protocol which your local - telephone service company provides. - - 1TR6 is an old call control protocol which was used in Germany - before E-DSS1 was established. Nowadays, all new lines in Germany - use E-DSS1. - -config HISAX_NI1 - bool "HiSax Support for US NI1" - help - Enable this if you like to use ISDN in US on a NI1 basic rate - interface. - -config HISAX_MAX_CARDS - int "Maximum number of cards supported by HiSax" - default "8" - help - This option allows you to specify the maximum number of cards which - the HiSax driver will be able to handle. - -comment "HiSax supported cards" - -config HISAX_16_0 - bool "Teles 16.0/8.0" - depends on ISA - help - This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 - and many compatibles. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port/shmem settings. - -config HISAX_16_3 - bool "Teles 16.3 or PNP or PCMCIA" - help - This enables HiSax support for the Teles ISDN-cards S0-16.3 the - Teles/Creatix PnP and the Teles PCMCIA. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_TELESPCI - bool "Teles PCI" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN))) - help - This enables HiSax support for the Teles PCI. - See <file:Documentation/isdn/README.HiSax> on how to configure it. - -config HISAX_S0BOX - bool "Teles S0Box" - help - This enables HiSax support for the Teles/Creatix parallel port - S0BOX. See <file:Documentation/isdn/README.HiSax> on how to - configure it. - -config HISAX_AVM_A1 - bool "AVM A1 (Fritz)" - depends on ISA - help - This enables HiSax support for the AVM A1 (aka "Fritz"). - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_FRITZPCI - bool "AVM PnP/PCI (Fritz!PnP/PCI)" - depends on BROKEN || !PPC64 - help - This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI". - See <file:Documentation/isdn/README.HiSax> on how to configure it. - -config HISAX_AVM_A1_PCMCIA - bool "AVM A1 PCMCIA (Fritz)" - help - This enables HiSax support for the AVM A1 "Fritz!PCMCIA"). - See <file:Documentation/isdn/README.HiSax> on how to configure it. - -config HISAX_ELSA - bool "Elsa cards" - help - This enables HiSax support for the Elsa Mircolink ISA cards, for the - Elsa Quickstep series cards and Elsa PCMCIA. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_IX1MICROR2 - bool "ITK ix1-micro Revision 2" - depends on ISA - help - This enables HiSax support for the ITK ix1-micro Revision 2 card. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_DIEHLDIVA - bool "Eicon.Diehl Diva cards" - help - This enables HiSax support for the Eicon.Diehl Diva none PRO - versions passive ISDN cards. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_ASUSCOM - bool "ASUSCOM ISA cards" - depends on ISA - help - This enables HiSax support for the AsusCom and their OEM versions - passive ISDN ISA cards. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_TELEINT - bool "TELEINT cards" - depends on ISA - help - This enables HiSax support for the TELEINT SA1 semiactiv ISDN card. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_HFCS - bool "HFC-S based cards" - depends on ISA - help - This enables HiSax support for the HFC-S 2BDS0 based cards, like - teles 16.3c. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_SEDLBAUER - bool "Sedlbauer cards" - help - This enables HiSax support for the Sedlbauer passive ISDN cards. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_SPORTSTER - bool "USR Sportster internal TA" - depends on ISA - help - This enables HiSax support for the USR Sportster internal TA card. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_MIC - bool "MIC card" - depends on ISA - help - This enables HiSax support for the ITH MIC card. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_NETJET - bool "NETjet card" - depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE)) - depends on VIRT_TO_BUS - help - This enables HiSax support for the NetJet from Traverse - Technologies. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_NETJET_U - bool "NETspider U card" - depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE)) - depends on VIRT_TO_BUS - help - This enables HiSax support for the Netspider U interface ISDN card - from Traverse Technologies. - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_NICCY - bool "Niccy PnP/PCI card" - help - This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_ISURF - bool "Siemens I-Surf card" - depends on ISA - help - This enables HiSax support for the Siemens I-Talk/I-Surf card with - ISAR chip. - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_HSTSAPHIR - bool "HST Saphir card" - depends on ISA - help - This enables HiSax support for the HST Saphir card. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_BKM_A4T - bool "Telekom A4T card" - depends on PCI - help - This enables HiSax support for the Telekom A4T card. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_SCT_QUADRO - bool "Scitel Quadro card" - depends on PCI - help - This enables HiSax support for the Scitel Quadro card. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_GAZEL - bool "Gazel cards" - help - This enables HiSax support for the Gazel cards. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_HFC_PCI - bool "HFC PCI-Bus cards" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN))) - help - This enables HiSax support for the HFC-S PCI 2BDS0 based cards. - - For more information see under - <file:Documentation/isdn/README.hfc-pci>. - -config HISAX_W6692 - bool "Winbond W6692 based cards" - depends on PCI - help - This enables HiSax support for Winbond W6692 based PCI ISDN cards. - - See <file:Documentation/isdn/README.HiSax> on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_HFC_SX - bool "HFC-S+, HFC-SP, HFC-PCMCIA cards" - help - This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA - cards. This code is not finished yet. - -config HISAX_ENTERNOW_PCI - bool "Formula-n enter:now PCI card" - depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || (XTENSA && !CPU_LITTLE_ENDIAN))) - help - This enables HiSax support for the Formula-n enter:now PCI - ISDN card. - -config HISAX_DEBUG - bool "HiSax debugging" - help - This enables debugging code in the new-style HiSax drivers, i.e. - the ST5481 USB driver currently. - If in doubt, say yes. - -comment "HiSax PCMCIA card service modules" - -config HISAX_SEDLBAUER_CS - tristate "Sedlbauer PCMCIA cards" - depends on PCMCIA && HISAX_SEDLBAUER - help - This enables the PCMCIA client driver for the Sedlbauer Speed Star - and Speed Star II cards. - -config HISAX_ELSA_CS - tristate "ELSA PCMCIA MicroLink cards" - depends on PCMCIA && HISAX_ELSA - help - This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink - card. - -config HISAX_AVM_A1_CS - tristate "AVM A1 PCMCIA cards" - depends on PCMCIA && ISDN_DRV_HISAX - help - This enables the PCMCIA client driver for the AVM A1 / Fritz!Card - PCMCIA cards. - -config HISAX_TELES_CS - tristate "TELES PCMCIA cards" - depends on PCMCIA && HISAX_16_3 - help - This enables the PCMCIA client driver for the Teles PCMCIA cards. - -comment "HiSax sub driver modules" - -config HISAX_ST5481 - tristate "ST5481 USB ISDN modem" - depends on USB - select ISDN_HDLC - select CRC_CCITT - select BITREVERSE - help - This enables the driver for ST5481 based USB ISDN adapters, - e.g. the BeWan Gazel 128 USB - -config HISAX_HFCUSB - tristate "HFC USB based ISDN modems" - depends on USB - help - This enables the driver for HFC USB based ISDN modems. - -config HISAX_HFC4S8S - tristate "HFC-4S/8S based ISDN cards" - help - This enables the driver for HFC-4S/8S based ISDN cards. - -config HISAX_FRITZ_PCIPNP - tristate "AVM Fritz!Card PCI/PCIv2/PnP support" - depends on PCI - help - This enables the driver for the AVM Fritz!Card PCI, - Fritz!Card PCI v2 and Fritz!Card PnP. - (the latter also needs you to select "ISA Plug and Play support" - from the menu "Plug and Play configuration") - -endif - -endmenu - diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile deleted file mode 100644 index 3eca9d23f1c2..000000000000 --- a/drivers/isdn/hisax/Makefile +++ /dev/null @@ -1,60 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Makefile for the hisax ISDN device driver - -# The target object and module list name. - -# Define maximum number of cards - -ccflags-y := -DHISAX_MAX_CARDS=$(CONFIG_HISAX_MAX_CARDS) - -obj-$(CONFIG_ISDN_DRV_HISAX) += hisax.o -obj-$(CONFIG_HISAX_SEDLBAUER_CS) += sedlbauer_cs.o -obj-$(CONFIG_HISAX_ELSA_CS) += elsa_cs.o -obj-$(CONFIG_HISAX_AVM_A1_CS) += avma1_cs.o -obj-$(CONFIG_HISAX_TELES_CS) += teles_cs.o -obj-$(CONFIG_HISAX_ST5481) += hisax_st5481.o -obj-$(CONFIG_HISAX_HFCUSB) += hfc_usb.o -obj-$(CONFIG_HISAX_HFC4S8S) += hfc4s8s_l1.o -obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_isac.o hisax_fcpcipnp.o - -# Multipart objects. - -hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \ - st5481_b.o - -hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \ - lmgr.o q931.o callc.o fsm.o -hisax-$(CONFIG_HISAX_EURO) += l3dss1.o -hisax-$(CONFIG_HISAX_NI1) += l3ni1.o -hisax-$(CONFIG_HISAX_1TR6) += l3_1tr6.o - -hisax-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o -hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o -hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o -hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o \ - isar.o -hisax-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o -hisax-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o -hisax-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o -hisax-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o -hisax-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o -hisax-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o -hisax-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o -hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o -hisax-$(CONFIG_HISAX_W6692) += w6692.o -hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o - diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c deleted file mode 100644 index 6c336366128c..000000000000 --- a/drivers/isdn/hisax/amd7930_fn.c +++ /dev/null @@ -1,794 +0,0 @@ -/* gerdes_amd7930.c,v 0.99 2001/10/02 - * - * gerdes_amd7930.c Amd 79C30A and 79C32A specific routines - * (based on HiSax driver by Karsten Keil) - * - * Author Christoph Ersfeld <info@formula-n.de> - * Formula-n Europe AG (www.formula-n.com) - * previously Gerdes AG - * - * - * This file is (c) under GNU PUBLIC LICENSE - * - * - * Notes: - * Version 0.99 is the first release of this driver and there are - * certainly a few bugs. - * - * Please don't report any malfunction to me without sending - * (compressed) debug-logs. - * It would be nearly impossible to retrace it. - * - * Log D-channel-processing as follows: - * - * 1. Load hisax with card-specific parameters, this example ist for - * Formula-n enter:now ISDN PCI and compatible - * (f.e. Gerdes Power ISDN PCI) - * - * modprobe hisax type=41 protocol=2 id=gerdes - * - * if you chose an other value for id, you need to modify the - * code below, too. - * - * 2. set debug-level - * - * hisaxctrl gerdes 1 0x3ff - * hisaxctrl gerdes 11 0x4f - * cat /dev/isdnctrl >> ~/log & - * - * Please take also a look into /var/log/messages if there is - * anything importand concerning HISAX. - * - * - * Credits: - * Programming the driver for Formula-n enter:now ISDN PCI and - * necessary this driver for the used Amd 7930 D-channel-controller - * was spnsored by Formula-n Europe AG. - * Thanks to Karsten Keil and Petr Novak, who gave me support in - * Hisax-specific questions. - * I want so say special thanks to Carl-Friedrich Braun, who had to - * answer a lot of questions about generally ISDN and about handling - * of the Amd-Chip. - * - */ - - -#include "hisax.h" -#include "isdnl1.h" -#include "isac.h" -#include "amd7930_fn.h" -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/gfp.h> - -static void Amd7930_new_ph(struct IsdnCardState *cs); - -static WORD initAMD[] = { - 0x0100, - - 0x00A5, 3, 0x01, 0x40, 0x58, // LPR, LMR1, LMR2 - 0x0086, 1, 0x0B, // DMR1 (D-Buffer TH-Interrupts on) - 0x0087, 1, 0xFF, // DMR2 - 0x0092, 1, 0x03, // EFCR (extended mode d-channel-fifo on) - 0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F, // FRAR4, SRAR4, DMR3, DMR4 (address recognition ) - 0x0084, 2, 0x80, 0x00, // DRLR - 0x00C0, 1, 0x47, // PPCR1 - 0x00C8, 1, 0x01, // PPCR2 - - 0x0102, - 0x0107, - 0x01A1, 1, - 0x0121, 1, - 0x0189, 2, - - 0x0045, 4, 0x61, 0x72, 0x00, 0x00, // MCR1, MCR2, MCR3, MCR4 - 0x0063, 2, 0x08, 0x08, // GX - 0x0064, 2, 0x08, 0x08, // GR - 0x0065, 2, 0x99, 0x00, // GER - 0x0066, 2, 0x7C, 0x8B, // STG - 0x0067, 2, 0x00, 0x00, // FTGR1, FTGR2 - 0x0068, 2, 0x20, 0x20, // ATGR1, ATGR2 - 0x0069, 1, 0x4F, // MMR1 - 0x006A, 1, 0x00, // MMR2 - 0x006C, 1, 0x40, // MMR3 - 0x0021, 1, 0x02, // INIT - 0x00A3, 1, 0x40, // LMR1 - - 0xFFFF -}; - - -static void /* macro wWordAMD */ -WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val) -{ - wByteAMD(cs, 0x00, reg); - wByteAMD(cs, 0x01, LOBYTE(val)); - wByteAMD(cs, 0x01, HIBYTE(val)); -} - -static WORD /* macro rWordAMD */ -ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg) -{ - WORD res; - /* direct access register */ - if (reg < 8) { - res = rByteAMD(cs, reg); - res += 256 * rByteAMD(cs, reg); - } - /* indirect access register */ - else { - wByteAMD(cs, 0x00, reg); - res = rByteAMD(cs, 0x01); - res += 256 * rByteAMD(cs, 0x01); - } - return (res); -} - - -static void -Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command); - - cs->dc.amd7930.lmr1 = command; - wByteAMD(cs, 0xA3, command); -} - - - -static BYTE i430States[] = { -// to reset F3 F4 F5 F6 F7 F8 AR from - 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // init - 0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00, // reset - 0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04, // F3 - 0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F4 - 0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, // F5 - 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, // F6 - 0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00, // F7 - 0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, // F8 - 0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A}; // AR - - -/* Row init - reset F3 F4 F5 F6 F7 F8 AR */ -static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; - - - - -static void -Amd7930_get_state(struct IsdnCardState *cs) { - BYTE lsr = rByteAMD(cs, 0xA1); - cs->dc.amd7930.ph_state = (lsr & 0x7) + 2; - Amd7930_new_ph(cs); -} - - - -static void -Amd7930_new_ph(struct IsdnCardState *cs) -{ - u_char index = stateHelper[cs->dc.amd7930.old_state] * 8 + stateHelper[cs->dc.amd7930.ph_state] - 1; - u_char message = i430States[index]; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d", - cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index); - - cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state; - - /* abort transmit if nessesary */ - if ((message & 0xf0) && (cs->tx_skb)) { - wByteAMD(cs, 0x21, 0xC2); - wByteAMD(cs, 0x21, 0x02); - } - - switch (message & 0x0f) { - - case (1): - l1_msg(cs, HW_RESET | INDICATION, NULL); - Amd7930_get_state(cs); - break; - case (2): /* init, Card starts in F3 */ - l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); - break; - case (3): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (4): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST"); - break; - case (5): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (6): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - case (7): /* init, Card starts in F7 */ - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - case (8): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - /* fall through */ - case (9): - Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set"); - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - case (10): - Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared"); - cs->dc.amd7930.old_state = 3; - break; - case (11): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - default: - break; - } -} - - - -static void -Amd7930_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - struct PStack *stptr; - - if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { - if (cs->debug) - debugl1(cs, "Amd7930: bh, D-Channel Busy cleared"); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); - stptr = stptr->next; - } - } - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "AMD7930: bh, D_L1STATECHANGE"); - Amd7930_new_ph(cs); - } - - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "AMD7930: bh, D_RCVBUFREADY"); - DChannel_proc_rcv(cs); - } - - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "AMD7930: bh, D_XMTBUFREADY"); - DChannel_proc_xmt(cs); - } -} - -static void -Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag) -{ - - BYTE stat, der; - BYTE *ptr; - struct sk_buff *skb; - - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "Amd7930: empty_Dfifo"); - - - ptr = cs->rcvbuf + cs->rcvidx; - - /* AMD interrupts off */ - AmdIrqOff(cs); - - /* read D-Channel-Fifo*/ - stat = rByteAMD(cs, 0x07); // DSR2 - - /* while Data in Fifo ... */ - while ((stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1)) { - *ptr = rByteAMD(cs, 0x04); // DCRB - ptr++; - stat = rByteAMD(cs, 0x07); // DSR2 - cs->rcvidx = ptr - cs->rcvbuf; - - /* Paket ready? */ - if (stat & 1) { - - der = rWordAMD(cs, 0x03); - - /* no errors, packet ok */ - if (!der && !flag) { - rWordAMD(cs, 0x89); // clear DRCR - - if ((cs->rcvidx) > 0) { - if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC))) - printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n"); - else { - /* Debugging */ - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx); - QuickHex(t, cs->rcvbuf, cs->rcvidx); - debugl1(cs, "%s", cs->dlog); - } - /* moves received data in sk-buffer */ - skb_put_data(skb, cs->rcvbuf, - cs->rcvidx); - skb_queue_tail(&cs->rq, skb); - } - } - - } - /* throw damaged packets away, reset receive-buffer, indicate RX */ - ptr = cs->rcvbuf; - cs->rcvidx = 0; - schedule_event(cs, D_RCVBUFREADY); - } - } - /* Packet to long, overflow */ - if (cs->rcvidx >= MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun"); - cs->rcvidx = 0; - return; - } - /* AMD interrupts on */ - AmdIrqOn(cs); -} - - -static void -Amd7930_fill_Dfifo(struct IsdnCardState *cs) -{ - - WORD dtcrr, dtcrw, len, count; - BYTE txstat, dmr3; - BYTE *ptr, *deb_ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "Amd7930: fill_Dfifo"); - - if ((!cs->tx_skb) || (cs->tx_skb->len <= 0)) - return; - - dtcrw = 0; - if (!cs->dc.amd7930.tx_xmtlen) - /* new Frame */ - len = dtcrw = cs->tx_skb->len; - /* continue frame */ - else len = cs->dc.amd7930.tx_xmtlen; - - - /* AMD interrupts off */ - AmdIrqOff(cs); - - deb_ptr = ptr = cs->tx_skb->data; - - /* while free place in tx-fifo available and data in sk-buffer */ - txstat = 0x10; - while ((txstat & 0x10) && (cs->tx_cnt < len)) { - wByteAMD(cs, 0x04, *ptr); - ptr++; - cs->tx_cnt++; - txstat = rByteAMD(cs, 0x07); - } - count = ptr - cs->tx_skb->data; - skb_pull(cs->tx_skb, count); - - - dtcrr = rWordAMD(cs, 0x85); // DTCR - dmr3 = rByteAMD(cs, 0x8E); - - if (cs->debug & L1_DEB_ISAC) { - debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw)); - } - - /* writeing of dtcrw starts transmit */ - if (!cs->dc.amd7930.tx_xmtlen) { - wWordAMD(cs, 0x85, dtcrw); - cs->dc.amd7930.tx_xmtlen = dtcrw; - } - - if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running"); - del_timer(&cs->dbusytimer); - } - cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000); - add_timer(&cs->dbusytimer); - - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count); - QuickHex(t, deb_ptr, count); - debugl1(cs, "%s", cs->dlog); - } - /* AMD interrupts on */ - AmdIrqOn(cs); -} - - -void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags) -{ - BYTE dsr1, dsr2, lsr; - WORD der; - - while (irflags) - { - - dsr1 = rByteAMD(cs, 0x02); - der = rWordAMD(cs, 0x03); - dsr2 = rByteAMD(cs, 0x07); - lsr = rByteAMD(cs, 0xA1); - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der); - - /* D error -> read DER and DSR2 bit 2 */ - if (der || (dsr2 & 4)) { - - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der); - - /* RX, TX abort if collision detected */ - if (der & 2) { - wByteAMD(cs, 0x21, 0xC2); - wByteAMD(cs, 0x21, 0x02); - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - /* restart frame */ - if (cs->tx_skb) { - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; - Amd7930_fill_Dfifo(cs); - } else { - printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n"); - debugl1(cs, "Amd7930: interrupt: D-Collision, no skb"); - } - } - /* remove damaged data from fifo */ - Amd7930_empty_Dfifo(cs, 1); - - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - /* restart TX-Frame */ - if (cs->tx_skb) { - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; - Amd7930_fill_Dfifo(cs); - } - } - - /* D TX FIFO empty -> fill */ - if (irflags & 1) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data"); - - /* AMD interrupts off */ - AmdIrqOff(cs); - - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) - Amd7930_fill_Dfifo(cs); - } - /* AMD interrupts on */ - AmdIrqOn(cs); - } - - - /* D RX FIFO full or tiny packet in Fifo -> empty */ - if ((irflags & 2) || (dsr1 & 2)) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: interrupt: empty D-FIFO"); - Amd7930_empty_Dfifo(cs, 0); - } - - - /* D-Frame transmit complete */ - if (dsr1 & 64) { - if (cs->debug & L1_DEB_ISAC) { - debugl1(cs, "Amd7930: interrupt: transmit packet ready"); - } - /* AMD interrupts off */ - AmdIrqOff(cs); - - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - - if (cs->tx_skb) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb"); - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; - cs->tx_skb = NULL; - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued"); - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; - Amd7930_fill_Dfifo(cs); - } - else - schedule_event(cs, D_XMTBUFREADY); - /* AMD interrupts on */ - AmdIrqOn(cs); - } - - /* LIU status interrupt -> read LSR, check statechanges */ - if (lsr & 0x38) { - /* AMD interrupts off */ - AmdIrqOff(cs); - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) + 2)); - - cs->dc.amd7930.ph_state = (lsr & 0x7) + 2; - - schedule_event(cs, D_L1STATECHANGE); - /* AMD interrupts on */ - AmdIrqOn(cs); - } - - /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */ - irflags = rByteAMD(cs, 0x00); - } - -} - -static void -Amd7930_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr); - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0); -#endif - Amd7930_fill_Dfifo(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; - cs->dc.amd7930.tx_xmtlen = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0); -#endif - Amd7930_fill_Dfifo(cs); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb) ? "yes" : "no"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - if (cs->dc.amd7930.ph_state == 8) { - /* b-channels off, PH-AR cleared - * change to F3 */ - Amd7930_ph_command(cs, 0x20, "HW_RESET REQUEST"); //LMR1 bit 5 - spin_unlock_irqrestore(&cs->lock, flags); - } else { - Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST"); - cs->dc.amd7930.ph_state = 2; - spin_unlock_irqrestore(&cs->lock, flags); - Amd7930_new_ph(cs); - } - break; - case (HW_ENABLE | REQUEST): - cs->dc.amd7930.ph_state = 9; - Amd7930_new_ph(cs); - break; - case (HW_INFO3 | REQUEST): - // automatic - break; - case (HW_TESTLOOP | REQUEST): - /* not implemented yet */ - break; - case (HW_DEACTIVATE | RESPONSE): - skb_queue_purge(&cs->rq); - skb_queue_purge(&cs->sq); - if (cs->tx_skb) { - dev_kfree_skb(cs->tx_skb); - cs->tx_skb = NULL; - } - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "Amd7930: l1hw: unknown %04x", pr); - break; - } -} - -static void -setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs) -{ - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: setstack called"); - - st->l1.l1hw = Amd7930_l1hw; -} - - -static void -DC_Close_Amd7930(struct IsdnCardState *cs) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: DC_Close called"); -} - - -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, dbusytimer); - u_long flags; - struct PStack *stptr; - WORD dtcr, der; - BYTE dsr1, dsr2; - - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: dbusy_timer expired!"); - - if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - spin_lock_irqsave(&cs->lock, flags); - /* D Transmit Byte Count Register: - * Counts down packet's number of Bytes, 0 if packet ready */ - dtcr = rWordAMD(cs, 0x85); - dsr1 = rByteAMD(cs, 0x02); - dsr2 = rByteAMD(cs, 0x07); - der = rWordAMD(cs, 0x03); - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt); - - if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) { /* D-Channel Busy */ - test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - stptr = cs->stlist; - spin_unlock_irqrestore(&cs->lock, flags); - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); - stptr = stptr->next; - } - - } else { - /* discard frame; reset transceiver */ - test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - cs->dc.amd7930.tx_xmtlen = 0; - } else { - printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n"); - debugl1(cs, "Amd7930: D-Channel Busy no skb"); - - } - /* Transmitter reset, abort transmit */ - wByteAMD(cs, 0x21, 0x82); - wByteAMD(cs, 0x21, 0x02); - spin_unlock_irqrestore(&cs->lock, flags); - cs->irq_func(cs->irq, cs); - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset"); - } - } -} - - - -void Amd7930_init(struct IsdnCardState *cs) -{ - WORD *ptr; - BYTE cmd, cnt; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Amd7930: initamd called"); - - cs->dc.amd7930.tx_xmtlen = 0; - cs->dc.amd7930.old_state = 0; - cs->dc.amd7930.lmr1 = 0x40; - cs->dc.amd7930.ph_command = Amd7930_ph_command; - cs->setstack_d = setstack_Amd7930; - cs->DC_Close = DC_Close_Amd7930; - - /* AMD Initialisation */ - for (ptr = initAMD; *ptr != 0xFFFF; ) { - cmd = LOBYTE(*ptr); - - /* read */ - if (*ptr++ >= 0x100) { - if (cmd < 8) - /* reset register */ - rByteAMD(cs, cmd); - else { - wByteAMD(cs, 0x00, cmd); - for (cnt = *ptr++; cnt > 0; cnt--) - rByteAMD(cs, 0x01); - } - } - /* write */ - else if (cmd < 8) - wByteAMD(cs, cmd, LOBYTE(*ptr++)); - - else { - wByteAMD(cs, 0x00, cmd); - for (cnt = *ptr++; cnt > 0; cnt--) - wByteAMD(cs, 0x01, LOBYTE(*ptr++)); - } - } -} - -void setup_Amd7930(struct IsdnCardState *cs) -{ - INIT_WORK(&cs->tqueue, Amd7930_bh); - timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0); -} diff --git a/drivers/isdn/hisax/amd7930_fn.h b/drivers/isdn/hisax/amd7930_fn.h deleted file mode 100644 index 1f4d80c5e5a6..000000000000 --- a/drivers/isdn/hisax/amd7930_fn.h +++ /dev/null @@ -1,37 +0,0 @@ -/* drivers/isdn/hisax/amd7930_fn.h - * - * gerdes_amd7930.h Header-file included by - * gerdes_amd7930.c - * - * Author Christoph Ersfeld <info@formula-n.de> - * Formula-n Europe AG (www.formula-n.com) - * previously Gerdes AG - * - * - * This file is (c) under GNU PUBLIC LICENSE - */ - - - - -#define BYTE unsigned char -#define WORD unsigned int -#define rByteAMD(cs, reg) cs->readisac(cs, reg) -#define wByteAMD(cs, reg, val) cs->writeisac(cs, reg, val) -#define rWordAMD(cs, reg) ReadWordAmd7930(cs, reg) -#define wWordAMD(cs, reg, val) WriteWordAmd7930(cs, reg, val) -#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256)) -#define LOBYTE(w) ((unsigned char)(w & 0x00ff)) - -#define AmdIrqOff(cs) cs->dc.amd7930.setIrqMask(cs, 0) -#define AmdIrqOn(cs) cs->dc.amd7930.setIrqMask(cs, 1) - -#define AMD_CR 0x00 -#define AMD_DR 0x01 - - -#define DBUSY_TIMER_VALUE 80 - -extern void Amd7930_interrupt(struct IsdnCardState *, unsigned char); -extern void Amd7930_init(struct IsdnCardState *); -extern void setup_Amd7930(struct IsdnCardState *); diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c deleted file mode 100644 index 2f784f96d439..000000000000 --- a/drivers/isdn/hisax/arcofi.c +++ /dev/null @@ -1,131 +0,0 @@ -/* $Id: arcofi.c,v 1.14.2.3 2004/01/13 14:31:24 keil Exp $ - * - * Ansteuerung ARCOFI 2165 - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/sched.h> -#include "hisax.h" -#include "isdnl1.h" -#include "isac.h" -#include "arcofi.h" - -#define ARCOFI_TIMER_VALUE 20 - -static void -add_arcofi_timer(struct IsdnCardState *cs) { - if (test_and_set_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { - del_timer(&cs->dc.isac.arcofitimer); - } - cs->dc.isac.arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ) / 1000); - add_timer(&cs->dc.isac.arcofitimer); -} - -static void -send_arcofi(struct IsdnCardState *cs) { - add_arcofi_timer(cs); - cs->dc.isac.mon_txp = 0; - cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len; - memcpy(cs->dc.isac.mon_tx, cs->dc.isac.arcofi_list->msg, cs->dc.isac.mon_txc); - switch (cs->dc.isac.arcofi_bc) { - case 0: break; - case 1: cs->dc.isac.mon_tx[1] |= 0x40; - break; - default: break; - } - cs->dc.isac.mocr &= 0x0f; - cs->dc.isac.mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - (void) cs->readisac(cs, ISAC_MOSR); - cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); - cs->dc.isac.mocr |= 0x10; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); -} - -int -arcofi_fsm(struct IsdnCardState *cs, int event, void *data) { - if (cs->debug & L1_DEB_MONITOR) { - debugl1(cs, "arcofi state %d event %d", cs->dc.isac.arcofi_state, event); - } - if (event == ARCOFI_TIMEOUT) { - cs->dc.isac.arcofi_state = ARCOFI_NOP; - test_and_set_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags); - wake_up(&cs->dc.isac.arcofi_wait); - return (1); - } - switch (cs->dc.isac.arcofi_state) { - case ARCOFI_NOP: - if (event == ARCOFI_START) { - cs->dc.isac.arcofi_list = data; - cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT; - send_arcofi(cs); - } - break; - case ARCOFI_TRANSMIT: - if (event == ARCOFI_TX_END) { - if (cs->dc.isac.arcofi_list->receive) { - add_arcofi_timer(cs); - cs->dc.isac.arcofi_state = ARCOFI_RECEIVE; - } else { - if (cs->dc.isac.arcofi_list->next) { - cs->dc.isac.arcofi_list = - cs->dc.isac.arcofi_list->next; - send_arcofi(cs); - } else { - if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { - del_timer(&cs->dc.isac.arcofitimer); - } - cs->dc.isac.arcofi_state = ARCOFI_NOP; - wake_up(&cs->dc.isac.arcofi_wait); - } - } - } - break; - case ARCOFI_RECEIVE: - if (event == ARCOFI_RX_END) { - if (cs->dc.isac.arcofi_list->next) { - cs->dc.isac.arcofi_list = - cs->dc.isac.arcofi_list->next; - cs->dc.isac.arcofi_state = ARCOFI_TRANSMIT; - send_arcofi(cs); - } else { - if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { - del_timer(&cs->dc.isac.arcofitimer); - } - cs->dc.isac.arcofi_state = ARCOFI_NOP; - wake_up(&cs->dc.isac.arcofi_wait); - } - } - break; - default: - debugl1(cs, "Arcofi unknown state %x", cs->dc.isac.arcofi_state); - return (2); - } - return (0); -} - -static void -arcofi_timer(struct timer_list *t) { - struct IsdnCardState *cs = from_timer(cs, t, dc.isac.arcofitimer); - arcofi_fsm(cs, ARCOFI_TIMEOUT, NULL); -} - -void -clear_arcofi(struct IsdnCardState *cs) { - if (test_and_clear_bit(FLG_ARCOFI_TIMER, &cs->HW_Flags)) { - del_timer(&cs->dc.isac.arcofitimer); - } -} - -void -init_arcofi(struct IsdnCardState *cs) { - timer_setup(&cs->dc.isac.arcofitimer, arcofi_timer, 0); - init_waitqueue_head(&cs->dc.isac.arcofi_wait); - test_and_set_bit(HW_ARCOFI, &cs->HW_Flags); -} diff --git a/drivers/isdn/hisax/arcofi.h b/drivers/isdn/hisax/arcofi.h deleted file mode 100644 index b9c77529fabf..000000000000 --- a/drivers/isdn/hisax/arcofi.h +++ /dev/null @@ -1,27 +0,0 @@ -/* $Id: arcofi.h,v 1.6.6.2 2001/09/23 22:24:46 kai Exp $ - * - * Ansteuerung ARCOFI 2165 - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define ARCOFI_USE 1 - -/* states */ -#define ARCOFI_NOP 0 -#define ARCOFI_TRANSMIT 1 -#define ARCOFI_RECEIVE 2 -/* events */ -#define ARCOFI_START 1 -#define ARCOFI_TX_END 2 -#define ARCOFI_RX_END 3 -#define ARCOFI_TIMEOUT 4 - -extern int arcofi_fsm(struct IsdnCardState *cs, int event, void *data); -extern void init_arcofi(struct IsdnCardState *cs); -extern void clear_arcofi(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c deleted file mode 100644 index 74c871495e81..000000000000 --- a/drivers/isdn/hisax/asuscom.c +++ /dev/null @@ -1,423 +0,0 @@ -/* $Id: asuscom.c,v 1.14.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for ASUSCOM NETWORK INC. ISDNLink cards - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to ASUSCOM NETWORK INC. Taiwan and Dynalink NL for information - * - */ - -#include <linux/init.h> -#include <linux/isapnp.h> -#include "hisax.h" -#include "isac.h" -#include "ipac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *Asuscom_revision = "$Revision: 1.14.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define ASUS_ISAC 0 -#define ASUS_HSCX 1 -#define ASUS_ADR 2 -#define ASUS_CTRL_U7 3 -#define ASUS_CTRL_POTS 5 - -#define ASUS_IPAC_ALE 0 -#define ASUS_IPAC_DATA 1 - -#define ASUS_ISACHSCX 1 -#define ASUS_IPAC 2 - -/* CARD_ADR (Write) */ -#define ASUS_RESET 0x80 /* Bit 7 Reset-Leitung */ - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0, data, size); -} - -static u_char -ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.asus.adr, cs->hw.asus.isac, offset | 0x80)); -} - -static void -WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.asus.adr, cs->hw.asus.isac, offset | 0x80, value); -} - -static void -ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size); -} - -static void -WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.asus.adr, cs->hw.asus.isac, 0x80, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.asus.adr, - cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.asus.adr, - cs->hw.asus.hscx, offset + (hscx ? 0x40 : 0), value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.asus.adr, \ - cs->hw.asus.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.asus.adr, \ - cs->hw.asus.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.asus.adr, \ - cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.asus.adr, \ - cs->hw.asus.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -asuscom_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_MASK, 0x0); - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_MASK + 0x40, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -asuscom_interrupt_ipac(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val, icnt = 5; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA); -Start_IPAC: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = readreg(cs->hw.asus.adr, cs->hw.asus.hscx, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - hscx_int_main(cs, val); - } - if (ista & 0x20) { - val = 0xfe & readreg(cs->hw.asus.adr, cs->hw.asus.isac, ISAC_ISTA | 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = readreg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPAC; - } - if (!icnt) - printk(KERN_WARNING "ASUS IRQ LOOP\n"); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xFF); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_asuscom(struct IsdnCardState *cs) -{ - int bytecnt = 8; - - if (cs->hw.asus.cfg_reg) - release_region(cs->hw.asus.cfg_reg, bytecnt); -} - -static void -reset_asuscom(struct IsdnCardState *cs) -{ - if (cs->subtyp == ASUS_IPAC) - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x20); - else - byteout(cs->hw.asus.adr, ASUS_RESET); /* Reset On */ - mdelay(10); - if (cs->subtyp == ASUS_IPAC) - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_POTA2, 0x0); - else - byteout(cs->hw.asus.adr, 0); /* Reset Off */ - mdelay(10); - if (cs->subtyp == ASUS_IPAC) { - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_CONF, 0x0); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_ACFG, 0xff); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_AOE, 0x0); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_MASK, 0xc0); - writereg(cs->hw.asus.adr, cs->hw.asus.isac, IPAC_PCFG, 0x12); - } -} - -static int -Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_asuscom(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_asuscom(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - cs->debug |= L1_DEB_IPAC; - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id asus_ids[] = { - { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688), - ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688), - (unsigned long) "Asus1688 PnP" }, - { ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690), - ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690), - (unsigned long) "Asus1690 PnP" }, - { ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020), - ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020), - (unsigned long) "Isurf2 PnP" }, - { ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000), - ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000), - (unsigned long) "Iscas TE320" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &asus_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_asuscom(struct IsdnCard *card) -{ - int bytecnt; - struct IsdnCardState *cs = card->cs; - u_char val; - char tmp[64]; - - strcpy(tmp, Asuscom_revision); - printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_ASUSCOM) - return (0); -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - break; - } else { - printk(KERN_ERR "AsusPnP: PnP error card found, no device\n"); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "AsusPnP: no ISAPnP card found\n"); - return (0); - } - } -#endif - bytecnt = 8; - cs->hw.asus.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (!request_region(cs->hw.asus.cfg_reg, bytecnt, "asuscom isdn")) { - printk(KERN_WARNING - "HiSax: ISDNLink config port %x-%x already in use\n", - cs->hw.asus.cfg_reg, - cs->hw.asus.cfg_reg + bytecnt); - return (0); - } - printk(KERN_INFO "ISDNLink: defined at 0x%x IRQ %d\n", - cs->hw.asus.cfg_reg, cs->irq); - setup_isac(cs); - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Asus_card_msg; - val = readreg(cs->hw.asus.cfg_reg + ASUS_IPAC_ALE, - cs->hw.asus.cfg_reg + ASUS_IPAC_DATA, IPAC_ID); - if ((val == 1) || (val == 2)) { - cs->subtyp = ASUS_IPAC; - cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_IPAC_ALE; - cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; - cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_IPAC_DATA; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->readisac = &ReadISAC_IPAC; - cs->writeisac = &WriteISAC_IPAC; - cs->readisacfifo = &ReadISACfifo_IPAC; - cs->writeisacfifo = &WriteISACfifo_IPAC; - cs->irq_func = &asuscom_interrupt_ipac; - printk(KERN_INFO "Asus: IPAC version %x\n", val); - } else { - cs->subtyp = ASUS_ISACHSCX; - cs->hw.asus.adr = cs->hw.asus.cfg_reg + ASUS_ADR; - cs->hw.asus.isac = cs->hw.asus.cfg_reg + ASUS_ISAC; - cs->hw.asus.hscx = cs->hw.asus.cfg_reg + ASUS_HSCX; - cs->hw.asus.u7 = cs->hw.asus.cfg_reg + ASUS_CTRL_U7; - cs->hw.asus.pots = cs->hw.asus.cfg_reg + ASUS_CTRL_POTS; - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->irq_func = &asuscom_interrupt; - ISACVersion(cs, "ISDNLink:"); - if (HscxVersion(cs, "ISDNLink:")) { - printk(KERN_WARNING - "ISDNLink: wrong HSCX versions check IO address\n"); - release_io_asuscom(cs); - return (0); - } - } - return (1); -} diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c deleted file mode 100644 index 7dd74087ad72..000000000000 --- a/drivers/isdn/hisax/avm_a1.c +++ /dev/null @@ -1,307 +0,0 @@ -/* $Id: avm_a1.c,v 2.15.2.4 2004/01/13 21:46:03 keil Exp $ - * - * low level stuff for AVM A1 (Fritz) isdn cards - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *avm_revision = "$Revision: 2.15.2.4 $"; - -#define AVM_A1_STAT_ISAC 0x01 -#define AVM_A1_STAT_HSCX 0x02 -#define AVM_A1_STAT_TIMER 0x04 - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static inline u_char -readreg(unsigned int adr, u_char off) -{ - return (bytein(adr + off)); -} - -static inline void -writereg(unsigned int adr, u_char off, u_char data) -{ - byteout(adr + off, data); -} - - -static inline void -read_fifo(unsigned int adr, u_char *data, int size) -{ - insb(adr, data, size); -} - -static void -write_fifo(unsigned int adr, u_char *data, int size) -{ - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.avm.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.avm.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo(cs->hw.avm.isacfifo, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo(cs->hw.avm.isacfifo, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.avm.hscx[hscx], offset)); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.avm.hscx[hscx], offset, value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.avm.hscx[nr], reg) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.avm.hscx[nr], reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.avm.hscxfifo[nr], ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -avm_a1_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - while (((sval = bytein(cs->hw.avm.cfg_reg)) & 0xf) != 0x7) { - if (!(sval & AVM_A1_STAT_TIMER)) { - byteout(cs->hw.avm.cfg_reg, 0x1E); - sval = bytein(cs->hw.avm.cfg_reg); - } else if (cs->debug & L1_DEB_INTSTAT) - debugl1(cs, "avm IntStatus %x", sval); - if (!(sval & AVM_A1_STAT_HSCX)) { - val = readreg(cs->hw.avm.hscx[1], HSCX_ISTA); - if (val) - hscx_int_main(cs, val); - } - if (!(sval & AVM_A1_STAT_ISAC)) { - val = readreg(cs->hw.avm.isac, ISAC_ISTA); - if (val) - isac_interrupt(cs, val); - } - } - writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0xFF); - writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0xFF); - writereg(cs->hw.avm.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.avm.isac, ISAC_MASK, 0x0); - writereg(cs->hw.avm.hscx[0], HSCX_MASK, 0x0); - writereg(cs->hw.avm.hscx[1], HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static inline void -release_ioregs(struct IsdnCardState *cs, int mask) -{ - release_region(cs->hw.avm.cfg_reg, 8); - if (mask & 1) - release_region(cs->hw.avm.isac + 32, 32); - if (mask & 2) - release_region(cs->hw.avm.isacfifo, 1); - if (mask & 4) - release_region(cs->hw.avm.hscx[0] + 32, 32); - if (mask & 8) - release_region(cs->hw.avm.hscxfifo[0], 1); - if (mask & 0x10) - release_region(cs->hw.avm.hscx[1] + 32, 32); - if (mask & 0x20) - release_region(cs->hw.avm.hscxfifo[1], 1); -} - -static int -AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - return (0); - case CARD_RELEASE: - release_ioregs(cs, 0x3f); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 1); - byteout(cs->hw.avm.cfg_reg, 0x16); - byteout(cs->hw.avm.cfg_reg, 0x1E); - inithscxisac(cs, 2); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -int setup_avm_a1(struct IsdnCard *card) -{ - u_char val; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, avm_revision); - printk(KERN_INFO "HiSax: AVM driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_A1) - return (0); - - cs->hw.avm.cfg_reg = card->para[1] + 0x1800; - cs->hw.avm.isac = card->para[1] + 0x1400 - 0x20; - cs->hw.avm.hscx[0] = card->para[1] + 0x400 - 0x20; - cs->hw.avm.hscx[1] = card->para[1] + 0xc00 - 0x20; - cs->hw.avm.isacfifo = card->para[1] + 0x1000; - cs->hw.avm.hscxfifo[0] = card->para[1]; - cs->hw.avm.hscxfifo[1] = card->para[1] + 0x800; - cs->irq = card->para[0]; - if (!request_region(cs->hw.avm.cfg_reg, 8, "avm cfg")) { - printk(KERN_WARNING - "HiSax: AVM A1 config port %x-%x already in use\n", - cs->hw.avm.cfg_reg, - cs->hw.avm.cfg_reg + 8); - return (0); - } - if (!request_region(cs->hw.avm.isac + 32, 32, "HiSax isac")) { - printk(KERN_WARNING - "HiSax: AVM A1 isac ports %x-%x already in use\n", - cs->hw.avm.isac + 32, - cs->hw.avm.isac + 64); - release_ioregs(cs, 0); - return (0); - } - if (!request_region(cs->hw.avm.isacfifo, 1, "HiSax isac fifo")) { - printk(KERN_WARNING - "HiSax: AVM A1 isac fifo port %x already in use\n", - cs->hw.avm.isacfifo); - release_ioregs(cs, 1); - return (0); - } - if (!request_region(cs->hw.avm.hscx[0] + 32, 32, "HiSax hscx A")) { - printk(KERN_WARNING - "HiSax: AVM A1 hscx A ports %x-%x already in use\n", - cs->hw.avm.hscx[0] + 32, - cs->hw.avm.hscx[0] + 64); - release_ioregs(cs, 3); - return (0); - } - if (!request_region(cs->hw.avm.hscxfifo[0], 1, "HiSax hscx A fifo")) { - printk(KERN_WARNING - "HiSax: AVM A1 hscx A fifo port %x already in use\n", - cs->hw.avm.hscxfifo[0]); - release_ioregs(cs, 7); - return (0); - } - if (!request_region(cs->hw.avm.hscx[1] + 32, 32, "HiSax hscx B")) { - printk(KERN_WARNING - "HiSax: AVM A1 hscx B ports %x-%x already in use\n", - cs->hw.avm.hscx[1] + 32, - cs->hw.avm.hscx[1] + 64); - release_ioregs(cs, 0xf); - return (0); - } - if (!request_region(cs->hw.avm.hscxfifo[1], 1, "HiSax hscx B fifo")) { - printk(KERN_WARNING - "HiSax: AVM A1 hscx B fifo port %x already in use\n", - cs->hw.avm.hscxfifo[1]); - release_ioregs(cs, 0x1f); - return (0); - } - byteout(cs->hw.avm.cfg_reg, 0x0); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg, 0x1); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg, 0x0); - HZDELAY(HZ / 5 + 1); - val = cs->irq; - if (val == 9) - val = 2; - byteout(cs->hw.avm.cfg_reg + 1, val); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg, 0x0); - HZDELAY(HZ / 5 + 1); - - val = bytein(cs->hw.avm.cfg_reg); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - cs->hw.avm.cfg_reg, val); - val = bytein(cs->hw.avm.cfg_reg + 3); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - cs->hw.avm.cfg_reg + 3, val); - val = bytein(cs->hw.avm.cfg_reg + 2); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - cs->hw.avm.cfg_reg + 2, val); - val = bytein(cs->hw.avm.cfg_reg); - printk(KERN_INFO "AVM A1: Byte at %x is %x\n", - cs->hw.avm.cfg_reg, val); - - printk(KERN_INFO "HiSax: AVM A1 config irq:%d cfg:0x%X\n", - cs->irq, - cs->hw.avm.cfg_reg); - printk(KERN_INFO - "HiSax: isac:0x%X/0x%X\n", - cs->hw.avm.isac + 32, cs->hw.avm.isacfifo); - printk(KERN_INFO - "HiSax: hscx A:0x%X/0x%X hscx B:0x%X/0x%X\n", - cs->hw.avm.hscx[0] + 32, cs->hw.avm.hscxfifo[0], - cs->hw.avm.hscx[1] + 32, cs->hw.avm.hscxfifo[1]); - - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - setup_isac(cs); - cs->cardmsg = &AVM_card_msg; - cs->irq_func = &avm_a1_interrupt; - ISACVersion(cs, "AVM A1:"); - if (HscxVersion(cs, "AVM A1:")) { - printk(KERN_WARNING - "AVM A1: wrong HSCX versions check IO address\n"); - release_ioregs(cs, 0x3f); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c deleted file mode 100644 index bc52d54ff5e1..000000000000 --- a/drivers/isdn/hisax/avm_a1p.c +++ /dev/null @@ -1,267 +0,0 @@ -/* $Id: avm_a1p.c,v 2.9.2.5 2004/01/24 20:47:19 keil Exp $ - * - * low level stuff for the following AVM cards: - * A1 PCMCIA - * FRITZ!Card PCMCIA - * FRITZ!Card PCMCIA 2.0 - * - * Author Carsten Paeth - * Copyright by Carsten Paeth <calle@calle.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -/* register offsets */ -#define ADDRREG_OFFSET 0x02 -#define DATAREG_OFFSET 0x03 -#define ASL0_OFFSET 0x04 -#define ASL1_OFFSET 0x05 -#define MODREG_OFFSET 0x06 -#define VERREG_OFFSET 0x07 - -/* address offsets */ -#define ISAC_FIFO_OFFSET 0x00 -#define ISAC_REG_OFFSET 0x20 -#define HSCX_CH_DIFF 0x40 -#define HSCX_FIFO_OFFSET 0x80 -#define HSCX_REG_OFFSET 0xa0 - -/* read bits ASL0 */ -#define ASL0_R_TIMER 0x10 /* active low */ -#define ASL0_R_ISAC 0x20 /* active low */ -#define ASL0_R_HSCX 0x40 /* active low */ -#define ASL0_R_TESTBIT 0x80 -#define ASL0_R_IRQPENDING (ASL0_R_ISAC | ASL0_R_HSCX | ASL0_R_TIMER) - -/* write bits ASL0 */ -#define ASL0_W_RESET 0x01 -#define ASL0_W_TDISABLE 0x02 -#define ASL0_W_TRESET 0x04 -#define ASL0_W_IRQENABLE 0x08 -#define ASL0_W_TESTBIT 0x80 - -/* write bits ASL1 */ -#define ASL1_W_LED0 0x10 -#define ASL1_W_LED1 0x20 -#define ASL1_W_ENABLE_S0 0xC0 - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static const char *avm_revision = "$Revision: 2.9.2.5 $"; - -static inline u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - u_char ret; - - offset -= 0x20; - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_REG_OFFSET + offset); - ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET); - return ret; -} - -static inline void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - offset -= 0x20; - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_REG_OFFSET + offset); - byteout(cs->hw.avm.cfg_reg + DATAREG_OFFSET, value); -} - -static inline void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_FIFO_OFFSET); - insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size); -} - -static inline void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, ISAC_FIFO_OFFSET); - outsb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size); -} - -static inline u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - u_char ret; - - offset -= 0x20; - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, - HSCX_REG_OFFSET + hscx * HSCX_CH_DIFF + offset); - ret = bytein(cs->hw.avm.cfg_reg + DATAREG_OFFSET); - return ret; -} - -static inline void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - offset -= 0x20; - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, - HSCX_REG_OFFSET + hscx * HSCX_CH_DIFF + offset); - byteout(cs->hw.avm.cfg_reg + DATAREG_OFFSET, value); -} - -static inline void -ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size) -{ - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, - HSCX_FIFO_OFFSET + hscx * HSCX_CH_DIFF); - insb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size); -} - -static inline void -WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size) -{ - byteout(cs->hw.avm.cfg_reg + ADDRREG_OFFSET, - HSCX_FIFO_OFFSET + hscx * HSCX_CH_DIFF); - outsb(cs->hw.avm.cfg_reg + DATAREG_OFFSET, data, size); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg) -#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -avm_a1p_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - while ((sval = (~bytein(cs->hw.avm.cfg_reg + ASL0_OFFSET) & ASL0_R_IRQPENDING))) { - if (cs->debug & L1_DEB_INTSTAT) - debugl1(cs, "avm IntStatus %x", sval); - if (sval & ASL0_R_HSCX) { - val = ReadHSCX(cs, 1, HSCX_ISTA); - if (val) - hscx_int_main(cs, val); - } - if (sval & ASL0_R_ISAC) { - val = ReadISAC(cs, ISAC_ISTA); - if (val) - isac_interrupt(cs, val); - } - } - WriteHSCX(cs, 0, HSCX_MASK, 0xff); - WriteHSCX(cs, 1, HSCX_MASK, 0xff); - WriteISAC(cs, ISAC_MASK, 0xff); - WriteISAC(cs, ISAC_MASK, 0x00); - WriteHSCX(cs, 0, HSCX_MASK, 0x00); - WriteHSCX(cs, 1, HSCX_MASK, 0x00); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static int -AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_RESET); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00); - spin_unlock_irqrestore(&cs->lock, flags); - return 0; - - case CARD_RELEASE: - /* free_irq is done in HiSax_closecard(). */ - /* free_irq(cs->irq, cs); */ - return 0; - - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_TDISABLE | ASL0_W_TRESET | ASL0_W_IRQENABLE); - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - inithscxisac(cs, 1); - inithscxisac(cs, 2); - spin_unlock_irqrestore(&cs->lock, flags); - return 0; - - case CARD_TEST: - /* we really don't need it for the PCMCIA Version */ - return 0; - - default: - /* all card drivers ignore others, so we do the same */ - return 0; - } - return 0; -} - -int setup_avm_a1_pcmcia(struct IsdnCard *card) -{ - u_char model, vers; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - - strcpy(tmp, avm_revision); - printk(KERN_INFO "HiSax: AVM A1 PCMCIA driver Rev. %s\n", - HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_A1_PCMCIA) - return (0); - - cs->hw.avm.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - - - byteout(cs->hw.avm.cfg_reg + ASL1_OFFSET, ASL1_W_ENABLE_S0); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_RESET); - HZDELAY(HZ / 5 + 1); - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, 0x00); - - byteout(cs->hw.avm.cfg_reg + ASL0_OFFSET, ASL0_W_TDISABLE | ASL0_W_TRESET); - - model = bytein(cs->hw.avm.cfg_reg + MODREG_OFFSET); - vers = bytein(cs->hw.avm.cfg_reg + VERREG_OFFSET); - - printk(KERN_INFO "AVM A1 PCMCIA: io 0x%x irq %d model %d version %d\n", - cs->hw.avm.cfg_reg, cs->irq, model, vers); - - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &AVM_card_msg; - cs->irq_flags = IRQF_SHARED; - cs->irq_func = &avm_a1p_interrupt; - - ISACVersion(cs, "AVM A1 PCMCIA:"); - if (HscxVersion(cs, "AVM A1 PCMCIA:")) { - printk(KERN_WARNING - "AVM A1 PCMCIA: wrong HSCX versions check IO address\n"); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c deleted file mode 100644 index b161456c942e..000000000000 --- a/drivers/isdn/hisax/avm_pci.c +++ /dev/null @@ -1,904 +0,0 @@ -/* $Id: avm_pci.c,v 1.29.2.4 2004/02/11 13:21:32 keil Exp $ - * - * low level stuff for AVM Fritz!PCI and ISA PnP isdn cards - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to AVM, Berlin for information - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "isdnl1.h" -#include <linux/pci.h> -#include <linux/slab.h> -#include <linux/isapnp.h> -#include <linux/interrupt.h> - -static const char *avm_pci_rev = "$Revision: 1.29.2.4 $"; - -#define AVM_FRITZ_PCI 1 -#define AVM_FRITZ_PNP 2 - -#define HDLC_FIFO 0x0 -#define HDLC_STATUS 0x4 - -#define AVM_HDLC_1 0x00 -#define AVM_HDLC_2 0x01 -#define AVM_ISAC_FIFO 0x02 -#define AVM_ISAC_REG_LOW 0x04 -#define AVM_ISAC_REG_HIGH 0x06 - -#define AVM_STATUS0_IRQ_ISAC 0x01 -#define AVM_STATUS0_IRQ_HDLC 0x02 -#define AVM_STATUS0_IRQ_TIMER 0x04 -#define AVM_STATUS0_IRQ_MASK 0x07 - -#define AVM_STATUS0_RESET 0x01 -#define AVM_STATUS0_DIS_TIMER 0x02 -#define AVM_STATUS0_RES_TIMER 0x04 -#define AVM_STATUS0_ENA_IRQ 0x08 -#define AVM_STATUS0_TESTBIT 0x10 - -#define AVM_STATUS1_INT_SEL 0x0f -#define AVM_STATUS1_ENA_IOM 0x80 - -#define HDLC_MODE_ITF_FLG 0x01 -#define HDLC_MODE_TRANS 0x02 -#define HDLC_MODE_CCR_7 0x04 -#define HDLC_MODE_CCR_16 0x08 -#define HDLC_MODE_TESTLOOP 0x80 - -#define HDLC_INT_XPR 0x80 -#define HDLC_INT_XDU 0x40 -#define HDLC_INT_RPR 0x20 -#define HDLC_INT_MASK 0xE0 - -#define HDLC_STAT_RME 0x01 -#define HDLC_STAT_RDO 0x10 -#define HDLC_STAT_CRCVFRRAB 0x0E -#define HDLC_STAT_CRCVFR 0x06 -#define HDLC_STAT_RML_MASK 0x3f00 - -#define HDLC_CMD_XRS 0x80 -#define HDLC_CMD_XME 0x01 -#define HDLC_CMD_RRS 0x20 -#define HDLC_CMD_XML_MASK 0x3f00 - - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; - register u_char val; - - outb(idx, cs->hw.avm.cfg_reg + 4); - val = inb(cs->hw.avm.isac + (offset & 0xf)); - return (val); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - register u_char idx = (offset > 0x2f) ? AVM_ISAC_REG_HIGH : AVM_ISAC_REG_LOW; - - outb(idx, cs->hw.avm.cfg_reg + 4); - outb(value, cs->hw.avm.isac + (offset & 0xf)); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4); - insb(cs->hw.avm.isac, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - outb(AVM_ISAC_FIFO, cs->hw.avm.cfg_reg + 4); - outsb(cs->hw.avm.isac, data, size); -} - -static inline u_int -ReadHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset) -{ - register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - register u_int val; - - outl(idx, cs->hw.avm.cfg_reg + 4); - val = inl(cs->hw.avm.isac + offset); - return (val); -} - -static inline void -WriteHDLCPCI(struct IsdnCardState *cs, int chan, u_char offset, u_int value) -{ - register u_int idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - - outl(idx, cs->hw.avm.cfg_reg + 4); - outl(value, cs->hw.avm.isac + offset); -} - -static inline u_char -ReadHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset) -{ - register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - register u_char val; - - outb(idx, cs->hw.avm.cfg_reg + 4); - val = inb(cs->hw.avm.isac + offset); - return (val); -} - -static inline void -WriteHDLCPnP(struct IsdnCardState *cs, int chan, u_char offset, u_char value) -{ - register u_char idx = chan ? AVM_HDLC_2 : AVM_HDLC_1; - - outb(idx, cs->hw.avm.cfg_reg + 4); - outb(value, cs->hw.avm.isac + offset); -} - -static u_char -ReadHDLC_s(struct IsdnCardState *cs, int chan, u_char offset) -{ - return (0xff & ReadHDLCPCI(cs, chan, offset)); -} - -static void -WriteHDLC_s(struct IsdnCardState *cs, int chan, u_char offset, u_char value) -{ - WriteHDLCPCI(cs, chan, offset, value); -} - -static inline -struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel) -{ - if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) - return (&cs->bcs[0]); - else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) - return (&cs->bcs[1]); - else - return (NULL); -} - -static void -write_ctrl(struct BCState *bcs, int which) { - - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "hdlc %c wr%x ctrl %x", - 'A' + bcs->channel, which, bcs->hw.hdlc.ctrl.ctrl); - if (bcs->cs->subtyp == AVM_FRITZ_PCI) { - WriteHDLCPCI(bcs->cs, bcs->channel, HDLC_STATUS, bcs->hw.hdlc.ctrl.ctrl); - } else { - if (which & 4) - WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 2, - bcs->hw.hdlc.ctrl.sr.mode); - if (which & 2) - WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS + 1, - bcs->hw.hdlc.ctrl.sr.xml); - if (which & 1) - WriteHDLCPnP(bcs->cs, bcs->channel, HDLC_STATUS, - bcs->hw.hdlc.ctrl.sr.cmd); - } -} - -static void -modehdlc(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int hdlc = bcs->channel; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hdlc %c mode %d --> %d ichan %d --> %d", - 'A' + hdlc, bcs->mode, mode, hdlc, bc); - bcs->hw.hdlc.ctrl.ctrl = 0; - switch (mode) { - case (-1): /* used for init */ - bcs->mode = 1; - bcs->channel = bc; - bc = 0; - /* fall through */ - case (L1_MODE_NULL): - if (bcs->mode == L1_MODE_NULL) - return; - bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS; - write_ctrl(bcs, 5); - bcs->mode = L1_MODE_NULL; - bcs->channel = bc; - break; - case (L1_MODE_TRANS): - bcs->mode = mode; - bcs->channel = bc; - bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_TRANS; - write_ctrl(bcs, 5); - bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.ctrl.sr.cmd = 0; - schedule_event(bcs, B_XMTBUFREADY); - break; - case (L1_MODE_HDLC): - bcs->mode = mode; - bcs->channel = bc; - bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - bcs->hw.hdlc.ctrl.sr.mode = HDLC_MODE_ITF_FLG; - write_ctrl(bcs, 5); - bcs->hw.hdlc.ctrl.sr.cmd = HDLC_CMD_XRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.ctrl.sr.cmd = 0; - schedule_event(bcs, B_XMTBUFREADY); - break; - } -} - -static inline void -hdlc_empty_fifo(struct BCState *bcs, int count) -{ - register u_int *ptr; - u_char *p; - u_char idx = bcs->channel ? AVM_HDLC_2 : AVM_HDLC_1; - int cnt = 0; - struct IsdnCardState *cs = bcs->cs; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hdlc_empty_fifo %d", count); - if (bcs->hw.hdlc.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hdlc_empty_fifo: incoming packet too large"); - return; - } - p = bcs->hw.hdlc.rcvbuf + bcs->hw.hdlc.rcvidx; - ptr = (u_int *)p; - bcs->hw.hdlc.rcvidx += count; - if (cs->subtyp == AVM_FRITZ_PCI) { - outl(idx, cs->hw.avm.cfg_reg + 4); - while (cnt < count) { -#ifdef __powerpc__ - *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac + _IO_BASE)); -#else - *ptr++ = inl(cs->hw.avm.isac); -#endif /* __powerpc__ */ - cnt += 4; - } - } else { - outb(idx, cs->hw.avm.cfg_reg + 4); - while (cnt < count) { - *p++ = inb(cs->hw.avm.isac); - cnt++; - } - } - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - if (cs->subtyp == AVM_FRITZ_PNP) - p = (u_char *) ptr; - t += sprintf(t, "hdlc_empty_fifo %c cnt %d", - bcs->channel ? 'B' : 'A', count); - QuickHex(t, p, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static inline void -hdlc_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int count, cnt = 0; - int fifo_size = 32; - u_char *p; - u_int *ptr; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hdlc_fill_fifo"); - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XME; - if (bcs->tx_skb->len > fifo_size) { - count = fifo_size; - } else { - count = bcs->tx_skb->len; - if (bcs->mode != L1_MODE_TRANS) - bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME; - } - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hdlc_fill_fifo %d/%u", count, bcs->tx_skb->len); - p = bcs->tx_skb->data; - ptr = (u_int *)p; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.hdlc.count += count; - bcs->hw.hdlc.ctrl.sr.xml = ((count == fifo_size) ? 0 : count); - write_ctrl(bcs, 3); /* sets the correct index too */ - if (cs->subtyp == AVM_FRITZ_PCI) { - while (cnt < count) { -#ifdef __powerpc__ - out_be32((unsigned *)(cs->hw.avm.isac + _IO_BASE), *ptr++); -#else - outl(*ptr++, cs->hw.avm.isac); -#endif /* __powerpc__ */ - cnt += 4; - } - } else { - while (cnt < count) { - outb(*p++, cs->hw.avm.isac); - cnt++; - } - } - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - if (cs->subtyp == AVM_FRITZ_PNP) - p = (u_char *) ptr; - t += sprintf(t, "hdlc_fill_fifo %c cnt %d", - bcs->channel ? 'B' : 'A', count); - QuickHex(t, p, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -HDLC_irq(struct BCState *bcs, u_int stat) { - int len; - struct sk_buff *skb; - - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat); - if (stat & HDLC_INT_RPR) { - if (stat & HDLC_STAT_RDO) { - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "RDO"); - else - debugl1(bcs->cs, "ch%d stat %#x", bcs->channel, stat); - bcs->hw.hdlc.ctrl.sr.xml = 0; - bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_RRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_RRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.rcvidx = 0; - } else { - if (!(len = (stat & HDLC_STAT_RML_MASK) >> 8)) - len = 32; - hdlc_empty_fifo(bcs, len); - if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) { - if (((stat & HDLC_STAT_CRCVFRRAB) == HDLC_STAT_CRCVFR) || - (bcs->mode == L1_MODE_TRANS)) { - if (!(skb = dev_alloc_skb(bcs->hw.hdlc.rcvidx))) - printk(KERN_WARNING "HDLC: receive out of memory\n"); - else { - skb_put_data(skb, - bcs->hw.hdlc.rcvbuf, - bcs->hw.hdlc.rcvidx); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.hdlc.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } else { - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "invalid frame"); - else - debugl1(bcs->cs, "ch%d invalid frame %#x", bcs->channel, stat); - bcs->hw.hdlc.rcvidx = 0; - } - } - } - } - if (stat & HDLC_INT_XDU) { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hdlc.count); - bcs->tx_cnt += bcs->hw.hdlc.count; - bcs->hw.hdlc.count = 0; - if (bcs->cs->debug & L1_DEB_WARN) - debugl1(bcs->cs, "ch%d XDU", bcs->channel); - } else if (bcs->cs->debug & L1_DEB_WARN) - debugl1(bcs->cs, "ch%d XDU without skb", bcs->channel); - bcs->hw.hdlc.ctrl.sr.xml = 0; - bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XRS; - write_ctrl(bcs, 1); - bcs->hw.hdlc.ctrl.sr.cmd &= ~HDLC_CMD_XRS; - write_ctrl(bcs, 1); - hdlc_fill_fifo(bcs); - } else if (stat & HDLC_INT_XPR) { - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - hdlc_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hdlc.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hdlc.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hdlc.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - hdlc_fill_fifo(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -} - -static inline void -HDLC_irq_main(struct IsdnCardState *cs) -{ - u_int stat; - struct BCState *bcs; - - if (cs->subtyp == AVM_FRITZ_PCI) { - stat = ReadHDLCPCI(cs, 0, HDLC_STATUS); - } else { - stat = ReadHDLCPnP(cs, 0, HDLC_STATUS); - if (stat & HDLC_INT_RPR) - stat |= (ReadHDLCPnP(cs, 0, HDLC_STATUS + 1)) << 8; - } - if (stat & HDLC_INT_MASK) { - if (!(bcs = Sel_BCS(cs, 0))) { - if (cs->debug) - debugl1(cs, "hdlc spurious channel 0 IRQ"); - } else - HDLC_irq(bcs, stat); - } - if (cs->subtyp == AVM_FRITZ_PCI) { - stat = ReadHDLCPCI(cs, 1, HDLC_STATUS); - } else { - stat = ReadHDLCPnP(cs, 1, HDLC_STATUS); - if (stat & HDLC_INT_RPR) - stat |= (ReadHDLCPnP(cs, 1, HDLC_STATUS + 1)) << 8; - } - if (stat & HDLC_INT_MASK) { - if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hdlc spurious channel 1 IRQ"); - } else - HDLC_irq(bcs, stat); - } -} - -static void -hdlc_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.hdlc.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "hdlc_l2l1: this shouldn't happen\n"); - } else { - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->hw.hdlc.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - modehdlc(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - modehdlc(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_hdlcstate(struct BCState *bcs) -{ - modehdlc(bcs, 0, 0); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.hdlc.rcvbuf); - bcs->hw.hdlc.rcvbuf = NULL; - kfree(bcs->blog); - bcs->blog = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static int -open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.hdlc.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for hdlc.rcvbuf\n"); - return (1); - } - if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for bcs->blog\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - kfree(bcs->hw.hdlc.rcvbuf); - bcs->hw.hdlc.rcvbuf = NULL; - return (2); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.hdlc.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_hdlc(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hdlcstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hdlc_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -#if 0 -void __init -clear_pending_hdlc_ints(struct IsdnCardState *cs) -{ - u_int val; - - if (cs->subtyp == AVM_FRITZ_PCI) { - val = ReadHDLCPCI(cs, 0, HDLC_STATUS); - debugl1(cs, "HDLC 1 STA %x", val); - val = ReadHDLCPCI(cs, 1, HDLC_STATUS); - debugl1(cs, "HDLC 2 STA %x", val); - } else { - val = ReadHDLCPnP(cs, 0, HDLC_STATUS); - debugl1(cs, "HDLC 1 STA %x", val); - val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 1); - debugl1(cs, "HDLC 1 RML %x", val); - val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 2); - debugl1(cs, "HDLC 1 MODE %x", val); - val = ReadHDLCPnP(cs, 0, HDLC_STATUS + 3); - debugl1(cs, "HDLC 1 VIN %x", val); - val = ReadHDLCPnP(cs, 1, HDLC_STATUS); - debugl1(cs, "HDLC 2 STA %x", val); - val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 1); - debugl1(cs, "HDLC 2 RML %x", val); - val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 2); - debugl1(cs, "HDLC 2 MODE %x", val); - val = ReadHDLCPnP(cs, 1, HDLC_STATUS + 3); - debugl1(cs, "HDLC 2 VIN %x", val); - } -} -#endif /* 0 */ - -static void -inithdlc(struct IsdnCardState *cs) -{ - cs->bcs[0].BC_SetStack = setstack_hdlc; - cs->bcs[1].BC_SetStack = setstack_hdlc; - cs->bcs[0].BC_Close = close_hdlcstate; - cs->bcs[1].BC_Close = close_hdlcstate; - modehdlc(cs->bcs, -1, 0); - modehdlc(cs->bcs + 1, -1, 1); -} - -static irqreturn_t -avm_pcipnp_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_long flags; - u_char val; - u_char sval; - - spin_lock_irqsave(&cs->lock, flags); - sval = inb(cs->hw.avm.cfg_reg + 2); - if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) { - /* possible a shared IRQ reqest */ - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (!(sval & AVM_STATUS0_IRQ_ISAC)) { - val = ReadISAC(cs, ISAC_ISTA); - isac_interrupt(cs, val); - } - if (!(sval & AVM_STATUS0_IRQ_HDLC)) { - HDLC_irq_main(cs); - } - WriteISAC(cs, ISAC_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -reset_avmpcipnp(struct IsdnCardState *cs) -{ - printk(KERN_INFO "AVM PCI/PnP: reset\n"); - outb(AVM_STATUS0_RESET | AVM_STATUS0_DIS_TIMER, cs->hw.avm.cfg_reg + 2); - mdelay(10); - outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); - outb(AVM_STATUS1_ENA_IOM | cs->irq, cs->hw.avm.cfg_reg + 3); - mdelay(10); - printk(KERN_INFO "AVM PCI/PnP: S1 %x\n", inb(cs->hw.avm.cfg_reg + 3)); -} - -static int -AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_avmpcipnp(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - outb(0, cs->hw.avm.cfg_reg + 2); - release_region(cs->hw.avm.cfg_reg, 32); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - reset_avmpcipnp(cs); - clear_pending_isac_ints(cs); - initisac(cs); - inithdlc(cs); - outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER, - cs->hw.avm.cfg_reg + 2); - WriteISAC(cs, ISAC_MASK, 0); - outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | - AVM_STATUS0_ENA_IRQ, cs->hw.avm.cfg_reg + 2); - /* RESET Receiver and Transmitter */ - WriteISAC(cs, ISAC_CMDR, 0x41); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int avm_setup_rest(struct IsdnCardState *cs) -{ - u_int val, ver; - - cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10; - if (!request_region(cs->hw.avm.cfg_reg, 32, - (cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) { - printk(KERN_WARNING - "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n", - cs->hw.avm.cfg_reg, - cs->hw.avm.cfg_reg + 31); - return (0); - } - switch (cs->subtyp) { - case AVM_FRITZ_PCI: - val = inl(cs->hw.avm.cfg_reg); - printk(KERN_INFO "AVM PCI: stat %#x\n", val); - printk(KERN_INFO "AVM PCI: Class %X Rev %d\n", - val & 0xff, (val >> 8) & 0xff); - cs->BC_Read_Reg = &ReadHDLC_s; - cs->BC_Write_Reg = &WriteHDLC_s; - break; - case AVM_FRITZ_PNP: - val = inb(cs->hw.avm.cfg_reg); - ver = inb(cs->hw.avm.cfg_reg + 1); - printk(KERN_INFO "AVM PnP: Class %X Rev %d\n", val, ver); - cs->BC_Read_Reg = &ReadHDLCPnP; - cs->BC_Write_Reg = &WriteHDLCPnP; - break; - default: - printk(KERN_WARNING "AVM unknown subtype %d\n", cs->subtyp); - return (0); - } - printk(KERN_INFO "HiSax: %s config irq:%d base:0x%X\n", - (cs->subtyp == AVM_FRITZ_PCI) ? "AVM Fritz!PCI" : "AVM Fritz!PnP", - cs->irq, cs->hw.avm.cfg_reg); - - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Send_Data = &hdlc_fill_fifo; - cs->cardmsg = &AVM_card_msg; - cs->irq_func = &avm_pcipnp_interrupt; - cs->writeisac(cs, ISAC_MASK, 0xFF); - ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:"); - return (1); -} - -#ifndef __ISAPNP__ - -static int avm_pnp_setup(struct IsdnCardState *cs) -{ - return (1); /* no-op: success */ -} - -#else - -static struct pnp_card *pnp_avm_c = NULL; - -static int avm_pnp_setup(struct IsdnCardState *cs) -{ - struct pnp_dev *pnp_avm_d = NULL; - - if (!isapnp_present()) - return (1); /* no-op: success */ - - if ((pnp_avm_c = pnp_find_card( - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_c))) { - if ((pnp_avm_d = pnp_find_dev(pnp_avm_c, - ISAPNP_VENDOR('A', 'V', 'M'), - ISAPNP_FUNCTION(0x0900), pnp_avm_d))) { - int err; - - pnp_disable_dev(pnp_avm_d); - err = pnp_activate_dev(pnp_avm_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - cs->hw.avm.cfg_reg = - pnp_port_start(pnp_avm_d, 0); - cs->irq = pnp_irq(pnp_avm_d, 0); - if (cs->irq == -1) { - printk(KERN_ERR "FritzPnP:No IRQ\n"); - return (0); - } - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPnP:No IO address\n"); - return (0); - } - cs->subtyp = AVM_FRITZ_PNP; - - return (2); /* goto 'ready' label */ - } - } - - return (1); -} - -#endif /* __ISAPNP__ */ - -#ifndef CONFIG_PCI - -static int avm_pci_setup(struct IsdnCardState *cs) -{ - return (1); /* no-op: success */ -} - -#else - -static struct pci_dev *dev_avm = NULL; - -static int avm_pci_setup(struct IsdnCardState *cs) -{ - if ((dev_avm = hisax_find_pci_device(PCI_VENDOR_ID_AVM, - PCI_DEVICE_ID_AVM_A1, dev_avm))) { - - if (pci_enable_device(dev_avm)) - return (0); - - cs->irq = dev_avm->irq; - if (!cs->irq) { - printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n"); - return (0); - } - - cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1); - if (!cs->hw.avm.cfg_reg) { - printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n"); - return (0); - } - - cs->subtyp = AVM_FRITZ_PCI; - } else { - printk(KERN_WARNING "FritzPCI: No PCI card found\n"); - return (0); - } - - cs->irq_flags |= IRQF_SHARED; - - return (1); -} - -#endif /* CONFIG_PCI */ - -int setup_avm_pcipnp(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - int rc; - - strcpy(tmp, avm_pci_rev); - printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp)); - - if (cs->typ != ISDN_CTYPE_FRITZPCI) - return (0); - - if (card->para[1]) { - /* old manual method */ - cs->hw.avm.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - cs->subtyp = AVM_FRITZ_PNP; - goto ready; - } - - rc = avm_pnp_setup(cs); - if (rc < 1) - return (0); - if (rc == 2) - goto ready; - - rc = avm_pci_setup(cs); - if (rc < 1) - return (0); - -ready: - return avm_setup_rest(cs); -} diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c deleted file mode 100644 index baad94ec1f4a..000000000000 --- a/drivers/isdn/hisax/avma1_cs.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * PCMCIA client driver for AVM A1 / Fritz!PCMCIA - * - * Author Carsten Paeth - * Copyright 1998-2001 by Carsten Paeth <calle@calle.in-berlin.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> - - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <asm/io.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/ds.h> -#include "hisax_cfg.h" - -MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for AVM A1/Fritz!PCMCIA cards"); -MODULE_AUTHOR("Carsten Paeth"); -MODULE_LICENSE("GPL"); - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -static int isdnprot = 2; - -module_param(isdnprot, int, 0); - -/*====================================================================*/ - -static int avma1cs_config(struct pcmcia_device *link); -static void avma1cs_release(struct pcmcia_device *link); -static void avma1cs_detach(struct pcmcia_device *p_dev); - -static int avma1cs_probe(struct pcmcia_device *p_dev) -{ - dev_dbg(&p_dev->dev, "avma1cs_attach()\n"); - - /* General socket configuration */ - p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - p_dev->config_index = 1; - p_dev->config_regs = PRESENT_OPTION; - - return avma1cs_config(p_dev); -} /* avma1cs_attach */ - -static void avma1cs_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link); - avma1cs_release(link); - kfree(link->priv); -} /* avma1cs_detach */ - -static int avma1cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->resource[0]->end = 16; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - p_dev->io_lines = 5; - - return pcmcia_request_io(p_dev); -} - - -static int avma1cs_config(struct pcmcia_device *link) -{ - int i = -1; - char devname[128]; - IsdnCard_t icard; - int busy = 0; - - dev_dbg(&link->dev, "avma1cs_config(0x%p)\n", link); - - devname[0] = 0; - if (link->prod_id[1]) - strlcpy(devname, link->prod_id[1], sizeof(devname)); - - if (pcmcia_loop_config(link, avma1cs_configcheck, NULL)) - return -ENODEV; - - do { - /* - * allocate an interrupt line - */ - if (!link->irq) { - /* undo */ - pcmcia_disable_device(link); - break; - } - - /* - * configure the PCMCIA socket - */ - i = pcmcia_enable_device(link); - if (i != 0) { - pcmcia_disable_device(link); - break; - } - - } while (0); - - /* If any step failed, release any partially configured state */ - if (i != 0) { - avma1cs_release(link); - return -ENODEV; - } - - icard.para[0] = link->irq; - icard.para[1] = link->resource[0]->start; - icard.protocol = isdnprot; - icard.typ = ISDN_CTYPE_A1_PCMCIA; - - i = hisax_init_pcmcia(link, &busy, &icard); - if (i < 0) { - printk(KERN_ERR "avma1_cs: failed to initialize AVM A1 " - "PCMCIA %d at i/o %#x\n", i, - (unsigned int) link->resource[0]->start); - avma1cs_release(link); - return -ENODEV; - } - link->priv = (void *) (unsigned long) i; - - return 0; -} /* avma1cs_config */ - -static void avma1cs_release(struct pcmcia_device *link) -{ - unsigned long minor = (unsigned long) link->priv; - - dev_dbg(&link->dev, "avma1cs_release(0x%p)\n", link); - - /* now unregister function with hisax */ - HiSax_closecard(minor); - - pcmcia_disable_device(link); -} /* avma1cs_release */ - -static const struct pcmcia_device_id avma1cs_ids[] = { - PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), - PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids); - -static struct pcmcia_driver avma1cs_driver = { - .owner = THIS_MODULE, - .name = "avma1_cs", - .probe = avma1cs_probe, - .remove = avma1cs_detach, - .id_table = avma1cs_ids, -}; -module_pcmcia_driver(avma1cs_driver); diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c deleted file mode 100644 index c360164bde1b..000000000000 --- a/drivers/isdn/hisax/bkm_a4t.c +++ /dev/null @@ -1,358 +0,0 @@ -/* $Id: bkm_a4t.c,v 1.22.2.4 2004/01/14 16:04:48 keil Exp $ - * - * low level stuff for T-Berkom A4T - * - * Author Roland Klabunde - * Copyright by Roland Klabunde <R.Klabunde@Berkom.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "jade.h" -#include "isdnl1.h" -#include <linux/pci.h> -#include "bkm_ax.h" - -static const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $"; - - -static inline u_char -readreg(unsigned int ale, unsigned long adr, u_char off) -{ - register u_int ret; - unsigned int *po = (unsigned int *) adr; /* Postoffice */ - - *po = (GCS_2 | PO_WRITE | off); - __WAITI20__(po); - *po = (ale | PO_READ); - __WAITI20__(po); - ret = *po; - return ((unsigned char) ret); -} - - -static inline void -readfifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size) -{ - int i; - for (i = 0; i < size; i++) - *data++ = readreg(ale, adr, off); -} - - -static inline void -writereg(unsigned int ale, unsigned long adr, u_char off, u_char data) -{ - unsigned int *po = (unsigned int *) adr; /* Postoffice */ - *po = (GCS_2 | PO_WRITE | off); - __WAITI20__(po); - *po = (ale | PO_WRITE | data); - __WAITI20__(po); -} - - -static inline void -writefifo(unsigned int ale, unsigned long adr, u_char off, u_char *data, int size) -{ - int i; - - for (i = 0; i < size; i++) - writereg(ale, adr, off, *data++); -} - - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size); -} - -static u_char -ReadJADE(struct IsdnCardState *cs, int jade, u_char offset) -{ - return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)))); -} - -static void -WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value) -{ - writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value); -} - -/* - * fast interrupt JADE stuff goes here - */ - -#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale, \ - cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80))) -#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale, \ - cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data) - -#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale, \ - cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt) -#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.jade_ale, \ - cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt) - -#include "jade_irq.c" - -static irqreturn_t -bkm_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val = 0; - u_long flags; - I20_REGISTER_FILE *pI20_Regs; - - spin_lock_irqsave(&cs->lock, flags); - pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - - /* ISDN interrupt pending? */ - if (pI20_Regs->i20IntStatus & intISDN) { - /* Reset the ISDN interrupt */ - pI20_Regs->i20IntStatus = intISDN; - /* Disable ISDN interrupt */ - pI20_Regs->i20IntCtrl &= ~intISDN; - /* Channel A first */ - val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80); - if (val) { - jade_int_main(cs, val, 0); - } - /* Channel B */ - val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0); - if (val) { - jade_int_main(cs, val, 1); - } - /* D-Channel */ - val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA); - if (val) { - isac_interrupt(cs, val); - } - /* Reenable ISDN interrupt */ - pI20_Regs->i20IntCtrl |= intISDN; - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } else { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } -} - -static void -release_io_bkm(struct IsdnCardState *cs) -{ - if (cs->hw.ax.base) { - iounmap((void *) cs->hw.ax.base); - cs->hw.ax.base = 0; - } -} - -static void -enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) -{ - if (cs->typ == ISDN_CTYPE_BKM_A4T) { - I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - if (bEnable) - pI20_Regs->i20IntCtrl |= (intISDN | intPCI); - else - /* CAUTION: This disables the video capture driver too */ - pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI); - } -} - -static void -reset_bkm(struct IsdnCardState *cs) -{ - if (cs->typ == ISDN_CTYPE_BKM_A4T) { - I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - /* Issue the I20 soft reset */ - pI20_Regs->i20SysControl = 0xFF; /* all in */ - mdelay(10); - /* Remove the soft reset */ - pI20_Regs->i20SysControl = sysRESET | 0xFF; - mdelay(10); - /* Set our configuration */ - pI20_Regs->i20SysControl = sysRESET | sysCFG; - /* Issue ISDN reset */ - pI20_Regs->i20GuestControl = guestWAIT_CFG | - g_A4T_JADE_RES | - g_A4T_ISAR_RES | - g_A4T_ISAC_RES | - g_A4T_JADE_BOOTR | - g_A4T_ISAR_BOOTR; - mdelay(10); - - /* Remove RESET state from ISDN */ - pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES | - g_A4T_JADE_RES | - g_A4T_ISAR_RES); - mdelay(10); - } -} - -static int -BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - /* Disable ints */ - spin_lock_irqsave(&cs->lock, flags); - enable_bkm_int(cs, 0); - reset_bkm(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - /* Sanity */ - spin_lock_irqsave(&cs->lock, flags); - enable_bkm_int(cs, 0); - reset_bkm(cs); - spin_unlock_irqrestore(&cs->lock, flags); - release_io_bkm(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - clear_pending_isac_ints(cs); - clear_pending_jade_ints(cs); - initisac(cs); - initjade(cs); - /* Enable ints */ - enable_bkm_int(cs, 1); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int a4t_pci_probe(struct pci_dev *dev_a4t, struct IsdnCardState *cs, - u_int *found, u_int *pci_memaddr) -{ - u16 sub_sys; - u16 sub_vendor; - - sub_vendor = dev_a4t->subsystem_vendor; - sub_sys = dev_a4t->subsystem_device; - if ((sub_sys == PCI_DEVICE_ID_BERKOM_A4T) && (sub_vendor == PCI_VENDOR_ID_BERKOM)) { - if (pci_enable_device(dev_a4t)) - return (0); /* end loop & function */ - *found = 1; - *pci_memaddr = pci_resource_start(dev_a4t, 0); - cs->irq = dev_a4t->irq; - return (1); /* end loop */ - } - - return (-1); /* continue looping */ -} - -static int a4t_cs_init(struct IsdnCard *card, struct IsdnCardState *cs, - u_int pci_memaddr) -{ - I20_REGISTER_FILE *pI20_Regs; - - if (!cs->irq) { /* IRQ range check ?? */ - printk(KERN_WARNING "HiSax: Telekom A4T: No IRQ\n"); - return (0); - } - cs->hw.ax.base = (long) ioremap(pci_memaddr, 4096); - /* Check suspecious address */ - pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base); - if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) { - printk(KERN_WARNING "HiSax: Telekom A4T address " - "%lx-%lx suspicious\n", - cs->hw.ax.base, cs->hw.ax.base + 4096); - iounmap((void *) cs->hw.ax.base); - cs->hw.ax.base = 0; - return (0); - } - cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET; - cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET; - cs->hw.ax.isac_ale = GCS_1; - cs->hw.ax.jade_ale = GCS_3; - - printk(KERN_INFO "HiSax: Telekom A4T: Card configured at " - "0x%lX IRQ %d\n", - cs->hw.ax.base, cs->irq); - - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadJADE; - cs->BC_Write_Reg = &WriteJADE; - cs->BC_Send_Data = &jade_fill_fifo; - cs->cardmsg = &BKM_card_msg; - cs->irq_func = &bkm_interrupt; - cs->irq_flags |= IRQF_SHARED; - ISACVersion(cs, "Telekom A4T:"); - /* Jade version */ - JadeVersion(cs, "Telekom A4T:"); - - return (1); -} - -static struct pci_dev *dev_a4t = NULL; - -int setup_bkm_a4t(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - u_int pci_memaddr = 0, found = 0; - int ret; - - strcpy(tmp, bkm_a4t_revision); - printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ == ISDN_CTYPE_BKM_A4T) { - cs->subtyp = BKM_A4T; - } else - return (0); - - while ((dev_a4t = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN, - PCI_DEVICE_ID_ZORAN_36120, dev_a4t))) { - ret = a4t_pci_probe(dev_a4t, cs, &found, &pci_memaddr); - if (!ret) - return (0); - if (ret > 0) - break; - } - if (!found) { - printk(KERN_WARNING "HiSax: Telekom A4T: Card not found\n"); - return (0); - } - if (!pci_memaddr) { - printk(KERN_WARNING "HiSax: Telekom A4T: " - "No Memory base address\n"); - return (0); - } - - return a4t_cs_init(card, cs, pci_memaddr); -} diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c deleted file mode 100644 index dd663ea57ec6..000000000000 --- a/drivers/isdn/hisax/bkm_a8.c +++ /dev/null @@ -1,433 +0,0 @@ -/* $Id: bkm_a8.c,v 1.22.2.4 2004/01/15 14:02:34 keil Exp $ - * - * low level stuff for Scitel Quadro (4*S0, passive) - * - * Author Roland Klabunde - * Copyright by Roland Klabunde <R.Klabunde@Berkom.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "ipac.h" -#include "hscx.h" -#include "isdnl1.h" -#include <linux/pci.h> -#include "bkm_ax.h" - -#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */ - -static const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $"; - -static const char *sct_quadro_subtypes[] = -{ - "", - "#1", - "#2", - "#3", - "#4" -}; - - -#define wordout(addr, val) outw(val, addr) -#define wordin(addr) inw(addr) - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - wordout(ale, off); - ret = wordin(adr) & 0xFF; - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - int i; - wordout(ale, off); - for (i = 0; i < size; i++) - data[i] = wordin(adr) & 0xFF; -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - wordout(ale, off); - wordout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - int i; - wordout(ale, off); - for (i = 0; i < size; i++) - wordout(adr, data[i]); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size); -} - - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value); -} - -/* Set the specific ipac to active */ -static void -set_ipac_active(struct IsdnCardState *cs, u_int active) -{ - /* set irq mask */ - writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, - active ? 0xc0 : 0xff); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \ - cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \ - cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data) -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \ - cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \ - cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -bkm_interrupt_ipac(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val, icnt = 5; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); - if (!(ista & 0x3f)) { /* not this IPAC */ - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } -Start_IPAC: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) { - hscx_int_main(cs, val); - } - } - if (ista & 0x20) { - val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPAC; - } - if (!icnt) - printk(KERN_WARNING "HiSax: Scitel Quadro (%s) IRQ LOOP\n", - sct_quadro_subtypes[cs->subtyp]); - writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF); - writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_sct_quadro(struct IsdnCardState *cs) -{ - release_region(cs->hw.ax.base & 0xffffffc0, 128); - if (cs->subtyp == SCT_1) - release_region(cs->hw.ax.plx_adr, 64); -} - -static void -enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable) -{ - if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { - if (bEnable) - wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41)); - else - wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41)); - } -} - -static void -reset_bkm(struct IsdnCardState *cs) -{ - if (cs->subtyp == SCT_1) { - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4)); - mdelay(10); - /* Remove the soft reset */ - wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4)); - mdelay(10); - } -} - -static int -BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - /* Disable ints */ - set_ipac_active(cs, 0); - enable_bkm_int(cs, 0); - reset_bkm(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - /* Sanity */ - spin_lock_irqsave(&cs->lock, flags); - set_ipac_active(cs, 0); - enable_bkm_int(cs, 0); - spin_unlock_irqrestore(&cs->lock, flags); - release_io_sct_quadro(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - cs->debug |= L1_DEB_IPAC; - set_ipac_active(cs, 1); - inithscxisac(cs, 3); - /* Enable ints */ - enable_bkm_int(cs, 1); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int sct_alloc_io(u_int adr, u_int len) -{ - if (!request_region(adr, len, "scitel")) { - printk(KERN_WARNING - "HiSax: Scitel port %#x-%#x already in use\n", - adr, adr + len); - return (1); - } - return (0); -} - -static struct pci_dev *dev_a8 = NULL; -static u16 sub_vendor_id = 0; -static u16 sub_sys_id = 0; -static u_char pci_bus = 0; -static u_char pci_device_fn = 0; -static u_char pci_irq = 0; - -int setup_sct_quadro(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - u_int found = 0; - u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5; - - strcpy(tmp, sct_quadro_revision); - printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ == ISDN_CTYPE_SCT_QUADRO) { - cs->subtyp = SCT_1; /* Preset */ - } else - return (0); - - /* Identify subtype by para[0] */ - if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4) - cs->subtyp = card->para[0]; - else { - printk(KERN_WARNING "HiSax: Scitel Quadro: Invalid " - "subcontroller in configuration, default to 1\n"); - return (0); - } - if ((cs->subtyp != SCT_1) && ((sub_sys_id != PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) || - (sub_vendor_id != PCI_VENDOR_ID_BERKOM))) - return (0); - if (cs->subtyp == SCT_1) { - while ((dev_a8 = hisax_find_pci_device(PCI_VENDOR_ID_PLX, - PCI_DEVICE_ID_PLX_9050, dev_a8))) { - - sub_vendor_id = dev_a8->subsystem_vendor; - sub_sys_id = dev_a8->subsystem_device; - if ((sub_sys_id == PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO) && - (sub_vendor_id == PCI_VENDOR_ID_BERKOM)) { - if (pci_enable_device(dev_a8)) - return (0); - pci_ioaddr1 = pci_resource_start(dev_a8, 1); - pci_irq = dev_a8->irq; - pci_bus = dev_a8->bus->number; - pci_device_fn = dev_a8->devfn; - found = 1; - break; - } - } - if (!found) { - printk(KERN_WARNING "HiSax: Scitel Quadro (%s): " - "Card not found\n", - sct_quadro_subtypes[cs->subtyp]); - return (0); - } -#ifdef ATTEMPT_PCI_REMAPPING -/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ - if ((pci_ioaddr1 & 0x80) && (dev_a8->revision == 1)) { - printk(KERN_WARNING "HiSax: Scitel Quadro (%s): " - "PLX rev 1, remapping required!\n", - sct_quadro_subtypes[cs->subtyp]); - /* Restart PCI negotiation */ - pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, (u_int)-1); - /* Move up by 0x80 byte */ - pci_ioaddr1 += 0x80; - pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; - pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, pci_ioaddr1); - dev_a8->resource[1].start = pci_ioaddr1; - } -#endif /* End HACK */ - } - if (!pci_irq) { /* IRQ range check ?? */ - printk(KERN_WARNING "HiSax: Scitel Quadro (%s): No IRQ\n", - sct_quadro_subtypes[cs->subtyp]); - return (0); - } - pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_1, &pci_ioaddr1); - pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_2, &pci_ioaddr2); - pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_3, &pci_ioaddr3); - pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_4, &pci_ioaddr4); - pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_5, &pci_ioaddr5); - if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) { - printk(KERN_WARNING "HiSax: Scitel Quadro (%s): " - "No IO base address(es)\n", - sct_quadro_subtypes[cs->subtyp]); - return (0); - } - pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; - pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK; - pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK; - pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK; - pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK; - /* Take over */ - cs->irq = pci_irq; - cs->irq_flags |= IRQF_SHARED; - /* pci_ioaddr1 is unique to all subdevices */ - /* pci_ioaddr2 is for the fourth subdevice only */ - /* pci_ioaddr3 is for the third subdevice only */ - /* pci_ioaddr4 is for the second subdevice only */ - /* pci_ioaddr5 is for the first subdevice only */ - cs->hw.ax.plx_adr = pci_ioaddr1; - /* Enter all ipac_base addresses */ - switch (cs->subtyp) { - case 1: - cs->hw.ax.base = pci_ioaddr5 + 0x00; - if (sct_alloc_io(pci_ioaddr1, 128)) - return (0); - if (sct_alloc_io(pci_ioaddr5, 64)) - return (0); - /* disable all IPAC */ - writereg(pci_ioaddr5, pci_ioaddr5 + 4, - IPAC_MASK, 0xFF); - writereg(pci_ioaddr4 + 0x08, pci_ioaddr4 + 0x0c, - IPAC_MASK, 0xFF); - writereg(pci_ioaddr3 + 0x10, pci_ioaddr3 + 0x14, - IPAC_MASK, 0xFF); - writereg(pci_ioaddr2 + 0x20, pci_ioaddr2 + 0x24, - IPAC_MASK, 0xFF); - break; - case 2: - cs->hw.ax.base = pci_ioaddr4 + 0x08; - if (sct_alloc_io(pci_ioaddr4, 64)) - return (0); - break; - case 3: - cs->hw.ax.base = pci_ioaddr3 + 0x10; - if (sct_alloc_io(pci_ioaddr3, 64)) - return (0); - break; - case 4: - cs->hw.ax.base = pci_ioaddr2 + 0x20; - if (sct_alloc_io(pci_ioaddr2, 64)) - return (0); - break; - } - /* For isac and hscx data path */ - cs->hw.ax.data_adr = cs->hw.ax.base + 4; - - printk(KERN_INFO "HiSax: Scitel Quadro (%s) configured at " - "0x%.4lX, 0x%.4lX, 0x%.4lX and IRQ %d\n", - sct_quadro_subtypes[cs->subtyp], - cs->hw.ax.plx_adr, - cs->hw.ax.base, - cs->hw.ax.data_adr, - cs->irq); - - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &BKM_card_msg; - cs->irq_func = &bkm_interrupt_ipac; - - printk(KERN_INFO "HiSax: Scitel Quadro (%s): IPAC Version %d\n", - sct_quadro_subtypes[cs->subtyp], - readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID)); - return (1); -} diff --git a/drivers/isdn/hisax/bkm_ax.h b/drivers/isdn/hisax/bkm_ax.h deleted file mode 100644 index 27ff8a88679b..000000000000 --- a/drivers/isdn/hisax/bkm_ax.h +++ /dev/null @@ -1,119 +0,0 @@ -/* $Id: bkm_ax.h,v 1.5.6.3 2001/09/23 22:24:46 kai Exp $ - * - * low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive) - * - * Author Roland Klabunde - * Copyright by Roland Klabunde <R.Klabunde@Berkom.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __BKM_AX_H__ -#define __BKM_AX_H__ - -/* Supported boards (subtypes) */ -#define SCT_1 1 -#define SCT_2 2 -#define SCT_3 3 -#define SCT_4 4 -#define BKM_A4T 5 - -#define PLX_ADDR_PLX 0x14 /* Addr PLX configuration */ -#define PLX_ADDR_ISAC 0x18 /* Addr ISAC */ -#define PLX_ADDR_HSCX 0x1C /* Addr HSCX */ -#define PLX_ADDR_ALE 0x20 /* Addr ALE */ -#define PLX_ADDR_ALEPLUS 0x24 /* Next Addr behind ALE */ - -#define PLX_SUBVEN 0x2C /* Offset SubVendor */ -#define PLX_SUBSYS 0x2E /* Offset SubSystem */ - - -/* Application specific registers I20 (Siemens SZB6120H) */ -typedef struct { - /* Video front end horizontal configuration register */ - volatile u_int i20VFEHorzCfg; /* Offset 00 */ - /* Video front end vertical configuration register */ - volatile u_int i20VFEVertCfg; /* Offset 04 */ - /* Video front end scaler and pixel format register */ - volatile u_int i20VFEScaler; /* Offset 08 */ - /* Video display top register */ - volatile u_int i20VDispTop; /* Offset 0C */ - /* Video display bottom register */ - volatile u_int i20VDispBottom; /* Offset 10 */ - /* Video stride, status and frame grab register */ - volatile u_int i20VidFrameGrab;/* Offset 14 */ - /* Video display configuration register */ - volatile u_int i20VDispCfg; /* Offset 18 */ - /* Video masking map top */ - volatile u_int i20VMaskTop; /* Offset 1C */ - /* Video masking map bottom */ - volatile u_int i20VMaskBottom; /* Offset 20 */ - /* Overlay control register */ - volatile u_int i20OvlyControl; /* Offset 24 */ - /* System, PCI and general purpose pins control register */ - volatile u_int i20SysControl; /* Offset 28 */ -#define sysRESET 0x01000000 /* bit 24:Softreset (Low) */ - /* GPIO 4...0: Output fixed for our cfg! */ -#define sysCFG 0x000000E0 /* GPIO 7,6,5: Input */ - /* General purpose pins and guest bus control register */ - volatile u_int i20GuestControl;/* Offset 2C */ -#define guestWAIT_CFG 0x00005555 /* 4 PCI waits for all */ -#define guestISDN_INT_E 0x01000000 /* ISDN Int en (low) */ -#define guestVID_INT_E 0x02000000 /* Video interrupt en (low) */ -#define guestADI1_INT_R 0x04000000 /* ADI #1 int req (low) */ -#define guestADI2_INT_R 0x08000000 /* ADI #2 int req (low) */ -#define guestISDN_RES 0x10000000 /* ISDN reset bit (high) */ -#define guestADI1_INT_S 0x20000000 /* ADI #1 int pending (low) */ -#define guestADI2_INT_S 0x40000000 /* ADI #2 int pending (low) */ -#define guestISDN_INT_S 0x80000000 /* ISAC int pending (low) */ - -#define g_A4T_JADE_RES 0x01000000 /* JADE Reset (High) */ -#define g_A4T_ISAR_RES 0x02000000 /* ISAR Reset (High) */ -#define g_A4T_ISAC_RES 0x04000000 /* ISAC Reset (High) */ -#define g_A4T_JADE_BOOTR 0x08000000 /* JADE enable boot SRAM (Low) NOT USED */ -#define g_A4T_ISAR_BOOTR 0x10000000 /* ISAR enable boot SRAM (Low) NOT USED */ -#define g_A4T_JADE_INT_S 0x20000000 /* JADE interrupt pnd (Low) */ -#define g_A4T_ISAR_INT_S 0x40000000 /* ISAR interrupt pnd (Low) */ -#define g_A4T_ISAC_INT_S 0x80000000 /* ISAC interrupt pnd (Low) */ - - volatile u_int i20CodeSource; /* Offset 30 */ - volatile u_int i20CodeXferCtrl;/* Offset 34 */ - volatile u_int i20CodeMemPtr; /* Offset 38 */ - - volatile u_int i20IntStatus; /* Offset 3C */ - volatile u_int i20IntCtrl; /* Offset 40 */ -#define intISDN 0x40000000 /* GIRQ1En (ISAC/ADI) (High) */ -#define intVID 0x20000000 /* GIRQ0En (VSYNC) (High) */ -#define intCOD 0x10000000 /* CodRepIrqEn (High) */ -#define intPCI 0x01000000 /* PCI IntA enable (High) */ - - volatile u_int i20I2CCtrl; /* Offset 44 */ -} I20_REGISTER_FILE, *PI20_REGISTER_FILE; - -/* - * Postoffice structure for A4T - * - */ -#define PO_OFFSET 0x00000200 /* Postoffice offset from base */ - -#define GCS_0 0x00000000 /* Guest bus chip selects */ -#define GCS_1 0x00100000 -#define GCS_2 0x00200000 -#define GCS_3 0x00300000 - -#define PO_READ 0x00000000 /* R/W from/to guest bus */ -#define PO_WRITE 0x00800000 - -#define PO_PEND 0x02000000 - -#define POSTOFFICE(postoffice) *(volatile unsigned int *)(postoffice) - -/* Wait unlimited (don't worry) */ -#define __WAITI20__(postoffice) \ - do { \ - while ((POSTOFFICE(postoffice) & PO_PEND)) ; \ - } while (0) - -#endif /* __BKM_AX_H__ */ diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c deleted file mode 100644 index 9ee06328784c..000000000000 --- a/drivers/isdn/hisax/callc.c +++ /dev/null @@ -1,1792 +0,0 @@ -/* $Id: callc.c,v 2.59.2.4 2004/02/11 13:21:32 keil Exp $ - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.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 - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include "hisax.h" -#include <linux/isdn/capicmd.h> - -const char *lli_revision = "$Revision: 2.59.2.4 $"; - -extern struct IsdnCard cards[]; - -static int init_b_st(struct Channel *chanp, int incoming); -static void release_b_st(struct Channel *chanp); - -static struct Fsm callcfsm; -static int chancount; - -/* experimental REJECT after ALERTING for CALLBACK to beat the 4s delay */ -#define ALERT_REJECT 0 - -/* Value to delay the sending of the first B-channel packet after CONNECT - * here is no value given by ITU, but experience shows that 300 ms will - * work on many networks, if you or your other side is behind local exchanges - * a greater value may be recommented. If the delay is to short the first paket - * will be lost and autodetect on many comercial routers goes wrong ! - * You can adjust this value on runtime with - * hisaxctrl <id> 2 <value> - * value is in milliseconds - */ -#define DEFAULT_B_DELAY 300 - -/* Flags for remembering action done in lli */ - -#define FLG_START_B 0 - -/* - * 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 (struct IsdnCardState *) 0; -} - -static __printf(3, 4) void - link_debug(struct Channel *chanp, int direction, char *fmt, ...) -{ - va_list args; - char tmp[16]; - - va_start(args, fmt); - sprintf(tmp, "Ch%d %s ", chanp->chan, - direction ? "LL->HL" : "HL->LL"); - VHiSax_putstatus(chanp->cs, tmp, fmt, args); - va_end(args); -} - -enum { - ST_NULL, /* 0 inactive */ - ST_OUT_DIAL, /* 1 outgoing, SETUP send; awaiting confirm */ - ST_IN_WAIT_LL, /* 2 incoming call received; wait for LL confirm */ - ST_IN_ALERT_SENT, /* 3 incoming call received; ALERT send */ - ST_IN_WAIT_CONN_ACK, /* 4 incoming CONNECT send; awaiting CONN_ACK */ - ST_WAIT_BCONN, /* 5 CONNECT/CONN_ACK received, awaiting b-channel prot. estbl. */ - ST_ACTIVE, /* 6 active, b channel prot. established */ - ST_WAIT_BRELEASE, /* 7 call clear. (initiator), awaiting b channel prot. rel. */ - ST_WAIT_BREL_DISC, /* 8 call clear. (receiver), DISCONNECT req. received */ - ST_WAIT_DCOMMAND, /* 9 call clear. (receiver), awaiting DCHANNEL message */ - ST_WAIT_DRELEASE, /* 10 DISCONNECT sent, awaiting RELEASE */ - ST_WAIT_D_REL_CNF, /* 11 RELEASE sent, awaiting RELEASE confirm */ - ST_IN_PROCEED_SEND, /* 12 incoming call, proceeding send */ -}; - - -#define STATE_COUNT (ST_IN_PROCEED_SEND + 1) - -static char *strState[] = -{ - "ST_NULL", - "ST_OUT_DIAL", - "ST_IN_WAIT_LL", - "ST_IN_ALERT_SENT", - "ST_IN_WAIT_CONN_ACK", - "ST_WAIT_BCONN", - "ST_ACTIVE", - "ST_WAIT_BRELEASE", - "ST_WAIT_BREL_DISC", - "ST_WAIT_DCOMMAND", - "ST_WAIT_DRELEASE", - "ST_WAIT_D_REL_CNF", - "ST_IN_PROCEED_SEND", -}; - -enum { - EV_DIAL, /* 0 */ - EV_SETUP_CNF, /* 1 */ - EV_ACCEPTB, /* 2 */ - EV_DISCONNECT_IND, /* 3 */ - EV_RELEASE, /* 4 */ - EV_LEASED, /* 5 */ - EV_LEASED_REL, /* 6 */ - EV_SETUP_IND, /* 7 */ - EV_ACCEPTD, /* 8 */ - EV_SETUP_CMPL_IND, /* 9 */ - EV_BC_EST, /* 10 */ - EV_WRITEBUF, /* 11 */ - EV_HANGUP, /* 12 */ - EV_BC_REL, /* 13 */ - EV_CINF, /* 14 */ - EV_SUSPEND, /* 15 */ - EV_RESUME, /* 16 */ - EV_NOSETUP_RSP, /* 17 */ - EV_SETUP_ERR, /* 18 */ - EV_CONNECT_ERR, /* 19 */ - EV_PROCEED, /* 20 */ - EV_ALERT, /* 21 */ - EV_REDIR, /* 22 */ -}; - -#define EVENT_COUNT (EV_REDIR + 1) - -static char *strEvent[] = -{ - "EV_DIAL", - "EV_SETUP_CNF", - "EV_ACCEPTB", - "EV_DISCONNECT_IND", - "EV_RELEASE", - "EV_LEASED", - "EV_LEASED_REL", - "EV_SETUP_IND", - "EV_ACCEPTD", - "EV_SETUP_CMPL_IND", - "EV_BC_EST", - "EV_WRITEBUF", - "EV_HANGUP", - "EV_BC_REL", - "EV_CINF", - "EV_SUSPEND", - "EV_RESUME", - "EV_NOSETUP_RSP", - "EV_SETUP_ERR", - "EV_CONNECT_ERR", - "EV_PROCEED", - "EV_ALERT", - "EV_REDIR", -}; - - -static inline void -HL_LL(struct Channel *chanp, int command) -{ - isdn_ctrl ic; - - ic.driver = chanp->cs->myid; - ic.command = command; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); -} - -static inline void -lli_deliver_cause(struct Channel *chanp) -{ - isdn_ctrl ic; - - if (!chanp->proc) - return; - if (chanp->proc->para.cause == NO_CAUSE) - return; - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; - if (chanp->cs->protocol == ISDN_PTYPE_EURO) - sprintf(ic.parm.num, "E%02X%02X", chanp->proc->para.loc & 0x7f, - chanp->proc->para.cause & 0x7f); - else - sprintf(ic.parm.num, "%02X%02X", chanp->proc->para.loc & 0x7f, - chanp->proc->para.cause & 0x7f); - chanp->cs->iif.statcallb(&ic); -} - -static inline void -lli_close(struct FsmInst *fi) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_NULL); - chanp->Flags = 0; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); -} - -static void -lli_leased_in(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - int ret; - - if (!chanp->leased) - return; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - FsmChangeState(fi, ST_IN_WAIT_LL); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_ICALL_LEASED"); - ic.driver = chanp->cs->myid; - ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW); - ic.arg = chanp->chan; - ic.parm.setup.si1 = 7; - ic.parm.setup.si2 = 0; - ic.parm.setup.plan = 0; - ic.parm.setup.screen = 0; - sprintf(ic.parm.setup.eazmsn, "%d", chanp->chan + 1); - sprintf(ic.parm.setup.phone, "LEASED%d", chanp->cs->myid); - ret = chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) - link_debug(chanp, 1, "statcallb ret=%d", ret); - if (!ret) { - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); - FsmChangeState(fi, ST_NULL); - } -} - - -/* - * Dial out - */ -static void -lli_init_bchan_out(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_WAIT_BCONN); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DCONN"); - HL_LL(chanp, ISDN_STAT_DCONN); - init_b_st(chanp, 0); - chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); -} - -static void -lli_prep_dialout(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmDelTimer(&chanp->drel_timer, 60); - FsmDelTimer(&chanp->dial_timer, 73); - chanp->l2_active_protocol = chanp->l2_protocol; - chanp->incoming = 0; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - if (chanp->leased) { - lli_init_bchan_out(fi, event, arg); - } else { - FsmChangeState(fi, ST_OUT_DIAL); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | REQUEST, chanp); - } -} - -static void -lli_resume(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmDelTimer(&chanp->drel_timer, 60); - FsmDelTimer(&chanp->dial_timer, 73); - chanp->l2_active_protocol = chanp->l2_protocol; - chanp->incoming = 0; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - if (chanp->leased) { - lli_init_bchan_out(fi, event, arg); - } else { - FsmChangeState(fi, ST_OUT_DIAL); - chanp->d_st->lli.l4l3(chanp->d_st, CC_RESUME | REQUEST, chanp); - } -} - -static void -lli_go_active(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - - FsmChangeState(fi, ST_ACTIVE); - chanp->data_open = !0; - if (chanp->bcs->conmsg) - strcpy(ic.parm.num, chanp->bcs->conmsg); - else - ic.parm.num[0] = 0; - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BCONN %s", ic.parm.num); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BCONN; - ic.arg = chanp->chan; - chanp->cs->iif.statcallb(&ic); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_CONN, (void *) (long)chanp->chan); -} - - -/* - * RESUME - */ - -/* incoming call */ - -static void -lli_deliver_call(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - int ret; - - chanp->cs->cardmsg(chanp->cs, MDL_INFO_SETUP, (void *) (long)chanp->chan); - /* - * Report incoming calls only once to linklevel, use CallFlags - * which is set to 3 with each broadcast message in isdnl1.c - * and resetted if a interface answered the STAT_ICALL. - */ - if (1) { /* for only one TEI */ - FsmChangeState(fi, ST_IN_WAIT_LL); - if (chanp->debug & 1) - link_debug(chanp, 0, (chanp->chan < 2) ? "STAT_ICALL" : "STAT_ICALLW"); - ic.driver = chanp->cs->myid; - ic.command = ((chanp->chan < 2) ? ISDN_STAT_ICALL : ISDN_STAT_ICALLW); - - ic.arg = chanp->chan; - /* - * No need to return "unknown" for calls without OAD, - * cause that's handled in linklevel now (replaced by '0') - */ - memcpy(&ic.parm.setup, &chanp->proc->para.setup, sizeof(setup_parm)); - ret = chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) - link_debug(chanp, 1, "statcallb ret=%d", ret); - - switch (ret) { - case 1: /* OK, someone likes this call */ - FsmDelTimer(&chanp->drel_timer, 61); - FsmChangeState(fi, ST_IN_ALERT_SENT); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); - break; - case 5: /* direct redirect */ - case 4: /* Proceeding desired */ - FsmDelTimer(&chanp->drel_timer, 61); - FsmChangeState(fi, ST_IN_PROCEED_SEND); - chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); - if (ret == 5) { - memcpy(&chanp->setup, &ic.parm.setup, sizeof(setup_parm)); - chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); - } - break; - case 2: /* Rejecting Call */ - break; - case 3: /* incomplete number */ - FsmDelTimer(&chanp->drel_timer, 61); - chanp->d_st->lli.l4l3(chanp->d_st, CC_MORE_INFO | REQUEST, chanp->proc); - break; - case 0: /* OK, nobody likes this call */ - default: /* statcallb problems */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); - FsmChangeState(fi, ST_NULL); - break; - } - } else { - chanp->d_st->lli.l4l3(chanp->d_st, CC_IGNORE | REQUEST, chanp->proc); - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); - } -} - -static void -lli_send_dconnect(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); -} - -static void -lli_send_alert(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_IN_ALERT_SENT); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); -} - -static void -lli_send_redir(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); -} - -static void -lli_init_bchan_in(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_WAIT_BCONN); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DCONN"); - HL_LL(chanp, ISDN_STAT_DCONN); - chanp->l2_active_protocol = chanp->l2_protocol; - chanp->incoming = !0; - init_b_st(chanp, !0); - chanp->b_st->lli.l4l3(chanp->b_st, DL_ESTABLISH | REQUEST, NULL); -} - -static void -lli_setup_rsp(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_init_bchan_in(fi, event, arg); - } else { - FsmChangeState(fi, ST_IN_WAIT_CONN_ACK); -#ifdef WANT_ALERT - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); -#endif - chanp->d_st->lli.l4l3(chanp->d_st, CC_SETUP | RESPONSE, chanp->proc); - } -} - -/* Call suspend */ - -static void -lli_suspend(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->d_st->lli.l4l3(chanp->d_st, CC_SUSPEND | REQUEST, chanp->proc); -} - -/* Call clearing */ - -static void -lli_leased_hup(struct FsmInst *fi, struct Channel *chanp) -{ - isdn_ctrl ic; - - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "L0010"); - chanp->cs->iif.statcallb(&ic); - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DHUP"); - HL_LL(chanp, ISDN_STAT_DHUP); - lli_close(fi); -} - -static void -lli_disconnect_req(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - } else { - FsmChangeState(fi, ST_WAIT_DRELEASE); - if (chanp->proc) - chanp->proc->para.cause = 0x10; /* Normal Call Clearing */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, - chanp->proc); - } -} - -static void -lli_disconnect_reject(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - } else { - FsmChangeState(fi, ST_WAIT_DRELEASE); - if (chanp->proc) - chanp->proc->para.cause = 0x15; /* Call Rejected */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_DISCONNECT | REQUEST, - chanp->proc); - } -} - -static void -lli_dhup_close(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - } else { - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DHUP"); - lli_deliver_cause(chanp); - HL_LL(chanp, ISDN_STAT_DHUP); - lli_close(fi); - } -} - -static void -lli_reject_req(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - return; - } -#ifndef ALERT_REJECT - if (chanp->proc) - chanp->proc->para.cause = 0x15; /* Call Rejected */ - chanp->d_st->lli.l4l3(chanp->d_st, CC_REJECT | REQUEST, chanp->proc); - lli_dhup_close(fi, event, arg); -#else - FsmRestartTimer(&chanp->drel_timer, 40, EV_HANGUP, NULL, 63); - FsmChangeState(fi, ST_IN_ALERT_SENT); - chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); -#endif -} - -static void -lli_disconn_bchan(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - FsmChangeState(fi, ST_WAIT_BRELEASE); - chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); -} - -static void -lli_start_disc(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - } else { - lli_disconnect_req(fi, event, arg); - } -} - -static void -lli_rel_b_disc(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_b_st(chanp); - lli_start_disc(fi, event, arg); -} - -static void -lli_bhup_disc(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - lli_rel_b_disc(fi, event, arg); -} - -static void -lli_bhup_rel_b(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - FsmChangeState(fi, ST_WAIT_DCOMMAND); - chanp->data_open = 0; - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - release_b_st(chanp); -} - -static void -lli_release_bchan(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - FsmChangeState(fi, ST_WAIT_BREL_DISC); - chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); -} - - -static void -lli_rel_b_dhup(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_b_st(chanp); - lli_dhup_close(fi, event, arg); -} - -static void -lli_bhup_dhup(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - lli_rel_b_dhup(fi, event, arg); -} - -static void -lli_abort(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); - lli_bhup_dhup(fi, event, arg); -} - -static void -lli_release_req(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->leased) { - lli_leased_hup(fi, chanp); - } else { - FsmChangeState(fi, ST_WAIT_D_REL_CNF); - chanp->d_st->lli.l4l3(chanp->d_st, CC_RELEASE | REQUEST, - chanp->proc); - } -} - -static void -lli_rel_b_release_req(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_b_st(chanp); - lli_release_req(fi, event, arg); -} - -static void -lli_bhup_release_req(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - lli_rel_b_release_req(fi, event, arg); -} - - -/* processing charge info */ -static void -lli_charge_info(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CINF; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "%d", chanp->proc->para.chargeinfo); - chanp->cs->iif.statcallb(&ic); -} - -/* error procedures */ - -static void -lli_dchan_not_ready(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DHUP"); - HL_LL(chanp, ISDN_STAT_DHUP); -} - -static void -lli_no_setup_rsp(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_DHUP"); - HL_LL(chanp, ISDN_STAT_DHUP); - lli_close(fi); -} - -static void -lli_error(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_WAIT_DRELEASE); -} - -static void -lli_failure_l(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - isdn_ctrl ic; - - FsmChangeState(fi, ST_NULL); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_CAUSE; - ic.arg = chanp->chan; - sprintf(ic.parm.num, "L%02X%02X", 0, 0x2f); - chanp->cs->iif.statcallb(&ic); - HL_LL(chanp, ISDN_STAT_DHUP); - chanp->Flags = 0; - chanp->cs->cardmsg(chanp->cs, MDL_INFO_REL, (void *) (long)chanp->chan); -} - -static void -lli_rel_b_fail(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - release_b_st(chanp); - lli_failure_l(fi, event, arg); -} - -static void -lli_bhup_fail(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - if (chanp->debug & 1) - link_debug(chanp, 0, "STAT_BHUP"); - HL_LL(chanp, ISDN_STAT_BHUP); - lli_rel_b_fail(fi, event, arg); -} - -static void -lli_failure_a(struct FsmInst *fi, int event, void *arg) -{ - struct Channel *chanp = fi->userdata; - - chanp->data_open = 0; - chanp->b_st->lli.l4l3(chanp->b_st, DL_RELEASE | REQUEST, NULL); - lli_bhup_fail(fi, event, arg); -} - -/* *INDENT-OFF* */ -static struct FsmNode fnlist[] __initdata = -{ - {ST_NULL, EV_DIAL, lli_prep_dialout}, - {ST_NULL, EV_RESUME, lli_resume}, - {ST_NULL, EV_SETUP_IND, lli_deliver_call}, - {ST_NULL, EV_LEASED, lli_leased_in}, - {ST_OUT_DIAL, EV_SETUP_CNF, lli_init_bchan_out}, - {ST_OUT_DIAL, EV_HANGUP, lli_disconnect_req}, - {ST_OUT_DIAL, EV_DISCONNECT_IND, lli_release_req}, - {ST_OUT_DIAL, EV_RELEASE, lli_dhup_close}, - {ST_OUT_DIAL, EV_NOSETUP_RSP, lli_no_setup_rsp}, - {ST_OUT_DIAL, EV_SETUP_ERR, lli_error}, - {ST_IN_WAIT_LL, EV_LEASED_REL, lli_failure_l}, - {ST_IN_WAIT_LL, EV_ACCEPTD, lli_setup_rsp}, - {ST_IN_WAIT_LL, EV_HANGUP, lli_reject_req}, - {ST_IN_WAIT_LL, EV_DISCONNECT_IND, lli_release_req}, - {ST_IN_WAIT_LL, EV_RELEASE, lli_dhup_close}, - {ST_IN_WAIT_LL, EV_SETUP_IND, lli_deliver_call}, - {ST_IN_WAIT_LL, EV_SETUP_ERR, lli_error}, - {ST_IN_ALERT_SENT, EV_SETUP_CMPL_IND, lli_init_bchan_in}, - {ST_IN_ALERT_SENT, EV_ACCEPTD, lli_send_dconnect}, - {ST_IN_ALERT_SENT, EV_HANGUP, lli_disconnect_reject}, - {ST_IN_ALERT_SENT, EV_DISCONNECT_IND, lli_release_req}, - {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close}, - {ST_IN_ALERT_SENT, EV_REDIR, lli_send_redir}, - {ST_IN_PROCEED_SEND, EV_REDIR, lli_send_redir}, - {ST_IN_PROCEED_SEND, EV_ALERT, lli_send_alert}, - {ST_IN_PROCEED_SEND, EV_ACCEPTD, lli_send_dconnect}, - {ST_IN_PROCEED_SEND, EV_HANGUP, lli_disconnect_reject}, - {ST_IN_PROCEED_SEND, EV_DISCONNECT_IND, lli_dhup_close}, - {ST_IN_ALERT_SENT, EV_RELEASE, lli_dhup_close}, - {ST_IN_WAIT_CONN_ACK, EV_SETUP_CMPL_IND, lli_init_bchan_in}, - {ST_IN_WAIT_CONN_ACK, EV_HANGUP, lli_disconnect_req}, - {ST_IN_WAIT_CONN_ACK, EV_DISCONNECT_IND, lli_release_req}, - {ST_IN_WAIT_CONN_ACK, EV_RELEASE, lli_dhup_close}, - {ST_IN_WAIT_CONN_ACK, EV_CONNECT_ERR, lli_error}, - {ST_WAIT_BCONN, EV_BC_EST, lli_go_active}, - {ST_WAIT_BCONN, EV_BC_REL, lli_rel_b_disc}, - {ST_WAIT_BCONN, EV_HANGUP, lli_rel_b_disc}, - {ST_WAIT_BCONN, EV_DISCONNECT_IND, lli_rel_b_release_req}, - {ST_WAIT_BCONN, EV_RELEASE, lli_rel_b_dhup}, - {ST_WAIT_BCONN, EV_LEASED_REL, lli_rel_b_fail}, - {ST_WAIT_BCONN, EV_CINF, lli_charge_info}, - {ST_ACTIVE, EV_CINF, lli_charge_info}, - {ST_ACTIVE, EV_BC_REL, lli_bhup_rel_b}, - {ST_ACTIVE, EV_SUSPEND, lli_suspend}, - {ST_ACTIVE, EV_HANGUP, lli_disconn_bchan}, - {ST_ACTIVE, EV_DISCONNECT_IND, lli_release_bchan}, - {ST_ACTIVE, EV_RELEASE, lli_abort}, - {ST_ACTIVE, EV_LEASED_REL, lli_failure_a}, - {ST_WAIT_BRELEASE, EV_BC_REL, lli_bhup_disc}, - {ST_WAIT_BRELEASE, EV_DISCONNECT_IND, lli_bhup_release_req}, - {ST_WAIT_BRELEASE, EV_RELEASE, lli_bhup_dhup}, - {ST_WAIT_BRELEASE, EV_LEASED_REL, lli_bhup_fail}, - {ST_WAIT_BREL_DISC, EV_BC_REL, lli_bhup_release_req}, - {ST_WAIT_BREL_DISC, EV_RELEASE, lli_bhup_dhup}, - {ST_WAIT_DCOMMAND, EV_HANGUP, lli_start_disc}, - {ST_WAIT_DCOMMAND, EV_DISCONNECT_IND, lli_release_req}, - {ST_WAIT_DCOMMAND, EV_RELEASE, lli_dhup_close}, - {ST_WAIT_DCOMMAND, EV_LEASED_REL, lli_failure_l}, - {ST_WAIT_DRELEASE, EV_RELEASE, lli_dhup_close}, - {ST_WAIT_DRELEASE, EV_DIAL, lli_dchan_not_ready}, - /* ETS 300-104 16.1 */ - {ST_WAIT_D_REL_CNF, EV_RELEASE, lli_dhup_close}, - {ST_WAIT_D_REL_CNF, EV_DIAL, lli_dchan_not_ready}, -}; -/* *INDENT-ON* */ - -int __init -CallcNew(void) -{ - callcfsm.state_count = STATE_COUNT; - callcfsm.event_count = EVENT_COUNT; - callcfsm.strEvent = strEvent; - callcfsm.strState = strState; - return FsmNew(&callcfsm, fnlist, ARRAY_SIZE(fnlist)); -} - -void -CallcFree(void) -{ - FsmFree(&callcfsm); -} - -static void -release_b_st(struct Channel *chanp) -{ - struct PStack *st = chanp->b_st; - - if (test_and_clear_bit(FLG_START_B, &chanp->Flags)) { - chanp->bcs->BC_Close(chanp->bcs); - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - releasestack_isdnl2(st); - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_HDLC_56K): - case (ISDN_PROTO_L2_TRANS): - case (ISDN_PROTO_L2_MODEM): - case (ISDN_PROTO_L2_FAX): - releasestack_transl2(st); - break; - } - } -} - -static struct Channel -*selectfreechannel(struct PStack *st, int bch) -{ - struct IsdnCardState *cs = st->l1.hardware; - struct Channel *chanp = st->lli.userdata; - int i; - - if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) - i = 1; - else - i = 0; - - if (!bch) { - i = 2; /* virtual channel */ - chanp += 2; - } - - while (i < ((bch) ? cs->chanlimit : (2 + MAX_WAITING_CALLS))) { - if (chanp->fi.state == ST_NULL) - return (chanp); - chanp++; - i++; - } - - if (bch) /* number of channels is limited */ { - i = 2; /* virtual channel */ - chanp = st->lli.userdata; - chanp += i; - while (i < (2 + MAX_WAITING_CALLS)) { - if (chanp->fi.state == ST_NULL) - return (chanp); - chanp++; - i++; - } - } - return (NULL); -} - -static void stat_redir_result(struct IsdnCardState *cs, int chan, ulong result) -{ isdn_ctrl ic; - - ic.driver = cs->myid; - ic.command = ISDN_STAT_REDIR; - ic.arg = chan; - ic.parm.num[0] = result; - cs->iif.statcallb(&ic); -} /* stat_redir_result */ - -static void -dchan_l3l4(struct PStack *st, int pr, void *arg) -{ - struct l3_process *pc = arg; - struct IsdnCardState *cs = st->l1.hardware; - struct Channel *chanp; - - if (!pc) - return; - - if (pr == (CC_SETUP | INDICATION)) { - if (!(chanp = selectfreechannel(pc->st, pc->para.bchannel))) { - pc->para.cause = 0x11; /* User busy */ - pc->st->lli.l4l3(pc->st, CC_REJECT | REQUEST, pc); - } else { - chanp->proc = pc; - pc->chan = chanp; - FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); - } - return; - } - if (!(chanp = pc->chan)) - return; - - switch (pr) { - case (CC_MORE_INFO | INDICATION): - FsmEvent(&chanp->fi, EV_SETUP_IND, NULL); - break; - case (CC_DISCONNECT | INDICATION): - FsmEvent(&chanp->fi, EV_DISCONNECT_IND, NULL); - break; - case (CC_RELEASE | CONFIRM): - FsmEvent(&chanp->fi, EV_RELEASE, NULL); - break; - case (CC_SUSPEND | CONFIRM): - FsmEvent(&chanp->fi, EV_RELEASE, NULL); - break; - case (CC_RESUME | CONFIRM): - FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); - break; - case (CC_RESUME_ERR): - FsmEvent(&chanp->fi, EV_RELEASE, NULL); - break; - case (CC_RELEASE | INDICATION): - FsmEvent(&chanp->fi, EV_RELEASE, NULL); - break; - case (CC_SETUP_COMPL | INDICATION): - FsmEvent(&chanp->fi, EV_SETUP_CMPL_IND, NULL); - break; - case (CC_SETUP | CONFIRM): - FsmEvent(&chanp->fi, EV_SETUP_CNF, NULL); - break; - case (CC_CHARGE | INDICATION): - FsmEvent(&chanp->fi, EV_CINF, NULL); - break; - case (CC_NOSETUP_RSP): - FsmEvent(&chanp->fi, EV_NOSETUP_RSP, NULL); - break; - case (CC_SETUP_ERR): - FsmEvent(&chanp->fi, EV_SETUP_ERR, NULL); - break; - case (CC_CONNECT_ERR): - FsmEvent(&chanp->fi, EV_CONNECT_ERR, NULL); - break; - case (CC_RELEASE_ERR): - FsmEvent(&chanp->fi, EV_RELEASE, NULL); - break; - case (CC_PROCEED_SEND | INDICATION): - case (CC_PROCEEDING | INDICATION): - case (CC_ALERTING | INDICATION): - case (CC_PROGRESS | INDICATION): - case (CC_NOTIFY | INDICATION): - break; - case (CC_REDIR | INDICATION): - stat_redir_result(cs, chanp->chan, pc->redir_result); - break; - default: - if (chanp->debug & 0x800) { - HiSax_putstatus(chanp->cs, "Ch", - "%d L3->L4 unknown primitiv %#x", - chanp->chan, pr); - } - } -} - -static void -dummy_pstack(struct PStack *st, int pr, void *arg) { - printk(KERN_WARNING"call to dummy_pstack pr=%04x arg %lx\n", pr, (long)arg); -} - -static int -init_PStack(struct PStack **stp) { - *stp = kmalloc(sizeof(struct PStack), GFP_KERNEL); - if (!*stp) - return -ENOMEM; - (*stp)->next = NULL; - (*stp)->l1.l1l2 = dummy_pstack; - (*stp)->l1.l1hw = dummy_pstack; - (*stp)->l1.l1tei = dummy_pstack; - (*stp)->l2.l2tei = dummy_pstack; - (*stp)->l2.l2l1 = dummy_pstack; - (*stp)->l2.l2l3 = dummy_pstack; - (*stp)->l3.l3l2 = dummy_pstack; - (*stp)->l3.l3ml3 = dummy_pstack; - (*stp)->l3.l3l4 = dummy_pstack; - (*stp)->lli.l4l3 = dummy_pstack; - (*stp)->ma.layer = dummy_pstack; - return 0; -} - -static int -init_d_st(struct Channel *chanp) -{ - struct PStack *st; - struct IsdnCardState *cs = chanp->cs; - char tmp[16]; - int err; - - err = init_PStack(&chanp->d_st); - if (err) - return err; - st = chanp->d_st; - st->next = NULL; - HiSax_addlist(cs, st); - setstack_HiSax(st, cs); - st->l2.sap = 0; - st->l2.tei = -1; - st->l2.flag = 0; - test_and_set_bit(FLG_MOD128, &st->l2.flag); - test_and_set_bit(FLG_LAPD, &st->l2.flag); - test_and_set_bit(FLG_ORIG, &st->l2.flag); - st->l2.maxlen = MAX_DFRAME_LEN; - st->l2.window = 1; - st->l2.T200 = 1000; /* 1000 milliseconds */ - st->l2.N200 = 3; /* try 3 times */ - st->l2.T203 = 10000; /* 10000 milliseconds */ - if (test_bit(FLG_TWO_DCHAN, &cs->HW_Flags)) - sprintf(tmp, "DCh%d Q.921 ", chanp->chan); - else - sprintf(tmp, "DCh Q.921 "); - setstack_isdnl2(st, tmp); - setstack_l3dc(st, chanp); - st->lli.userdata = chanp; - st->l3.l3l4 = dchan_l3l4; - - return 0; -} - -static __printf(2, 3) void - callc_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - struct Channel *chanp = fi->userdata; - char tmp[16]; - - va_start(args, fmt); - sprintf(tmp, "Ch%d callc ", chanp->chan); - VHiSax_putstatus(chanp->cs, tmp, fmt, args); - va_end(args); -} - -static int -init_chan(int chan, struct IsdnCardState *csta) -{ - struct Channel *chanp = csta->channel + chan; - int err; - - chanp->cs = csta; - chanp->bcs = csta->bcs + chan; - chanp->chan = chan; - chanp->incoming = 0; - chanp->debug = 0; - chanp->Flags = 0; - chanp->leased = 0; - err = init_PStack(&chanp->b_st); - if (err) - return err; - chanp->b_st->l1.delay = DEFAULT_B_DELAY; - chanp->fi.fsm = &callcfsm; - chanp->fi.state = ST_NULL; - chanp->fi.debug = 0; - chanp->fi.userdata = chanp; - chanp->fi.printdebug = callc_debug; - FsmInitTimer(&chanp->fi, &chanp->dial_timer); - FsmInitTimer(&chanp->fi, &chanp->drel_timer); - if (!chan || (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags) && chan < 2)) { - err = init_d_st(chanp); - if (err) - return err; - } else { - chanp->d_st = csta->channel->d_st; - } - chanp->data_open = 0; - return 0; -} - -int -CallcNewChan(struct IsdnCardState *csta) { - int i, err; - - chancount += 2; - err = init_chan(0, csta); - if (err) - return err; - err = init_chan(1, csta); - if (err) - return err; - printk(KERN_INFO "HiSax: 2 channels added\n"); - - for (i = 0; i < MAX_WAITING_CALLS; i++) { - err = init_chan(i + 2, csta); - if (err) - return err; - } - printk(KERN_INFO "HiSax: MAX_WAITING_CALLS added\n"); - if (test_bit(FLG_PTP, &csta->channel->d_st->l2.flag)) { - printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); - csta->channel->d_st->lli.l4l3(csta->channel->d_st, - DL_ESTABLISH | REQUEST, NULL); - } - return (0); -} - -static void -release_d_st(struct Channel *chanp) -{ - struct PStack *st = chanp->d_st; - - if (!st) - return; - releasestack_isdnl2(st); - releasestack_isdnl3(st); - HiSax_rmlist(st->l1.hardware, st); - kfree(st); - chanp->d_st = NULL; -} - -void -CallcFreeChan(struct IsdnCardState *csta) -{ - int i; - - for (i = 0; i < 2; i++) { - FsmDelTimer(&csta->channel[i].drel_timer, 74); - FsmDelTimer(&csta->channel[i].dial_timer, 75); - if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) - release_d_st(csta->channel + i); - if (csta->channel[i].b_st) { - release_b_st(csta->channel + i); - kfree(csta->channel[i].b_st); - csta->channel[i].b_st = NULL; - } else - printk(KERN_WARNING "CallcFreeChan b_st ch%d already freed\n", i); - if (i || test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { - release_d_st(csta->channel + i); - } else - csta->channel[i].d_st = NULL; - } -} - -static void -lldata_handler(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - struct sk_buff *skb = arg; - - switch (pr) { - case (DL_DATA | INDICATION): - if (chanp->data_open) { - if (chanp->debug & 0x800) - link_debug(chanp, 0, "lldata: %d", skb->len); - chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - } else { - link_debug(chanp, 0, "lldata: channel not open"); - dev_kfree_skb(skb); - } - break; - case (DL_ESTABLISH | INDICATION): - case (DL_ESTABLISH | CONFIRM): - FsmEvent(&chanp->fi, EV_BC_EST, NULL); - break; - case (DL_RELEASE | INDICATION): - case (DL_RELEASE | CONFIRM): - FsmEvent(&chanp->fi, EV_BC_REL, NULL); - break; - default: - printk(KERN_WARNING "lldata_handler unknown primitive %#x\n", - pr); - break; - } -} - -static void -lltrans_handler(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - struct sk_buff *skb = arg; - - switch (pr) { - case (PH_DATA | INDICATION): - if (chanp->data_open) { - if (chanp->debug & 0x800) - link_debug(chanp, 0, "lltrans: %d", skb->len); - chanp->cs->iif.rcvcallb_skb(chanp->cs->myid, chanp->chan, skb); - } else { - link_debug(chanp, 0, "lltrans: channel not open"); - dev_kfree_skb(skb); - } - break; - case (PH_ACTIVATE | INDICATION): - case (PH_ACTIVATE | CONFIRM): - FsmEvent(&chanp->fi, EV_BC_EST, NULL); - break; - case (PH_DEACTIVATE | INDICATION): - case (PH_DEACTIVATE | CONFIRM): - FsmEvent(&chanp->fi, EV_BC_REL, NULL); - break; - default: - printk(KERN_WARNING "lltrans_handler unknown primitive %#x\n", - pr); - break; - } -} - -void -lli_writewakeup(struct PStack *st, int len) -{ - struct Channel *chanp = st->lli.userdata; - isdn_ctrl ic; - - if (chanp->debug & 0x800) - link_debug(chanp, 0, "llwakeup: %d", len); - ic.driver = chanp->cs->myid; - ic.command = ISDN_STAT_BSENT; - ic.arg = chanp->chan; - ic.parm.length = len; - chanp->cs->iif.statcallb(&ic); -} - -static int -init_b_st(struct Channel *chanp, int incoming) -{ - struct PStack *st = chanp->b_st; - struct IsdnCardState *cs = chanp->cs; - char tmp[16]; - - st->l1.hardware = cs; - if (chanp->leased) - st->l1.bc = chanp->chan & 1; - else - st->l1.bc = chanp->proc->para.bchannel - 1; - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - case (ISDN_PROTO_L2_HDLC): - st->l1.mode = L1_MODE_HDLC; - break; - case (ISDN_PROTO_L2_HDLC_56K): - st->l1.mode = L1_MODE_HDLC_56K; - break; - case (ISDN_PROTO_L2_TRANS): - st->l1.mode = L1_MODE_TRANS; - break; - case (ISDN_PROTO_L2_MODEM): - st->l1.mode = L1_MODE_V32; - break; - case (ISDN_PROTO_L2_FAX): - st->l1.mode = L1_MODE_FAX; - break; - } - chanp->bcs->conmsg = NULL; - if (chanp->bcs->BC_SetStack(st, chanp->bcs)) - return (-1); - st->l2.flag = 0; - test_and_set_bit(FLG_LAPB, &st->l2.flag); - st->l2.maxlen = MAX_DATA_SIZE; - if (!incoming) - test_and_set_bit(FLG_ORIG, &st->l2.flag); - st->l2.T200 = 1000; /* 1000 milliseconds */ - st->l2.window = 7; - st->l2.N200 = 4; /* try 4 times */ - st->l2.T203 = 5000; /* 5000 milliseconds */ - st->l3.debug = 0; - switch (chanp->l2_active_protocol) { - case (ISDN_PROTO_L2_X75I): - sprintf(tmp, "Ch%d X.75", chanp->chan); - setstack_isdnl2(st, tmp); - setstack_l3bc(st, chanp); - st->l2.l2l3 = lldata_handler; - st->lli.userdata = chanp; - test_and_clear_bit(FLG_LLI_L1WAKEUP, &st->lli.flag); - test_and_set_bit(FLG_LLI_L2WAKEUP, &st->lli.flag); - st->l2.l2m.debug = chanp->debug & 16; - st->l2.debug = chanp->debug & 64; - break; - case (ISDN_PROTO_L2_HDLC): - case (ISDN_PROTO_L2_HDLC_56K): - case (ISDN_PROTO_L2_TRANS): - case (ISDN_PROTO_L2_MODEM): - case (ISDN_PROTO_L2_FAX): - st->l1.l1l2 = lltrans_handler; - st->lli.userdata = chanp; - test_and_set_bit(FLG_LLI_L1WAKEUP, &st->lli.flag); - test_and_clear_bit(FLG_LLI_L2WAKEUP, &st->lli.flag); - setstack_transl2(st); - setstack_l3bc(st, chanp); - break; - } - test_and_set_bit(FLG_START_B, &chanp->Flags); - return (0); -} - -static void -leased_l4l3(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - struct sk_buff *skb = arg; - - switch (pr) { - case (DL_DATA | REQUEST): - link_debug(chanp, 0, "leased line d-channel DATA"); - dev_kfree_skb(skb); - break; - case (DL_ESTABLISH | REQUEST): - st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL); - break; - case (DL_RELEASE | REQUEST): - break; - default: - printk(KERN_WARNING "transd_l4l3 unknown primitive %#x\n", - pr); - break; - } -} - -static void -leased_l1l2(struct PStack *st, int pr, void *arg) -{ - struct Channel *chanp = (struct Channel *) st->lli.userdata; - struct sk_buff *skb = arg; - int i, event = EV_LEASED_REL; - - switch (pr) { - case (PH_DATA | INDICATION): - link_debug(chanp, 0, "leased line d-channel DATA"); - dev_kfree_skb(skb); - break; - case (PH_ACTIVATE | INDICATION): - case (PH_ACTIVATE | CONFIRM): - event = EV_LEASED; - /* fall through */ - case (PH_DEACTIVATE | INDICATION): - case (PH_DEACTIVATE | CONFIRM): - if (test_bit(FLG_TWO_DCHAN, &chanp->cs->HW_Flags)) - i = 1; - else - i = 0; - while (i < 2) { - FsmEvent(&chanp->fi, event, NULL); - chanp++; - i++; - } - break; - default: - printk(KERN_WARNING - "transd_l1l2 unknown primitive %#x\n", pr); - break; - } -} - -static void -distr_debug(struct IsdnCardState *csta, int debugflags) -{ - int i; - struct Channel *chanp = csta->channel; - - for (i = 0; i < (2 + MAX_WAITING_CALLS); i++) { - chanp[i].debug = debugflags; - chanp[i].fi.debug = debugflags & 2; - chanp[i].d_st->l2.l2m.debug = debugflags & 8; - chanp[i].b_st->l2.l2m.debug = debugflags & 0x10; - chanp[i].d_st->l2.debug = debugflags & 0x20; - chanp[i].b_st->l2.debug = debugflags & 0x40; - chanp[i].d_st->l3.l3m.debug = debugflags & 0x80; - chanp[i].b_st->l3.l3m.debug = debugflags & 0x100; - chanp[i].b_st->ma.tei_m.debug = debugflags & 0x200; - chanp[i].b_st->ma.debug = debugflags & 0x200; - chanp[i].d_st->l1.l1m.debug = debugflags & 0x1000; - chanp[i].b_st->l1.l1m.debug = debugflags & 0x2000; - } - if (debugflags & 4) - csta->debug |= DEB_DLOG_HEX; - else - csta->debug &= ~DEB_DLOG_HEX; -} - -static char tmpbuf[256]; - -static void -capi_debug(struct Channel *chanp, capi_msg *cm) -{ - char *t = tmpbuf; - - t += QuickHex(t, (u_char *)cm, (cm->Length > 50) ? 50 : cm->Length); - t--; - *t = 0; - HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf); -} - -static void -lli_got_fac_req(struct Channel *chanp, capi_msg *cm) { - if ((cm->para[0] != 3) || (cm->para[1] != 0)) - return; - if (cm->para[2] < 3) - return; - if (cm->para[4] != 0) - return; - switch (cm->para[3]) { - case 4: /* Suspend */ - strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] + 1); - FsmEvent(&chanp->fi, EV_SUSPEND, cm); - break; - case 5: /* Resume */ - strncpy(chanp->setup.phone, &cm->para[5], cm->para[5] + 1); - if (chanp->fi.state == ST_NULL) { - FsmEvent(&chanp->fi, EV_RESUME, cm); - } else { - FsmDelTimer(&chanp->dial_timer, 72); - FsmAddTimer(&chanp->dial_timer, 80, EV_RESUME, cm, 73); - } - break; - } -} - -static void -lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) { - if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) || - (cs->typ == ISDN_CTYPE_ELSA_PCI)) { - if (cs->hw.elsa.MFlag) { - cs->cardmsg(cs, CARD_AUX_IND, cm->para); - } - } -} - - -/***************************************************************/ -/* Limit the available number of channels for the current card */ -/***************************************************************/ -static int -set_channel_limit(struct IsdnCardState *cs, int chanmax) -{ - isdn_ctrl ic; - int i, ii; - - if ((chanmax < 0) || (chanmax > 2)) - return (-EINVAL); - cs->chanlimit = 0; - for (ii = 0; ii < 2; ii++) { - ic.driver = cs->myid; - ic.command = ISDN_STAT_DISCH; - ic.arg = ii; - if (ii >= chanmax) - ic.parm.num[0] = 0; /* disabled */ - else - ic.parm.num[0] = 1; /* enabled */ - i = cs->iif.statcallb(&ic); - if (i) return (-EINVAL); - if (ii < chanmax) - cs->chanlimit++; - } - return (0); -} /* set_channel_limit */ - -int -HiSax_command(isdn_ctrl *ic) -{ - struct IsdnCardState *csta = hisax_findcard(ic->driver); - struct PStack *st; - struct Channel *chanp; - int i; - u_int num; - - if (!csta) { - printk(KERN_ERR - "HiSax: if_command %d called with invalid driverId %d!\n", - ic->command, ic->driver); - return -ENODEV; - } - switch (ic->command) { - case (ISDN_CMD_SETEAZ): - chanp = csta->channel + ic->arg; - break; - case (ISDN_CMD_SETL2): - chanp = csta->channel + (ic->arg & 0xff); - if (chanp->debug & 1) - link_debug(chanp, 1, "SETL2 card %d %ld", - csta->cardnr + 1, ic->arg >> 8); - chanp->l2_protocol = ic->arg >> 8; - break; - case (ISDN_CMD_SETL3): - chanp = csta->channel + (ic->arg & 0xff); - if (chanp->debug & 1) - link_debug(chanp, 1, "SETL3 card %d %ld", - csta->cardnr + 1, ic->arg >> 8); - chanp->l3_protocol = ic->arg >> 8; - break; - case (ISDN_CMD_DIAL): - chanp = csta->channel + (ic->arg & 0xff); - if (chanp->debug & 1) - link_debug(chanp, 1, "DIAL %s -> %s (%d,%d)", - ic->parm.setup.eazmsn, ic->parm.setup.phone, - ic->parm.setup.si1, ic->parm.setup.si2); - memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); - if (!strcmp(chanp->setup.eazmsn, "0")) - chanp->setup.eazmsn[0] = '\0'; - /* this solution is dirty and may be change, if - * we make a callreference based callmanager */ - if (chanp->fi.state == ST_NULL) { - FsmEvent(&chanp->fi, EV_DIAL, NULL); - } else { - FsmDelTimer(&chanp->dial_timer, 70); - FsmAddTimer(&chanp->dial_timer, 50, EV_DIAL, NULL, 71); - } - break; - case (ISDN_CMD_ACCEPTB): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - link_debug(chanp, 1, "ACCEPTB"); - FsmEvent(&chanp->fi, EV_ACCEPTB, NULL); - break; - case (ISDN_CMD_ACCEPTD): - chanp = csta->channel + ic->arg; - memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); - if (chanp->debug & 1) - link_debug(chanp, 1, "ACCEPTD"); - FsmEvent(&chanp->fi, EV_ACCEPTD, NULL); - break; - case (ISDN_CMD_HANGUP): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - link_debug(chanp, 1, "HANGUP"); - FsmEvent(&chanp->fi, EV_HANGUP, NULL); - break; - case (CAPI_PUT_MESSAGE): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - capi_debug(chanp, &ic->parm.cmsg); - if (ic->parm.cmsg.Length < 8) - break; - switch (ic->parm.cmsg.Command) { - case CAPI_FACILITY: - if (ic->parm.cmsg.Subcommand == CAPI_REQ) - lli_got_fac_req(chanp, &ic->parm.cmsg); - break; - case CAPI_MANUFACTURER: - if (ic->parm.cmsg.Subcommand == CAPI_REQ) - lli_got_manufacturer(chanp, csta, &ic->parm.cmsg); - break; - default: - break; - } - break; - case (ISDN_CMD_IOCTL): - switch (ic->arg) { - case (0): - num = *(unsigned int *) ic->parm.num; - HiSax_reportcard(csta->cardnr, num); - break; - case (1): - num = *(unsigned int *) ic->parm.num; - distr_debug(csta, num); - printk(KERN_DEBUG "HiSax: debugging flags card %d set to %x\n", - csta->cardnr + 1, num); - HiSax_putstatus(csta, "debugging flags ", - "card %d set to %x", csta->cardnr + 1, num); - break; - case (2): - num = *(unsigned int *) ic->parm.num; - csta->channel[0].b_st->l1.delay = num; - csta->channel[1].b_st->l1.delay = num; - HiSax_putstatus(csta, "delay ", "card %d set to %d ms", - csta->cardnr + 1, num); - printk(KERN_DEBUG "HiSax: delay card %d set to %d ms\n", - csta->cardnr + 1, num); - break; - case (5): /* set card in leased mode */ - num = *(unsigned int *) ic->parm.num; - if ((num < 1) || (num > 2)) { - HiSax_putstatus(csta, "Set LEASED ", - "wrong channel %d", num); - printk(KERN_WARNING "HiSax: Set LEASED wrong channel %d\n", - num); - } else { - num--; - chanp = csta->channel + num; - chanp->leased = 1; - HiSax_putstatus(csta, "Card", - "%d channel %d set leased mode\n", - csta->cardnr + 1, num + 1); - chanp->d_st->l1.l1l2 = leased_l1l2; - chanp->d_st->lli.l4l3 = leased_l4l3; - chanp->d_st->lli.l4l3(chanp->d_st, - DL_ESTABLISH | REQUEST, NULL); - } - break; - case (6): /* set B-channel test loop */ - num = *(unsigned int *) ic->parm.num; - if (csta->stlist) - csta->stlist->l2.l2l1(csta->stlist, - PH_TESTLOOP | REQUEST, (void *) (long)num); - break; - case (7): /* set card in PTP mode */ - num = *(unsigned int *) ic->parm.num; - if (test_bit(FLG_TWO_DCHAN, &csta->HW_Flags)) { - printk(KERN_ERR "HiSax PTP mode only with one TEI possible\n"); - } else if (num) { - test_and_set_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag); - test_and_set_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag); - csta->channel[0].d_st->l2.tei = 0; - HiSax_putstatus(csta, "set card ", "in PTP mode"); - printk(KERN_DEBUG "HiSax: set card in PTP mode\n"); - printk(KERN_INFO "LAYER2 WATCHING ESTABLISH\n"); - csta->channel[0].d_st->lli.l4l3(csta->channel[0].d_st, - DL_ESTABLISH | REQUEST, NULL); - } else { - test_and_clear_bit(FLG_PTP, &csta->channel[0].d_st->l2.flag); - test_and_clear_bit(FLG_FIXED_TEI, &csta->channel[0].d_st->l2.flag); - HiSax_putstatus(csta, "set card ", "in PTMP mode"); - printk(KERN_DEBUG "HiSax: set card in PTMP mode\n"); - } - break; - case (8): /* set card in FIXED TEI mode */ - num = *(unsigned int *)ic->parm.num; - chanp = csta->channel + (num & 1); - num = num >> 1; - if (num == 127) { - test_and_clear_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag); - chanp->d_st->l2.tei = -1; - HiSax_putstatus(csta, "set card ", "in VAR TEI mode"); - printk(KERN_DEBUG "HiSax: set card in VAR TEI mode\n"); - } else { - test_and_set_bit(FLG_FIXED_TEI, &chanp->d_st->l2.flag); - chanp->d_st->l2.tei = num; - HiSax_putstatus(csta, "set card ", "in FIXED TEI (%d) mode", num); - printk(KERN_DEBUG "HiSax: set card in FIXED TEI (%d) mode\n", - num); - } - chanp->d_st->lli.l4l3(chanp->d_st, - DL_ESTABLISH | REQUEST, NULL); - break; - case (11): - num = csta->debug & DEB_DLOG_HEX; - csta->debug = *(unsigned int *) ic->parm.num; - csta->debug |= num; - HiSax_putstatus(cards[0].cs, "l1 debugging ", - "flags card %d set to %x", - csta->cardnr + 1, csta->debug); - printk(KERN_DEBUG "HiSax: l1 debugging flags card %d set to %x\n", - csta->cardnr + 1, csta->debug); - break; - case (13): - csta->channel[0].d_st->l3.debug = *(unsigned int *) ic->parm.num; - csta->channel[1].d_st->l3.debug = *(unsigned int *) ic->parm.num; - HiSax_putstatus(cards[0].cs, "l3 debugging ", - "flags card %d set to %x\n", csta->cardnr + 1, - *(unsigned int *) ic->parm.num); - printk(KERN_DEBUG "HiSax: l3 debugging flags card %d set to %x\n", - csta->cardnr + 1, *(unsigned int *) ic->parm.num); - break; - case (10): - i = *(unsigned int *) ic->parm.num; - return (set_channel_limit(csta, i)); - default: - if (csta->auxcmd) - return (csta->auxcmd(csta, ic)); - printk(KERN_DEBUG "HiSax: invalid ioctl %d\n", - (int) ic->arg); - return (-EINVAL); - } - break; - - case (ISDN_CMD_PROCEED): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - link_debug(chanp, 1, "PROCEED"); - FsmEvent(&chanp->fi, EV_PROCEED, NULL); - break; - - case (ISDN_CMD_ALERT): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - link_debug(chanp, 1, "ALERT"); - FsmEvent(&chanp->fi, EV_ALERT, NULL); - break; - - case (ISDN_CMD_REDIR): - chanp = csta->channel + ic->arg; - if (chanp->debug & 1) - link_debug(chanp, 1, "REDIR"); - memcpy(&chanp->setup, &ic->parm.setup, sizeof(setup_parm)); - FsmEvent(&chanp->fi, EV_REDIR, NULL); - break; - - /* protocol specific io commands */ - case (ISDN_CMD_PROT_IO): - for (st = csta->stlist; st; st = st->next) - if (st->protocol == (ic->arg & 0xFF)) - return (st->lli.l4l3_proto(st, ic)); - return (-EINVAL); - break; - default: - if (csta->auxcmd) - return (csta->auxcmd(csta, ic)); - return (-EINVAL); - } - return (0); -} - -int -HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb) -{ - struct IsdnCardState *csta = hisax_findcard(id); - struct Channel *chanp; - struct PStack *st; - int len = skb->len; - struct sk_buff *nskb; - - if (!csta) { - printk(KERN_ERR - "HiSax: if_sendbuf called with invalid driverId!\n"); - return -ENODEV; - } - chanp = csta->channel + chan; - st = chanp->b_st; - if (!chanp->data_open) { - link_debug(chanp, 1, "writebuf: channel not open"); - return -EIO; - } - if (len > MAX_DATA_SIZE) { - link_debug(chanp, 1, "writebuf: packet too large (%d bytes)", len); - printk(KERN_WARNING "HiSax_writebuf: packet too large (%d bytes) !\n", - len); - return -EINVAL; - } - if (len) { - if ((len + chanp->bcs->tx_cnt) > MAX_DATA_MEM) { - /* Must return 0 here, since this is not an error - * but a temporary lack of resources. - */ - if (chanp->debug & 0x800) - link_debug(chanp, 1, "writebuf: no buffers for %d bytes", len); - return 0; - } else if (chanp->debug & 0x800) - link_debug(chanp, 1, "writebuf %d/%d/%d", len, chanp->bcs->tx_cnt, MAX_DATA_MEM); - nskb = skb_clone(skb, GFP_ATOMIC); - if (nskb) { - nskb->truesize = nskb->len; - if (!ack) - nskb->pkt_type = PACKET_NOACK; - if (chanp->l2_active_protocol == ISDN_PROTO_L2_X75I) - st->l3.l3l2(st, DL_DATA | REQUEST, nskb); - else { - chanp->bcs->tx_cnt += len; - st->l2.l2l1(st, PH_DATA | REQUEST, nskb); - } - dev_kfree_skb(skb); - } else - len = 0; - } - return (len); -} diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c deleted file mode 100644 index de965115a183..000000000000 --- a/drivers/isdn/hisax/config.c +++ /dev/null @@ -1,1993 +0,0 @@ -/* $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/init.h> -#include "hisax.h" -#include <linux/module.h> -#include <linux/kernel_stat.h> -#include <linux/workqueue.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#define HISAX_STATUS_BUFSIZE 4096 - -/* - * 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_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, }; - -static 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] = { 0, }; -static int io1[HISAX_MAX_CARDS] = { 0, }; -#endif -static int irq[HISAX_MAX_CARDS] = { 0, }; -static int mem[HISAX_MAX_CARDS] = { 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_hw_array(io, int, ioport, NULL, 0); -module_param_hw_array(irq, int, irq, NULL, 0); -module_param_hw_array(mem, int, iomem, NULL, 0); -module_param(id, charp, 0); -#ifdef IO0_IO1 -module_param_hw_array(io0, int, ioport, NULL, 0); -module_param_hw_array(io1, int, ioport, NULL, 0); -#endif -#endif /* MODULE */ - -int nrcards; - -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; -} - -static 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_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_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 - */ -#if 0 -struct IsdnCardState *hisax_get_card(int cardnr) -{ - if ((cardnr <= nrcards) && (cardnr > 0)) - if (cards[cardnr - 1].cs) - return cards[cardnr - 1].cs; - return NULL; -} -#endif /* 0 */ - -static 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; - if (copy_to_user(p, cs->status_read, count)) - return -EFAULT; - 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; - if (copy_to_user(p, cs->status_read, cnt)) - return -EFAULT; - 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, const 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; - const u_char *data; - - if (!cs) { - printk(KERN_WARNING "HiSax: No CardStatus for message"); - return; - } - spin_lock_irqsave(&cs->statlock, flags); - if (head) { - p = tmpbuf; - p += jiftime(p, jiffies); - p += sprintf(p, " %s", head); - p += vsprintf(p, fmt, args); - *p++ = '\n'; - *p = 0; - len = p - tmpbuf; - data = tmpbuf; - } else { - data = 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, data, i); - cs->status_write += i; - if (cs->status_write > cs->status_end) - cs->status_write = cs->status_buf; - if (len) { - memcpy(cs->status_write, data + i, 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, const 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; -} - -static 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); - 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); - 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 irqreturn_t card_irq(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - irqreturn_t ret = cs->irq_func(intno, cs); - - if (ret == IRQ_HANDLED) - cs->irq_cnt++; - return ret; -} - -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 = cs->irq_cnt = 0; - printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ], - cs->irq, irq_cnt); - if (request_irq(cs->irq, card_irq, 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, cs->irq_cnt); - if (cs->irq_cnt == 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 hisax_cs_setup_card(struct IsdnCard *card) -{ - int ret; - - 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_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_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]); - ret = 0; - break; - } - - return ret; -} - -static int hisax_cs_new(int cardnr, char *id, struct IsdnCard *card, - struct IsdnCardState **cs_out, int *busy_flag, - struct module *lockowner) -{ - struct IsdnCardState *cs; - - *cs_out = NULL; - - cs = kzalloc(sizeof(struct IsdnCardState), GFP_KERNEL); - if (!cs) { - printk(KERN_WARNING - "HiSax: No memory for IsdnCardState(card %d)\n", - cardnr + 1); - goto out; - } - 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_KERNEL))) { - 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_KERNEL))) { - 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; - - *cs_out = cs; - return 1; /* success */ - -outf_dlog: - kfree(cs->dlog); -outf_cs: - kfree(cs); - card->cs = NULL; -out: - return 0; /* error */ -} - -static int hisax_cs_setup(int cardnr, struct IsdnCard *card, - struct IsdnCardState *cs) -{ - int ret; - - if (!(cs->rcvbuf = kmalloc(MAX_DFRAME_LEN_L1, GFP_KERNEL))) { - 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; - - 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); - goto outf_cs; - } - init_tei(cs, cs->protocol); - ret = CallcNewChan(cs); - if (ret) { - closecard(cardnr); - goto outf_cs; - } - /* ISAR needs firmware download first */ - if (!test_bit(HW_ISAR, &cs->HW_Flags)) - ll_run(cs, 0); - - return 1; - -outf_cs: - kfree(cs); - card->cs = NULL; - return 0; -} - -static int checkcard(int cardnr, char *id, int *busy_flag, - struct module *lockowner, hisax_setup_func_t card_setup) -{ - int ret; - struct IsdnCard *card = cards + cardnr; - struct IsdnCardState *cs; - - ret = hisax_cs_new(cardnr, id, card, &cs, busy_flag, lockowner); - if (!ret) - return 0; - - 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); - - ret = card_setup(card); - if (!ret) { - ll_unload(cs); - goto outf_cs; - } - - ret = hisax_cs_setup(cardnr, card, cs); - goto out; - -outf_cs: - kfree(cs); - card->cs = NULL; -out: - return ret; -} - -static 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])); -} - -static int __init 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, - hisax_cs_setup_card)) { - 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; - - printk(KERN_DEBUG "HiSax: reportcard No %d\n", cardnr + 1); - printk(KERN_DEBUG "HiSax: Type %s\n", CardType[cs->typ]); - printk(KERN_DEBUG "HiSax: debuglevel %x\n", cs->debug); - printk(KERN_DEBUG "HiSax: HiSax_reportcard address 0x%px\n", - HiSax_reportcard); - printk(KERN_DEBUG "HiSax: cs 0x%px\n", cs); - printk(KERN_DEBUG "HiSax: HW_Flags %lx bc0 flg %lx bc1 flg %lx\n", - cs->HW_Flags, cs->bcs[0].Flag, cs->bcs[1].Flag); - printk(KERN_DEBUG "HiSax: bcs 0 mode %d ch%d\n", - cs->bcs[0].mode, cs->bcs[0].channel); - printk(KERN_DEBUG "HiSax: bcs 1 mode %d ch%d\n", - cs->bcs[1].mode, cs->bcs[1].channel); -#ifdef ERROR_STATISTIC - printk(KERN_DEBUG "HiSax: dc errors(rx,crc,tx) %d,%d,%d\n", - cs->err_rx, cs->err_crc, cs->err_tx); - printk(KERN_DEBUG - "HiSax: bc0 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n", - cs->bcs[0].err_inv, cs->bcs[0].err_rdo, cs->bcs[0].err_crc, - cs->bcs[0].err_tx); - printk(KERN_DEBUG - "HiSax: bc1 errors(inv,rdo,crc,tx) %d,%d,%d,%d\n", - cs->bcs[1].err_inv, cs->bcs[1].err_rdo, cs->bcs[1].err_crc, - cs->bcs[1].err_tx); - if (sel == 99) { - cs->err_rx = 0; - cs->err_crc = 0; - cs->err_tx = 0; - cs->bcs[0].err_inv = 0; - cs->bcs[0].err_rdo = 0; - cs->bcs[0].err_crc = 0; - cs->bcs[0].err_tx = 0; - cs->bcs[1].err_inv = 0; - cs->bcs[1].err_rdo = 0; - cs->bcs[1].err_crc = 0; - cs->bcs[1].err_tx = 0; - } -#endif -} - -static int __init HiSax_init(void) -{ - int i, retval; -#ifdef MODULE - int j; - int nzproto = 0; -#endif - - HiSaxVersion(); - retval = CallcNew(); - if (retval) - goto out; - retval = Isdnl3New(); - if (retval) - goto out_callc; - retval = Isdnl2New(); - if (retval) - goto out_isdnl3; - retval = TeiNew(); - if (retval) - goto out_isdnl2; - retval = Isdnl1New(); - if (retval) - goto out_tei; - -#ifdef MODULE - if (!type[0]) { - /* We 'll register drivers later, but init basic functions */ - for (i = 0; i < HISAX_MAX_CARDS; i++) - cards[i].typ = 0; - return 0; - } -#ifdef CONFIG_HISAX_ELSA - if (type[0] == ISDN_CTYPE_ELSA_PCMCIA) { - /* we have exported and return in this case */ - return 0; - } -#endif -#ifdef CONFIG_HISAX_SEDLBAUER - if (type[0] == ISDN_CTYPE_SEDLBAUER_PCMCIA) { - /* we have to export and return in this case */ - return 0; - } -#endif -#ifdef CONFIG_HISAX_AVM_A1_PCMCIA - if (type[0] == ISDN_CTYPE_A1_PCMCIA) { - /* we have to export and return in this case */ - return 0; - } -#endif -#ifdef CONFIG_HISAX_HFC_SX - if (type[0] == ISDN_CTYPE_HFC_SP_PCMCIA) { - /* we have to export and return in this case */ - return 0; - } -#endif -#endif - nrcards = 0; -#ifdef MODULE - if (id) /* If id= string used */ - HiSax_id = id; - for (i = j = 0; j < HISAX_MAX_CARDS; i++) { - cards[j].typ = type[i]; - if (protocol[i]) { - cards[j].protocol = protocol[i]; - nzproto++; - } else { - cards[j].protocol = DEFAULT_PROTO; - } - switch (type[i]) { - case ISDN_CTYPE_16_0: - cards[j].para[0] = irq[i]; - cards[j].para[1] = mem[i]; - cards[j].para[2] = io[i]; - break; - - case ISDN_CTYPE_8_0: - cards[j].para[0] = irq[i]; - cards[j].para[1] = mem[i]; - break; - -#ifdef IO0_IO1 - case ISDN_CTYPE_PNP: - case ISDN_CTYPE_NICCY: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io0[i]; - cards[j].para[2] = io1[i]; - break; - case ISDN_CTYPE_COMPAQ_ISA: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io0[i]; - cards[j].para[2] = io1[i]; - cards[j].para[3] = io[i]; - break; -#endif - case ISDN_CTYPE_ELSA: - case ISDN_CTYPE_HFC_PCI: - cards[j].para[0] = io[i]; - break; - case ISDN_CTYPE_16_3: - case ISDN_CTYPE_TELESPCMCIA: - case ISDN_CTYPE_A1: - case ISDN_CTYPE_A1_PCMCIA: - case ISDN_CTYPE_ELSA_PNP: - case ISDN_CTYPE_ELSA_PCMCIA: - case ISDN_CTYPE_IX1MICROR2: - case ISDN_CTYPE_DIEHLDIVA: - case ISDN_CTYPE_ASUSCOM: - case ISDN_CTYPE_TELEINT: - case ISDN_CTYPE_SEDLBAUER: - case ISDN_CTYPE_SEDLBAUER_PCMCIA: - case ISDN_CTYPE_SEDLBAUER_FAX: - case ISDN_CTYPE_SPORTSTER: - case ISDN_CTYPE_MIC: - case ISDN_CTYPE_TELES3C: - case ISDN_CTYPE_ACERP10: - case ISDN_CTYPE_S0BOX: - case ISDN_CTYPE_FRITZPCI: - case ISDN_CTYPE_HSTSAPHIR: - case ISDN_CTYPE_GAZEL: - case ISDN_CTYPE_HFC_SX: - case ISDN_CTYPE_HFC_SP_PCMCIA: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io[i]; - break; - case ISDN_CTYPE_ISURF: - cards[j].para[0] = irq[i]; - cards[j].para[1] = io[i]; - cards[j].para[2] = mem[i]; - break; - case ISDN_CTYPE_ELSA_PCI: - case ISDN_CTYPE_NETJET_S: - case ISDN_CTYPE_TELESPCI: - case ISDN_CTYPE_W6692: - case ISDN_CTYPE_NETJET_U: - break; - case ISDN_CTYPE_BKM_A4T: - break; - case ISDN_CTYPE_SCT_QUADRO: - if (irq[i]) { - cards[j].para[0] = irq[i]; - } else { - /* QUADRO is a 4 BRI card */ - cards[j++].para[0] = 1; - /* we need to check if further cards can be added */ - if (j < HISAX_MAX_CARDS) { - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j++].para[0] = 2; - } - if (j < HISAX_MAX_CARDS) { - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j++].para[0] = 3; - } - if (j < HISAX_MAX_CARDS) { - cards[j].typ = ISDN_CTYPE_SCT_QUADRO; - cards[j].protocol = protocol[i]; - cards[j].para[0] = 4; - } - } - break; - } - j++; - } - if (!nzproto) { - printk(KERN_WARNING - "HiSax: Warning - no protocol specified\n"); - printk(KERN_WARNING "HiSax: using protocol %s\n", - DEFAULT_PROTO_NAME); - } -#endif - if (!HiSax_id) - HiSax_id = HiSaxID; - if (!HiSaxID[0]) - strcpy(HiSaxID, "HiSax"); - for (i = 0; i < HISAX_MAX_CARDS; i++) - if (cards[i].typ > 0) - nrcards++; - printk(KERN_DEBUG "HiSax: Total %d card%s defined\n", - nrcards, (nrcards > 1) ? "s" : ""); - - /* Install only, if at least one card found */ - if (!HiSax_inithardware(NULL)) - return -ENODEV; - return 0; - -out_tei: - TeiFree(); -out_isdnl2: - Isdnl2Free(); -out_isdnl3: - Isdnl3Free(); -out_callc: - CallcFree(); -out: - return retval; -} - -static void __exit HiSax_exit(void) -{ - int cardnr = nrcards - 1; - - while (cardnr >= 0) - HiSax_closecard(cardnr--); - Isdnl1Free(); - TeiFree(); - Isdnl2Free(); - Isdnl3Free(); - CallcFree(); - printk(KERN_INFO "HiSax module removed\n"); -} - -int hisax_init_pcmcia(void *pcm_iob, int *busy_flag, struct IsdnCard *card) -{ - u_char ids[16]; - int ret = -1; - - cards[nrcards] = *card; - if (nrcards) - sprintf(ids, "HiSax%d", nrcards); - else - sprintf(ids, "HiSax"); - if (!checkcard(nrcards, ids, busy_flag, THIS_MODULE, - hisax_cs_setup_card)) - goto error; - - ret = nrcards; - nrcards++; -error: - return ret; -} -EXPORT_SYMBOL(hisax_init_pcmcia); - -EXPORT_SYMBOL(HiSax_closecard); - -#include "hisax_if.h" - -EXPORT_SYMBOL(hisax_register); -EXPORT_SYMBOL(hisax_unregister); - -static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg); -static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg); -static void hisax_d_l2l1(struct PStack *st, int pr, void *arg); -static void hisax_b_l2l1(struct PStack *st, int pr, void *arg); -static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg); -static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs); -static void hisax_bc_close(struct BCState *bcs); -static void hisax_bh(struct work_struct *work); -static void EChannel_proc_rcv(struct hisax_d_if *d_if); - -static int hisax_setup_card_dynamic(struct IsdnCard *card) -{ - return 2; -} - -int hisax_register(struct hisax_d_if *hisax_d_if, struct hisax_b_if *b_if[], - char *name, int protocol) -{ - int i, retval; - char id[20]; - struct IsdnCardState *cs; - - for (i = 0; i < HISAX_MAX_CARDS; i++) { - if (!cards[i].typ) - break; - } - - if (i >= HISAX_MAX_CARDS) - return -EBUSY; - - cards[i].typ = ISDN_CTYPE_DYNAMIC; - cards[i].protocol = protocol; - sprintf(id, "%s%d", name, i); - nrcards++; - retval = checkcard(i, id, NULL, hisax_d_if->owner, - hisax_setup_card_dynamic); - if (retval == 0) { // yuck - cards[i].typ = 0; - nrcards--; - return -EINVAL; - } - cs = cards[i].cs; - hisax_d_if->cs = cs; - cs->hw.hisax_d_if = hisax_d_if; - cs->cardmsg = hisax_cardmsg; - INIT_WORK(&cs->tqueue, hisax_bh); - cs->channel[0].d_st->l2.l2l1 = hisax_d_l2l1; - for (i = 0; i < 2; i++) { - cs->bcs[i].BC_SetStack = hisax_bc_setstack; - cs->bcs[i].BC_Close = hisax_bc_close; - - b_if[i]->ifc.l1l2 = hisax_b_l1l2; - - hisax_d_if->b_if[i] = b_if[i]; - } - hisax_d_if->ifc.l1l2 = hisax_d_l1l2; - skb_queue_head_init(&hisax_d_if->erq); - clear_bit(0, &hisax_d_if->ph_state); - - return 0; -} - -void hisax_unregister(struct hisax_d_if *hisax_d_if) -{ - cards[hisax_d_if->cs->cardnr].typ = 0; - HiSax_closecard(hisax_d_if->cs->cardnr); - skb_queue_purge(&hisax_d_if->erq); -} - -#include "isdnl1.h" - -static void hisax_sched_event(struct IsdnCardState *cs, int event) -{ - test_and_set_bit(event, &cs->event); - schedule_work(&cs->tqueue); -} - -static void hisax_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - struct PStack *st; - int pr; - - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(E_RCVBUFREADY, &cs->event)) - EChannel_proc_rcv(cs->hw.hisax_d_if); - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - if (test_bit(0, &cs->hw.hisax_d_if->ph_state)) - pr = PH_ACTIVATE | INDICATION; - else - pr = PH_DEACTIVATE | INDICATION; - for (st = cs->stlist; st; st = st->next) - st->l1.l1l2(st, pr, NULL); - - } -} - -static void hisax_b_sched_event(struct BCState *bcs, int event) -{ - test_and_set_bit(event, &bcs->event); - schedule_work(&bcs->tqueue); -} - -static inline void D_L2L1(struct hisax_d_if *d_if, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) d_if; - ifc->l2l1(ifc, pr, arg); -} - -static inline void B_L2L1(struct hisax_b_if *b_if, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) b_if; - ifc->l2l1(ifc, pr, arg); -} - -static void hisax_d_l1l2(struct hisax_if *ifc, int pr, void *arg) -{ - struct hisax_d_if *d_if = (struct hisax_d_if *) ifc; - struct IsdnCardState *cs = d_if->cs; - struct PStack *st; - struct sk_buff *skb; - - switch (pr) { - case PH_ACTIVATE | INDICATION: - set_bit(0, &d_if->ph_state); - hisax_sched_event(cs, D_L1STATECHANGE); - break; - case PH_DEACTIVATE | INDICATION: - clear_bit(0, &d_if->ph_state); - hisax_sched_event(cs, D_L1STATECHANGE); - break; - case PH_DATA | INDICATION: - skb_queue_tail(&cs->rq, arg); - hisax_sched_event(cs, D_RCVBUFREADY); - break; - case PH_DATA | CONFIRM: - skb = skb_dequeue(&cs->sq); - if (skb) { - D_L2L1(d_if, PH_DATA | REQUEST, skb); - break; - } - clear_bit(FLG_L1_DBUSY, &cs->HW_Flags); - for (st = cs->stlist; st; st = st->next) { - if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) { - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - break; - } - } - break; - case PH_DATA_E | INDICATION: - skb_queue_tail(&d_if->erq, arg); - hisax_sched_event(cs, E_RCVBUFREADY); - break; - default: - printk("pr %#x\n", pr); - break; - } -} - -static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg) -{ - struct hisax_b_if *b_if = (struct hisax_b_if *) ifc; - struct BCState *bcs = b_if->bcs; - struct PStack *st = bcs->st; - struct sk_buff *skb; - - // FIXME use isdnl1? - switch (pr) { - case PH_ACTIVATE | INDICATION: - st->l1.l1l2(st, pr, NULL); - break; - case PH_DEACTIVATE | INDICATION: - st->l1.l1l2(st, pr, NULL); - clear_bit(BC_FLG_BUSY, &bcs->Flag); - skb_queue_purge(&bcs->squeue); - bcs->hw.b_if = NULL; - break; - case PH_DATA | INDICATION: - skb_queue_tail(&bcs->rqueue, arg); - hisax_b_sched_event(bcs, B_RCVBUFREADY); - break; - case PH_DATA | CONFIRM: - bcs->tx_cnt -= (long)arg; - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += (long)arg; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - skb = skb_dequeue(&bcs->squeue); - if (skb) { - B_L2L1(b_if, PH_DATA | REQUEST, skb); - break; - } - clear_bit(BC_FLG_BUSY, &bcs->Flag); - if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) { - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } - break; - default: - printk("hisax_b_l1l2 pr %#x\n", pr); - break; - } -} - -static void hisax_d_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = st->l1.hardware; - struct hisax_d_if *hisax_d_if = cs->hw.hisax_d_if; - struct sk_buff *skb = arg; - - switch (pr) { - case PH_DATA | REQUEST: - case PH_PULL | INDICATION: - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - Logl2Frame(cs, skb, "PH_DATA_REQ", 0); - // FIXME lock? - if (!test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - D_L2L1(hisax_d_if, PH_DATA | REQUEST, skb); - else - skb_queue_tail(&cs->sq, skb); - break; - case PH_PULL | REQUEST: - if (!test_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - else - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - default: - D_L2L1(hisax_d_if, pr, arg); - break; - } -} - -static int hisax_cardmsg(struct IsdnCardState *cs, int mt, void *arg) -{ - return 0; -} - -static void hisax_b_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct hisax_b_if *b_if = bcs->hw.b_if; - - switch (pr) { - case PH_ACTIVATE | REQUEST: - B_L2L1(b_if, pr, (void *)(unsigned long)st->l1.mode); - break; - case PH_DATA | REQUEST: - case PH_PULL | INDICATION: - // FIXME lock? - if (!test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) { - B_L2L1(b_if, PH_DATA | REQUEST, arg); - } else { - skb_queue_tail(&bcs->squeue, arg); - } - break; - case PH_PULL | REQUEST: - if (!test_bit(BC_FLG_BUSY, &bcs->Flag)) - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - else - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case PH_DEACTIVATE | REQUEST: - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - skb_queue_purge(&bcs->squeue); - /* fall through */ - default: - B_L2L1(b_if, pr, arg); - break; - } -} - -static int hisax_bc_setstack(struct PStack *st, struct BCState *bcs) -{ - struct IsdnCardState *cs = st->l1.hardware; - struct hisax_d_if *hisax_d_if = cs->hw.hisax_d_if; - - bcs->channel = st->l1.bc; - - bcs->hw.b_if = hisax_d_if->b_if[st->l1.bc]; - hisax_d_if->b_if[st->l1.bc]->bcs = bcs; - - st->l1.bcs = bcs; - st->l2.l2l1 = hisax_b_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - return 0; -} - -static void hisax_bc_close(struct BCState *bcs) -{ - struct hisax_b_if *b_if = bcs->hw.b_if; - - if (b_if) - B_L2L1(b_if, PH_DEACTIVATE | REQUEST, NULL); -} - -static void EChannel_proc_rcv(struct hisax_d_if *d_if) -{ - struct IsdnCardState *cs = d_if->cs; - u_char *ptr; - struct sk_buff *skb; - - while ((skb = skb_dequeue(&d_if->erq)) != NULL) { - if (cs->debug & DEB_DLOG_HEX) { - ptr = cs->dlog; - if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) { - *ptr++ = 'E'; - *ptr++ = 'C'; - *ptr++ = 'H'; - *ptr++ = 'O'; - *ptr++ = ':'; - ptr += QuickHex(ptr, skb->data, skb->len); - ptr--; - *ptr++ = '\n'; - *ptr = 0; - HiSax_putstatus(cs, NULL, cs->dlog); - } else - HiSax_putstatus(cs, "LogEcho: ", - "warning Frame too big (%d)", - skb->len); - } - dev_kfree_skb_any(skb); - } -} - -#ifdef CONFIG_PCI -#include <linux/pci.h> - -static const struct pci_device_id hisax_pci_tbl[] __used = { -#ifdef CONFIG_HISAX_FRITZPCI - {PCI_VDEVICE(AVM, PCI_DEVICE_ID_AVM_A1) }, -#endif -#ifdef CONFIG_HISAX_DIEHLDIVA - {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20) }, - {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA20_U) }, - {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA201) }, -/*##########################################################################*/ - {PCI_VDEVICE(EICON, PCI_DEVICE_ID_EICON_DIVA202) }, -/*##########################################################################*/ -#endif -#ifdef CONFIG_HISAX_ELSA - {PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_MICROLINK) }, - {PCI_VDEVICE(ELSA, PCI_DEVICE_ID_ELSA_QS3000) }, -#endif -#ifdef CONFIG_HISAX_GAZEL - {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R685) }, - {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_R753) }, - {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_DJINN_ITOO) }, - {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_OLITEC) }, -#endif -#ifdef CONFIG_HISAX_SCT_QUADRO - {PCI_VDEVICE(PLX, PCI_DEVICE_ID_PLX_9050) }, -#endif -#ifdef CONFIG_HISAX_NICCY - {PCI_VDEVICE(SATSAGEM, PCI_DEVICE_ID_SATSAGEM_NICCY) }, -#endif -#ifdef CONFIG_HISAX_SEDLBAUER - {PCI_VDEVICE(TIGERJET, PCI_DEVICE_ID_TIGERJET_100) }, -#endif -#if defined(CONFIG_HISAX_NETJET) || defined(CONFIG_HISAX_NETJET_U) - {PCI_VDEVICE(TIGERJET, PCI_DEVICE_ID_TIGERJET_300) }, -#endif -#if defined(CONFIG_HISAX_TELESPCI) || defined(CONFIG_HISAX_SCT_QUADRO) - {PCI_VDEVICE(ZORAN, PCI_DEVICE_ID_ZORAN_36120) }, -#endif -#ifdef CONFIG_HISAX_W6692 - {PCI_VDEVICE(DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH) }, - {PCI_VDEVICE(WINBOND2, PCI_DEVICE_ID_WINBOND2_6692) }, -#endif -#ifdef CONFIG_HISAX_HFC_PCI - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_2BD0) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B000) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B006) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B007) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B008) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B009) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00A) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00B) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B00C) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B100) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B700) }, - {PCI_VDEVICE(CCD, PCI_DEVICE_ID_CCD_B701) }, - {PCI_VDEVICE(ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1) }, - {PCI_VDEVICE(ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675) }, - {PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT) }, - {PCI_VDEVICE(BERKOM, PCI_DEVICE_ID_BERKOM_A1T) }, - {PCI_VDEVICE(ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575) }, - {PCI_VDEVICE(ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0) }, - {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E) }, - {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_E) }, - {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A) }, - {PCI_VDEVICE(DIGI, PCI_DEVICE_ID_DIGI_DF_M_A) }, -#endif - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(pci, hisax_pci_tbl); -#endif /* CONFIG_PCI */ - -module_init(HiSax_init); -module_exit(HiSax_exit); - -EXPORT_SYMBOL(FsmNew); -EXPORT_SYMBOL(FsmFree); -EXPORT_SYMBOL(FsmEvent); -EXPORT_SYMBOL(FsmChangeState); -EXPORT_SYMBOL(FsmInitTimer); -EXPORT_SYMBOL(FsmDelTimer); -EXPORT_SYMBOL(FsmRestartTimer); diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c deleted file mode 100644 index d23df7a7784d..000000000000 --- a/drivers/isdn/hisax/diva.c +++ /dev/null @@ -1,1282 +0,0 @@ -/* $Id: diva.c,v 1.33.2.6 2004/02/11 13:21:33 keil Exp $ - * - * low level stuff for Eicon.Diehl Diva Family ISDN cards - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.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 - * - * Thanks to Eicon Technology for documents and information - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "ipac.h" -#include "ipacx.h" -#include "isdnl1.h" -#include <linux/pci.h> -#include <linux/isapnp.h> - -static const char *Diva_revision = "$Revision: 1.33.2.6 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define DIVA_HSCX_DATA 0 -#define DIVA_HSCX_ADR 4 -#define DIVA_ISA_ISAC_DATA 2 -#define DIVA_ISA_ISAC_ADR 6 -#define DIVA_ISA_CTRL 7 -#define DIVA_IPAC_ADR 0 -#define DIVA_IPAC_DATA 1 - -#define DIVA_PCI_ISAC_DATA 8 -#define DIVA_PCI_ISAC_ADR 0xc -#define DIVA_PCI_CTRL 0x10 - -/* SUB Types */ -#define DIVA_ISA 1 -#define DIVA_PCI 2 -#define DIVA_IPAC_ISA 3 -#define DIVA_IPAC_PCI 4 -#define DIVA_IPACX_PCI 5 - -/* CTRL (Read) */ -#define DIVA_IRQ_STAT 0x01 -#define DIVA_EEPROM_SDA 0x02 - -/* CTRL (Write) */ -#define DIVA_IRQ_REQ 0x01 -#define DIVA_RESET 0x08 -#define DIVA_EEPROM_CLK 0x40 -#define DIVA_PCI_LED_A 0x10 -#define DIVA_PCI_LED_B 0x20 -#define DIVA_ISA_LED_A 0x20 -#define DIVA_ISA_LED_B 0x40 -#define DIVA_IRQ_CLR 0x80 - -/* Siemens PITA */ -#define PITA_MISC_REG 0x1c -#ifdef __BIG_ENDIAN -#define PITA_PARA_SOFTRESET 0x00000001 -#define PITA_SER_SOFTRESET 0x00000002 -#define PITA_PARA_MPX_MODE 0x00000004 -#define PITA_INT0_ENABLE 0x00000200 -#else -#define PITA_PARA_SOFTRESET 0x01000000 -#define PITA_SER_SOFTRESET 0x02000000 -#define PITA_PARA_MPX_MODE 0x04000000 -#define PITA_INT0_ENABLE 0x00020000 -#endif -#define PITA_INT0_STATUS 0x02 - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -static inline u_char -memreadreg(unsigned long adr, u_char off) -{ - return (*((unsigned char *) - (((unsigned int *)adr) + off))); -} - -static inline void -memwritereg(unsigned long adr, u_char off, u_char data) -{ - register u_char *p; - - p = (unsigned char *)(((unsigned int *)adr) + off); - *p = data; -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0, data, size); -} - -static u_char -ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset + 0x80)); -} - -static void -WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, offset | 0x80, value); -} - -static void -ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size); -} - -static void -WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.diva.isac_adr, cs->hw.diva.isac, 0x80, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.diva.hscx_adr, - cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.diva.hscx_adr, - cs->hw.diva.hscx, offset + (hscx ? 0x40 : 0), value); -} - -static u_char -MemReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) -{ - return (memreadreg(cs->hw.diva.cfg_reg, offset + 0x80)); -} - -static void -MemWriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - memwritereg(cs->hw.diva.cfg_reg, offset | 0x80, value); -} - -static void -MemReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - while (size--) - *data++ = memreadreg(cs->hw.diva.cfg_reg, 0x80); -} - -static void -MemWriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - while (size--) - memwritereg(cs->hw.diva.cfg_reg, 0x80, *data++); -} - -static u_char -MemReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (memreadreg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0))); -} - -static void -MemWriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value); -} - -/* IO-Functions for IPACX type cards */ -static u_char -MemReadISAC_IPACX(struct IsdnCardState *cs, u_char offset) -{ - return (memreadreg(cs->hw.diva.cfg_reg, offset)); -} - -static void -MemWriteISAC_IPACX(struct IsdnCardState *cs, u_char offset, u_char value) -{ - memwritereg(cs->hw.diva.cfg_reg, offset, value); -} - -static void -MemReadISACfifo_IPACX(struct IsdnCardState *cs, u_char *data, int size) -{ - while (size--) - *data++ = memreadreg(cs->hw.diva.cfg_reg, 0); -} - -static void -MemWriteISACfifo_IPACX(struct IsdnCardState *cs, u_char *data, int size) -{ - while (size--) - memwritereg(cs->hw.diva.cfg_reg, 0, *data++); -} - -static u_char -MemReadHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (memreadreg(cs->hw.diva.cfg_reg, offset + - (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1))); -} - -static void -MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - memwritereg(cs->hw.diva.cfg_reg, offset + - (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1), value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.diva.hscx_adr, \ - cs->hw.diva.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.diva.hscx_adr, \ - cs->hw.diva.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.diva.hscx_adr, \ - cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.diva.hscx_adr, \ - cs->hw.diva.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -diva_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - u_long flags; - int cnt = 5; - - spin_lock_irqsave(&cs->lock, flags); - while (((sval = bytein(cs->hw.diva.ctrl)) & DIVA_IRQ_REQ) && cnt) { - val = readreg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_ISTA + 0x40); - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA); - if (val) - isac_interrupt(cs, val); - cnt--; - } - if (!cnt) - printk(KERN_WARNING "Diva: IRQ LOOP\n"); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_MASK, 0x0); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.diva.hscx_adr, cs->hw.diva.hscx, HSCX_MASK + 0x40, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -diva_irq_ipac_isa(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val; - u_long flags; - int icnt = 5; - - spin_lock_irqsave(&cs->lock, flags); - ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); -Start_IPACISA: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - hscx_int_main(cs, val); - } - if (ista & 0x20) { - val = 0xfe & readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, ISAC_ISTA + 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPACISA; - } - if (!icnt) - printk(KERN_WARNING "DIVA IPAC IRQ LOOP\n"); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xFF); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static inline void -MemwaitforCEC(struct IsdnCardState *cs, int hscx) -{ - int to = 50; - - while ((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: waitforCEC timeout\n"); -} - - -static inline void -MemwaitforXFW(struct IsdnCardState *cs, int hscx) -{ - int to = 50; - - while (((MemReadHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: waitforXFW timeout\n"); -} - -static inline void -MemWriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data) -{ - MemwaitforCEC(cs, hscx); - MemWriteHSCX(cs, hscx, HSCX_CMDR, data); -} - -static void -Memhscx_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct IsdnCardState *cs = bcs->cs; - int cnt; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hscx_empty_fifo"); - - if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hscx_empty_fifo: incoming packet too large"); - MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); - bcs->hw.hscx.rcvidx = 0; - return; - } - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - cnt = count; - while (cnt--) - *ptr++ = memreadreg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0); - MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - bcs->hw.hscx.rcvidx += count; - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "hscx_empty_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -Memhscx_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int more, count, cnt; - int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32; - u_char *ptr, *p; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hscx_fill_fifo"); - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->tx_skb->len > fifo_size) { - more = !0; - count = fifo_size; - } else - count = bcs->tx_skb->len; - cnt = count; - MemwaitforXFW(cs, bcs->hw.hscx.hscx); - p = ptr = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.hscx.count += count; - while (cnt--) - memwritereg(cs->hw.diva.cfg_reg, bcs->hw.hscx.hscx ? 0x40 : 0, - *p++); - MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "hscx_fill_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -Memhscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) -{ - u_char r; - struct BCState *bcs = cs->bcs + hscx; - struct sk_buff *skb; - int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32; - int count; - - if (!test_bit(BC_FLG_INIT, &bcs->Flag)) - return; - - if (val & 0x80) { /* RME */ - r = MemReadHSCX(cs, hscx, HSCX_RSTA); - if ((r & 0xf0) != 0xa0) { - if (!(r & 0x80)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX invalid frame"); - if ((r & 0x40) && bcs->mode) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX RDO mode=%d", - bcs->mode); - if (!(r & 0x20)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX CRC error"); - MemWriteHSCXCMDR(cs, hscx, 0x80); - } else { - count = MemReadHSCX(cs, hscx, HSCX_RBCL) & ( - test_bit(HW_IPAC, &cs->HW_Flags) ? 0x3f : 0x1f); - if (count == 0) - count = fifo_size; - Memhscx_empty_fifo(bcs, count); - if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "HX Frame %d", count); - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "HSCX: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - count); - skb_queue_tail(&bcs->rqueue, skb); - } - } - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - if (val & 0x40) { /* RPF */ - Memhscx_empty_fifo(bcs, fifo_size); - if (bcs->mode == L1_MODE_TRANS) { - /* receive audio data */ - if (!(skb = dev_alloc_skb(fifo_size))) - printk(KERN_WARNING "HiSax: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - fifo_size); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - } - if (val & 0x10) { /* XPR */ - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - Memhscx_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hscx.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hscx.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - Memhscx_fill_fifo(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -} - -static inline void -Memhscx_int_main(struct IsdnCardState *cs, u_char val) -{ - - u_char exval; - struct BCState *bcs; - - if (val & 0x01) { // EXB - bcs = cs->bcs + 1; - exval = MemReadHSCX(cs, 1, HSCX_EXIR); - if (exval & 0x40) { - if (bcs->mode == 1) - Memhscx_fill_fifo(bcs); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX B EXIR %x Lost TX", exval); - } - } else if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX B EXIR %x", exval); - } - if (val & 0xf8) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX B interrupt %x", val); - Memhscx_interrupt(cs, val, 1); - } - if (val & 0x02) { // EXA - bcs = cs->bcs; - exval = MemReadHSCX(cs, 0, HSCX_EXIR); - if (exval & 0x40) { - if (bcs->mode == L1_MODE_TRANS) - Memhscx_fill_fifo(bcs); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - MemWriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX A EXIR %x Lost TX", exval); - } - } else if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX A EXIR %x", exval); - } - if (val & 0x04) { // ICA - exval = MemReadHSCX(cs, 0, HSCX_ISTA); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX A interrupt %x", exval); - Memhscx_interrupt(cs, exval, 0); - } -} - -static irqreturn_t -diva_irq_ipac_pci(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val; - int icnt = 5; - u_char *cfg; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - cfg = (u_char *) cs->hw.diva.pci_cfg; - val = *cfg; - if (!(val & PITA_INT0_STATUS)) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; /* other shared IRQ */ - } - *cfg = PITA_INT0_STATUS; /* Reset pending INT0 */ - ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA); -Start_IPACPCI: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = memreadreg(cs->hw.diva.cfg_reg, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - Memhscx_int_main(cs, val); - } - if (ista & 0x20) { - val = 0xfe & memreadreg(cs->hw.diva.cfg_reg, ISAC_ISTA + 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = memreadreg(cs->hw.diva.cfg_reg, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPACPCI; - } - if (!icnt) - printk(KERN_WARNING "DIVA IPAC PCI IRQ LOOP\n"); - memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xFF); - memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -diva_irq_ipacx_pci(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_char *cfg; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - cfg = (u_char *) cs->hw.diva.pci_cfg; - val = *cfg; - if (!(val & PITA_INT0_STATUS)) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; // other shared IRQ - } - interrupt_ipacx(cs); // handler for chip - *cfg = PITA_INT0_STATUS; // Reset PLX interrupt - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_diva(struct IsdnCardState *cs) -{ - int bytecnt; - - if ((cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI)) { - u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg; - - *cfg = 0; /* disable INT0/1 */ - *cfg = 2; /* reset pending INT0 */ - if (cs->hw.diva.cfg_reg) - iounmap((void *)cs->hw.diva.cfg_reg); - if (cs->hw.diva.pci_cfg) - iounmap((void *)cs->hw.diva.pci_cfg); - return; - } else if (cs->subtyp != DIVA_IPAC_ISA) { - del_timer(&cs->hw.diva.tl); - if (cs->hw.diva.cfg_reg) - byteout(cs->hw.diva.ctrl, 0); /* LED off, Reset */ - } - if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) - bytecnt = 8; - else - bytecnt = 32; - if (cs->hw.diva.cfg_reg) { - release_region(cs->hw.diva.cfg_reg, bytecnt); - } -} - -static void -iounmap_diva(struct IsdnCardState *cs) -{ - if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_IPACX_PCI)) { - if (cs->hw.diva.cfg_reg) { - iounmap((void *)cs->hw.diva.cfg_reg); - cs->hw.diva.cfg_reg = 0; - } - if (cs->hw.diva.pci_cfg) { - iounmap((void *)cs->hw.diva.pci_cfg); - cs->hw.diva.pci_cfg = 0; - } - } - - return; -} - -static void -reset_diva(struct IsdnCardState *cs) -{ - if (cs->subtyp == DIVA_IPAC_ISA) { - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x20); - mdelay(10); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_POTA2, 0x00); - mdelay(10); - writereg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_MASK, 0xc0); - } else if (cs->subtyp == DIVA_IPAC_PCI) { - unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg + - PITA_MISC_REG); - *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE; - mdelay(10); - *ireg = PITA_PARA_MPX_MODE; - mdelay(10); - memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0); - } else if (cs->subtyp == DIVA_IPACX_PCI) { - unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg + - PITA_MISC_REG); - *ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE; - mdelay(10); - *ireg = PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET; - mdelay(10); - MemWriteISAC_IPACX(cs, IPACX_MASK, 0xff); // Interrupts off - } else { /* DIVA 2.0 */ - cs->hw.diva.ctrl_reg = 0; /* Reset On */ - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - mdelay(10); - cs->hw.diva.ctrl_reg |= DIVA_RESET; /* Reset Off */ - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - mdelay(10); - if (cs->subtyp == DIVA_ISA) - cs->hw.diva.ctrl_reg |= DIVA_ISA_LED_A; - else { - /* Workaround PCI9060 */ - byteout(cs->hw.diva.pci_cfg + 0x69, 9); - cs->hw.diva.ctrl_reg |= DIVA_PCI_LED_A; - } - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - } -} - -#define DIVA_ASSIGN 1 - -static void -diva_led_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.diva.tl); - int blink = 0; - - if ((cs->subtyp == DIVA_IPAC_ISA) || - (cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI)) - return; - del_timer(&cs->hw.diva.tl); - if (cs->hw.diva.status & DIVA_ASSIGN) - cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ? - DIVA_ISA_LED_A : DIVA_PCI_LED_A; - else { - cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ? - DIVA_ISA_LED_A : DIVA_PCI_LED_A; - blink = 250; - } - if (cs->hw.diva.status & 0xf000) - cs->hw.diva.ctrl_reg |= (DIVA_ISA == cs->subtyp) ? - DIVA_ISA_LED_B : DIVA_PCI_LED_B; - else if (cs->hw.diva.status & 0x0f00) { - cs->hw.diva.ctrl_reg ^= (DIVA_ISA == cs->subtyp) ? - DIVA_ISA_LED_B : DIVA_PCI_LED_B; - blink = 500; - } else - cs->hw.diva.ctrl_reg &= ~((DIVA_ISA == cs->subtyp) ? - DIVA_ISA_LED_B : DIVA_PCI_LED_B); - - byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg); - if (blink) { - cs->hw.diva.tl.expires = jiffies + ((blink * HZ) / 1000); - add_timer(&cs->hw.diva.tl); - } -} - -static int -Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_int *ireg; - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_diva(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_diva(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - reset_diva(cs); - if (cs->subtyp == DIVA_IPACX_PCI) { - ireg = (unsigned int *)cs->hw.diva.pci_cfg; - *ireg = PITA_INT0_ENABLE; - init_ipacx(cs, 3); // init chip and enable interrupts - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - } - if (cs->subtyp == DIVA_IPAC_PCI) { - ireg = (unsigned int *)cs->hw.diva.pci_cfg; - *ireg = PITA_INT0_ENABLE; - } - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - case (MDL_REMOVE | REQUEST): - cs->hw.diva.status = 0; - break; - case (MDL_ASSIGN | REQUEST): - cs->hw.diva.status |= DIVA_ASSIGN; - break; - case MDL_INFO_SETUP: - if ((long)arg) - cs->hw.diva.status |= 0x0200; - else - cs->hw.diva.status |= 0x0100; - break; - case MDL_INFO_CONN: - if ((long)arg) - cs->hw.diva.status |= 0x2000; - else - cs->hw.diva.status |= 0x1000; - break; - case MDL_INFO_REL: - if ((long)arg) { - cs->hw.diva.status &= ~0x2000; - cs->hw.diva.status &= ~0x0200; - } else { - cs->hw.diva.status &= ~0x1000; - cs->hw.diva.status &= ~0x0100; - } - break; - } - if ((cs->subtyp != DIVA_IPAC_ISA) && - (cs->subtyp != DIVA_IPAC_PCI) && - (cs->subtyp != DIVA_IPACX_PCI)) { - spin_lock_irqsave(&cs->lock, flags); - diva_led_handler(&cs->hw.diva.tl); - spin_unlock_irqrestore(&cs->lock, flags); - } - return (0); -} - -static int setup_diva_common(struct IsdnCardState *cs) -{ - int bytecnt; - u_char val; - - if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA)) - bytecnt = 8; - else - bytecnt = 32; - - printk(KERN_INFO - "Diva: %s card configured at %#lx IRQ %d\n", - (cs->subtyp == DIVA_PCI) ? "PCI" : - (cs->subtyp == DIVA_ISA) ? "ISA" : - (cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" : - (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI", - cs->hw.diva.cfg_reg, cs->irq); - if ((cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI) || - (cs->subtyp == DIVA_PCI)) - printk(KERN_INFO "Diva: %s space at %#lx\n", - (cs->subtyp == DIVA_PCI) ? "PCI" : - (cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI", - cs->hw.diva.pci_cfg); - if ((cs->subtyp != DIVA_IPAC_PCI) && - (cs->subtyp != DIVA_IPACX_PCI)) { - if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) { - printk(KERN_WARNING - "HiSax: %s config port %lx-%lx already in use\n", - "diva", - cs->hw.diva.cfg_reg, - cs->hw.diva.cfg_reg + bytecnt); - iounmap_diva(cs); - return (0); - } - } - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Diva_card_msg; - setup_isac(cs); - if (cs->subtyp == DIVA_IPAC_ISA) { - cs->readisac = &ReadISAC_IPAC; - cs->writeisac = &WriteISAC_IPAC; - cs->readisacfifo = &ReadISACfifo_IPAC; - cs->writeisacfifo = &WriteISACfifo_IPAC; - cs->irq_func = &diva_irq_ipac_isa; - val = readreg(cs->hw.diva.isac_adr, cs->hw.diva.isac, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - } else if (cs->subtyp == DIVA_IPAC_PCI) { - cs->readisac = &MemReadISAC_IPAC; - cs->writeisac = &MemWriteISAC_IPAC; - cs->readisacfifo = &MemReadISACfifo_IPAC; - cs->writeisacfifo = &MemWriteISACfifo_IPAC; - cs->BC_Read_Reg = &MemReadHSCX; - cs->BC_Write_Reg = &MemWriteHSCX; - cs->BC_Send_Data = &Memhscx_fill_fifo; - cs->irq_func = &diva_irq_ipac_pci; - val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - } else if (cs->subtyp == DIVA_IPACX_PCI) { - cs->readisac = &MemReadISAC_IPACX; - cs->writeisac = &MemWriteISAC_IPACX; - cs->readisacfifo = &MemReadISACfifo_IPACX; - cs->writeisacfifo = &MemWriteISACfifo_IPACX; - cs->BC_Read_Reg = &MemReadHSCX_IPACX; - cs->BC_Write_Reg = &MemWriteHSCX_IPACX; - cs->BC_Send_Data = NULL; // function located in ipacx module - cs->irq_func = &diva_irq_ipacx_pci; - printk(KERN_INFO "Diva: IPACX Design Id: %x\n", - MemReadISAC_IPACX(cs, IPACX_ID) & 0x3F); - } else { /* DIVA 2.0 */ - timer_setup(&cs->hw.diva.tl, diva_led_handler, 0); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->irq_func = &diva_interrupt; - ISACVersion(cs, "Diva:"); - if (HscxVersion(cs, "Diva:")) { - printk(KERN_WARNING - "Diva: wrong HSCX versions check IO address\n"); - release_io_diva(cs); - return (0); - } - } - return (1); -} - -#ifdef CONFIG_ISA - -static int setup_diva_isa(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - u_char val; - - if (!card->para[1]) - return (-1); /* card not found; continue search */ - - cs->hw.diva.ctrl_reg = 0; - cs->hw.diva.cfg_reg = card->para[1]; - val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR, - cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID); - printk(KERN_INFO "Diva: IPAC version %x\n", val); - if ((val == 1) || (val == 2)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR; - } - cs->irq = card->para[0]; - - return (1); /* card found */ -} - -#else /* if !CONFIG_ISA */ - -static int setup_diva_isa(struct IsdnCard *card) -{ - return (-1); /* card not found; continue search */ -} - -#endif /* CONFIG_ISA */ - -#ifdef __ISAPNP__ -static struct isapnp_device_id diva_ids[] = { - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), - (unsigned long) "Diva picola" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), - (unsigned long) "Diva 2.0" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), - ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), - (unsigned long) "Diva 2.01" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &diva_ids[0]; -static struct pnp_card *pnp_c = NULL; - -static int setup_diva_isapnp(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - struct pnp_dev *pnp_d; - - if (!isapnp_present()) - return (-1); /* card not found; continue search */ - - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - cs->hw.diva.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0xA1)) { - cs->subtyp = DIVA_IPAC_ISA; - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_IPAC_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_IPAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_IPAC_ADR; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = DIVA_ISA; - cs->hw.diva.ctrl = - card->para[1] + DIVA_ISA_CTRL; - cs->hw.diva.isac = - card->para[1] + DIVA_ISA_ISAC_DATA; - cs->hw.diva.hscx = - card->para[1] + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = - card->para[1] + DIVA_ISA_ISAC_ADR; - cs->hw.diva.hscx_adr = - card->para[1] + DIVA_HSCX_ADR; - } - return (1); /* card found */ - } else { - printk(KERN_ERR "Diva PnP: PnP error card found, no device\n"); - return (0); - } - } - ipid++; - pnp_c = NULL; - } - - return (-1); /* card not found; continue search */ -} - -#else /* if !ISAPNP */ - -static int setup_diva_isapnp(struct IsdnCard *card) -{ - return (-1); /* card not found; continue search */ -} - -#endif /* ISAPNP */ - -#ifdef CONFIG_PCI -static struct pci_dev *dev_diva = NULL; -static struct pci_dev *dev_diva_u = NULL; -static struct pci_dev *dev_diva201 = NULL; -static struct pci_dev *dev_diva202 = NULL; - -static int setup_diva_pci(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - - cs->subtyp = 0; - if ((dev_diva = hisax_find_pci_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) { - if (pci_enable_device(dev_diva)) - return (0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2); - } else if ((dev_diva_u = hisax_find_pci_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) { - if (pci_enable_device(dev_diva_u)) - return (0); - cs->subtyp = DIVA_PCI; - cs->irq = dev_diva_u->irq; - cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2); - } else if ((dev_diva201 = hisax_find_pci_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) { - if (pci_enable_device(dev_diva201)) - return (0); - cs->subtyp = DIVA_IPAC_PCI; - cs->irq = dev_diva201->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096); - } else if ((dev_diva202 = hisax_find_pci_device(PCI_VENDOR_ID_EICON, - PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) { - if (pci_enable_device(dev_diva202)) - return (0); - cs->subtyp = DIVA_IPACX_PCI; - cs->irq = dev_diva202->irq; - cs->hw.diva.pci_cfg = - (ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096); - cs->hw.diva.cfg_reg = - (ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096); - } else { - return (-1); /* card not found; continue search */ - } - - if (!cs->irq) { - printk(KERN_WARNING "Diva: No IRQ for PCI card found\n"); - iounmap_diva(cs); - return (0); - } - - if (!cs->hw.diva.cfg_reg) { - printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n"); - iounmap_diva(cs); - return (0); - } - cs->irq_flags |= IRQF_SHARED; - - if ((cs->subtyp == DIVA_IPAC_PCI) || - (cs->subtyp == DIVA_IPACX_PCI)) { - cs->hw.diva.ctrl = 0; - cs->hw.diva.isac = 0; - cs->hw.diva.hscx = 0; - cs->hw.diva.isac_adr = 0; - cs->hw.diva.hscx_adr = 0; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL; - cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA; - cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA; - cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR; - cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR; - } - - return (1); /* card found */ -} - -#else /* if !CONFIG_PCI */ - -static int setup_diva_pci(struct IsdnCard *card) -{ - return (-1); /* card not found; continue search */ -} - -#endif /* CONFIG_PCI */ - -int setup_diva(struct IsdnCard *card) -{ - int rc, have_card = 0; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, Diva_revision); - printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_DIEHLDIVA) - return (0); - cs->hw.diva.status = 0; - - rc = setup_diva_isa(card); - if (!rc) - return rc; - if (rc > 0) { - have_card = 1; - goto ready; - } - - rc = setup_diva_isapnp(card); - if (!rc) - return rc; - if (rc > 0) { - have_card = 1; - goto ready; - } - - rc = setup_diva_pci(card); - if (!rc) - return rc; - if (rc > 0) - have_card = 1; - -ready: - if (!have_card) { - printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n"); - return (0); - } - - return setup_diva_common(card->cs); -} diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c deleted file mode 100644 index 0754c0743790..000000000000 --- a/drivers/isdn/hisax/elsa.c +++ /dev/null @@ -1,1245 +0,0 @@ -/* $Id: elsa.c,v 2.32.2.4 2004/01/24 20:47:21 keil Exp $ - * - * low level stuff for Elsa isdn cards - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.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 - * - * Thanks to Elsa GmbH for documents and information - * - * Klaus Lichtenwalder (Klaus.Lichtenwalder@WebForum.DE) - * for ELSA PCMCIA support - * - */ - -#include <linux/init.h> -#include <linux/slab.h> -#include "hisax.h" -#include "arcofi.h" -#include "isac.h" -#include "ipac.h" -#include "hscx.h" -#include "isdnl1.h" -#include <linux/pci.h> -#include <linux/isapnp.h> -#include <linux/serial.h> -#include <linux/serial_reg.h> - -static const char *Elsa_revision = "$Revision: 2.32.2.4 $"; -static const char *Elsa_Types[] = -{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", - "PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI", - "PCMCIA-IPAC" }; - -static const char *ITACVer[] = -{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2", - "B1", "A1"}; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define ELSA_ISAC 0 -#define ELSA_ISAC_PCM 1 -#define ELSA_ITAC 1 -#define ELSA_HSCX 2 -#define ELSA_ALE 3 -#define ELSA_ALE_PCM 4 -#define ELSA_CONTROL 4 -#define ELSA_CONFIG 5 -#define ELSA_START_TIMER 6 -#define ELSA_TRIG_IRQ 7 - -#define ELSA_PC 1 -#define ELSA_PCC8 2 -#define ELSA_PCC16 3 -#define ELSA_PCF 4 -#define ELSA_PCFPRO 5 -#define ELSA_PCMCIA 6 -#define ELSA_QS1000 7 -#define ELSA_QS3000 8 -#define ELSA_QS1000PCI 9 -#define ELSA_QS3000PCI 10 -#define ELSA_PCMCIA_IPAC 11 - -/* PCI stuff */ -#define ELSA_PCI_IRQ_MASK 0x04 - -/* ITAC Registeradressen (only Microlink PC) */ -#define ITAC_SYS 0x34 -#define ITAC_ISEN 0x48 -#define ITAC_RFIE 0x4A -#define ITAC_XFIE 0x4C -#define ITAC_SCIE 0x4E -#define ITAC_STIE 0x46 - -/*** *** - *** Makros als Befehle fuer die Kartenregister *** - *** (mehrere Befehle werden durch Bit-Oderung kombiniert) *** - *** ***/ - -/* Config-Register (Read) */ -#define ELIRQF_TIMER_RUN 0x02 /* Bit 1 des Config-Reg */ -#define ELIRQF_TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */ -#define ELSA_IRQ_IDX 0x38 /* Bit 3,4,5 des Config-Reg */ -#define ELSA_IRQ_IDX_PCC8 0x30 /* Bit 4,5 des Config-Reg */ -#define ELSA_IRQ_IDX_PC 0x0c /* Bit 2,3 des Config-Reg */ - -/* Control-Register (Write) */ -#define ELSA_LINE_LED 0x02 /* Bit 1 Gelbe LED */ -#define ELSA_STAT_LED 0x08 /* Bit 3 Gruene LED */ -#define ELSA_ISDN_RESET 0x20 /* Bit 5 Reset-Leitung */ -#define ELSA_ENA_TIMER_INT 0x80 /* Bit 7 Freigabe Timer Interrupt */ - -/* ALE-Register (Read) */ -#define ELSA_HW_RELEASE 0x07 /* Bit 0-2 Hardwarerkennung */ -#define ELSA_S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */ - -/* Status Flags */ -#define ELIRQF_TIMER_AKTIV 1 -#define ELSA_BAD_PWR 2 -#define ELSA_ASSIGN 4 - -#define RS_ISR_PASS_LIMIT 256 -#define FLG_MODEM_ACTIVE 1 -/* IPAC AUX */ -#define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */ -#define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */ - -#if ARCOFI_USE -static struct arcofi_msg ARCOFI_XOP_F = -{NULL,0,2,{0xa1,0x3f,0,0,0,0,0,0,0,0}}; /* Normal OP */ -static struct arcofi_msg ARCOFI_XOP_1 = -{&ARCOFI_XOP_F,0,2,{0xa1,0x31,0,0,0,0,0,0,0,0}}; /* PWR UP */ -static struct arcofi_msg ARCOFI_SOP_F = -{&ARCOFI_XOP_1,0,10,{0xa1,0x1f,0x00,0x50,0x10,0x00,0x00,0x80,0x02,0x12}}; -static struct arcofi_msg ARCOFI_COP_9 = -{&ARCOFI_SOP_F,0,10,{0xa1,0x29,0x80,0xcb,0xe9,0x88,0x00,0xc8,0xd8,0x80}}; /* RX */ -static struct arcofi_msg ARCOFI_COP_8 = -{&ARCOFI_COP_9,0,10,{0xa1,0x28,0x49,0x31,0x8,0x13,0x6e,0x88,0x2a,0x61}}; /* TX */ -static struct arcofi_msg ARCOFI_COP_7 = -{&ARCOFI_COP_8,0,4,{0xa1,0x27,0x80,0x80,0,0,0,0,0,0}}; /* GZ */ -static struct arcofi_msg ARCOFI_COP_6 = -{&ARCOFI_COP_7,0,6,{0xa1,0x26,0,0,0x82,0x7c,0,0,0,0}}; /* GRL GRH */ -static struct arcofi_msg ARCOFI_COP_5 = -{&ARCOFI_COP_6,0,4,{0xa1,0x25,0xbb,0x4a,0,0,0,0,0,0}}; /* GTX */ -static struct arcofi_msg ARCOFI_VERSION = -{NULL,1,2,{0xa0,0,0,0,0,0,0,0,0,0}}; -static struct arcofi_msg ARCOFI_XOP_0 = -{NULL,0,2,{0xa1,0x30,0,0,0,0,0,0,0,0}}; /* PWR Down */ - -static void set_arcofi(struct IsdnCardState *cs, int bc); - -#include "elsa_ser.c" -#endif /* ARCOFI_USE */ - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0, data, size); -} - -static u_char -ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset + 0x80)); -} - -static void -WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, offset | 0x80, value); -} - -static void -ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size); -} - -static void -WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.elsa.ale, cs->hw.elsa.isac, 0x80, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.elsa.ale, - cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.elsa.ale, - cs->hw.elsa.hscx, offset + (hscx ? 0x40 : 0), value); -} - -static inline u_char -readitac(struct IsdnCardState *cs, u_char off) -{ - register u_char ret; - - byteout(cs->hw.elsa.ale, off); - ret = bytein(cs->hw.elsa.itac); - return (ret); -} - -static inline void -writeitac(struct IsdnCardState *cs, u_char off, u_char data) -{ - byteout(cs->hw.elsa.ale, off); - byteout(cs->hw.elsa.itac, data); -} - -static inline int -TimerRun(struct IsdnCardState *cs) -{ - register u_char v; - - v = bytein(cs->hw.elsa.cfg); - if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000)) - return (0 == (v & ELIRQF_TIMER_RUN)); - else if (cs->subtyp == ELSA_PCC8) - return (v & ELIRQF_TIMER_RUN_PCC8); - return (v & ELIRQF_TIMER_RUN); -} -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.elsa.ale, \ - cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.elsa.ale, \ - cs->hw.elsa.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.elsa.ale, \ - cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.elsa.ale, \ - cs->hw.elsa.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -elsa_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_long flags; - u_char val; - int icnt = 5; - - if ((cs->typ == ISDN_CTYPE_ELSA_PCMCIA) && (*cs->busy_flag == 1)) { - /* The card tends to generate interrupts while being removed - causing us to just crash the kernel. bad. */ - printk(KERN_WARNING "Elsa: card not available!\n"); - return IRQ_NONE; - } - spin_lock_irqsave(&cs->lock, flags); -#if ARCOFI_USE - if (cs->hw.elsa.MFlag) { - val = serial_inp(cs, UART_IIR); - if (!(val & UART_IIR_NO_INT)) { - debugl1(cs, "IIR %02x", val); - rs_interrupt_elsa(cs); - } - } -#endif - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) { - hscx_int_main(cs, val); - } - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA); -Start_ISAC: - if (val) { - isac_interrupt(cs, val); - } - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); - if (val && icnt) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - icnt--; - goto Start_HSCX; - } - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA); - if (val && icnt) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - icnt--; - goto Start_ISAC; - } - if (!icnt) - printk(KERN_WARNING"ELSA IRQ LOOP\n"); - writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF); - if (cs->hw.elsa.status & ELIRQF_TIMER_AKTIV) { - if (!TimerRun(cs)) { - /* Timer Restart */ - byteout(cs->hw.elsa.timer, 0); - cs->hw.elsa.counter++; - } - } -#if ARCOFI_USE - if (cs->hw.elsa.MFlag) { - val = serial_inp(cs, UART_MCR); - val ^= 0x8; - serial_outp(cs, UART_MCR, val); - val = serial_inp(cs, UART_MCR); - val ^= 0x8; - serial_outp(cs, UART_MCR, val); - } -#endif - if (cs->hw.elsa.trig) - byteout(cs->hw.elsa.trig, 0x00); - writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0x0); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -elsa_interrupt_ipac(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_long flags; - u_char ista, val; - int icnt = 5; - - spin_lock_irqsave(&cs->lock, flags); - if (cs->subtyp == ELSA_QS1000PCI || cs->subtyp == ELSA_QS3000PCI) { - val = bytein(cs->hw.elsa.cfg + 0x4c); /* PCI IRQ */ - if (!(val & ELSA_PCI_IRQ_MASK)) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - } -#if ARCOFI_USE - if (cs->hw.elsa.MFlag) { - val = serial_inp(cs, UART_IIR); - if (!(val & UART_IIR_NO_INT)) { - debugl1(cs, "IIR %02x", val); - rs_interrupt_elsa(cs); - } - } -#endif - ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); -Start_IPAC: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - hscx_int_main(cs, val); - } - if (ista & 0x20) { - val = 0xfe & readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_ISTA + 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPAC; - } - if (!icnt) - printk(KERN_WARNING "ELSA IRQ LOOP\n"); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xFF); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_elsa(struct IsdnCardState *cs) -{ - int bytecnt = 8; - - del_timer(&cs->hw.elsa.tl); -#if ARCOFI_USE - clear_arcofi(cs); -#endif - if (cs->hw.elsa.ctrl) - byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */ - if (cs->subtyp == ELSA_QS1000PCI) { - byteout(cs->hw.elsa.cfg + 0x4c, 0x01); /* disable IRQ */ - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); - bytecnt = 2; - release_region(cs->hw.elsa.cfg, 0x80); - } - if (cs->subtyp == ELSA_QS3000PCI) { - byteout(cs->hw.elsa.cfg + 0x4c, 0x03); /* disable ELSA PCI IRQ */ - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); - release_region(cs->hw.elsa.cfg, 0x80); - } - if (cs->subtyp == ELSA_PCMCIA_IPAC) { - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); - } - if ((cs->subtyp == ELSA_PCFPRO) || - (cs->subtyp == ELSA_QS3000) || - (cs->subtyp == ELSA_PCF) || - (cs->subtyp == ELSA_QS3000PCI)) { - bytecnt = 16; -#if ARCOFI_USE - release_modem(cs); -#endif - } - if (cs->hw.elsa.base) - release_region(cs->hw.elsa.base, bytecnt); -} - -static void -reset_elsa(struct IsdnCardState *cs) -{ - if (cs->hw.elsa.timer) { - /* Wait 1 Timer */ - byteout(cs->hw.elsa.timer, 0); - while (TimerRun(cs)); - cs->hw.elsa.ctrl_reg |= 0x50; - cs->hw.elsa.ctrl_reg &= ~ELSA_ISDN_RESET; /* Reset On */ - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - /* Wait 1 Timer */ - byteout(cs->hw.elsa.timer, 0); - while (TimerRun(cs)); - cs->hw.elsa.ctrl_reg |= ELSA_ISDN_RESET; /* Reset Off */ - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - /* Wait 1 Timer */ - byteout(cs->hw.elsa.timer, 0); - while (TimerRun(cs)); - if (cs->hw.elsa.trig) - byteout(cs->hw.elsa.trig, 0xff); - } - if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) { - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x20); - mdelay(10); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_POTA2, 0x00); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_MASK, 0xc0); - mdelay(10); - if (cs->subtyp != ELSA_PCMCIA_IPAC) { - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x0); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0x3c); - } else { - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_PCFG, 0x10); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ACFG, 0x4); - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_AOE, 0xf8); - } - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, 0xff); - if (cs->subtyp == ELSA_QS1000PCI) - byteout(cs->hw.elsa.cfg + 0x4c, 0x41); /* enable ELSA PCI IRQ */ - else if (cs->subtyp == ELSA_QS3000PCI) - byteout(cs->hw.elsa.cfg + 0x4c, 0x43); /* enable ELSA PCI IRQ */ - } -} - -#if ARCOFI_USE - -static void -set_arcofi(struct IsdnCardState *cs, int bc) { - cs->dc.isac.arcofi_bc = bc; - arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5); - wait_event_interruptible(cs->dc.isac.arcofi_wait, - cs->dc.isac.arcofi_state == ARCOFI_NOP); -} - -static int -check_arcofi(struct IsdnCardState *cs) -{ - int arcofi_present = 0; - char tmp[40]; - char *t; - u_char *p; - - if (!cs->dc.isac.mon_tx) - if (!(cs->dc.isac.mon_tx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC MON TX out of buffers!"); - return (0); - } - cs->dc.isac.arcofi_bc = 0; - arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION); - wait_event_interruptible(cs->dc.isac.arcofi_wait, - cs->dc.isac.arcofi_state == ARCOFI_NOP); - if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) { - debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp); - p = cs->dc.isac.mon_rx; - t = tmp; - t += sprintf(tmp, "Arcofi data"); - QuickHex(t, p, cs->dc.isac.mon_rxp); - debugl1(cs, "%s", tmp); - if ((cs->dc.isac.mon_rxp == 2) && (cs->dc.isac.mon_rx[0] == 0xa0)) { - switch (cs->dc.isac.mon_rx[1]) { - case 0x80: - debugl1(cs, "Arcofi 2160 detected"); - arcofi_present = 1; - break; - case 0x82: - debugl1(cs, "Arcofi 2165 detected"); - arcofi_present = 2; - break; - case 0x84: - debugl1(cs, "Arcofi 2163 detected"); - arcofi_present = 3; - break; - default: - debugl1(cs, "unknown Arcofi response"); - break; - } - } else - debugl1(cs, "undefined Monitor response"); - cs->dc.isac.mon_rxp = 0; - } else if (cs->dc.isac.mon_tx) { - debugl1(cs, "Arcofi not detected"); - } - if (arcofi_present) { - if (cs->subtyp == ELSA_QS1000) { - cs->subtyp = ELSA_QS3000; - printk(KERN_INFO - "Elsa: %s detected modem at 0x%lx\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base + 8); - release_region(cs->hw.elsa.base, 8); - if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) { - printk(KERN_WARNING - "HiSax: %s config port %lx-%lx already in use\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base + 8, - cs->hw.elsa.base + 16); - } - } else if (cs->subtyp == ELSA_PCC16) { - cs->subtyp = ELSA_PCF; - printk(KERN_INFO - "Elsa: %s detected modem at 0x%lx\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base + 8); - release_region(cs->hw.elsa.base, 8); - if (!request_region(cs->hw.elsa.base, 16, "elsa isdn modem")) { - printk(KERN_WARNING - "HiSax: %s config port %lx-%lx already in use\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base + 8, - cs->hw.elsa.base + 16); - } - } else - printk(KERN_INFO - "Elsa: %s detected modem at 0x%lx\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base + 8); - arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0); - wait_event_interruptible(cs->dc.isac.arcofi_wait, - cs->dc.isac.arcofi_state == ARCOFI_NOP); - return (1); - } - return (0); -} -#endif /* ARCOFI_USE */ - -static void -elsa_led_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.elsa.tl); - int blink = 0; - - if (cs->subtyp == ELSA_PCMCIA || cs->subtyp == ELSA_PCMCIA_IPAC) - return; - del_timer(&cs->hw.elsa.tl); - if (cs->hw.elsa.status & ELSA_ASSIGN) - cs->hw.elsa.ctrl_reg |= ELSA_STAT_LED; - else if (cs->hw.elsa.status & ELSA_BAD_PWR) - cs->hw.elsa.ctrl_reg &= ~ELSA_STAT_LED; - else { - cs->hw.elsa.ctrl_reg ^= ELSA_STAT_LED; - blink = 250; - } - if (cs->hw.elsa.status & 0xf000) - cs->hw.elsa.ctrl_reg |= ELSA_LINE_LED; - else if (cs->hw.elsa.status & 0x0f00) { - cs->hw.elsa.ctrl_reg ^= ELSA_LINE_LED; - blink = 500; - } else - cs->hw.elsa.ctrl_reg &= ~ELSA_LINE_LED; - - if ((cs->subtyp == ELSA_QS1000PCI) || - (cs->subtyp == ELSA_QS3000PCI)) { - u_char led = 0xff; - if (cs->hw.elsa.ctrl_reg & ELSA_LINE_LED) - led ^= ELSA_IPAC_LINE_LED; - if (cs->hw.elsa.ctrl_reg & ELSA_STAT_LED) - led ^= ELSA_IPAC_STAT_LED; - writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ATX, led); - } else - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - if (blink) { - cs->hw.elsa.tl.expires = jiffies + ((blink * HZ) / 1000); - add_timer(&cs->hw.elsa.tl); - } -} - -static int -Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - int ret = 0; - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_elsa(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_elsa(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - cs->debug |= L1_DEB_IPAC; - reset_elsa(cs); - inithscxisac(cs, 1); - if ((cs->subtyp == ELSA_QS1000) || - (cs->subtyp == ELSA_QS3000)) - { - byteout(cs->hw.elsa.timer, 0); - } - if (cs->hw.elsa.trig) - byteout(cs->hw.elsa.trig, 0xff); - inithscxisac(cs, 2); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - if ((cs->subtyp == ELSA_PCMCIA) || - (cs->subtyp == ELSA_PCMCIA_IPAC) || - (cs->subtyp == ELSA_QS1000PCI)) { - return (0); - } else if (cs->subtyp == ELSA_QS3000PCI) { - ret = 0; - } else { - spin_lock_irqsave(&cs->lock, flags); - cs->hw.elsa.counter = 0; - cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT; - cs->hw.elsa.status |= ELIRQF_TIMER_AKTIV; - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - byteout(cs->hw.elsa.timer, 0); - spin_unlock_irqrestore(&cs->lock, flags); - msleep(110); - spin_lock_irqsave(&cs->lock, flags); - cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT; - byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg); - cs->hw.elsa.status &= ~ELIRQF_TIMER_AKTIV; - spin_unlock_irqrestore(&cs->lock, flags); - printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n", - cs->hw.elsa.counter); - if ((cs->hw.elsa.counter > 10) && - (cs->hw.elsa.counter < 16)) { - printk(KERN_INFO "Elsa: timer and irq OK\n"); - ret = 0; - } else { - printk(KERN_WARNING - "Elsa: timer tic problem (%d/12) maybe an IRQ(%d) conflict\n", - cs->hw.elsa.counter, cs->irq); - ret = 1; - } - } -#if ARCOFI_USE - if (check_arcofi(cs)) { - init_modem(cs); - } -#endif - elsa_led_handler(&cs->hw.elsa.tl); - return (ret); - case (MDL_REMOVE | REQUEST): - cs->hw.elsa.status &= 0; - break; - case (MDL_ASSIGN | REQUEST): - cs->hw.elsa.status |= ELSA_ASSIGN; - break; - case MDL_INFO_SETUP: - if ((long) arg) - cs->hw.elsa.status |= 0x0200; - else - cs->hw.elsa.status |= 0x0100; - break; - case MDL_INFO_CONN: - if ((long) arg) - cs->hw.elsa.status |= 0x2000; - else - cs->hw.elsa.status |= 0x1000; - break; - case MDL_INFO_REL: - if ((long) arg) { - cs->hw.elsa.status &= ~0x2000; - cs->hw.elsa.status &= ~0x0200; - } else { - cs->hw.elsa.status &= ~0x1000; - cs->hw.elsa.status &= ~0x0100; - } - break; -#if ARCOFI_USE - case CARD_AUX_IND: - if (cs->hw.elsa.MFlag) { - int len; - u_char *msg; - - if (!arg) - return (0); - msg = arg; - len = *msg; - msg++; - modem_write_cmd(cs, msg, len); - } - break; -#endif - } - if (cs->typ == ISDN_CTYPE_ELSA) { - int pwr = bytein(cs->hw.elsa.ale); - if (pwr & 0x08) - cs->hw.elsa.status |= ELSA_BAD_PWR; - else - cs->hw.elsa.status &= ~ELSA_BAD_PWR; - } - elsa_led_handler(&cs->hw.elsa.tl); - return (ret); -} - -static unsigned char -probe_elsa_adr(unsigned int adr, int typ) -{ - int i, in1, in2, p16_1 = 0, p16_2 = 0, p8_1 = 0, p8_2 = 0, pc_1 = 0, - pc_2 = 0, pfp_1 = 0, pfp_2 = 0; - - /* In case of the elsa pcmcia card, this region is in use, - reserved for us by the card manager. So we do not check it - here, it would fail. */ - if (typ != ISDN_CTYPE_ELSA_PCMCIA) { - if (request_region(adr, 8, "elsa card")) { - release_region(adr, 8); - } else { - printk(KERN_WARNING - "Elsa: Probing Port 0x%x: already in use\n", adr); - return (0); - } - } - for (i = 0; i < 16; i++) { - in1 = inb(adr + ELSA_CONFIG); /* 'toggelt' bei */ - in2 = inb(adr + ELSA_CONFIG); /* jedem Zugriff */ - p16_1 += 0x04 & in1; - p16_2 += 0x04 & in2; - p8_1 += 0x02 & in1; - p8_2 += 0x02 & in2; - pc_1 += 0x01 & in1; - pc_2 += 0x01 & in2; - pfp_1 += 0x40 & in1; - pfp_2 += 0x40 & in2; - } - printk(KERN_INFO "Elsa: Probing IO 0x%x", adr); - if (65 == ++p16_1 * ++p16_2) { - printk(" PCC-16/PCF found\n"); - return (ELSA_PCC16); - } else if (1025 == ++pfp_1 * ++pfp_2) { - printk(" PCF-Pro found\n"); - return (ELSA_PCFPRO); - } else if (33 == ++p8_1 * ++p8_2) { - printk(" PCC8 found\n"); - return (ELSA_PCC8); - } else if (17 == ++pc_1 * ++pc_2) { - printk(" PC found\n"); - return (ELSA_PC); - } else { - printk(" failed\n"); - return (0); - } -} - -static unsigned int -probe_elsa(struct IsdnCardState *cs) -{ - int i; - unsigned int CARD_portlist[] = - {0x160, 0x170, 0x260, 0x360, 0}; - - for (i = 0; CARD_portlist[i]; i++) { - if ((cs->subtyp = probe_elsa_adr(CARD_portlist[i], cs->typ))) - break; - } - return (CARD_portlist[i]); -} - -static int setup_elsa_isa(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - u_char val; - - cs->hw.elsa.base = card->para[0]; - printk(KERN_INFO "Elsa: Microlink IO probing\n"); - if (cs->hw.elsa.base) { - if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base, - cs->typ))) { - printk(KERN_WARNING - "Elsa: no Elsa Microlink at %#lx\n", - cs->hw.elsa.base); - return (0); - } - } else - cs->hw.elsa.base = probe_elsa(cs); - - if (!cs->hw.elsa.base) { - printk(KERN_WARNING - "No Elsa Microlink found\n"); - return (0); - } - - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - val = bytein(cs->hw.elsa.cfg); - if (cs->subtyp == ELSA_PC) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2]; - } else if (cs->subtyp == ELSA_PCC8) { - const u_char CARD_IrqTab[8] = - {7, 3, 5, 9, 0, 0, 0, 0}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4]; - } else { - const u_char CARD_IrqTab[8] = - {15, 10, 15, 3, 11, 5, 11, 9}; - cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3]; - } - val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE; - if (val < 3) - val |= 8; - val += 'A' - 3; - if (val == 'B' || val == 'C') - val ^= 1; - if ((cs->subtyp == ELSA_PCFPRO) && (val == 'G')) - val = 'C'; - printk(KERN_INFO - "Elsa: %s found at %#lx Rev.:%c IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - val, cs->irq); - val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD; - if (val) { - printk(KERN_WARNING - "Elsa: Microlink S0 bus power bad\n"); - cs->hw.elsa.status |= ELSA_BAD_PWR; - } - - return (1); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id elsa_ids[] = { - { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), - ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), - (unsigned long) "Elsa QS1000" }, - { ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), - ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), - (unsigned long) "Elsa QS3000" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &elsa_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif /* __ISAPNP__ */ - -static int setup_elsa_isapnp(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - if (ipid->function == ISAPNP_FUNCTION(0x133)) - cs->subtyp = ELSA_QS1000; - else - cs->subtyp = ELSA_QS3000; - break; - } else { - printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n"); - return (0); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n"); - return (0); - } - } -#endif /* __ISAPNP__ */ - - if (card->para[1] && card->para[0]) { - cs->hw.elsa.base = card->para[1]; - cs->irq = card->para[0]; - if (!cs->subtyp) - cs->subtyp = ELSA_QS1000; - } else { - printk(KERN_ERR "Elsa PnP: no parameter\n"); - } - cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ; - cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER; - cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); - - return (1); -} - -static void setup_elsa_pcmcia(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - u_char val; - - cs->hw.elsa.base = card->para[1]; - cs->irq = card->para[0]; - val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID); - if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */ - cs->subtyp = ELSA_PCMCIA_IPAC; - cs->hw.elsa.ale = cs->hw.elsa.base + 0; - cs->hw.elsa.isac = cs->hw.elsa.base + 2; - cs->hw.elsa.hscx = cs->hw.elsa.base + 2; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - } else { - cs->subtyp = ELSA_PCMCIA; - cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM; - cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM; - cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX; - } - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->hw.elsa.ctrl = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->irq); -} - -#ifdef CONFIG_PCI -static struct pci_dev *dev_qs1000 = NULL; -static struct pci_dev *dev_qs3000 = NULL; - -static int setup_elsa_pci(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - - cs->subtyp = 0; - if ((dev_qs1000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) { - if (pci_enable_device(dev_qs1000)) - return (0); - cs->subtyp = ELSA_QS1000PCI; - cs->irq = dev_qs1000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3); - } else if ((dev_qs3000 = hisax_find_pci_device(PCI_VENDOR_ID_ELSA, - PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) { - if (pci_enable_device(dev_qs3000)) - return (0); - cs->subtyp = ELSA_QS3000PCI; - cs->irq = dev_qs3000->irq; - cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1); - cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3); - } else { - printk(KERN_WARNING "Elsa: No PCI card found\n"); - return (0); - } - if (!cs->irq) { - printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n"); - return (0); - } - - if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) { - printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n"); - return (0); - } - if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) { - printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n"); - printk(KERN_WARNING "Elsa: If your system hangs now, read\n"); - printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n"); - } - cs->hw.elsa.ale = cs->hw.elsa.base; - cs->hw.elsa.isac = cs->hw.elsa.base + 1; - cs->hw.elsa.hscx = cs->hw.elsa.base + 1; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->hw.elsa.timer = 0; - cs->hw.elsa.trig = 0; - cs->irq_flags |= IRQF_SHARED; - printk(KERN_INFO - "Elsa: %s defined at %#lx/0x%x IRQ %d\n", - Elsa_Types[cs->subtyp], - cs->hw.elsa.base, - cs->hw.elsa.cfg, - cs->irq); - - return (1); -} - -#else - -static int setup_elsa_pci(struct IsdnCard *card) -{ - return (1); -} -#endif /* CONFIG_PCI */ - -static int setup_elsa_common(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - u_char val; - int bytecnt; - - switch (cs->subtyp) { - case ELSA_PC: - case ELSA_PCC8: - case ELSA_PCC16: - case ELSA_QS1000: - case ELSA_PCMCIA: - case ELSA_PCMCIA_IPAC: - bytecnt = 8; - break; - case ELSA_PCFPRO: - case ELSA_PCF: - case ELSA_QS3000: - case ELSA_QS3000PCI: - bytecnt = 16; - break; - case ELSA_QS1000PCI: - bytecnt = 2; - break; - default: - printk(KERN_WARNING - "Unknown ELSA subtype %d\n", cs->subtyp); - return (0); - } - /* In case of the elsa pcmcia card, this region is in use, - reserved for us by the card manager. So we do not check it - here, it would fail. */ - if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) { - printk(KERN_WARNING - "HiSax: ELSA config port %#lx-%#lx already in use\n", - cs->hw.elsa.base, - cs->hw.elsa.base + bytecnt); - return (0); - } - if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) { - if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) { - printk(KERN_WARNING - "HiSax: ELSA pci port %x-%x already in use\n", - cs->hw.elsa.cfg, - cs->hw.elsa.cfg + 0x80); - release_region(cs->hw.elsa.base, bytecnt); - return (0); - } - } -#if ARCOFI_USE - init_arcofi(cs); -#endif - setup_isac(cs); - timer_setup(&cs->hw.elsa.tl, elsa_led_handler, 0); - /* Teste Timer */ - if (cs->hw.elsa.timer) { - byteout(cs->hw.elsa.trig, 0xff); - byteout(cs->hw.elsa.timer, 0); - if (!TimerRun(cs)) { - byteout(cs->hw.elsa.timer, 0); /* 2. Versuch */ - if (!TimerRun(cs)) { - printk(KERN_WARNING - "Elsa: timer do not start\n"); - release_io_elsa(cs); - return (0); - } - } - HZDELAY((HZ / 100) + 1); /* wait >=10 ms */ - if (TimerRun(cs)) { - printk(KERN_WARNING "Elsa: timer do not run down\n"); - release_io_elsa(cs); - return (0); - } - printk(KERN_INFO "Elsa: timer OK; resetting card\n"); - } - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Elsa_card_msg; - if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI) || (cs->subtyp == ELSA_PCMCIA_IPAC)) { - cs->readisac = &ReadISAC_IPAC; - cs->writeisac = &WriteISAC_IPAC; - cs->readisacfifo = &ReadISACfifo_IPAC; - cs->writeisacfifo = &WriteISACfifo_IPAC; - cs->irq_func = &elsa_interrupt_ipac; - val = readreg(cs->hw.elsa.ale, cs->hw.elsa.isac, IPAC_ID); - printk(KERN_INFO "Elsa: IPAC version %x\n", val); - } else { - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->irq_func = &elsa_interrupt; - ISACVersion(cs, "Elsa:"); - if (HscxVersion(cs, "Elsa:")) { - printk(KERN_WARNING - "Elsa: wrong HSCX versions check IO address\n"); - release_io_elsa(cs); - return (0); - } - } - if (cs->subtyp == ELSA_PC) { - val = readitac(cs, ITAC_SYS); - printk(KERN_INFO "Elsa: ITAC version %s\n", ITACVer[val & 7]); - writeitac(cs, ITAC_ISEN, 0); - writeitac(cs, ITAC_RFIE, 0); - writeitac(cs, ITAC_XFIE, 0); - writeitac(cs, ITAC_SCIE, 0); - writeitac(cs, ITAC_STIE, 0); - } - return (1); -} - -int setup_elsa(struct IsdnCard *card) -{ - int rc; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, Elsa_revision); - printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp)); - cs->hw.elsa.ctrl_reg = 0; - cs->hw.elsa.status = 0; - cs->hw.elsa.MFlag = 0; - cs->subtyp = 0; - - if (cs->typ == ISDN_CTYPE_ELSA) { - rc = setup_elsa_isa(card); - if (!rc) - return (0); - - } else if (cs->typ == ISDN_CTYPE_ELSA_PNP) { - rc = setup_elsa_isapnp(card); - if (!rc) - return (0); - - } else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) - setup_elsa_pcmcia(card); - - else if (cs->typ == ISDN_CTYPE_ELSA_PCI) { - rc = setup_elsa_pci(card); - if (!rc) - return (0); - - } else - return (0); - - return setup_elsa_common(card); -} diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c deleted file mode 100644 index 40f6fad79de3..000000000000 --- a/drivers/isdn/hisax/elsa_cs.c +++ /dev/null @@ -1,218 +0,0 @@ -/*====================================================================== - - An elsa_cs PCMCIA client driver - - This driver is for the Elsa PCM ISDN Cards, i.e. the MicroLink - - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - <dahinds@users.sourceforge.net>. Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Modifications from dummy_cs.c are Copyright (C) 1999-2001 Klaus - Lichtenwalder <Lichtenwalder@ACM.org>. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in - which case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - - ======================================================================*/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <asm/io.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> -#include "hisax_cfg.h" - -MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Elsa PCM cards"); -MODULE_AUTHOR("Klaus Lichtenwalder"); -MODULE_LICENSE("Dual MPL/GPL"); - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -static int protocol = 2; /* EURO-ISDN Default */ -module_param(protocol, int, 0); - -static int elsa_cs_config(struct pcmcia_device *link); -static void elsa_cs_release(struct pcmcia_device *link); -static void elsa_cs_detach(struct pcmcia_device *p_dev); - -typedef struct local_info_t { - struct pcmcia_device *p_dev; - int busy; - int cardnr; -} local_info_t; - -static int elsa_cs_probe(struct pcmcia_device *link) -{ - local_info_t *local; - - dev_dbg(&link->dev, "elsa_cs_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(local_info_t), GFP_KERNEL); - if (!local) return -ENOMEM; - - local->p_dev = link; - link->priv = local; - - local->cardnr = -1; - - return elsa_cs_config(link); -} /* elsa_cs_attach */ - -static void elsa_cs_detach(struct pcmcia_device *link) -{ - local_info_t *info = link->priv; - - dev_dbg(&link->dev, "elsa_cs_detach(0x%p)\n", link); - - info->busy = 1; - elsa_cs_release(link); - - kfree(info); -} /* elsa_cs_detach */ - -static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - int j; - - p_dev->io_lines = 3; - p_dev->resource[0]->end = 8; - p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) { - printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n"); - if (!pcmcia_request_io(p_dev)) - return 0; - } else { - printk(KERN_INFO "(elsa_cs: looks like the 97 model)\n"); - for (j = 0x2f0; j > 0x100; j -= 0x10) { - p_dev->resource[0]->start = j; - if (!pcmcia_request_io(p_dev)) - return 0; - } - } - return -ENODEV; -} - -static int elsa_cs_config(struct pcmcia_device *link) -{ - int i; - IsdnCard_t icard; - - dev_dbg(&link->dev, "elsa_config(0x%p)\n", link); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL); - if (i != 0) - goto failed; - - if (!link->irq) - goto failed; - - i = pcmcia_enable_device(link); - if (i != 0) - goto failed; - - icard.para[0] = link->irq; - icard.para[1] = link->resource[0]->start; - icard.protocol = protocol; - icard.typ = ISDN_CTYPE_ELSA_PCMCIA; - - i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard); - if (i < 0) { - printk(KERN_ERR "elsa_cs: failed to initialize Elsa " - "PCMCIA %d with %pR\n", i, link->resource[0]); - elsa_cs_release(link); - } else - ((local_info_t *)link->priv)->cardnr = i; - - return 0; -failed: - elsa_cs_release(link); - return -ENODEV; -} /* elsa_cs_config */ - -static void elsa_cs_release(struct pcmcia_device *link) -{ - local_info_t *local = link->priv; - - dev_dbg(&link->dev, "elsa_cs_release(0x%p)\n", link); - - if (local) { - if (local->cardnr >= 0) { - /* no unregister function with hisax */ - HiSax_closecard(local->cardnr); - } - } - - pcmcia_disable_device(link); -} /* elsa_cs_release */ - -static int elsa_suspend(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->busy = 1; - - return 0; -} - -static int elsa_resume(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->busy = 0; - - return 0; -} - -static const struct pcmcia_device_id elsa_ids[] = { - PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257), - PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, elsa_ids); - -static struct pcmcia_driver elsa_cs_driver = { - .owner = THIS_MODULE, - .name = "elsa_cs", - .probe = elsa_cs_probe, - .remove = elsa_cs_detach, - .id_table = elsa_ids, - .suspend = elsa_suspend, - .resume = elsa_resume, -}; -module_pcmcia_driver(elsa_cs_driver); diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c deleted file mode 100644 index 999effd7a276..000000000000 --- a/drivers/isdn/hisax/elsa_ser.c +++ /dev/null @@ -1,659 +0,0 @@ -/* $Id: elsa_ser.c,v 2.14.2.3 2004/02/11 13:21:33 keil Exp $ - * - * stuff for the serial modem on ELSA cards - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/serial.h> -#include <linux/serial_reg.h> -#include <linux/slab.h> - -#define MAX_MODEM_BUF 256 -#define WAKEUP_CHARS (MAX_MODEM_BUF / 2) -#define RS_ISR_PASS_LIMIT 256 -#define BASE_BAUD (1843200 / 16) - -//#define SERIAL_DEBUG_OPEN 1 -//#define SERIAL_DEBUG_INTR 1 -//#define SERIAL_DEBUG_FLOW 1 -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_FLOW -#undef SERIAL_DEBUG_REG -//#define SERIAL_DEBUG_REG 1 - -#ifdef SERIAL_DEBUG_REG -static u_char deb[32]; -const char *ModemIn[] = {"RBR", "IER", "IIR", "LCR", "MCR", "LSR", "MSR", "SCR"}; -const char *ModemOut[] = {"THR", "IER", "FCR", "LCR", "MCR", "LSR", "MSR", "SCR"}; -#endif - -static char *MInit_1 = "AT&F&C1E0&D2\r\0"; -static char *MInit_2 = "ATL2M1S64=13\r\0"; -static char *MInit_3 = "AT+FCLASS=0\r\0"; -static char *MInit_4 = "ATV1S2=128X1\r\0"; -static char *MInit_5 = "AT\\V8\\N3\r\0"; -static char *MInit_6 = "ATL0M0&G0%E1\r\0"; -static char *MInit_7 = "AT%L1%M0%C3\r\0"; - -static char *MInit_speed28800 = "AT%G0%B28800\r\0"; - -static char *MInit_dialout = "ATs7=60 x1 d\r\0"; -static char *MInit_dialin = "ATs7=60 x1 a\r\0"; - - -static inline unsigned int serial_in(struct IsdnCardState *cs, int offset) -{ -#ifdef SERIAL_DEBUG_REG - u_int val = inb(cs->hw.elsa.base + 8 + offset); - debugl1(cs, "in %s %02x", ModemIn[offset], val); - return (val); -#else - return inb(cs->hw.elsa.base + 8 + offset); -#endif -} - -static inline unsigned int serial_inp(struct IsdnCardState *cs, int offset) -{ -#ifdef SERIAL_DEBUG_REG -#ifdef ELSA_SERIAL_NOPAUSE_IO - u_int val = inb(cs->hw.elsa.base + 8 + offset); - debugl1(cs, "inp %s %02x", ModemIn[offset], val); -#else - u_int val = inb_p(cs->hw.elsa.base + 8 + offset); - debugl1(cs, "inP %s %02x", ModemIn[offset], val); -#endif - return (val); -#else -#ifdef ELSA_SERIAL_NOPAUSE_IO - return inb(cs->hw.elsa.base + 8 + offset); -#else - return inb_p(cs->hw.elsa.base + 8 + offset); -#endif -#endif -} - -static inline void serial_out(struct IsdnCardState *cs, int offset, int value) -{ -#ifdef SERIAL_DEBUG_REG - debugl1(cs, "out %s %02x", ModemOut[offset], value); -#endif - outb(value, cs->hw.elsa.base + 8 + offset); -} - -static inline void serial_outp(struct IsdnCardState *cs, int offset, - int value) -{ -#ifdef SERIAL_DEBUG_REG -#ifdef ELSA_SERIAL_NOPAUSE_IO - debugl1(cs, "outp %s %02x", ModemOut[offset], value); -#else - debugl1(cs, "outP %s %02x", ModemOut[offset], value); -#endif -#endif -#ifdef ELSA_SERIAL_NOPAUSE_IO - outb(value, cs->hw.elsa.base + 8 + offset); -#else - outb_p(value, cs->hw.elsa.base + 8 + offset); -#endif -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void change_speed(struct IsdnCardState *cs, int baud) -{ - int quot = 0, baud_base; - unsigned cval, fcr = 0; - - - /* byte size and parity */ - cval = 0x03; - /* Determine divisor based on baud rate */ - baud_base = BASE_BAUD; - quot = baud_base / baud; - /* If the quotient is ever zero, default to 9600 bps */ - if (!quot) - quot = baud_base / 9600; - - /* Set up FIFO's */ - if ((baud_base / quot) < 2400) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; - else - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; - serial_outp(cs, UART_FCR, fcr); - /* CTS flow control flag and modem status interrupts */ - cs->hw.elsa.IER &= ~UART_IER_MSI; - cs->hw.elsa.IER |= UART_IER_MSI; - serial_outp(cs, UART_IER, cs->hw.elsa.IER); - - debugl1(cs, "modem quot=0x%x", quot); - serial_outp(cs, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ - serial_outp(cs, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_outp(cs, UART_DLM, quot >> 8); /* MS of divisor */ - serial_outp(cs, UART_LCR, cval); /* reset DLAB */ - serial_inp(cs, UART_RX); -} - -static int mstartup(struct IsdnCardState *cs) -{ - int retval = 0; - - /* - * Clear the FIFO buffers and disable them - * (they will be reenabled in change_speed()) - */ - serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); - - /* - * At this point there's no way the LSR could still be 0xFF; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (serial_inp(cs, UART_LSR) == 0xff) { - retval = -ENODEV; - goto errout; - } - - /* - * Clear the interrupt registers. - */ - (void) serial_inp(cs, UART_RX); - (void) serial_inp(cs, UART_IIR); - (void) serial_inp(cs, UART_MSR); - - /* - * Now, initialize the UART - */ - serial_outp(cs, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ - - cs->hw.elsa.MCR = 0; - cs->hw.elsa.MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; - serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); - - /* - * Finally, enable interrupts - */ - cs->hw.elsa.IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; - serial_outp(cs, UART_IER, cs->hw.elsa.IER); /* enable interrupts */ - - /* - * And clear the interrupt registers again for luck. - */ - (void)serial_inp(cs, UART_LSR); - (void)serial_inp(cs, UART_RX); - (void)serial_inp(cs, UART_IIR); - (void)serial_inp(cs, UART_MSR); - - cs->hw.elsa.transcnt = cs->hw.elsa.transp = 0; - cs->hw.elsa.rcvcnt = cs->hw.elsa.rcvp = 0; - - /* - * and set the speed of the serial port - */ - change_speed(cs, BASE_BAUD); - cs->hw.elsa.MFlag = 1; -errout: - return retval; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void mshutdown(struct IsdnCardState *cs) -{ - -#ifdef SERIAL_DEBUG_OPEN - printk(KERN_DEBUG"Shutting down serial ...."); -#endif - - /* - * clear delta_msr_wait queue to avoid mem leaks: we may free the irq - * here so the queue might never be waken up - */ - - cs->hw.elsa.IER = 0; - serial_outp(cs, UART_IER, 0x00); /* disable all intrs */ - cs->hw.elsa.MCR &= ~UART_MCR_OUT2; - - /* disable break condition */ - serial_outp(cs, UART_LCR, serial_inp(cs, UART_LCR) & ~UART_LCR_SBC); - - cs->hw.elsa.MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); - serial_outp(cs, UART_MCR, cs->hw.elsa.MCR); - - /* disable FIFO's */ - serial_outp(cs, UART_FCR, (UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT)); - serial_inp(cs, UART_RX); /* read data port to reset things */ - -#ifdef SERIAL_DEBUG_OPEN - printk(" done\n"); -#endif -} - -static inline int -write_modem(struct BCState *bcs) { - int ret = 0; - struct IsdnCardState *cs = bcs->cs; - int count, len, fp; - - if (!bcs->tx_skb) - return 0; - if (bcs->tx_skb->len <= 0) - return 0; - len = bcs->tx_skb->len; - if (len > MAX_MODEM_BUF - cs->hw.elsa.transcnt) - len = MAX_MODEM_BUF - cs->hw.elsa.transcnt; - fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp; - fp &= (MAX_MODEM_BUF - 1); - count = len; - if (count > MAX_MODEM_BUF - fp) { - count = MAX_MODEM_BUF - fp; - skb_copy_from_linear_data(bcs->tx_skb, - cs->hw.elsa.transbuf + fp, count); - skb_pull(bcs->tx_skb, count); - cs->hw.elsa.transcnt += count; - ret = count; - count = len - count; - fp = 0; - } - skb_copy_from_linear_data(bcs->tx_skb, - cs->hw.elsa.transbuf + fp, count); - skb_pull(bcs->tx_skb, count); - cs->hw.elsa.transcnt += count; - ret += count; - - if (cs->hw.elsa.transcnt && - !(cs->hw.elsa.IER & UART_IER_THRI)) { - cs->hw.elsa.IER |= UART_IER_THRI; - serial_outp(cs, UART_IER, cs->hw.elsa.IER); - } - return (ret); -} - -static inline void -modem_fill(struct BCState *bcs) { - - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - write_modem(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hscx.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - write_modem(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } -} - -static inline void receive_chars(struct IsdnCardState *cs, - int *status) -{ - unsigned char ch; - struct sk_buff *skb; - - do { - ch = serial_in(cs, UART_RX); - if (cs->hw.elsa.rcvcnt >= MAX_MODEM_BUF) - break; - cs->hw.elsa.rcvbuf[cs->hw.elsa.rcvcnt++] = ch; -#ifdef SERIAL_DEBUG_INTR - printk("DR%02x:%02x...", ch, *status); -#endif - if (*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE)) { - -#ifdef SERIAL_DEBUG_INTR - printk("handling exept...."); -#endif - } - *status = serial_inp(cs, UART_LSR); - } while (*status & UART_LSR_DR); - if (cs->hw.elsa.MFlag == 2) { - if (!(skb = dev_alloc_skb(cs->hw.elsa.rcvcnt))) - printk(KERN_WARNING "ElsaSER: receive out of memory\n"); - else { - skb_put_data(skb, cs->hw.elsa.rcvbuf, - cs->hw.elsa.rcvcnt); - skb_queue_tail(&cs->hw.elsa.bcs->rqueue, skb); - } - schedule_event(cs->hw.elsa.bcs, B_RCVBUFREADY); - } else { - char tmp[128]; - char *t = tmp; - - t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt); - QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt); - debugl1(cs, "%s", tmp); - } - cs->hw.elsa.rcvcnt = 0; -} - -static inline void transmit_chars(struct IsdnCardState *cs, int *intr_done) -{ - int count; - - debugl1(cs, "transmit_chars: p(%x) cnt(%x)", cs->hw.elsa.transp, - cs->hw.elsa.transcnt); - - if (cs->hw.elsa.transcnt <= 0) { - cs->hw.elsa.IER &= ~UART_IER_THRI; - serial_out(cs, UART_IER, cs->hw.elsa.IER); - return; - } - count = 16; - do { - serial_outp(cs, UART_TX, cs->hw.elsa.transbuf[cs->hw.elsa.transp++]); - if (cs->hw.elsa.transp >= MAX_MODEM_BUF) - cs->hw.elsa.transp = 0; - if (--cs->hw.elsa.transcnt <= 0) - break; - } while (--count > 0); - if ((cs->hw.elsa.transcnt < WAKEUP_CHARS) && (cs->hw.elsa.MFlag == 2)) - modem_fill(cs->hw.elsa.bcs); - -#ifdef SERIAL_DEBUG_INTR - printk("THRE..."); -#endif - if (intr_done) - *intr_done = 0; - if (cs->hw.elsa.transcnt <= 0) { - cs->hw.elsa.IER &= ~UART_IER_THRI; - serial_outp(cs, UART_IER, cs->hw.elsa.IER); - } -} - - -static void rs_interrupt_elsa(struct IsdnCardState *cs) -{ - int status, iir, msr; - int pass_counter = 0; - -#ifdef SERIAL_DEBUG_INTR - printk(KERN_DEBUG "rs_interrupt_single(%d)...", cs->irq); -#endif - - do { - status = serial_inp(cs, UART_LSR); - debugl1(cs, "rs LSR %02x", status); -#ifdef SERIAL_DEBUG_INTR - printk("status = %x...", status); -#endif - if (status & UART_LSR_DR) - receive_chars(cs, &status); - if (status & UART_LSR_THRE) - transmit_chars(cs, NULL); - if (pass_counter++ > RS_ISR_PASS_LIMIT) { - printk("rs_single loop break.\n"); - break; - } - iir = serial_inp(cs, UART_IIR); - debugl1(cs, "rs IIR %02x", iir); - if ((iir & 0xf) == 0) { - msr = serial_inp(cs, UART_MSR); - debugl1(cs, "rs MSR %02x", msr); - } - } while (!(iir & UART_IIR_NO_INT)); -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} - -extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs); -extern void modehscx(struct BCState *bcs, int mode, int bc); -extern void hscx_l2l1(struct PStack *st, int pr, void *arg); - -static void -close_elsastate(struct BCState *bcs) -{ - modehscx(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - if (bcs->hw.hscx.rcvbuf) { - if (bcs->mode != L1_MODE_MODEM) - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - } - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static void -modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) { - int count, fp; - u_char *msg = buf; - - if (!len) - return; - if (len > (MAX_MODEM_BUF - cs->hw.elsa.transcnt)) { - return; - } - fp = cs->hw.elsa.transcnt + cs->hw.elsa.transp; - fp &= (MAX_MODEM_BUF - 1); - count = len; - if (count > MAX_MODEM_BUF - fp) { - count = MAX_MODEM_BUF - fp; - memcpy(cs->hw.elsa.transbuf + fp, msg, count); - cs->hw.elsa.transcnt += count; - msg += count; - count = len - count; - fp = 0; - } - memcpy(cs->hw.elsa.transbuf + fp, msg, count); - cs->hw.elsa.transcnt += count; - if (cs->hw.elsa.transcnt && - !(cs->hw.elsa.IER & UART_IER_THRI)) { - cs->hw.elsa.IER |= UART_IER_THRI; - serial_outp(cs, UART_IER, cs->hw.elsa.IER); - } -} - -static void -modem_set_init(struct IsdnCardState *cs) { - int timeout; - -#define RCV_DELAY 20 - modem_write_cmd(cs, MInit_1, strlen(MInit_1)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_2, strlen(MInit_2)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_3, strlen(MInit_3)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_4, strlen(MInit_4)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_5, strlen(MInit_5)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_6, strlen(MInit_6)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - modem_write_cmd(cs, MInit_7, strlen(MInit_7)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); -} - -static void -modem_set_dial(struct IsdnCardState *cs, int outgoing) { - int timeout; -#define RCV_DELAY 20 - - modem_write_cmd(cs, MInit_speed28800, strlen(MInit_speed28800)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); - if (outgoing) - modem_write_cmd(cs, MInit_dialout, strlen(MInit_dialout)); - else - modem_write_cmd(cs, MInit_dialin, strlen(MInit_dialin)); - timeout = 1000; - while (timeout-- && cs->hw.elsa.transcnt) - udelay(1000); - debugl1(cs, "msi tout=%d", timeout); - mdelay(RCV_DELAY); -} - -static void -modem_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - if (pr == (PH_DATA | REQUEST)) { - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.hscx.count = 0; - write_modem(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - } else if (pr == (PH_ACTIVATE | REQUEST)) { - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - set_arcofi(bcs->cs, st->l1.bc); - mstartup(bcs->cs); - modem_set_dial(bcs->cs, test_bit(FLG_ORIG, &st->l2.flag)); - bcs->cs->hw.elsa.MFlag = 2; - } else if (pr == (PH_DEACTIVATE | REQUEST)) { - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - bcs->cs->dc.isac.arcofi_bc = st->l1.bc; - arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0); - wait_event_interruptible(bcs->cs->dc.isac.arcofi_wait, - bcs->cs->dc.isac.arcofi_state == ARCOFI_NOP); - bcs->cs->hw.elsa.MFlag = 1; - } else { - printk(KERN_WARNING "ElsaSer: unknown pr %x\n", pr); - } -} - -static int -setstack_elsa(struct PStack *st, struct BCState *bcs) -{ - - bcs->channel = st->l1.bc; - switch (st->l1.mode) { - case L1_MODE_HDLC: - case L1_MODE_TRANS: - if (open_hscxstate(st->l1.hardware, bcs)) - return (-1); - st->l2.l2l1 = hscx_l2l1; - break; - case L1_MODE_MODEM: - bcs->mode = L1_MODE_MODEM; - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - bcs->hw.hscx.rcvbuf = bcs->cs->hw.elsa.rcvbuf; - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.hscx.rcvidx = 0; - bcs->tx_cnt = 0; - bcs->cs->hw.elsa.bcs = bcs; - st->l2.l2l1 = modem_l2l1; - break; - } - st->l1.bcs = bcs; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -static void -init_modem(struct IsdnCardState *cs) { - - cs->bcs[0].BC_SetStack = setstack_elsa; - cs->bcs[1].BC_SetStack = setstack_elsa; - cs->bcs[0].BC_Close = close_elsastate; - cs->bcs[1].BC_Close = close_elsastate; - if (!(cs->hw.elsa.rcvbuf = kmalloc(MAX_MODEM_BUF, - GFP_ATOMIC))) { - printk(KERN_WARNING - "Elsa: No modem mem hw.elsa.rcvbuf\n"); - return; - } - if (!(cs->hw.elsa.transbuf = kmalloc(MAX_MODEM_BUF, - GFP_ATOMIC))) { - printk(KERN_WARNING - "Elsa: No modem mem hw.elsa.transbuf\n"); - kfree(cs->hw.elsa.rcvbuf); - cs->hw.elsa.rcvbuf = NULL; - return; - } - if (mstartup(cs)) { - printk(KERN_WARNING "Elsa: problem startup modem\n"); - } - modem_set_init(cs); -} - -static void -release_modem(struct IsdnCardState *cs) { - - cs->hw.elsa.MFlag = 0; - if (cs->hw.elsa.transbuf) { - if (cs->hw.elsa.rcvbuf) { - mshutdown(cs); - kfree(cs->hw.elsa.rcvbuf); - cs->hw.elsa.rcvbuf = NULL; - } - kfree(cs->hw.elsa.transbuf); - cs->hw.elsa.transbuf = NULL; - } -} diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c deleted file mode 100644 index e8d431a8302d..000000000000 --- a/drivers/isdn/hisax/enternow_pci.c +++ /dev/null @@ -1,420 +0,0 @@ -/* enternow_pci.c,v 0.99 2001/10/02 - * - * enternow_pci.c Card-specific routines for - * Formula-n enter:now ISDN PCI ab - * Gerdes AG Power ISDN PCI - * Woerltronic SA 16 PCI - * (based on HiSax driver by Karsten Keil) - * - * Author Christoph Ersfeld <info@formula-n.de> - * Formula-n Europe AG (www.formula-n.com) - * previously Gerdes AG - * - * - * This file is (c) under GNU PUBLIC LICENSE - * - * Notes: - * This driver interfaces to netjet.c which performs B-channel - * processing. - * - * Version 0.99 is the first release of this driver and there are - * certainly a few bugs. - * It isn't testet on linux 2.4 yet, so consider this code to be - * beta. - * - * Please don't report me any malfunction without sending - * (compressed) debug-logs. - * It would be nearly impossible to retrace it. - * - * Log D-channel-processing as follows: - * - * 1. Load hisax with card-specific parameters, this example ist for - * Formula-n enter:now ISDN PCI and compatible - * (f.e. Gerdes Power ISDN PCI) - * - * modprobe hisax type=41 protocol=2 id=gerdes - * - * if you chose an other value for id, you need to modify the - * code below, too. - * - * 2. set debug-level - * - * hisaxctrl gerdes 1 0x3ff - * hisaxctrl gerdes 11 0x4f - * cat /dev/isdnctrl >> ~/log & - * - * Please take also a look into /var/log/messages if there is - * anything importand concerning HISAX. - * - * - * Credits: - * Programming the driver for Formula-n enter:now ISDN PCI and - * necessary the driver for the used Amd 7930 D-channel-controller - * was spnsored by Formula-n Europe AG. - * Thanks to Karsten Keil and Petr Novak, who gave me support in - * Hisax-specific questions. - * I want so say special thanks to Carl-Friedrich Braun, who had to - * answer a lot of questions about generally ISDN and about handling - * of the Amd-Chip. - * - */ - - -#include "hisax.h" -#include "isac.h" -#include "isdnl1.h" -#include "amd7930_fn.h" -#include <linux/interrupt.h> -#include <linux/ppp_defs.h> -#include <linux/pci.h> -#include <linux/init.h> -#include "netjet.h" - - - -static const char *enternow_pci_rev = "$Revision: 1.1.4.5 $"; - - -/* for PowerISDN PCI */ -#define TJ_AMD_IRQ 0x20 -#define TJ_LED1 0x40 -#define TJ_LED2 0x80 - - -/* The window to [the] AMD [chip]... - * From address hw.njet.base + TJ_AMD_PORT onwards, the AMD - * maps [consecutive/multiple] 8 bits into the TigerJet I/O space - * -> 0x01 of the AMD at hw.njet.base + 0C4 */ -#define TJ_AMD_PORT 0xC0 - - - -/* *************************** I/O-Interface functions ************************************* */ - - -/* cs->readisac, macro rByteAMD */ -static unsigned char -ReadByteAmd7930(struct IsdnCardState *cs, unsigned char offset) -{ - /* direct register */ - if (offset < 8) - return (inb(cs->hw.njet.isac + 4 * offset)); - - /* indirect register */ - else { - outb(offset, cs->hw.njet.isac + 4 * AMD_CR); - return (inb(cs->hw.njet.isac + 4 * AMD_DR)); - } -} - -/* cs->writeisac, macro wByteAMD */ -static void -WriteByteAmd7930(struct IsdnCardState *cs, unsigned char offset, unsigned char value) -{ - /* direct register */ - if (offset < 8) - outb(value, cs->hw.njet.isac + 4 * offset); - - /* indirect register */ - else { - outb(offset, cs->hw.njet.isac + 4 * AMD_CR); - outb(value, cs->hw.njet.isac + 4 * AMD_DR); - } -} - - -static void -enpci_setIrqMask(struct IsdnCardState *cs, unsigned char val) { - if (!val) - outb(0x00, cs->hw.njet.base + NETJET_IRQMASK1); - else - outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1); -} - - -static unsigned char dummyrr(struct IsdnCardState *cs, int chan, unsigned char off) -{ - return (5); -} - -static void dummywr(struct IsdnCardState *cs, int chan, unsigned char off, unsigned char value) -{ - -} - - -/* ******************************************************************************** */ - - -static void -reset_enpci(struct IsdnCardState *cs) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "enter:now PCI: reset"); - - /* Reset on, (also for AMD) */ - cs->hw.njet.ctrl_reg = 0x07; - outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); - mdelay(20); - /* Reset off */ - cs->hw.njet.ctrl_reg = 0x30; - outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); - /* 20ms delay */ - mdelay(20); - cs->hw.njet.auxd = 0; // LED-status - cs->hw.njet.dmactrl = 0; - outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL); - outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1); - outb(cs->hw.njet.auxd, cs->hw.njet.auxa); // LED off -} - - -static int -enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - unsigned char *chan; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt); - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_enpci(cs); - Amd7930_init(cs); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case CARD_RELEASE: - release_io_netjet(cs); - break; - case CARD_INIT: - reset_enpci(cs); - inittiger(cs); - /* irq must be on here */ - Amd7930_init(cs); - break; - case CARD_TEST: - break; - case MDL_ASSIGN: - /* TEI assigned, LED1 on */ - cs->hw.njet.auxd = TJ_AMD_IRQ << 1; - outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); - break; - case MDL_REMOVE: - /* TEI removed, LEDs off */ - cs->hw.njet.auxd = 0; - outb(0x00, cs->hw.njet.base + NETJET_AUXDATA); - break; - case MDL_BC_ASSIGN: - /* activate B-channel */ - chan = (unsigned char *)arg; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan); - - cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN"); - /* at least one b-channel in use, LED 2 on */ - cs->hw.njet.auxd |= TJ_AMD_IRQ << 2; - outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); - break; - case MDL_BC_RELEASE: - /* deactivate B-channel */ - chan = (unsigned char *)arg; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan); - - cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE"); - /* no b-channel active -> LED2 off */ - if (!(cs->dc.amd7930.lmr1 & 3)) { - cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2); - outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA); - } - break; - default: - break; - - } - return (0); -} - -static irqreturn_t -enpci_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - unsigned char s0val, s1val, ir; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - s1val = inb(cs->hw.njet.base + NETJET_IRQSTAT1); - - /* AMD threw an interrupt */ - if (!(s1val & TJ_AMD_IRQ)) { - /* read and clear interrupt-register */ - ir = ReadByteAmd7930(cs, 0x00); - Amd7930_interrupt(cs, ir); - s1val = 1; - } else - s1val = 0; - s0val = inb(cs->hw.njet.base + NETJET_IRQSTAT0); - if ((s0val | s1val) == 0) { // shared IRQ - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (s0val) - outb(s0val, cs->hw.njet.base + NETJET_IRQSTAT0); - - /* DMA-Interrupt: B-channel-stuff */ - /* set bits in sval to indicate which page is free */ - if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) - /* the 2nd write page is free */ - s0val = 0x08; - else /* the 1st write page is free */ - s0val = 0x04; - if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) - /* the 2nd read page is free */ - s0val = s0val | 0x02; - else /* the 1st read page is free */ - s0val = s0val | 0x01; - if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */ - { - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } - cs->hw.njet.irqstat0 = s0val; - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) - /* we have a read dma int */ - read_tiger(cs); - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) - /* we have a write dma int */ - write_tiger(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static int en_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs) -{ - if (pci_enable_device(dev_netjet)) - return (0); - cs->irq = dev_netjet->irq; - if (!cs->irq) { - printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.njet.base = pci_resource_start(dev_netjet, 0); - if (!cs->hw.njet.base) { - printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n"); - return (0); - } - /* checks Sub-Vendor ID because system crashes with Traverse-Card */ - if ((dev_netjet->subsystem_vendor != 0x55) || - (dev_netjet->subsystem_device != 0x02)) { - printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n"); - printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n"); - return (0); - } - - return (1); -} - -static void en_cs_init(struct IsdnCard *card, struct IsdnCardState *cs) -{ - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD - - /* Reset an */ - cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff - outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); - /* 20 ms Pause */ - mdelay(20); - - cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */ - outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL); - mdelay(10); - - cs->hw.njet.auxd = 0x00; // war 0xc0 - cs->hw.njet.dmactrl = 0; - - outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL); - outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1); - outb(cs->hw.njet.auxd, cs->hw.njet.auxa); -} - -static int en_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs) -{ - const int bytecnt = 256; - - printk(KERN_INFO - "enter:now PCI: PCI card configured at 0x%lx IRQ %d\n", - cs->hw.njet.base, cs->irq); - if (!request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN")) { - printk(KERN_WARNING - "HiSax: enter:now config port %lx-%lx already in use\n", - cs->hw.njet.base, - cs->hw.njet.base + bytecnt); - return (0); - } - - setup_Amd7930(cs); - cs->hw.njet.last_is0 = 0; - /* macro rByteAMD */ - cs->readisac = &ReadByteAmd7930; - /* macro wByteAMD */ - cs->writeisac = &WriteByteAmd7930; - cs->dc.amd7930.setIrqMask = &enpci_setIrqMask; - - cs->BC_Read_Reg = &dummyrr; - cs->BC_Write_Reg = &dummywr; - cs->BC_Send_Data = &netjet_fill_dma; - cs->cardmsg = &enpci_card_msg; - cs->irq_func = &enpci_interrupt; - cs->irq_flags |= IRQF_SHARED; - - return (1); -} - -static struct pci_dev *dev_netjet = NULL; - -/* called by config.c */ -int setup_enternow_pci(struct IsdnCard *card) -{ - int ret; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - -#ifdef __BIG_ENDIAN -#error "not running on big endian machines now" -#endif - - strcpy(tmp, enternow_pci_rev); - printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_ENTERNOW) - return (0); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - - for (;;) - { - if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { - ret = en_pci_probe(dev_netjet, cs); - if (!ret) - return (0); - } else { - printk(KERN_WARNING "enter:now PCI: No PCI card found\n"); - return (0); - } - - en_cs_init(card, cs); - break; - } - - return en_cs_init_rest(card, cs); -} diff --git a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c deleted file mode 100644 index 80ba82f77c63..000000000000 --- a/drivers/isdn/hisax/fsm.c +++ /dev/null @@ -1,161 +0,0 @@ -/* $Id: fsm.c,v 1.14.6.4 2001/09/23 22:24:47 kai Exp $ - * - * Finite state machine - * - * 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. - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include "hisax.h" - -#define FSM_TIMER_DEBUG 0 - -int -FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount) -{ - int i; - - fsm->jumpmatrix = - kzalloc(array3_size(sizeof(FSMFNPTR), fsm->state_count, - fsm->event_count), - GFP_KERNEL); - if (!fsm->jumpmatrix) - return -ENOMEM; - - for (i = 0; i < fncount; i++) - if ((fnlist[i].state >= fsm->state_count) || (fnlist[i].event >= fsm->event_count)) { - printk(KERN_ERR "FsmNew Error line %d st(%ld/%ld) ev(%ld/%ld)\n", - i, (long)fnlist[i].state, (long)fsm->state_count, - (long)fnlist[i].event, (long)fsm->event_count); - } else - fsm->jumpmatrix[fsm->state_count * fnlist[i].event + - fnlist[i].state] = (FSMFNPTR)fnlist[i].routine; - return 0; -} - -void -FsmFree(struct Fsm *fsm) -{ - kfree((void *) fsm->jumpmatrix); -} - -int -FsmEvent(struct FsmInst *fi, int event, void *arg) -{ - FSMFNPTR r; - - if ((fi->state >= fi->fsm->state_count) || (event >= fi->fsm->event_count)) { - printk(KERN_ERR "FsmEvent Error st(%ld/%ld) ev(%d/%ld)\n", - (long)fi->state, (long)fi->fsm->state_count, event, (long)fi->fsm->event_count); - return (1); - } - r = fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state]; - if (r) { - if (fi->debug) - fi->printdebug(fi, "State %s Event %s", - fi->fsm->strState[fi->state], - fi->fsm->strEvent[event]); - r(fi, event, arg); - return (0); - } else { - if (fi->debug) - fi->printdebug(fi, "State %s Event %s no routine", - fi->fsm->strState[fi->state], - fi->fsm->strEvent[event]); - return (!0); - } -} - -void -FsmChangeState(struct FsmInst *fi, int newstate) -{ - fi->state = newstate; - if (fi->debug) - fi->printdebug(fi, "ChangeState %s", - fi->fsm->strState[newstate]); -} - -static void -FsmExpireTimer(struct timer_list *t) -{ - struct FsmTimer *ft = from_timer(ft, t, tl); -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmExpireTimer %lx", (long) ft); -#endif - FsmEvent(ft->fi, ft->event, ft->arg); -} - -void -FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft) -{ - ft->fi = fi; -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmInitTimer %lx", (long) ft); -#endif - timer_setup(&ft->tl, FsmExpireTimer, 0); -} - -void -FsmDelTimer(struct FsmTimer *ft, int where) -{ -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmDelTimer %lx %d", (long) ft, where); -#endif - del_timer(&ft->tl); -} - -int -FsmAddTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) -{ - -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmAddTimer %lx %d %d", - (long) ft, millisec, where); -#endif - - if (timer_pending(&ft->tl)) { - printk(KERN_WARNING "FsmAddTimer: timer already active!\n"); - ft->fi->printdebug(ft->fi, "FsmAddTimer already active!"); - return -1; - } - ft->event = event; - ft->arg = arg; - ft->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&ft->tl); - return 0; -} - -void -FsmRestartTimer(struct FsmTimer *ft, - int millisec, int event, void *arg, int where) -{ - -#if FSM_TIMER_DEBUG - if (ft->fi->debug) - ft->fi->printdebug(ft->fi, "FsmRestartTimer %lx %d %d", - (long) ft, millisec, where); -#endif - - if (timer_pending(&ft->tl)) - del_timer(&ft->tl); - ft->event = event; - ft->arg = arg; - ft->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&ft->tl); -} diff --git a/drivers/isdn/hisax/fsm.h b/drivers/isdn/hisax/fsm.h deleted file mode 100644 index 8c7385619a46..000000000000 --- a/drivers/isdn/hisax/fsm.h +++ /dev/null @@ -1,61 +0,0 @@ -/* $Id: fsm.h,v 1.3.2.2 2001/09/23 22:24:47 kai Exp $ - * - * Finite state machine - * - * 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. - * - */ - -#ifndef __FSM_H__ -#define __FSM_H__ - -#include <linux/timer.h> - -struct FsmInst; - -typedef void (*FSMFNPTR)(struct FsmInst *, int, void *); - -struct Fsm { - FSMFNPTR *jumpmatrix; - int state_count, event_count; - char **strEvent, **strState; -}; - -struct FsmInst { - struct Fsm *fsm; - int state; - int debug; - void *userdata; - int userint; - void (*printdebug) (struct FsmInst *, char *, ...); -}; - -struct FsmNode { - int state, event; - void (*routine) (struct FsmInst *, int, void *); -}; - -struct FsmTimer { - struct FsmInst *fi; - struct timer_list tl; - int event; - void *arg; -}; - -int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount); -void FsmFree(struct Fsm *fsm); -int FsmEvent(struct FsmInst *fi, int event, void *arg); -void FsmChangeState(struct FsmInst *fi, int newstate); -void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft); -int FsmAddTimer(struct FsmTimer *ft, int millisec, int event, - void *arg, int where); -void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event, - void *arg, int where); -void FsmDelTimer(struct FsmTimer *ft, int where); - -#endif diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c deleted file mode 100644 index a6d8af02354a..000000000000 --- a/drivers/isdn/hisax/gazel.c +++ /dev/null @@ -1,691 +0,0 @@ -/* $Id: gazel.c,v 2.19.2.4 2004/01/14 16:04:48 keil Exp $ - * - * low level stuff for Gazel isdn cards - * - * Author BeWan Systems - * based on source code from Karsten Keil - * Copyright by BeWan Systems - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" -#include "ipac.h" -#include <linux/pci.h> - -static const char *gazel_revision = "$Revision: 2.19.2.4 $"; - -#define R647 1 -#define R685 2 -#define R753 3 -#define R742 4 - -#define PLX_CNTRL 0x50 /* registre de controle PLX */ -#define RESET_GAZEL 0x4 -#define RESET_9050 0x40000000 -#define PLX_INCSR 0x4C /* registre d'IT du 9050 */ -#define INT_ISAC_EN 0x8 /* 1 = enable IT isac */ -#define INT_ISAC 0x20 /* 1 = IT isac en cours */ -#define INT_HSCX_EN 0x1 /* 1 = enable IT hscx */ -#define INT_HSCX 0x4 /* 1 = IT hscx en cours */ -#define INT_PCI_EN 0x40 /* 1 = enable IT PCI */ -#define INT_IPAC_EN 0x3 /* enable IT ipac */ - - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static inline u_char -readreg(unsigned int adr, u_short off) -{ - return bytein(adr + off); -} - -static inline void -writereg(unsigned int adr, u_short off, u_char data) -{ - byteout(adr + off, data); -} - - -static inline void -read_fifo(unsigned int adr, u_char *data, int size) -{ - insb(adr, data, size); -} - -static void -write_fifo(unsigned int adr, u_char *data, int size) -{ - outsb(adr, data, size); -} - -static inline u_char -readreg_ipac(unsigned int adr, u_short off) -{ - register u_char ret; - - byteout(adr, off); - ret = bytein(adr + 4); - return ret; -} - -static inline void -writereg_ipac(unsigned int adr, u_short off, u_char data) -{ - byteout(adr, off); - byteout(adr + 4, data); -} - - -static inline void -read_fifo_ipac(unsigned int adr, u_short off, u_char *data, int size) -{ - byteout(adr, off); - insb(adr + 4, data, size); -} - -static void -write_fifo_ipac(unsigned int adr, u_short off, u_char *data, int size) -{ - byteout(adr, off); - outsb(adr + 4, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - u_short off2 = offset; - - switch (cs->subtyp) { - case R647: - off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); - /* fall through */ - case R685: - return (readreg(cs->hw.gazel.isac, off2)); - case R753: - case R742: - return (readreg_ipac(cs->hw.gazel.ipac, 0x80 + off2)); - } - return 0; -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - u_short off2 = offset; - - switch (cs->subtyp) { - case R647: - off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); - /* fall through */ - case R685: - writereg(cs->hw.gazel.isac, off2, value); - break; - case R753: - case R742: - writereg_ipac(cs->hw.gazel.ipac, 0x80 + off2, value); - break; - } -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - switch (cs->subtyp) { - case R647: - case R685: - read_fifo(cs->hw.gazel.isacfifo, data, size); - break; - case R753: - case R742: - read_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size); - break; - } -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - switch (cs->subtyp) { - case R647: - case R685: - write_fifo(cs->hw.gazel.isacfifo, data, size); - break; - case R753: - case R742: - write_fifo_ipac(cs->hw.gazel.ipac, 0x80, data, size); - break; - } -} - -static void -ReadHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size) -{ - switch (cs->subtyp) { - case R647: - case R685: - read_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); - break; - case R753: - case R742: - read_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size); - break; - } -} - -static void -WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char *data, int size) -{ - switch (cs->subtyp) { - case R647: - case R685: - write_fifo(cs->hw.gazel.hscxfifo[hscx], data, size); - break; - case R753: - case R742: - write_fifo_ipac(cs->hw.gazel.ipac, hscx * 0x40, data, size); - break; - } -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - u_short off2 = offset; - - switch (cs->subtyp) { - case R647: - off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); - /* fall through */ - case R685: - return (readreg(cs->hw.gazel.hscx[hscx], off2)); - case R753: - case R742: - return (readreg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2)); - } - return 0; -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - u_short off2 = offset; - - switch (cs->subtyp) { - case R647: - off2 = ((off2 << 8 & 0xf000) | (off2 & 0xf)); - /* fall through */ - case R685: - writereg(cs->hw.gazel.hscx[hscx], off2, value); - break; - case R753: - case R742: - writereg_ipac(cs->hw.gazel.ipac, hscx * 0x40 + off2, value); - break; - } -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) ReadHSCX(cs, nr, reg) -#define WRITEHSCX(cs, nr, reg, data) WriteHSCX(cs, nr, reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) ReadHSCXfifo(cs, nr, ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) WriteHSCXfifo(cs, nr, ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -gazel_interrupt(int intno, void *dev_id) -{ -#define MAXCOUNT 5 - struct IsdnCardState *cs = dev_id; - u_char valisac, valhscx; - int count = 0; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - do { - valhscx = ReadHSCX(cs, 1, HSCX_ISTA); - if (valhscx) - hscx_int_main(cs, valhscx); - valisac = ReadISAC(cs, ISAC_ISTA); - if (valisac) - isac_interrupt(cs, valisac); - count++; - } while ((valhscx || valisac) && (count < MAXCOUNT)); - - WriteHSCX(cs, 0, HSCX_MASK, 0xFF); - WriteHSCX(cs, 1, HSCX_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0xFF); - WriteISAC(cs, ISAC_MASK, 0x0); - WriteHSCX(cs, 0, HSCX_MASK, 0x0); - WriteHSCX(cs, 1, HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - - -static irqreturn_t -gazel_interrupt_ipac(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val; - int count = 0; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - ista = ReadISAC(cs, IPAC_ISTA - 0x80); - do { - if (ista & 0x0f) { - val = ReadHSCX(cs, 1, HSCX_ISTA); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) { - hscx_int_main(cs, val); - } - } - if (ista & 0x20) { - val = 0xfe & ReadISAC(cs, ISAC_ISTA); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = ReadISAC(cs, IPAC_ISTA - 0x80); - count++; - } - while ((ista & 0x3f) && (count < MAXCOUNT)); - - WriteISAC(cs, IPAC_MASK - 0x80, 0xFF); - WriteISAC(cs, IPAC_MASK - 0x80, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_gazel(struct IsdnCardState *cs) -{ - unsigned int i; - - switch (cs->subtyp) { - case R647: - for (i = 0x0000; i < 0xC000; i += 0x1000) - release_region(i + cs->hw.gazel.hscx[0], 16); - release_region(0xC000 + cs->hw.gazel.hscx[0], 1); - break; - - case R685: - release_region(cs->hw.gazel.hscx[0], 0x100); - release_region(cs->hw.gazel.cfg_reg, 0x80); - break; - - case R753: - release_region(cs->hw.gazel.ipac, 0x8); - release_region(cs->hw.gazel.cfg_reg, 0x80); - break; - - case R742: - release_region(cs->hw.gazel.ipac, 8); - break; - } -} - -static int -reset_gazel(struct IsdnCardState *cs) -{ - unsigned long plxcntrl, addr = cs->hw.gazel.cfg_reg; - - switch (cs->subtyp) { - case R647: - writereg(addr, 0, 0); - HZDELAY(10); - writereg(addr, 0, 1); - HZDELAY(2); - break; - case R685: - plxcntrl = inl(addr + PLX_CNTRL); - plxcntrl |= (RESET_9050 + RESET_GAZEL); - outl(plxcntrl, addr + PLX_CNTRL); - plxcntrl &= ~(RESET_9050 + RESET_GAZEL); - HZDELAY(4); - outl(plxcntrl, addr + PLX_CNTRL); - HZDELAY(10); - outb(INT_ISAC_EN + INT_HSCX_EN + INT_PCI_EN, addr + PLX_INCSR); - break; - case R753: - plxcntrl = inl(addr + PLX_CNTRL); - plxcntrl |= (RESET_9050 + RESET_GAZEL); - outl(plxcntrl, addr + PLX_CNTRL); - plxcntrl &= ~(RESET_9050 + RESET_GAZEL); - WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20); - HZDELAY(4); - outl(plxcntrl, addr + PLX_CNTRL); - HZDELAY(10); - WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00); - WriteISAC(cs, IPAC_ACFG - 0x80, 0xff); - WriteISAC(cs, IPAC_AOE - 0x80, 0x0); - WriteISAC(cs, IPAC_MASK - 0x80, 0xff); - WriteISAC(cs, IPAC_CONF - 0x80, 0x1); - outb(INT_IPAC_EN + INT_PCI_EN, addr + PLX_INCSR); - WriteISAC(cs, IPAC_MASK - 0x80, 0xc0); - break; - case R742: - WriteISAC(cs, IPAC_POTA2 - 0x80, 0x20); - HZDELAY(4); - WriteISAC(cs, IPAC_POTA2 - 0x80, 0x00); - WriteISAC(cs, IPAC_ACFG - 0x80, 0xff); - WriteISAC(cs, IPAC_AOE - 0x80, 0x0); - WriteISAC(cs, IPAC_MASK - 0x80, 0xff); - WriteISAC(cs, IPAC_CONF - 0x80, 0x1); - WriteISAC(cs, IPAC_MASK - 0x80, 0xc0); - break; - } - return (0); -} - -static int -Gazel_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_gazel(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_gazel(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 1); - if ((cs->subtyp == R647) || (cs->subtyp == R685)) { - int i; - for (i = 0; i < (2 + MAX_WAITING_CALLS); i++) { - cs->bcs[i].hw.hscx.tsaxr0 = 0x1f; - cs->bcs[i].hw.hscx.tsaxr1 = 0x23; - } - } - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int -reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs) -{ - unsigned int i, j, base = 0, adr = 0, len = 0; - - switch (cs->subtyp) { - case R647: - base = cs->hw.gazel.hscx[0]; - if (!request_region(adr = (0xC000 + base), len = 1, "gazel")) - goto error; - for (i = 0x0000; i < 0xC000; i += 0x1000) { - if (!request_region(adr = (i + base), len = 16, "gazel")) - goto error; - } - if (i != 0xC000) { - for (j = 0; j < i; j += 0x1000) - release_region(j + base, 16); - release_region(0xC000 + base, 1); - goto error; - } - break; - - case R685: - if (!request_region(adr = cs->hw.gazel.hscx[0], len = 0x100, "gazel")) - goto error; - if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) { - release_region(cs->hw.gazel.hscx[0], 0x100); - goto error; - } - break; - - case R753: - if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel")) - goto error; - if (!request_region(adr = cs->hw.gazel.cfg_reg, len = 0x80, "gazel")) { - release_region(cs->hw.gazel.ipac, 8); - goto error; - } - break; - - case R742: - if (!request_region(adr = cs->hw.gazel.ipac, len = 0x8, "gazel")) - goto error; - break; - } - - return 0; - -error: - printk(KERN_WARNING "Gazel: io ports 0x%x-0x%x already in use\n", - adr, adr + len); - return 1; -} - -static int setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs) -{ - printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n"); - // we got an irq parameter, assume it is an ISA card - // R742 decodes address even in not started... - // R647 returns FF if not present or not started - // eventually needs improvment - if (readreg_ipac(card->para[1], IPAC_ID) == 1) - cs->subtyp = R742; - else - cs->subtyp = R647; - - setup_isac(cs); - cs->hw.gazel.cfg_reg = card->para[1] + 0xC000; - cs->hw.gazel.ipac = card->para[1]; - cs->hw.gazel.isac = card->para[1] + 0x8000; - cs->hw.gazel.hscx[0] = card->para[1]; - cs->hw.gazel.hscx[1] = card->para[1] + 0x4000; - cs->irq = card->para[0]; - cs->hw.gazel.isacfifo = cs->hw.gazel.isac; - cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0]; - cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1]; - - switch (cs->subtyp) { - case R647: - printk(KERN_INFO "Gazel: Card ISA R647/R648 found\n"); - cs->dc.isac.adf2 = 0x87; - printk(KERN_INFO - "Gazel: config irq:%d isac:0x%X cfg:0x%X\n", - cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg); - printk(KERN_INFO - "Gazel: hscx A:0x%X hscx B:0x%X\n", - cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); - - break; - case R742: - printk(KERN_INFO "Gazel: Card ISA R742 found\n"); - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - printk(KERN_INFO - "Gazel: config irq:%d ipac:0x%X\n", - cs->irq, cs->hw.gazel.ipac); - break; - } - - return (0); -} - -#ifdef CONFIG_PCI -static struct pci_dev *dev_tel = NULL; - -static int setup_gazelpci(struct IsdnCardState *cs) -{ - u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0; - u_char pci_irq = 0, found; - u_int nbseek, seekcard; - - printk(KERN_WARNING "Gazel: PCI card automatic recognition\n"); - - found = 0; - seekcard = PCI_DEVICE_ID_PLX_R685; - for (nbseek = 0; nbseek < 4; nbseek++) { - if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_PLX, - seekcard, dev_tel))) { - if (pci_enable_device(dev_tel)) - return 1; - pci_irq = dev_tel->irq; - pci_ioaddr0 = pci_resource_start(dev_tel, 1); - pci_ioaddr1 = pci_resource_start(dev_tel, 2); - found = 1; - } - if (found) - break; - else { - switch (seekcard) { - case PCI_DEVICE_ID_PLX_R685: - seekcard = PCI_DEVICE_ID_PLX_R753; - break; - case PCI_DEVICE_ID_PLX_R753: - seekcard = PCI_DEVICE_ID_PLX_DJINN_ITOO; - break; - case PCI_DEVICE_ID_PLX_DJINN_ITOO: - seekcard = PCI_DEVICE_ID_PLX_OLITEC; - break; - } - } - } - if (!found) { - printk(KERN_WARNING "Gazel: No PCI card found\n"); - return (1); - } - if (!pci_irq) { - printk(KERN_WARNING "Gazel: No IRQ for PCI card found\n"); - return 1; - } - cs->hw.gazel.pciaddr[0] = pci_ioaddr0; - cs->hw.gazel.pciaddr[1] = pci_ioaddr1; - setup_isac(cs); - pci_ioaddr1 &= 0xfffe; - cs->hw.gazel.cfg_reg = pci_ioaddr0 & 0xfffe; - cs->hw.gazel.ipac = pci_ioaddr1; - cs->hw.gazel.isac = pci_ioaddr1 + 0x80; - cs->hw.gazel.hscx[0] = pci_ioaddr1; - cs->hw.gazel.hscx[1] = pci_ioaddr1 + 0x40; - cs->hw.gazel.isacfifo = cs->hw.gazel.isac; - cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0]; - cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1]; - cs->irq = pci_irq; - cs->irq_flags |= IRQF_SHARED; - - switch (seekcard) { - case PCI_DEVICE_ID_PLX_R685: - printk(KERN_INFO "Gazel: Card PCI R685 found\n"); - cs->subtyp = R685; - cs->dc.isac.adf2 = 0x87; - printk(KERN_INFO - "Gazel: config irq:%d isac:0x%X cfg:0x%X\n", - cs->irq, cs->hw.gazel.isac, cs->hw.gazel.cfg_reg); - printk(KERN_INFO - "Gazel: hscx A:0x%X hscx B:0x%X\n", - cs->hw.gazel.hscx[0], cs->hw.gazel.hscx[1]); - break; - case PCI_DEVICE_ID_PLX_R753: - case PCI_DEVICE_ID_PLX_DJINN_ITOO: - case PCI_DEVICE_ID_PLX_OLITEC: - printk(KERN_INFO "Gazel: Card PCI R753 found\n"); - cs->subtyp = R753; - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - printk(KERN_INFO - "Gazel: config irq:%d ipac:0x%X cfg:0x%X\n", - cs->irq, cs->hw.gazel.ipac, cs->hw.gazel.cfg_reg); - break; - } - - return (0); -} -#endif /* CONFIG_PCI */ - -int setup_gazel(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - u_char val; - - strcpy(tmp, gazel_revision); - printk(KERN_INFO "Gazel: Driver Revision %s\n", HiSax_getrev(tmp)); - - if (cs->typ != ISDN_CTYPE_GAZEL) - return (0); - - if (card->para[0]) { - if (setup_gazelisa(card, cs)) - return (0); - } else { - -#ifdef CONFIG_PCI - if (setup_gazelpci(cs)) - return (0); -#else - printk(KERN_WARNING "Gazel: Card PCI requested and NO_PCI_BIOS, unable to config\n"); - return (0); -#endif /* CONFIG_PCI */ - } - - if (reserve_regions(card, cs)) { - return (0); - } - if (reset_gazel(cs)) { - printk(KERN_WARNING "Gazel: wrong IRQ\n"); - release_io_gazel(cs); - return (0); - } - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Gazel_card_msg; - - switch (cs->subtyp) { - case R647: - case R685: - cs->irq_func = &gazel_interrupt; - ISACVersion(cs, "Gazel:"); - if (HscxVersion(cs, "Gazel:")) { - printk(KERN_WARNING - "Gazel: wrong HSCX versions check IO address\n"); - release_io_gazel(cs); - return (0); - } - break; - case R742: - case R753: - cs->irq_func = &gazel_interrupt_ipac; - val = ReadISAC(cs, IPAC_ID - 0x80); - printk(KERN_INFO "Gazel: IPAC version %x\n", val); - break; - } - - return (1); -} diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c deleted file mode 100644 index e9bb8fb67ad0..000000000000 --- a/drivers/isdn/hisax/hfc4s8s_l1.c +++ /dev/null @@ -1,1584 +0,0 @@ -/*************************************************************************/ -/* $Id: hfc4s8s_l1.c,v 1.10 2005/02/09 16:31:09 martinb1 Exp $ */ -/* HFC-4S/8S low layer interface for Cologne Chip HFC-4S/8S isdn chips */ -/* The low layer (L1) is implemented as a loadable module for usage with */ -/* the HiSax isdn driver for passive cards. */ -/* */ -/* Author: Werner Cornelius */ -/* (C) 2003 Cornelius Consult (werner@cornelius-consult.de) */ -/* */ -/* Driver maintained by Cologne Chip */ -/* - Martin Bachem, support@colognechip.com */ -/* */ -/* This driver only works with chip revisions >= 1, older revision 0 */ -/* engineering samples (only first manufacturer sample cards) will not */ -/* work and are rejected by the driver. */ -/* */ -/* This file distributed under the GNU GPL. */ -/* */ -/* See Version History at the end of this file */ -/* */ -/*************************************************************************/ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/timer.h> -#include <linux/skbuff.h> -#include <linux/wait.h> -#include <asm/io.h> -#include "hisax_if.h" -#include "hfc4s8s_l1.h" - -static const char hfc4s8s_rev[] = "Revision: 1.10"; - -/***************************************************************/ -/* adjustable transparent mode fifo threshold */ -/* The value defines the used fifo threshold with the equation */ -/* */ -/* notify number of bytes = 2 * 2 ^ TRANS_FIFO_THRES */ -/* */ -/* The default value is 5 which results in a buffer size of 64 */ -/* and an interrupt rate of 8ms. */ -/* The maximum value is 7 due to fifo size restrictions. */ -/* Values below 3-4 are not recommended due to high interrupt */ -/* load of the processor. For non critical applications the */ -/* value should be raised to 7 to reduce any interrupt overhead*/ -/***************************************************************/ -#define TRANS_FIFO_THRES 5 - -/*************/ -/* constants */ -/*************/ -#define CLOCKMODE_0 0 /* ext. 24.576 MhZ clk freq, int. single clock mode */ -#define CLOCKMODE_1 1 /* ext. 49.576 MhZ clk freq, int. single clock mode */ -#define CHIP_ID_SHIFT 4 -#define HFC_MAX_ST 8 -#define MAX_D_FRAME_SIZE 270 -#define MAX_B_FRAME_SIZE 1536 -#define TRANS_TIMER_MODE (TRANS_FIFO_THRES & 0xf) -#define TRANS_FIFO_BYTES (2 << TRANS_FIFO_THRES) -#define MAX_F_CNT 0x0f - -#define CLKDEL_NT 0x6c -#define CLKDEL_TE 0xf -#define CTRL0_NT 4 -#define CTRL0_TE 0 - -#define L1_TIMER_T4 2 /* minimum in jiffies */ -#define L1_TIMER_T3 (7 * HZ) /* activation timeout */ -#define L1_TIMER_T1 ((120 * HZ) / 1000) /* NT mode deactivation timeout */ - - -/******************/ -/* types and vars */ -/******************/ -static int card_cnt; - -/* private driver_data */ -typedef struct { - int chip_id; - int clock_mode; - int max_st_ports; - char *device_name; -} hfc4s8s_param; - -static const struct pci_device_id hfc4s8s_ids[] = { - {.vendor = PCI_VENDOR_ID_CCD, - .device = PCI_DEVICE_ID_4S, - .subvendor = 0x1397, - .subdevice = 0x08b4, - .driver_data = - (unsigned long) &((hfc4s8s_param) {CHIP_ID_4S, CLOCKMODE_0, 4, - "HFC-4S Evaluation Board"}), - }, - {.vendor = PCI_VENDOR_ID_CCD, - .device = PCI_DEVICE_ID_8S, - .subvendor = 0x1397, - .subdevice = 0x16b8, - .driver_data = - (unsigned long) &((hfc4s8s_param) {CHIP_ID_8S, CLOCKMODE_0, 8, - "HFC-8S Evaluation Board"}), - }, - {.vendor = PCI_VENDOR_ID_CCD, - .device = PCI_DEVICE_ID_4S, - .subvendor = 0x1397, - .subdevice = 0xb520, - .driver_data = - (unsigned long) &((hfc4s8s_param) {CHIP_ID_4S, CLOCKMODE_1, 4, - "IOB4ST"}), - }, - {.vendor = PCI_VENDOR_ID_CCD, - .device = PCI_DEVICE_ID_8S, - .subvendor = 0x1397, - .subdevice = 0xb522, - .driver_data = - (unsigned long) &((hfc4s8s_param) {CHIP_ID_8S, CLOCKMODE_1, 8, - "IOB8ST"}), - }, - {} -}; - -MODULE_DEVICE_TABLE(pci, hfc4s8s_ids); - -MODULE_AUTHOR("Werner Cornelius, werner@cornelius-consult.de"); -MODULE_DESCRIPTION("ISDN layer 1 for Cologne Chip HFC-4S/8S chips"); -MODULE_LICENSE("GPL"); - -/***********/ -/* layer 1 */ -/***********/ -struct hfc4s8s_btype { - spinlock_t lock; - struct hisax_b_if b_if; - struct hfc4s8s_l1 *l1p; - struct sk_buff_head tx_queue; - struct sk_buff *tx_skb; - struct sk_buff *rx_skb; - __u8 *rx_ptr; - int tx_cnt; - int bchan; - int mode; -}; - -struct _hfc4s8s_hw; - -struct hfc4s8s_l1 { - spinlock_t lock; - struct _hfc4s8s_hw *hw; /* pointer to hardware area */ - int l1_state; /* actual l1 state */ - struct timer_list l1_timer; /* layer 1 timer structure */ - int nt_mode; /* set to nt mode */ - int st_num; /* own index */ - int enabled; /* interface is enabled */ - struct sk_buff_head d_tx_queue; /* send queue */ - int tx_cnt; /* bytes to send */ - struct hisax_d_if d_if; /* D-channel interface */ - struct hfc4s8s_btype b_ch[2]; /* B-channel data */ - struct hisax_b_if *b_table[2]; -}; - -/**********************/ -/* hardware structure */ -/**********************/ -typedef struct _hfc4s8s_hw { - spinlock_t lock; - - int cardnum; - int ifnum; - int iobase; - int nt_mode; - u_char *membase; - u_char *hw_membase; - void *pdev; - int max_fifo; - hfc4s8s_param driver_data; - int irq; - int fifo_sched_cnt; - struct work_struct tqueue; - struct hfc4s8s_l1 l1[HFC_MAX_ST]; - char card_name[60]; - struct { - u_char r_irq_ctrl; - u_char r_ctrl0; - volatile u_char r_irq_statech; /* active isdn l1 status */ - u_char r_irqmsk_statchg; /* enabled isdn status ints */ - u_char r_irq_fifo_blx[8]; /* fifo status registers */ - u_char fifo_rx_trans_enables[8]; /* mask for enabled transparent rx fifos */ - u_char fifo_slow_timer_service[8]; /* mask for fifos needing slower timer service */ - volatile u_char r_irq_oview; /* contents of overview register */ - volatile u_char timer_irq; - int timer_usg_cnt; /* number of channels using timer */ - } mr; -} hfc4s8s_hw; - - - -/* inline functions io mapped */ -static inline void -SetRegAddr(hfc4s8s_hw *a, u_char b) -{ - outb(b, (a->iobase) + 4); -} - -static inline u_char -GetRegAddr(hfc4s8s_hw *a) -{ - return (inb((volatile u_int) (a->iobase + 4))); -} - - -static inline void -Write_hfc8(hfc4s8s_hw *a, u_char b, u_char c) -{ - SetRegAddr(a, b); - outb(c, a->iobase); -} - -static inline void -fWrite_hfc8(hfc4s8s_hw *a, u_char c) -{ - outb(c, a->iobase); -} - -static inline void -fWrite_hfc32(hfc4s8s_hw *a, u_long c) -{ - outl(c, a->iobase); -} - -static inline u_char -Read_hfc8(hfc4s8s_hw *a, u_char b) -{ - SetRegAddr(a, b); - return (inb((volatile u_int) a->iobase)); -} - -static inline u_char -fRead_hfc8(hfc4s8s_hw *a) -{ - return (inb((volatile u_int) a->iobase)); -} - - -static inline u_short -Read_hfc16(hfc4s8s_hw *a, u_char b) -{ - SetRegAddr(a, b); - return (inw((volatile u_int) a->iobase)); -} - -static inline u_long -fRead_hfc32(hfc4s8s_hw *a) -{ - return (inl((volatile u_int) a->iobase)); -} - -static inline void -wait_busy(hfc4s8s_hw *a) -{ - SetRegAddr(a, R_STATUS); - while (inb((volatile u_int) a->iobase) & M_BUSY); -} - -#define PCI_ENA_REGIO 0x01 - -/******************************************************/ -/* function to read critical counter registers that */ -/* may be updated by the chip during read */ -/******************************************************/ -static u_char -Read_hfc8_stable(hfc4s8s_hw *hw, int reg) -{ - u_char ref8; - u_char in8; - ref8 = Read_hfc8(hw, reg); - while (((in8 = Read_hfc8(hw, reg)) != ref8)) { - ref8 = in8; - } - return in8; -} - -static int -Read_hfc16_stable(hfc4s8s_hw *hw, int reg) -{ - int ref16; - int in16; - - ref16 = Read_hfc16(hw, reg); - while (((in16 = Read_hfc16(hw, reg)) != ref16)) { - ref16 = in16; - } - return in16; -} - -/*****************************/ -/* D-channel call from HiSax */ -/*****************************/ -static void -dch_l2l1(struct hisax_d_if *iface, int pr, void *arg) -{ - struct hfc4s8s_l1 *l1 = iface->ifc.priv; - struct sk_buff *skb = (struct sk_buff *) arg; - u_long flags; - - switch (pr) { - - case (PH_DATA | REQUEST): - if (!l1->enabled) { - dev_kfree_skb(skb); - break; - } - spin_lock_irqsave(&l1->lock, flags); - skb_queue_tail(&l1->d_tx_queue, skb); - if ((skb_queue_len(&l1->d_tx_queue) == 1) && - (l1->tx_cnt <= 0)) { - l1->hw->mr.r_irq_fifo_blx[l1->st_num] |= - 0x10; - spin_unlock_irqrestore(&l1->lock, flags); - schedule_work(&l1->hw->tqueue); - } else - spin_unlock_irqrestore(&l1->lock, flags); - break; - - case (PH_ACTIVATE | REQUEST): - if (!l1->enabled) - break; - if (!l1->nt_mode) { - if (l1->l1_state < 6) { - spin_lock_irqsave(&l1->lock, - flags); - - Write_hfc8(l1->hw, R_ST_SEL, - l1->st_num); - Write_hfc8(l1->hw, A_ST_WR_STA, - 0x60); - mod_timer(&l1->l1_timer, - jiffies + L1_TIMER_T3); - spin_unlock_irqrestore(&l1->lock, - flags); - } else if (l1->l1_state == 7) - l1->d_if.ifc.l1l2(&l1->d_if.ifc, - PH_ACTIVATE | - INDICATION, - NULL); - } else { - if (l1->l1_state != 3) { - spin_lock_irqsave(&l1->lock, - flags); - Write_hfc8(l1->hw, R_ST_SEL, - l1->st_num); - Write_hfc8(l1->hw, A_ST_WR_STA, - 0x60); - spin_unlock_irqrestore(&l1->lock, - flags); - } else if (l1->l1_state == 3) - l1->d_if.ifc.l1l2(&l1->d_if.ifc, - PH_ACTIVATE | - INDICATION, - NULL); - } - break; - - default: - printk(KERN_INFO - "HFC-4S/8S: Unknown D-chan cmd 0x%x received, ignored\n", - pr); - break; - } - if (!l1->enabled) - l1->d_if.ifc.l1l2(&l1->d_if.ifc, - PH_DEACTIVATE | INDICATION, NULL); -} /* dch_l2l1 */ - -/*****************************/ -/* B-channel call from HiSax */ -/*****************************/ -static void -bch_l2l1(struct hisax_if *ifc, int pr, void *arg) -{ - struct hfc4s8s_btype *bch = ifc->priv; - struct hfc4s8s_l1 *l1 = bch->l1p; - struct sk_buff *skb = (struct sk_buff *) arg; - long mode = (long) arg; - u_long flags; - - switch (pr) { - - case (PH_DATA | REQUEST): - if (!l1->enabled || (bch->mode == L1_MODE_NULL)) { - dev_kfree_skb(skb); - break; - } - spin_lock_irqsave(&l1->lock, flags); - skb_queue_tail(&bch->tx_queue, skb); - if (!bch->tx_skb && (bch->tx_cnt <= 0)) { - l1->hw->mr.r_irq_fifo_blx[l1->st_num] |= - ((bch->bchan == 1) ? 1 : 4); - spin_unlock_irqrestore(&l1->lock, flags); - schedule_work(&l1->hw->tqueue); - } else - spin_unlock_irqrestore(&l1->lock, flags); - break; - - case (PH_ACTIVATE | REQUEST): - case (PH_DEACTIVATE | REQUEST): - if (!l1->enabled) - break; - if (pr == (PH_DEACTIVATE | REQUEST)) - mode = L1_MODE_NULL; - - switch (mode) { - case L1_MODE_HDLC: - spin_lock_irqsave(&l1->lock, - flags); - l1->hw->mr.timer_usg_cnt++; - l1->hw->mr. - fifo_slow_timer_service[l1-> - st_num] - |= - ((bch->bchan == - 1) ? 0x2 : 0x8); - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 0 : 2))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_CON_HDLC, 0xc); /* HDLC mode, flag fill, connect ST */ - Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */ - Write_hfc8(l1->hw, A_IRQ_MSK, 1); /* enable TX interrupts for hdlc */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(l1->hw); - - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 1 : 3))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_CON_HDLC, 0xc); /* HDLC mode, flag fill, connect ST */ - Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */ - Write_hfc8(l1->hw, A_IRQ_MSK, 1); /* enable RX interrupts for hdlc */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ - - Write_hfc8(l1->hw, R_ST_SEL, - l1->st_num); - l1->hw->mr.r_ctrl0 |= - (bch->bchan & 3); - Write_hfc8(l1->hw, A_ST_CTRL0, - l1->hw->mr.r_ctrl0); - bch->mode = L1_MODE_HDLC; - spin_unlock_irqrestore(&l1->lock, - flags); - - bch->b_if.ifc.l1l2(&bch->b_if.ifc, - PH_ACTIVATE | - INDICATION, - NULL); - break; - - case L1_MODE_TRANS: - spin_lock_irqsave(&l1->lock, - flags); - l1->hw->mr. - fifo_rx_trans_enables[l1-> - st_num] - |= - ((bch->bchan == - 1) ? 0x2 : 0x8); - l1->hw->mr.timer_usg_cnt++; - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 0 : 2))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_CON_HDLC, 0xf); /* Transparent mode, 1 fill, connect ST */ - Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */ - Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable TX interrupts */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(l1->hw); - - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 1 : 3))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_CON_HDLC, 0xf); /* Transparent mode, 1 fill, connect ST */ - Write_hfc8(l1->hw, A_SUBCH_CFG, 0); /* 8 bits */ - Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable RX interrupts */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ - - Write_hfc8(l1->hw, R_ST_SEL, - l1->st_num); - l1->hw->mr.r_ctrl0 |= - (bch->bchan & 3); - Write_hfc8(l1->hw, A_ST_CTRL0, - l1->hw->mr.r_ctrl0); - bch->mode = L1_MODE_TRANS; - spin_unlock_irqrestore(&l1->lock, - flags); - - bch->b_if.ifc.l1l2(&bch->b_if.ifc, - PH_ACTIVATE | - INDICATION, - NULL); - break; - - default: - if (bch->mode == L1_MODE_NULL) - break; - spin_lock_irqsave(&l1->lock, - flags); - l1->hw->mr. - fifo_slow_timer_service[l1-> - st_num] - &= - ~((bch->bchan == - 1) ? 0x3 : 0xc); - l1->hw->mr. - fifo_rx_trans_enables[l1-> - st_num] - &= - ~((bch->bchan == - 1) ? 0x3 : 0xc); - l1->hw->mr.timer_usg_cnt--; - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 0 : 2))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable TX interrupts */ - wait_busy(l1->hw); - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == - 1) ? 1 : 3))); - wait_busy(l1->hw); - Write_hfc8(l1->hw, A_IRQ_MSK, 0); /* disable RX interrupts */ - Write_hfc8(l1->hw, R_ST_SEL, - l1->st_num); - l1->hw->mr.r_ctrl0 &= - ~(bch->bchan & 3); - Write_hfc8(l1->hw, A_ST_CTRL0, - l1->hw->mr.r_ctrl0); - spin_unlock_irqrestore(&l1->lock, - flags); - - bch->mode = L1_MODE_NULL; - bch->b_if.ifc.l1l2(&bch->b_if.ifc, - PH_DEACTIVATE | - INDICATION, - NULL); - if (bch->tx_skb) { - dev_kfree_skb(bch->tx_skb); - bch->tx_skb = NULL; - } - if (bch->rx_skb) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; - } - skb_queue_purge(&bch->tx_queue); - bch->tx_cnt = 0; - bch->rx_ptr = NULL; - break; - } - - /* timer is only used when at least one b channel */ - /* is set up to transparent mode */ - if (l1->hw->mr.timer_usg_cnt) { - Write_hfc8(l1->hw, R_IRQMSK_MISC, - M_TI_IRQMSK); - } else { - Write_hfc8(l1->hw, R_IRQMSK_MISC, 0); - } - - break; - - default: - printk(KERN_INFO - "HFC-4S/8S: Unknown B-chan cmd 0x%x received, ignored\n", - pr); - break; - } - if (!l1->enabled) - bch->b_if.ifc.l1l2(&bch->b_if.ifc, - PH_DEACTIVATE | INDICATION, NULL); -} /* bch_l2l1 */ - -/**************************/ -/* layer 1 timer function */ -/**************************/ -static void -hfc_l1_timer(struct timer_list *t) -{ - struct hfc4s8s_l1 *l1 = from_timer(l1, t, l1_timer); - u_long flags; - - if (!l1->enabled) - return; - - spin_lock_irqsave(&l1->lock, flags); - if (l1->nt_mode) { - l1->l1_state = 1; - Write_hfc8(l1->hw, R_ST_SEL, l1->st_num); - Write_hfc8(l1->hw, A_ST_WR_STA, 0x11); - spin_unlock_irqrestore(&l1->lock, flags); - l1->d_if.ifc.l1l2(&l1->d_if.ifc, - PH_DEACTIVATE | INDICATION, NULL); - spin_lock_irqsave(&l1->lock, flags); - l1->l1_state = 1; - Write_hfc8(l1->hw, A_ST_WR_STA, 0x1); - spin_unlock_irqrestore(&l1->lock, flags); - } else { - /* activation timed out */ - Write_hfc8(l1->hw, R_ST_SEL, l1->st_num); - Write_hfc8(l1->hw, A_ST_WR_STA, 0x13); - spin_unlock_irqrestore(&l1->lock, flags); - l1->d_if.ifc.l1l2(&l1->d_if.ifc, - PH_DEACTIVATE | INDICATION, NULL); - spin_lock_irqsave(&l1->lock, flags); - Write_hfc8(l1->hw, R_ST_SEL, l1->st_num); - Write_hfc8(l1->hw, A_ST_WR_STA, 0x3); - spin_unlock_irqrestore(&l1->lock, flags); - } -} /* hfc_l1_timer */ - -/****************************************/ -/* a complete D-frame has been received */ -/****************************************/ -static void -rx_d_frame(struct hfc4s8s_l1 *l1p, int ech) -{ - int z1, z2; - u_char f1, f2, df; - struct sk_buff *skb; - u_char *cp; - - - if (!l1p->enabled) - return; - do { - /* E/D RX fifo */ - Write_hfc8(l1p->hw, R_FIFO, - (l1p->st_num * 8 + ((ech) ? 7 : 5))); - wait_busy(l1p->hw); - - f1 = Read_hfc8_stable(l1p->hw, A_F1); - f2 = Read_hfc8(l1p->hw, A_F2); - - if (f1 < f2) - df = MAX_F_CNT + 1 + f1 - f2; - else - df = f1 - f2; - - if (!df) - return; /* no complete frame in fifo */ - - z1 = Read_hfc16_stable(l1p->hw, A_Z1); - z2 = Read_hfc16(l1p->hw, A_Z2); - - z1 = z1 - z2 + 1; - if (z1 < 0) - z1 += 384; - - if (!(skb = dev_alloc_skb(MAX_D_FRAME_SIZE))) { - printk(KERN_INFO - "HFC-4S/8S: Could not allocate D/E " - "channel receive buffer"); - Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2); - wait_busy(l1p->hw); - return; - } - - if (((z1 < 4) || (z1 > MAX_D_FRAME_SIZE))) { - if (skb) - dev_kfree_skb(skb); - /* remove errornous D frame */ - if (df == 1) { - /* reset fifo */ - Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2); - wait_busy(l1p->hw); - return; - } else { - /* read errornous D frame */ - SetRegAddr(l1p->hw, A_FIFO_DATA0); - - while (z1 >= 4) { - fRead_hfc32(l1p->hw); - z1 -= 4; - } - - while (z1--) - fRead_hfc8(l1p->hw); - - Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); - wait_busy(l1p->hw); - return; - } - } - - cp = skb->data; - - SetRegAddr(l1p->hw, A_FIFO_DATA0); - - while (z1 >= 4) { - *((unsigned long *) cp) = fRead_hfc32(l1p->hw); - cp += 4; - z1 -= 4; - } - - while (z1--) - *cp++ = fRead_hfc8(l1p->hw); - - Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */ - wait_busy(l1p->hw); - - if (*(--cp)) { - dev_kfree_skb(skb); - } else { - skb->len = (cp - skb->data) - 2; - if (ech) - l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, - PH_DATA_E | INDICATION, - skb); - else - l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, - PH_DATA | INDICATION, - skb); - } - } while (1); -} /* rx_d_frame */ - -/*************************************************************/ -/* a B-frame has been received (perhaps not fully completed) */ -/*************************************************************/ -static void -rx_b_frame(struct hfc4s8s_btype *bch) -{ - int z1, z2, hdlc_complete; - u_char f1, f2; - struct hfc4s8s_l1 *l1 = bch->l1p; - struct sk_buff *skb; - - if (!l1->enabled || (bch->mode == L1_MODE_NULL)) - return; - - do { - /* RX Fifo */ - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + ((bch->bchan == 1) ? 1 : 3))); - wait_busy(l1->hw); - - if (bch->mode == L1_MODE_HDLC) { - f1 = Read_hfc8_stable(l1->hw, A_F1); - f2 = Read_hfc8(l1->hw, A_F2); - hdlc_complete = ((f1 ^ f2) & MAX_F_CNT); - } else - hdlc_complete = 0; - z1 = Read_hfc16_stable(l1->hw, A_Z1); - z2 = Read_hfc16(l1->hw, A_Z2); - z1 = (z1 - z2); - if (hdlc_complete) - z1++; - if (z1 < 0) - z1 += 384; - - if (!z1) - break; - - if (!(skb = bch->rx_skb)) { - if (! - (skb = - dev_alloc_skb((bch->mode == - L1_MODE_TRANS) ? z1 - : (MAX_B_FRAME_SIZE + 3)))) { - printk(KERN_ERR - "HFC-4S/8S: Could not allocate B " - "channel receive buffer"); - return; - } - bch->rx_ptr = skb->data; - bch->rx_skb = skb; - } - - skb->len = (bch->rx_ptr - skb->data) + z1; - - /* HDLC length check */ - if ((bch->mode == L1_MODE_HDLC) && - ((hdlc_complete && (skb->len < 4)) || - (skb->len > (MAX_B_FRAME_SIZE + 3)))) { - - skb->len = 0; - bch->rx_ptr = skb->data; - Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(l1->hw); - return; - } - SetRegAddr(l1->hw, A_FIFO_DATA0); - - while (z1 >= 4) { - *((unsigned long *) bch->rx_ptr) = - fRead_hfc32(l1->hw); - bch->rx_ptr += 4; - z1 -= 4; - } - - while (z1--) - *(bch->rx_ptr++) = fRead_hfc8(l1->hw); - - if (hdlc_complete) { - /* increment f counter */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 1); - wait_busy(l1->hw); - - /* hdlc crc check */ - bch->rx_ptr--; - if (*bch->rx_ptr) { - skb->len = 0; - bch->rx_ptr = skb->data; - continue; - } - skb->len -= 3; - } - if (hdlc_complete || (bch->mode == L1_MODE_TRANS)) { - bch->rx_skb = NULL; - bch->rx_ptr = NULL; - bch->b_if.ifc.l1l2(&bch->b_if.ifc, - PH_DATA | INDICATION, skb); - } - - } while (1); -} /* rx_b_frame */ - -/********************************************/ -/* a D-frame has been/should be transmitted */ -/********************************************/ -static void -tx_d_frame(struct hfc4s8s_l1 *l1p) -{ - struct sk_buff *skb; - u_char f1, f2; - u_char *cp; - long cnt; - - if (l1p->l1_state != 7) - return; - - /* TX fifo */ - Write_hfc8(l1p->hw, R_FIFO, (l1p->st_num * 8 + 4)); - wait_busy(l1p->hw); - - f1 = Read_hfc8(l1p->hw, A_F1); - f2 = Read_hfc8_stable(l1p->hw, A_F2); - - if ((f1 ^ f2) & MAX_F_CNT) - return; /* fifo is still filled */ - - if (l1p->tx_cnt > 0) { - cnt = l1p->tx_cnt; - l1p->tx_cnt = 0; - l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA | CONFIRM, - (void *) cnt); - } - - if ((skb = skb_dequeue(&l1p->d_tx_queue))) { - cp = skb->data; - cnt = skb->len; - SetRegAddr(l1p->hw, A_FIFO_DATA0); - - while (cnt >= 4) { - SetRegAddr(l1p->hw, A_FIFO_DATA0); - fWrite_hfc32(l1p->hw, *(unsigned long *) cp); - cp += 4; - cnt -= 4; - } - - while (cnt--) - fWrite_hfc8(l1p->hw, *cp++); - - l1p->tx_cnt = skb->truesize; - Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */ - wait_busy(l1p->hw); - - dev_kfree_skb(skb); - } -} /* tx_d_frame */ - -/******************************************************/ -/* a B-frame may be transmitted (or is not completed) */ -/******************************************************/ -static void -tx_b_frame(struct hfc4s8s_btype *bch) -{ - struct sk_buff *skb; - struct hfc4s8s_l1 *l1 = bch->l1p; - u_char *cp; - int cnt, max, hdlc_num; - long ack_len = 0; - - if (!l1->enabled || (bch->mode == L1_MODE_NULL)) - return; - - /* TX fifo */ - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + ((bch->bchan == 1) ? 0 : 2))); - wait_busy(l1->hw); - do { - - if (bch->mode == L1_MODE_HDLC) { - hdlc_num = Read_hfc8(l1->hw, A_F1) & MAX_F_CNT; - hdlc_num -= - (Read_hfc8_stable(l1->hw, A_F2) & MAX_F_CNT); - if (hdlc_num < 0) - hdlc_num += 16; - if (hdlc_num >= 15) - break; /* fifo still filled up with hdlc frames */ - } else - hdlc_num = 0; - - if (!(skb = bch->tx_skb)) { - if (!(skb = skb_dequeue(&bch->tx_queue))) { - l1->hw->mr.fifo_slow_timer_service[l1-> - st_num] - &= ~((bch->bchan == 1) ? 1 : 4); - break; /* list empty */ - } - bch->tx_skb = skb; - bch->tx_cnt = 0; - } - - if (!hdlc_num) - l1->hw->mr.fifo_slow_timer_service[l1->st_num] |= - ((bch->bchan == 1) ? 1 : 4); - else - l1->hw->mr.fifo_slow_timer_service[l1->st_num] &= - ~((bch->bchan == 1) ? 1 : 4); - - max = Read_hfc16_stable(l1->hw, A_Z2); - max -= Read_hfc16(l1->hw, A_Z1); - if (max <= 0) - max += 384; - max--; - - if (max < 16) - break; /* don't write to small amounts of bytes */ - - cnt = skb->len - bch->tx_cnt; - if (cnt > max) - cnt = max; - cp = skb->data + bch->tx_cnt; - bch->tx_cnt += cnt; - - SetRegAddr(l1->hw, A_FIFO_DATA0); - while (cnt >= 4) { - fWrite_hfc32(l1->hw, *(unsigned long *) cp); - cp += 4; - cnt -= 4; - } - - while (cnt--) - fWrite_hfc8(l1->hw, *cp++); - - if (bch->tx_cnt >= skb->len) { - if (bch->mode == L1_MODE_HDLC) { - /* increment f counter */ - Write_hfc8(l1->hw, A_INC_RES_FIFO, 1); - } - ack_len += skb->truesize; - bch->tx_skb = NULL; - bch->tx_cnt = 0; - dev_kfree_skb(skb); - } else - /* Re-Select */ - Write_hfc8(l1->hw, R_FIFO, - (l1->st_num * 8 + - ((bch->bchan == 1) ? 0 : 2))); - wait_busy(l1->hw); - } while (1); - - if (ack_len) - bch->b_if.ifc.l1l2((struct hisax_if *) &bch->b_if, - PH_DATA | CONFIRM, (void *) ack_len); -} /* tx_b_frame */ - -/*************************************/ -/* bottom half handler for interrupt */ -/*************************************/ -static void -hfc4s8s_bh(struct work_struct *work) -{ - hfc4s8s_hw *hw = container_of(work, hfc4s8s_hw, tqueue); - u_char b; - struct hfc4s8s_l1 *l1p; - volatile u_char *fifo_stat; - int idx; - - /* handle layer 1 state changes */ - b = 1; - l1p = hw->l1; - while (b) { - if ((b & hw->mr.r_irq_statech)) { - /* reset l1 event */ - hw->mr.r_irq_statech &= ~b; - if (l1p->enabled) { - if (l1p->nt_mode) { - u_char oldstate = l1p->l1_state; - - Write_hfc8(l1p->hw, R_ST_SEL, - l1p->st_num); - l1p->l1_state = - Read_hfc8(l1p->hw, - A_ST_RD_STA) & 0xf; - - if ((oldstate == 3) - && (l1p->l1_state != 3)) - l1p->d_if.ifc.l1l2(&l1p-> - d_if. - ifc, - PH_DEACTIVATE - | - INDICATION, - NULL); - - if (l1p->l1_state != 2) { - del_timer(&l1p->l1_timer); - if (l1p->l1_state == 3) { - l1p->d_if.ifc. - l1l2(&l1p-> - d_if.ifc, - PH_ACTIVATE - | - INDICATION, - NULL); - } - } else { - /* allow transition */ - Write_hfc8(hw, A_ST_WR_STA, - M_SET_G2_G3); - mod_timer(&l1p->l1_timer, - jiffies + - L1_TIMER_T1); - } - printk(KERN_INFO - "HFC-4S/8S: NT ch %d l1 state %d -> %d\n", - l1p->st_num, oldstate, - l1p->l1_state); - } else { - u_char oldstate = l1p->l1_state; - - Write_hfc8(l1p->hw, R_ST_SEL, - l1p->st_num); - l1p->l1_state = - Read_hfc8(l1p->hw, - A_ST_RD_STA) & 0xf; - - if (((l1p->l1_state == 3) && - ((oldstate == 7) || - (oldstate == 8))) || - ((timer_pending - (&l1p->l1_timer)) - && (l1p->l1_state == 8))) { - mod_timer(&l1p->l1_timer, - L1_TIMER_T4 + - jiffies); - } else { - if (l1p->l1_state == 7) { - del_timer(&l1p-> - l1_timer); - l1p->d_if.ifc. - l1l2(&l1p-> - d_if.ifc, - PH_ACTIVATE - | - INDICATION, - NULL); - tx_d_frame(l1p); - } - if (l1p->l1_state == 3) { - if (oldstate != 3) - l1p->d_if. - ifc. - l1l2 - (&l1p-> - d_if. - ifc, - PH_DEACTIVATE - | - INDICATION, - NULL); - } - } - printk(KERN_INFO - "HFC-4S/8S: TE %d ch %d l1 state %d -> %d\n", - l1p->hw->cardnum, - l1p->st_num, oldstate, - l1p->l1_state); - } - } - } - b <<= 1; - l1p++; - } - - /* now handle the fifos */ - idx = 0; - fifo_stat = hw->mr.r_irq_fifo_blx; - l1p = hw->l1; - while (idx < hw->driver_data.max_st_ports) { - - if (hw->mr.timer_irq) { - *fifo_stat |= hw->mr.fifo_rx_trans_enables[idx]; - if (hw->fifo_sched_cnt <= 0) { - *fifo_stat |= - hw->mr.fifo_slow_timer_service[l1p-> - st_num]; - } - } - /* ignore fifo 6 (TX E fifo) */ - *fifo_stat &= 0xff - 0x40; - - while (*fifo_stat) { - - if (!l1p->nt_mode) { - /* RX Fifo has data to read */ - if ((*fifo_stat & 0x20)) { - *fifo_stat &= ~0x20; - rx_d_frame(l1p, 0); - } - /* E Fifo has data to read */ - if ((*fifo_stat & 0x80)) { - *fifo_stat &= ~0x80; - rx_d_frame(l1p, 1); - } - /* TX Fifo completed send */ - if ((*fifo_stat & 0x10)) { - *fifo_stat &= ~0x10; - tx_d_frame(l1p); - } - } - /* B1 RX Fifo has data to read */ - if ((*fifo_stat & 0x2)) { - *fifo_stat &= ~0x2; - rx_b_frame(l1p->b_ch); - } - /* B1 TX Fifo has send completed */ - if ((*fifo_stat & 0x1)) { - *fifo_stat &= ~0x1; - tx_b_frame(l1p->b_ch); - } - /* B2 RX Fifo has data to read */ - if ((*fifo_stat & 0x8)) { - *fifo_stat &= ~0x8; - rx_b_frame(l1p->b_ch + 1); - } - /* B2 TX Fifo has send completed */ - if ((*fifo_stat & 0x4)) { - *fifo_stat &= ~0x4; - tx_b_frame(l1p->b_ch + 1); - } - } - fifo_stat++; - l1p++; - idx++; - } - - if (hw->fifo_sched_cnt <= 0) - hw->fifo_sched_cnt += (1 << (7 - TRANS_TIMER_MODE)); - hw->mr.timer_irq = 0; /* clear requested timer irq */ -} /* hfc4s8s_bh */ - -/*********************/ -/* interrupt handler */ -/*********************/ -static irqreturn_t -hfc4s8s_interrupt(int intno, void *dev_id) -{ - hfc4s8s_hw *hw = dev_id; - u_char b, ovr; - volatile u_char *ovp; - int idx; - u_char old_ioreg; - - if (!hw || !(hw->mr.r_irq_ctrl & M_GLOB_IRQ_EN)) - return IRQ_NONE; - - /* read current selected regsister */ - old_ioreg = GetRegAddr(hw); - - /* Layer 1 State change */ - hw->mr.r_irq_statech |= - (Read_hfc8(hw, R_SCI) & hw->mr.r_irqmsk_statchg); - if (! - (b = (Read_hfc8(hw, R_STATUS) & (M_MISC_IRQSTA | M_FR_IRQSTA))) - && !hw->mr.r_irq_statech) { - SetRegAddr(hw, old_ioreg); - return IRQ_NONE; - } - - /* timer event */ - if (Read_hfc8(hw, R_IRQ_MISC) & M_TI_IRQ) { - hw->mr.timer_irq = 1; - hw->fifo_sched_cnt--; - } - - /* FIFO event */ - if ((ovr = Read_hfc8(hw, R_IRQ_OVIEW))) { - hw->mr.r_irq_oview |= ovr; - idx = R_IRQ_FIFO_BL0; - ovp = hw->mr.r_irq_fifo_blx; - while (ovr) { - if ((ovr & 1)) { - *ovp |= Read_hfc8(hw, idx); - } - ovp++; - idx++; - ovr >>= 1; - } - } - - /* queue the request to allow other cards to interrupt */ - schedule_work(&hw->tqueue); - - SetRegAddr(hw, old_ioreg); - return IRQ_HANDLED; -} /* hfc4s8s_interrupt */ - -/***********************************************************************/ -/* reset the complete chip, don't release the chips irq but disable it */ -/***********************************************************************/ -static void -chipreset(hfc4s8s_hw *hw) -{ - u_long flags; - - spin_lock_irqsave(&hw->lock, flags); - Write_hfc8(hw, R_CTRL, 0); /* use internal RAM */ - Write_hfc8(hw, R_RAM_MISC, 0); /* 32k*8 RAM */ - Write_hfc8(hw, R_FIFO_MD, 0); /* fifo mode 386 byte/fifo simple mode */ - Write_hfc8(hw, R_CIRM, M_SRES); /* reset chip */ - hw->mr.r_irq_ctrl = 0; /* interrupt is inactive */ - spin_unlock_irqrestore(&hw->lock, flags); - - udelay(3); - Write_hfc8(hw, R_CIRM, 0); /* disable reset */ - wait_busy(hw); - - Write_hfc8(hw, R_PCM_MD0, M_PCM_MD); /* master mode */ - Write_hfc8(hw, R_RAM_MISC, M_FZ_MD); /* transmit fifo option */ - if (hw->driver_data.clock_mode == 1) - Write_hfc8(hw, R_BRG_PCM_CFG, M_PCM_CLK); /* PCM clk / 2 */ - Write_hfc8(hw, R_TI_WD, TRANS_TIMER_MODE); /* timer interval */ - - memset(&hw->mr, 0, sizeof(hw->mr)); -} /* chipreset */ - -/********************************************/ -/* disable/enable hardware in nt or te mode */ -/********************************************/ -static void -hfc_hardware_enable(hfc4s8s_hw *hw, int enable, int nt_mode) -{ - u_long flags; - char if_name[40]; - int i; - - if (enable) { - /* save system vars */ - hw->nt_mode = nt_mode; - - /* enable fifo and state irqs, but not global irq enable */ - hw->mr.r_irq_ctrl = M_FIFO_IRQ; - Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl); - hw->mr.r_irqmsk_statchg = 0; - Write_hfc8(hw, R_SCI_MSK, hw->mr.r_irqmsk_statchg); - Write_hfc8(hw, R_PWM_MD, 0x80); - Write_hfc8(hw, R_PWM1, 26); - if (!nt_mode) - Write_hfc8(hw, R_ST_SYNC, M_AUTO_SYNC); - - /* enable the line interfaces and fifos */ - for (i = 0; i < hw->driver_data.max_st_ports; i++) { - hw->mr.r_irqmsk_statchg |= (1 << i); - Write_hfc8(hw, R_SCI_MSK, hw->mr.r_irqmsk_statchg); - Write_hfc8(hw, R_ST_SEL, i); - Write_hfc8(hw, A_ST_CLK_DLY, - ((nt_mode) ? CLKDEL_NT : CLKDEL_TE)); - hw->mr.r_ctrl0 = ((nt_mode) ? CTRL0_NT : CTRL0_TE); - Write_hfc8(hw, A_ST_CTRL0, hw->mr.r_ctrl0); - Write_hfc8(hw, A_ST_CTRL2, 3); - Write_hfc8(hw, A_ST_WR_STA, 0); /* enable state machine */ - - hw->l1[i].enabled = 1; - hw->l1[i].nt_mode = nt_mode; - - if (!nt_mode) { - /* setup E-fifo */ - Write_hfc8(hw, R_FIFO, i * 8 + 7); /* E fifo */ - wait_busy(hw); - Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */ - Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */ - Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */ - Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(hw); - - /* setup D RX-fifo */ - Write_hfc8(hw, R_FIFO, i * 8 + 5); /* RX fifo */ - wait_busy(hw); - Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */ - Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */ - Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */ - Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(hw); - - /* setup D TX-fifo */ - Write_hfc8(hw, R_FIFO, i * 8 + 4); /* TX fifo */ - wait_busy(hw); - Write_hfc8(hw, A_CON_HDLC, 0x11); /* HDLC mode, 1 fill, connect ST */ - Write_hfc8(hw, A_SUBCH_CFG, 2); /* only 2 bits */ - Write_hfc8(hw, A_IRQ_MSK, 1); /* enable interrupt */ - Write_hfc8(hw, A_INC_RES_FIFO, 2); /* reset fifo */ - wait_busy(hw); - } - - sprintf(if_name, "hfc4s8s_%d%d_", hw->cardnum, i); - - if (hisax_register - (&hw->l1[i].d_if, hw->l1[i].b_table, if_name, - ((nt_mode) ? 3 : 2))) { - - hw->l1[i].enabled = 0; - hw->mr.r_irqmsk_statchg &= ~(1 << i); - Write_hfc8(hw, R_SCI_MSK, - hw->mr.r_irqmsk_statchg); - printk(KERN_INFO - "HFC-4S/8S: Unable to register S/T device %s, break\n", - if_name); - break; - } - } - spin_lock_irqsave(&hw->lock, flags); - hw->mr.r_irq_ctrl |= M_GLOB_IRQ_EN; - Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl); - spin_unlock_irqrestore(&hw->lock, flags); - } else { - /* disable hardware */ - spin_lock_irqsave(&hw->lock, flags); - hw->mr.r_irq_ctrl &= ~M_GLOB_IRQ_EN; - Write_hfc8(hw, R_IRQ_CTRL, hw->mr.r_irq_ctrl); - spin_unlock_irqrestore(&hw->lock, flags); - - for (i = hw->driver_data.max_st_ports - 1; i >= 0; i--) { - hw->l1[i].enabled = 0; - hisax_unregister(&hw->l1[i].d_if); - del_timer(&hw->l1[i].l1_timer); - skb_queue_purge(&hw->l1[i].d_tx_queue); - skb_queue_purge(&hw->l1[i].b_ch[0].tx_queue); - skb_queue_purge(&hw->l1[i].b_ch[1].tx_queue); - } - chipreset(hw); - } -} /* hfc_hardware_enable */ - -/******************************************/ -/* disable memory mapped ports / io ports */ -/******************************************/ -static void -release_pci_ports(hfc4s8s_hw *hw) -{ - pci_write_config_word(hw->pdev, PCI_COMMAND, 0); - if (hw->iobase) - release_region(hw->iobase, 8); -} - -/*****************************************/ -/* enable memory mapped ports / io ports */ -/*****************************************/ -static void -enable_pci_ports(hfc4s8s_hw *hw) -{ - pci_write_config_word(hw->pdev, PCI_COMMAND, PCI_ENA_REGIO); -} - -/*************************************/ -/* initialise the HFC-4s/8s hardware */ -/* return 0 on success. */ -/*************************************/ -static int -setup_instance(hfc4s8s_hw *hw) -{ - int err = -EIO; - int i; - - for (i = 0; i < HFC_MAX_ST; i++) { - struct hfc4s8s_l1 *l1p; - - l1p = hw->l1 + i; - spin_lock_init(&l1p->lock); - l1p->hw = hw; - timer_setup(&l1p->l1_timer, hfc_l1_timer, 0); - l1p->st_num = i; - skb_queue_head_init(&l1p->d_tx_queue); - l1p->d_if.ifc.priv = hw->l1 + i; - l1p->d_if.ifc.l2l1 = (void *) dch_l2l1; - - spin_lock_init(&l1p->b_ch[0].lock); - l1p->b_ch[0].b_if.ifc.l2l1 = (void *) bch_l2l1; - l1p->b_ch[0].b_if.ifc.priv = (void *) &l1p->b_ch[0]; - l1p->b_ch[0].l1p = hw->l1 + i; - l1p->b_ch[0].bchan = 1; - l1p->b_table[0] = &l1p->b_ch[0].b_if; - skb_queue_head_init(&l1p->b_ch[0].tx_queue); - - spin_lock_init(&l1p->b_ch[1].lock); - l1p->b_ch[1].b_if.ifc.l2l1 = (void *) bch_l2l1; - l1p->b_ch[1].b_if.ifc.priv = (void *) &l1p->b_ch[1]; - l1p->b_ch[1].l1p = hw->l1 + i; - l1p->b_ch[1].bchan = 2; - l1p->b_table[1] = &l1p->b_ch[1].b_if; - skb_queue_head_init(&l1p->b_ch[1].tx_queue); - } - - enable_pci_ports(hw); - chipreset(hw); - - i = Read_hfc8(hw, R_CHIP_ID) >> CHIP_ID_SHIFT; - if (i != hw->driver_data.chip_id) { - printk(KERN_INFO - "HFC-4S/8S: invalid chip id 0x%x instead of 0x%x, card ignored\n", - i, hw->driver_data.chip_id); - goto out; - } - - i = Read_hfc8(hw, R_CHIP_RV) & 0xf; - if (!i) { - printk(KERN_INFO - "HFC-4S/8S: chip revision 0 not supported, card ignored\n"); - goto out; - } - - INIT_WORK(&hw->tqueue, hfc4s8s_bh); - - if (request_irq - (hw->irq, hfc4s8s_interrupt, IRQF_SHARED, hw->card_name, hw)) { - printk(KERN_INFO - "HFC-4S/8S: unable to alloc irq %d, card ignored\n", - hw->irq); - goto out; - } - printk(KERN_INFO - "HFC-4S/8S: found PCI card at iobase 0x%x, irq %d\n", - hw->iobase, hw->irq); - - hfc_hardware_enable(hw, 1, 0); - - return (0); - -out: - hw->irq = 0; - release_pci_ports(hw); - kfree(hw); - return (err); -} - -/*****************************************/ -/* PCI hotplug interface: probe new card */ -/*****************************************/ -static int -hfc4s8s_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err = -ENOMEM; - hfc4s8s_param *driver_data = (hfc4s8s_param *) ent->driver_data; - hfc4s8s_hw *hw; - - if (!(hw = kzalloc(sizeof(hfc4s8s_hw), GFP_ATOMIC))) { - printk(KERN_ERR "No kmem for HFC-4S/8S card\n"); - return (err); - } - - hw->pdev = pdev; - err = pci_enable_device(pdev); - - if (err) - goto out; - - hw->cardnum = card_cnt; - sprintf(hw->card_name, "hfc4s8s_%d", hw->cardnum); - printk(KERN_INFO "HFC-4S/8S: found adapter %s (%s) at %s\n", - driver_data->device_name, hw->card_name, pci_name(pdev)); - - spin_lock_init(&hw->lock); - - hw->driver_data = *driver_data; - hw->irq = pdev->irq; - hw->iobase = pci_resource_start(pdev, 0); - - if (!request_region(hw->iobase, 8, hw->card_name)) { - printk(KERN_INFO - "HFC-4S/8S: failed to request address space at 0x%04x\n", - hw->iobase); - err = -EBUSY; - goto out; - } - - pci_set_drvdata(pdev, hw); - err = setup_instance(hw); - if (!err) - card_cnt++; - return (err); - -out: - kfree(hw); - return (err); -} - -/**************************************/ -/* PCI hotplug interface: remove card */ -/**************************************/ -static void -hfc4s8s_remove(struct pci_dev *pdev) -{ - hfc4s8s_hw *hw = pci_get_drvdata(pdev); - - printk(KERN_INFO "HFC-4S/8S: removing card %d\n", hw->cardnum); - hfc_hardware_enable(hw, 0, 0); - - if (hw->irq) - free_irq(hw->irq, hw); - hw->irq = 0; - release_pci_ports(hw); - - card_cnt--; - pci_disable_device(pdev); - kfree(hw); - return; -} - -static struct pci_driver hfc4s8s_driver = { - .name = "hfc4s8s_l1", - .probe = hfc4s8s_probe, - .remove = hfc4s8s_remove, - .id_table = hfc4s8s_ids, -}; - -/**********************/ -/* driver Module init */ -/**********************/ -static int __init -hfc4s8s_module_init(void) -{ - int err; - - printk(KERN_INFO - "HFC-4S/8S: Layer 1 driver module for HFC-4S/8S isdn chips, %s\n", - hfc4s8s_rev); - printk(KERN_INFO - "HFC-4S/8S: (C) 2003 Cornelius Consult, www.cornelius-consult.de\n"); - - card_cnt = 0; - - err = pci_register_driver(&hfc4s8s_driver); - if (err < 0) { - goto out; - } - printk(KERN_INFO "HFC-4S/8S: found %d cards\n", card_cnt); - - return 0; -out: - return (err); -} /* hfc4s8s_init_hw */ - -/*************************************/ -/* driver module exit : */ -/* release the HFC-4s/8s hardware */ -/*************************************/ -static void __exit -hfc4s8s_module_exit(void) -{ - pci_unregister_driver(&hfc4s8s_driver); - printk(KERN_INFO "HFC-4S/8S: module removed\n"); -} /* hfc4s8s_release_hw */ - -module_init(hfc4s8s_module_init); -module_exit(hfc4s8s_module_exit); diff --git a/drivers/isdn/hisax/hfc4s8s_l1.h b/drivers/isdn/hisax/hfc4s8s_l1.h deleted file mode 100644 index 4665b9d5df16..000000000000 --- a/drivers/isdn/hisax/hfc4s8s_l1.h +++ /dev/null @@ -1,89 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/***************************************************************/ -/* $Id: hfc4s8s_l1.h,v 1.1 2005/02/02 17:28:55 martinb1 Exp $ */ -/* */ -/* This file is a minimal required extraction of hfc48scu.h */ -/* (Genero 3.2, HFC XML 1.7a for HFC-E1, HFC-4S and HFC-8S) */ -/* */ -/* To get this complete register description contact */ -/* Cologne Chip AG : */ -/* Internet: http://www.colognechip.com/ */ -/* E-Mail: info@colognechip.com */ -/***************************************************************/ - -#ifndef _HFC4S8S_L1_H_ -#define _HFC4S8S_L1_H_ - - -/* - * include Genero generated HFC-4S/8S header file hfc48scu.h - * for complete register description. This will define _HFC48SCU_H_ - * to prevent redefinitions - */ - -// #include "hfc48scu.h" - -#ifndef _HFC48SCU_H_ -#define _HFC48SCU_H_ - -#ifndef PCI_VENDOR_ID_CCD -#define PCI_VENDOR_ID_CCD 0x1397 -#endif - -#define CHIP_ID_4S 0x0C -#define CHIP_ID_8S 0x08 -#define PCI_DEVICE_ID_4S 0x08B4 -#define PCI_DEVICE_ID_8S 0x16B8 - -#define R_IRQ_MISC 0x11 -#define M_TI_IRQ 0x02 -#define A_ST_RD_STA 0x30 -#define A_ST_WR_STA 0x30 -#define M_SET_G2_G3 0x80 -#define A_ST_CTRL0 0x31 -#define A_ST_CTRL2 0x33 -#define A_ST_CLK_DLY 0x37 -#define A_Z1 0x04 -#define A_Z2 0x06 -#define R_CIRM 0x00 -#define M_SRES 0x08 -#define R_CTRL 0x01 -#define R_BRG_PCM_CFG 0x02 -#define M_PCM_CLK 0x20 -#define R_RAM_MISC 0x0C -#define M_FZ_MD 0x80 -#define R_FIFO_MD 0x0D -#define A_INC_RES_FIFO 0x0E -#define R_FIFO 0x0F -#define A_F1 0x0C -#define A_F2 0x0D -#define R_IRQ_OVIEW 0x10 -#define R_CHIP_ID 0x16 -#define R_STATUS 0x1C -#define M_BUSY 0x01 -#define M_MISC_IRQSTA 0x40 -#define M_FR_IRQSTA 0x80 -#define R_CHIP_RV 0x1F -#define R_IRQ_CTRL 0x13 -#define M_FIFO_IRQ 0x01 -#define M_GLOB_IRQ_EN 0x08 -#define R_PCM_MD0 0x14 -#define M_PCM_MD 0x01 -#define A_FIFO_DATA0 0x80 -#define R_TI_WD 0x1A -#define R_PWM1 0x39 -#define R_PWM_MD 0x46 -#define R_IRQ_FIFO_BL0 0xC8 -#define A_CON_HDLC 0xFA -#define A_SUBCH_CFG 0xFB -#define A_IRQ_MSK 0xFF -#define R_SCI_MSK 0x12 -#define R_ST_SEL 0x16 -#define R_ST_SYNC 0x17 -#define M_AUTO_SYNC 0x08 -#define R_SCI 0x12 -#define R_IRQMSK_MISC 0x11 -#define M_TI_IRQMSK 0x02 - -#endif /* _HFC4S8S_L1_H_ */ -#endif /* _HFC48SCU_H_ */ diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c deleted file mode 100644 index 3715fa0343db..000000000000 --- a/drivers/isdn/hisax/hfc_2bds0.c +++ /dev/null @@ -1,1078 +0,0 @@ -/* $Id: hfc_2bds0.c,v 1.18.2.6 2004/02/11 13:21:33 keil Exp $ - * - * specific routines for CCD's HFC 2BDS0 - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include "hisax.h" -#include "hfc_2bds0.h" -#include "isdnl1.h" -#include <linux/interrupt.h> -/* - #define KDEBUG_DEF - #include "kdebug.h" -*/ - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static void -dummyf(struct IsdnCardState *cs, u_char *data, int size) -{ - printk(KERN_WARNING "HiSax: hfcd dummy fifo called\n"); -} - -static inline u_char -ReadReg(struct IsdnCardState *cs, int data, u_char reg) -{ - register u_char ret; - - if (data) { - if (cs->hw.hfcD.cip != reg) { - cs->hw.hfcD.cip = reg; - byteout(cs->hw.hfcD.addr | 1, reg); - } - ret = bytein(cs->hw.hfcD.addr); -#ifdef HFC_REG_DEBUG - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) - debugl1(cs, "t3c RD %02x %02x", reg, ret); -#endif - } else - ret = bytein(cs->hw.hfcD.addr | 1); - return (ret); -} - -static inline void -WriteReg(struct IsdnCardState *cs, int data, u_char reg, u_char value) -{ - if (cs->hw.hfcD.cip != reg) { - cs->hw.hfcD.cip = reg; - byteout(cs->hw.hfcD.addr | 1, reg); - } - if (data) - byteout(cs->hw.hfcD.addr, value); -#ifdef HFC_REG_DEBUG - if (cs->debug & L1_DEB_HSCX_FIFO && (data != HFCD_DATA_NODEB)) - debugl1(cs, "t3c W%c %02x %02x", data ? 'D' : 'C', reg, value); -#endif -} - -/* Interface functions */ - -static u_char -readreghfcd(struct IsdnCardState *cs, u_char offset) -{ - return (ReadReg(cs, HFCD_DATA, offset)); -} - -static void -writereghfcd(struct IsdnCardState *cs, u_char offset, u_char value) -{ - WriteReg(cs, HFCD_DATA, offset, value); -} - -static inline int -WaitForBusy(struct IsdnCardState *cs) -{ - int to = 130; - - while (!(ReadReg(cs, HFCD_DATA, HFCD_STAT) & HFCD_BUSY) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: WaitForBusy timeout\n"); - return (to); -} - -static inline int -WaitNoBusy(struct IsdnCardState *cs) -{ - int to = 130; - - while ((ReadReg(cs, HFCD_STATUS, HFCD_STATUS) & HFCD_BUSY) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: WaitNoBusy timeout\n"); - return (to); -} - -static int -SelFiFo(struct IsdnCardState *cs, u_char FiFo) -{ - u_char cip; - - if (cs->hw.hfcD.fifo == FiFo) - return (1); - switch (FiFo) { - case 0: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B1; - break; - case 1: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B1; - break; - case 2: cip = HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_B2; - break; - case 3: cip = HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_B2; - break; - case 4: cip = HFCD_FIFO | HFCD_Z1 | HFCD_SEND; - break; - case 5: cip = HFCD_FIFO | HFCD_Z1 | HFCD_REC; - break; - default: - debugl1(cs, "SelFiFo Error"); - return (0); - } - cs->hw.hfcD.fifo = FiFo; - WaitNoBusy(cs); - cs->BC_Write_Reg(cs, HFCD_DATA, cip, 0); - WaitForBusy(cs); - return (2); -} - -static int -GetFreeFifoBytes_B(struct BCState *bcs) -{ - int s; - - if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2) - return (bcs->cs->hw.hfcD.bfifosize); - s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2]; - if (s <= 0) - s += bcs->cs->hw.hfcD.bfifosize; - s = bcs->cs->hw.hfcD.bfifosize - s; - return (s); -} - -static int -GetFreeFifoBytes_D(struct IsdnCardState *cs) -{ - int s; - - if (cs->hw.hfcD.f1 == cs->hw.hfcD.f2) - return (cs->hw.hfcD.dfifosize); - s = cs->hw.hfcD.send[cs->hw.hfcD.f1] - cs->hw.hfcD.send[cs->hw.hfcD.f2]; - if (s <= 0) - s += cs->hw.hfcD.dfifosize; - s = cs->hw.hfcD.dfifosize - s; - return (s); -} - -static int -ReadZReg(struct IsdnCardState *cs, u_char reg) -{ - int val; - - WaitNoBusy(cs); - val = 256 * ReadReg(cs, HFCD_DATA, reg | HFCB_Z_HIGH); - WaitNoBusy(cs); - val += ReadReg(cs, HFCD_DATA, reg | HFCB_Z_LOW); - return (val); -} - -static struct sk_buff -*hfc_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct sk_buff *skb; - struct IsdnCardState *cs = bcs->cs; - int idx; - int chksum; - u_char stat, cip; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hfc_empty_fifo"); - idx = 0; - if (count > HSCX_BUFMAX + 3) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfc_empty_fifo: incoming packet too large"); - cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel); - while (idx++ < count) { - WaitNoBusy(cs); - ReadReg(cs, HFCD_DATA_NODEB, cip); - } - skb = NULL; - } else if (count < 4) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfc_empty_fifo: incoming packet too small"); - cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel); -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - while ((idx++ < count) && WaitNoBusy(cs)) - ReadReg(cs, HFCD_DATA_NODEB, cip); - skb = NULL; - } else if (!(skb = dev_alloc_skb(count - 3))) - printk(KERN_WARNING "HFC: receive out of memory\n"); - else { - ptr = skb_put(skb, count - 3); - idx = 0; - cip = HFCB_FIFO | HFCB_FIFO_OUT | HFCB_REC | HFCB_CHANNEL(bcs->channel); - while (idx < (count - 3)) { - if (!WaitNoBusy(cs)) - break; - *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip); - ptr++; - idx++; - } - if (idx != count - 3) { - debugl1(cs, "RFIFO BUSY error"); - printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb_irq(skb); - skb = NULL; - } else { - WaitNoBusy(cs); - chksum = (ReadReg(cs, HFCD_DATA, cip) << 8); - WaitNoBusy(cs); - chksum += ReadReg(cs, HFCD_DATA, cip); - WaitNoBusy(cs); - stat = ReadReg(cs, HFCD_DATA, cip); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", - bcs->channel, chksum, stat); - if (stat) { - debugl1(cs, "FIFO CRC error"); - dev_kfree_skb_irq(skb); - skb = NULL; -#ifdef ERROR_STATISTIC - bcs->err_crc++; -#endif - } - } - } - WaitForBusy(cs); - WaitNoBusy(cs); - stat = ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F2_INC | - HFCB_REC | HFCB_CHANNEL(bcs->channel)); - WaitForBusy(cs); - return (skb); -} - -static void -hfc_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int idx, fcnt; - int count; - u_char cip; - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - SelFiFo(cs, HFCB_SEND | HFCB_CHANNEL(bcs->channel)); - cip = HFCB_FIFO | HFCB_F1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel); - WaitNoBusy(cs); - bcs->hw.hfc.f1 = ReadReg(cs, HFCD_DATA, cip); - WaitNoBusy(cs); - cip = HFCB_FIFO | HFCB_F2 | HFCB_SEND | HFCB_CHANNEL(bcs->channel); - WaitNoBusy(cs); - bcs->hw.hfc.f2 = ReadReg(cs, HFCD_DATA, cip); - bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_SEND | HFCB_CHANNEL(bcs->channel)); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", - bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, - bcs->hw.hfc.send[bcs->hw.hfc.f1]); - fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; - if (fcnt < 0) - fcnt += 32; - if (fcnt > 30) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo more as 30 frames"); - return; - } - count = GetFreeFifoBytes_B(bcs); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo %d count(%u/%d),%lx", - bcs->channel, bcs->tx_skb->len, - count, current->state); - if (count < bcs->tx_skb->len) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo no fifo mem"); - return; - } - cip = HFCB_FIFO | HFCB_FIFO_IN | HFCB_SEND | HFCB_CHANNEL(bcs->channel); - idx = 0; - WaitForBusy(cs); - WaitNoBusy(cs); - WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); - while (idx < bcs->tx_skb->len) { - if (!WaitNoBusy(cs)) - break; - WriteReg(cs, HFCD_DATA_NODEB, cip, bcs->tx_skb->data[idx]); - idx++; - } - if (idx != bcs->tx_skb->len) { - debugl1(cs, "FIFO Send BUSY error"); - printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); - } else { - bcs->tx_cnt -= bcs->tx_skb->len; - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->tx_skb->len; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - } - WaitForBusy(cs); - WaitNoBusy(cs); - ReadReg(cs, HFCD_DATA, HFCB_FIFO | HFCB_F1_INC | HFCB_SEND | HFCB_CHANNEL(bcs->channel)); - WaitForBusy(cs); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - return; -} - -static void -hfc_send_data(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "send_data %d blocked", bcs->channel); -} - -static void -main_rec_2bds0(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int z1, z2, rcnt; - u_char f1, f2, cip; - int receive, count = 5; - struct sk_buff *skb; - -Begin: - count--; - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_data %d blocked", bcs->channel); - return; - } - SelFiFo(cs, HFCB_REC | HFCB_CHANNEL(bcs->channel)); - cip = HFCB_FIFO | HFCB_F1 | HFCB_REC | HFCB_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f1 = ReadReg(cs, HFCD_DATA, cip); - cip = HFCB_FIFO | HFCB_F2 | HFCB_REC | HFCB_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f2 = ReadReg(cs, HFCD_DATA, cip); - if (f1 != f2) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc rec %d f1(%d) f2(%d)", - bcs->channel, f1, f2); - z1 = ReadZReg(cs, HFCB_FIFO | HFCB_Z1 | HFCB_REC | HFCB_CHANNEL(bcs->channel)); - z2 = ReadZReg(cs, HFCB_FIFO | HFCB_Z2 | HFCB_REC | HFCB_CHANNEL(bcs->channel)); - rcnt = z1 - z2; - if (rcnt < 0) - rcnt += cs->hw.hfcD.bfifosize; - rcnt++; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", - bcs->channel, z1, z2, rcnt); - if ((skb = hfc_empty_fifo(bcs, rcnt))) { - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } - rcnt = f1 - f2; - if (rcnt < 0) - rcnt += 32; - if (rcnt > 1) - receive = 1; - else - receive = 0; - } else - receive = 0; - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - if (count && receive) - goto Begin; - return; -} - -static void -mode_2bs0(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HFCD bchannel mode %d bchan %d/%d", - mode, bc, bcs->channel); - bcs->mode = mode; - bcs->channel = bc; - switch (mode) { - case (L1_MODE_NULL): - if (bc) { - cs->hw.hfcD.conn |= 0x18; - cs->hw.hfcD.sctrl &= ~SCTRL_B2_ENA; - } else { - cs->hw.hfcD.conn |= 0x3; - cs->hw.hfcD.sctrl &= ~SCTRL_B1_ENA; - } - break; - case (L1_MODE_TRANS): - if (bc) { - cs->hw.hfcD.ctmt |= 2; - cs->hw.hfcD.conn &= ~0x18; - cs->hw.hfcD.sctrl |= SCTRL_B2_ENA; - } else { - cs->hw.hfcD.ctmt |= 1; - cs->hw.hfcD.conn &= ~0x3; - cs->hw.hfcD.sctrl |= SCTRL_B1_ENA; - } - break; - case (L1_MODE_HDLC): - if (bc) { - cs->hw.hfcD.ctmt &= ~2; - cs->hw.hfcD.conn &= ~0x18; - cs->hw.hfcD.sctrl |= SCTRL_B2_ENA; - } else { - cs->hw.hfcD.ctmt &= ~1; - cs->hw.hfcD.conn &= ~0x3; - cs->hw.hfcD.sctrl |= SCTRL_B1_ENA; - } - break; - } - WriteReg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl); - WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); - WriteReg(cs, HFCD_DATA, HFCD_CONN, cs->hw.hfcD.conn); -} - -static void -hfc_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); - } else { -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - mode_2bs0(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - mode_2bs0(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_2bs0(struct BCState *bcs) -{ - mode_2bs0(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static int -open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_2b(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hfcstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hfc_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -static void -hfcd_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - switch (cs->dc.hfcd.ph_state) { - case (0): - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - case (3): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (8): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (6): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (7): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - default: - break; - } - } - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -} - -static -int receive_dmsg(struct IsdnCardState *cs) -{ - struct sk_buff *skb; - int idx; - int rcnt, z1, z2; - u_char stat, cip, f1, f2; - int chksum; - int count = 5; - u_char *ptr; - - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_dmsg blocked"); - return (1); - } - SelFiFo(cs, 4 | HFCD_REC); - cip = HFCD_FIFO | HFCD_F1 | HFCD_REC; - WaitNoBusy(cs); - f1 = cs->readisac(cs, cip) & 0xf; - cip = HFCD_FIFO | HFCD_F2 | HFCD_REC; - WaitNoBusy(cs); - f2 = cs->readisac(cs, cip) & 0xf; - while ((f1 != f2) && count--) { - z1 = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_REC); - z2 = ReadZReg(cs, HFCD_FIFO | HFCD_Z2 | HFCD_REC); - rcnt = z1 - z2; - if (rcnt < 0) - rcnt += cs->hw.hfcD.dfifosize; - rcnt++; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcd recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", - f1, f2, z1, z2, rcnt); - idx = 0; - cip = HFCD_FIFO | HFCD_FIFO_OUT | HFCD_REC; - if (rcnt > MAX_DFRAME_LEN + 3) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "empty_fifo d: incoming packet too large"); - while (idx < rcnt) { - if (!(WaitNoBusy(cs))) - break; - ReadReg(cs, HFCD_DATA_NODEB, cip); - idx++; - } - } else if (rcnt < 4) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "empty_fifo d: incoming packet too small"); - while ((idx++ < rcnt) && WaitNoBusy(cs)) - ReadReg(cs, HFCD_DATA_NODEB, cip); - } else if ((skb = dev_alloc_skb(rcnt - 3))) { - ptr = skb_put(skb, rcnt - 3); - while (idx < (rcnt - 3)) { - if (!(WaitNoBusy(cs))) - break; - *ptr = ReadReg(cs, HFCD_DATA_NODEB, cip); - idx++; - ptr++; - } - if (idx != (rcnt - 3)) { - debugl1(cs, "RFIFO D BUSY error"); - printk(KERN_WARNING "HFC DFIFO channel BUSY Error\n"); - dev_kfree_skb_irq(skb); - skb = NULL; -#ifdef ERROR_STATISTIC - cs->err_rx++; -#endif - } else { - WaitNoBusy(cs); - chksum = (ReadReg(cs, HFCD_DATA, cip) << 8); - WaitNoBusy(cs); - chksum += ReadReg(cs, HFCD_DATA, cip); - WaitNoBusy(cs); - stat = ReadReg(cs, HFCD_DATA, cip); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "empty_dfifo chksum %x stat %x", - chksum, stat); - if (stat) { - debugl1(cs, "FIFO CRC error"); - dev_kfree_skb_irq(skb); - skb = NULL; -#ifdef ERROR_STATISTIC - cs->err_crc++; -#endif - } else { - skb_queue_tail(&cs->rq, skb); - schedule_event(cs, D_RCVBUFREADY); - } - } - } else - printk(KERN_WARNING "HFC: D receive out of memory\n"); - WaitForBusy(cs); - cip = HFCD_FIFO | HFCD_F2_INC | HFCD_REC; - WaitNoBusy(cs); - stat = ReadReg(cs, HFCD_DATA, cip); - WaitForBusy(cs); - cip = HFCD_FIFO | HFCD_F2 | HFCD_REC; - WaitNoBusy(cs); - f2 = cs->readisac(cs, cip) & 0xf; - } - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - return (1); -} - -static void -hfc_fill_dfifo(struct IsdnCardState *cs) -{ - int idx, fcnt; - int count; - u_char cip; - - if (!cs->tx_skb) - return; - if (cs->tx_skb->len <= 0) - return; - - SelFiFo(cs, 4 | HFCD_SEND); - cip = HFCD_FIFO | HFCD_F1 | HFCD_SEND; - WaitNoBusy(cs); - cs->hw.hfcD.f1 = ReadReg(cs, HFCD_DATA, cip) & 0xf; - WaitNoBusy(cs); - cip = HFCD_FIFO | HFCD_F2 | HFCD_SEND; - cs->hw.hfcD.f2 = ReadReg(cs, HFCD_DATA, cip) & 0xf; - cs->hw.hfcD.send[cs->hw.hfcD.f1] = ReadZReg(cs, HFCD_FIFO | HFCD_Z1 | HFCD_SEND); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfc_fill_Dfifo f1(%d) f2(%d) z1(%x)", - cs->hw.hfcD.f1, cs->hw.hfcD.f2, - cs->hw.hfcD.send[cs->hw.hfcD.f1]); - fcnt = cs->hw.hfcD.f1 - cs->hw.hfcD.f2; - if (fcnt < 0) - fcnt += 16; - if (fcnt > 14) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_Dfifo more as 14 frames"); - return; - } - count = GetFreeFifoBytes_D(cs); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfc_fill_Dfifo count(%u/%d)", - cs->tx_skb->len, count); - if (count < cs->tx_skb->len) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfc_fill_Dfifo no fifo mem"); - return; - } - cip = HFCD_FIFO | HFCD_FIFO_IN | HFCD_SEND; - idx = 0; - WaitForBusy(cs); - WaitNoBusy(cs); - WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx++]); - while (idx < cs->tx_skb->len) { - if (!(WaitNoBusy(cs))) - break; - WriteReg(cs, HFCD_DATA_NODEB, cip, cs->tx_skb->data[idx]); - idx++; - } - if (idx != cs->tx_skb->len) { - debugl1(cs, "DFIFO Send BUSY error"); - printk(KERN_WARNING "HFC S DFIFO channel BUSY Error\n"); - } - WaitForBusy(cs); - WaitNoBusy(cs); - ReadReg(cs, HFCD_DATA, HFCD_FIFO | HFCD_F1_INC | HFCD_SEND); - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - WaitForBusy(cs); - return; -} - -static -struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel) -{ - if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) - return (&cs->bcs[0]); - else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) - return (&cs->bcs[1]); - else - return (NULL); -} - -void -hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val) -{ - u_char exval; - struct BCState *bcs; - int count = 15; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCD irq %x %s", val, - test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? - "locked" : "unlocked"); - val &= cs->hw.hfcD.int_m1; - if (val & 0x40) { /* TE state machine irq */ - exval = cs->readisac(cs, HFCD_STATES) & 0xf; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcd.ph_state, - exval); - cs->dc.hfcd.ph_state = exval; - schedule_event(cs, D_L1STATECHANGE); - val &= ~0x40; - } - while (val) { - if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - cs->hw.hfcD.int_s1 |= val; - return; - } - if (cs->hw.hfcD.int_s1 & 0x18) { - exval = val; - val = cs->hw.hfcD.int_s1; - cs->hw.hfcD.int_s1 = exval; - } - if (val & 0x08) { - if (!(bcs = Sel_BCS(cs, 0))) { - if (cs->debug) - debugl1(cs, "hfcd spurious 0x08 IRQ"); - } else - main_rec_2bds0(bcs); - } - if (val & 0x10) { - if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcd spurious 0x10 IRQ"); - } else - main_rec_2bds0(bcs); - } - if (val & 0x01) { - if (!(bcs = Sel_BCS(cs, 0))) { - if (cs->debug) - debugl1(cs, "hfcd spurious 0x01 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - schedule_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x02) { - if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcd spurious 0x02 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - schedule_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x20) { /* receive dframe */ - receive_dmsg(cs); - } - if (val & 0x04) { /* dframe transmitted */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfc_fill_dfifo irq blocked"); - } - goto afterXPR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfc_fill_dfifo irq blocked"); - } - } else - schedule_event(cs, D_XMTBUFREADY); - } - afterXPR: - if (cs->hw.hfcD.int_s1 && count--) { - val = cs->hw.hfcD.int_s1; - cs->hw.hfcD.int_s1 = 0; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCD irq %x loop %d", val, 15-count); - } else - val = 0; - } -} - -static void -HFCD_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfc_fill_dfifo blocked"); - - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfc_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfc_fill_dfifo blocked"); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->writeisac(cs, HFCD_STATES, HFCD_LOAD_STATE | 3); /* HFC ST 3 */ - udelay(6); - cs->writeisac(cs, HFCD_STATES, 3); /* HFC ST 2 */ - cs->hw.hfcD.mst_m |= HFCD_MASTER; - cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); - cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->writeisac(cs, HFCD_STATES, HFCD_ACTIVATE | HFCD_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_DEACTIVATE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcD.mst_m &= ~HFCD_MASTER; - cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcD.mst_m |= HFCD_MASTER; - cs->writeisac(cs, HFCD_MST_MODE, cs->hw.hfcD.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcd_l1hw unknown pr %4x", pr); - break; - } -} - -static void -setstack_hfcd(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = HFCD_l1hw; -} - -static void -hfc_dbusy_timer(struct timer_list *t) -{ -} - -static unsigned int -*init_send_hfcd(int cnt) -{ - int i; - unsigned *send; - - if (!(send = kmalloc_array(cnt, sizeof(unsigned int), GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for hfcd.send\n"); - return (NULL); - } - for (i = 0; i < cnt; i++) - send[i] = 0x1fff; - return (send); -} - -void -init2bds0(struct IsdnCardState *cs) -{ - cs->setstack_d = setstack_hfcd; - if (!cs->hw.hfcD.send) - cs->hw.hfcD.send = init_send_hfcd(16); - if (!cs->bcs[0].hw.hfc.send) - cs->bcs[0].hw.hfc.send = init_send_hfcd(32); - if (!cs->bcs[1].hw.hfc.send) - cs->bcs[1].hw.hfc.send = init_send_hfcd(32); - cs->BC_Send_Data = &hfc_send_data; - cs->bcs[0].BC_SetStack = setstack_2b; - cs->bcs[1].BC_SetStack = setstack_2b; - cs->bcs[0].BC_Close = close_2bs0; - cs->bcs[1].BC_Close = close_2bs0; - mode_2bs0(cs->bcs, 0, 0); - mode_2bs0(cs->bcs + 1, 0, 1); -} - -void -release2bds0(struct IsdnCardState *cs) -{ - kfree(cs->bcs[0].hw.hfc.send); - cs->bcs[0].hw.hfc.send = NULL; - kfree(cs->bcs[1].hw.hfc.send); - cs->bcs[1].hw.hfc.send = NULL; - kfree(cs->hw.hfcD.send); - cs->hw.hfcD.send = NULL; -} - -void -set_cs_func(struct IsdnCardState *cs) -{ - cs->readisac = &readreghfcd; - cs->writeisac = &writereghfcd; - cs->readisacfifo = &dummyf; - cs->writeisacfifo = &dummyf; - cs->BC_Read_Reg = &ReadReg; - cs->BC_Write_Reg = &WriteReg; - timer_setup(&cs->dbusytimer, hfc_dbusy_timer, 0); - INIT_WORK(&cs->tqueue, hfcd_bh); -} diff --git a/drivers/isdn/hisax/hfc_2bds0.h b/drivers/isdn/hisax/hfc_2bds0.h deleted file mode 100644 index 8c7582a3c51e..000000000000 --- a/drivers/isdn/hisax/hfc_2bds0.h +++ /dev/null @@ -1,128 +0,0 @@ -/* $Id: hfc_2bds0.h,v 1.6.2.2 2004/01/12 22:52:26 keil Exp $ - * - * specific defines for CCD's HFC 2BDS0 - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define HFCD_CIRM 0x18 -#define HFCD_CTMT 0x19 -#define HFCD_INT_M1 0x1A -#define HFCD_INT_M2 0x1B -#define HFCD_INT_S1 0x1E -#define HFCD_STAT 0x1C -#define HFCD_STAT_DISB 0x1D -#define HFCD_STATES 0x30 -#define HFCD_SCTRL 0x31 -#define HFCD_TEST 0x32 -#define HFCD_SQ 0x34 -#define HFCD_CLKDEL 0x37 -#define HFCD_MST_MODE 0x2E -#define HFCD_CONN 0x2F - -#define HFCD_FIFO 0x80 -#define HFCD_Z1 0x10 -#define HFCD_Z2 0x18 -#define HFCD_Z_LOW 0x00 -#define HFCD_Z_HIGH 0x04 -#define HFCD_F1_INC 0x12 -#define HFCD_FIFO_IN 0x16 -#define HFCD_F1 0x1a -#define HFCD_F2 0x1e -#define HFCD_F2_INC 0x22 -#define HFCD_FIFO_OUT 0x26 -#define HFCD_REC 0x01 -#define HFCD_SEND 0x00 - -#define HFCB_FIFO 0x80 -#define HFCB_Z1 0x00 -#define HFCB_Z2 0x08 -#define HFCB_Z_LOW 0x00 -#define HFCB_Z_HIGH 0x04 -#define HFCB_F1_INC 0x28 -#define HFCB_FIFO_IN 0x2c -#define HFCB_F1 0x30 -#define HFCB_F2 0x34 -#define HFCB_F2_INC 0x38 -#define HFCB_FIFO_OUT 0x3c -#define HFCB_REC 0x01 -#define HFCB_SEND 0x00 -#define HFCB_B1 0x00 -#define HFCB_B2 0x02 -#define HFCB_CHANNEL(ch) (ch ? HFCB_B2 : HFCB_B1) - -#define HFCD_STATUS 0 -#define HFCD_DATA 1 -#define HFCD_DATA_NODEB 2 - -/* Status (READ) */ -#define HFCD_BUSY 0x01 -#define HFCD_BUSY_NBUSY 0x04 -#define HFCD_TIMER_ELAP 0x10 -#define HFCD_STATINT 0x20 -#define HFCD_FRAMEINT 0x40 -#define HFCD_ANYINT 0x80 - -/* CTMT (Write) */ -#define HFCD_CLTIMER 0x80 -#define HFCD_TIM25 0x00 -#define HFCD_TIM50 0x08 -#define HFCD_TIM400 0x10 -#define HFCD_TIM800 0x18 -#define HFCD_AUTO_TIMER 0x20 -#define HFCD_TRANSB2 0x02 -#define HFCD_TRANSB1 0x01 - -/* CIRM (Write) */ -#define HFCD_RESET 0x08 -#define HFCD_MEM8K 0x10 -#define HFCD_INTA 0x01 -#define HFCD_INTB 0x02 -#define HFCD_INTC 0x03 -#define HFCD_INTD 0x04 -#define HFCD_INTE 0x05 -#define HFCD_INTF 0x06 - -/* INT_M1;INT_S1 */ -#define HFCD_INTS_B1TRANS 0x01 -#define HFCD_INTS_B2TRANS 0x02 -#define HFCD_INTS_DTRANS 0x04 -#define HFCD_INTS_B1REC 0x08 -#define HFCD_INTS_B2REC 0x10 -#define HFCD_INTS_DREC 0x20 -#define HFCD_INTS_L1STATE 0x40 -#define HFCD_INTS_TIMER 0x80 - -/* INT_M2 */ -#define HFCD_IRQ_ENABLE 0x08 - -/* STATES */ -#define HFCD_LOAD_STATE 0x10 -#define HFCD_ACTIVATE 0x20 -#define HFCD_DO_ACTION 0x40 - -/* HFCD_MST_MODE */ -#define HFCD_MASTER 0x01 - -/* HFCD_SCTRL */ -#define SCTRL_B1_ENA 0x01 -#define SCTRL_B2_ENA 0x02 -#define SCTRL_LOW_PRIO 0x08 -#define SCTRL_SQ_ENA 0x10 -#define SCTRL_TEST 0x20 -#define SCTRL_NONE_CAP 0x40 -#define SCTRL_PWR_DOWN 0x80 - -/* HFCD_TEST */ -#define HFCD_AUTO_AWAKE 0x01 - -extern void main_irq_2bds0(struct BCState *bcs); -extern void init2bds0(struct IsdnCardState *cs); -extern void release2bds0(struct IsdnCardState *cs); -extern void hfc2bds0_interrupt(struct IsdnCardState *cs, u_char val); -extern void set_cs_func(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c deleted file mode 100644 index 34d59992839a..000000000000 --- a/drivers/isdn/hisax/hfc_2bs0.c +++ /dev/null @@ -1,591 +0,0 @@ -/* $Id: hfc_2bs0.c,v 1.20.2.6 2004/02/11 13:21:33 keil Exp $ - * - * specific routines for CCD's HFC 2BS0 - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "hfc_2bs0.h" -#include "isac.h" -#include "isdnl1.h" -#include <linux/interrupt.h> -#include <linux/slab.h> - -static inline int -WaitForBusy(struct IsdnCardState *cs) -{ - int to = 130; - u_char val; - - while (!(cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) { - val = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2 | - (cs->hw.hfc.cip & 3)); - udelay(1); - to--; - } - if (!to) { - printk(KERN_WARNING "HiSax: %s timeout\n", __func__); - return (0); - } else - return (to); -} - -static inline int -WaitNoBusy(struct IsdnCardState *cs) -{ - int to = 125; - - while ((cs->BC_Read_Reg(cs, HFC_STATUS, 0) & HFC_BUSY) && to) { - udelay(1); - to--; - } - if (!to) { - printk(KERN_WARNING "HiSax: waitforBusy timeout\n"); - return (0); - } else - return (to); -} - -static int -GetFreeFifoBytes(struct BCState *bcs) -{ - int s; - - if (bcs->hw.hfc.f1 == bcs->hw.hfc.f2) - return (bcs->cs->hw.hfc.fifosize); - s = bcs->hw.hfc.send[bcs->hw.hfc.f1] - bcs->hw.hfc.send[bcs->hw.hfc.f2]; - if (s <= 0) - s += bcs->cs->hw.hfc.fifosize; - s = bcs->cs->hw.hfc.fifosize - s; - return (s); -} - -static int -ReadZReg(struct BCState *bcs, u_char reg) -{ - int val; - - WaitNoBusy(bcs->cs); - val = 256 * bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_HIGH); - WaitNoBusy(bcs->cs); - val += bcs->cs->BC_Read_Reg(bcs->cs, HFC_DATA, reg | HFC_CIP | HFC_Z_LOW); - return (val); -} - -static void -hfc_clear_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int idx, cnt; - int rcnt, z1, z2; - u_char cip, f1, f2; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hfc_clear_fifo"); - cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel); - if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { - cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); - WaitForBusy(cs); - } - WaitNoBusy(cs); - f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); - z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); - cnt = 32; - while (((f1 != f2) || (z1 != z2)) && cnt--) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc clear %d f1(%d) f2(%d)", - bcs->channel, f1, f2); - rcnt = z1 - z2; - if (rcnt < 0) - rcnt += cs->hw.hfc.fifosize; - if (rcnt) - rcnt++; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc clear %d z1(%x) z2(%x) cnt(%d)", - bcs->channel, z1, z2, rcnt); - cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - idx = 0; - while ((idx < rcnt) && WaitNoBusy(cs)) { - cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); - idx++; - } - if (f1 != f2) { - WaitNoBusy(cs); - cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); - } - cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); - z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); - } - return; -} - - -static struct sk_buff -* -hfc_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct sk_buff *skb; - struct IsdnCardState *cs = bcs->cs; - int idx; - int chksum; - u_char stat, cip; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hfc_empty_fifo"); - idx = 0; - if (count > HSCX_BUFMAX + 3) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfc_empty_fifo: incoming packet too large"); - cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - while ((idx++ < count) && WaitNoBusy(cs)) - cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); - return (NULL); - } - if ((count < 4) && (bcs->mode != L1_MODE_TRANS)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfc_empty_fifo: incoming packet too small"); - cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - while ((idx++ < count) && WaitNoBusy(cs)) - cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - return (NULL); - } - if (bcs->mode == L1_MODE_TRANS) - count -= 1; - else - count -= 3; - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "HFC: receive out of memory\n"); - else { - ptr = skb_put(skb, count); - idx = 0; - cip = HFC_CIP | HFC_FIFO_OUT | HFC_REC | HFC_CHANNEL(bcs->channel); - while ((idx < count) && WaitNoBusy(cs)) { - *ptr++ = cs->BC_Read_Reg(cs, HFC_DATA_NODEB, cip); - idx++; - } - if (idx != count) { - debugl1(cs, "RFIFO BUSY error"); - printk(KERN_WARNING "HFC FIFO channel %d BUSY Error\n", bcs->channel); - dev_kfree_skb_any(skb); - if (bcs->mode != L1_MODE_TRANS) { - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); - } - return (NULL); - } - if (bcs->mode != L1_MODE_TRANS) { - WaitNoBusy(cs); - chksum = (cs->BC_Read_Reg(cs, HFC_DATA, cip) << 8); - WaitNoBusy(cs); - chksum += cs->BC_Read_Reg(cs, HFC_DATA, cip); - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, cip); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_empty_fifo %d chksum %x stat %x", - bcs->channel, chksum, stat); - if (stat) { - debugl1(cs, "FIFO CRC error"); - dev_kfree_skb_any(skb); - skb = NULL; -#ifdef ERROR_STATISTIC - bcs->err_crc++; -#endif - } - WaitNoBusy(cs); - stat = cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F2_INC | HFC_REC | - HFC_CHANNEL(bcs->channel)); - WaitForBusy(cs); - } - } - return (skb); -} - -static void -hfc_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int idx, fcnt; - int count; - int z1, z2; - u_char cip; - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - cip = HFC_CIP | HFC_F1 | HFC_SEND | HFC_CHANNEL(bcs->channel); - if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { - cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); - WaitForBusy(cs); - } - WaitNoBusy(cs); - if (bcs->mode != L1_MODE_TRANS) { - bcs->hw.hfc.f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - cip = HFC_CIP | HFC_F2 | HFC_SEND | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - bcs->hw.hfc.f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - bcs->hw.hfc.send[bcs->hw.hfc.f1] = ReadZReg(bcs, HFC_Z1 | HFC_SEND | HFC_CHANNEL(bcs->channel)); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo %d f1(%d) f2(%d) z1(%x)", - bcs->channel, bcs->hw.hfc.f1, bcs->hw.hfc.f2, - bcs->hw.hfc.send[bcs->hw.hfc.f1]); - fcnt = bcs->hw.hfc.f1 - bcs->hw.hfc.f2; - if (fcnt < 0) - fcnt += 32; - if (fcnt > 30) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo more as 30 frames"); - return; - } - count = GetFreeFifoBytes(bcs); - } - else { - WaitForBusy(cs); - z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); - z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); - count = z1 - z2; - if (count < 0) - count += cs->hw.hfc.fifosize; - } /* L1_MODE_TRANS */ - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo %d count(%u/%d)", - bcs->channel, bcs->tx_skb->len, - count); - if (count < bcs->tx_skb->len) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc_fill_fifo no fifo mem"); - return; - } - cip = HFC_CIP | HFC_FIFO_IN | HFC_SEND | HFC_CHANNEL(bcs->channel); - idx = 0; - while ((idx < bcs->tx_skb->len) && WaitNoBusy(cs)) - cs->BC_Write_Reg(cs, HFC_DATA_NODEB, cip, bcs->tx_skb->data[idx++]); - if (idx != bcs->tx_skb->len) { - debugl1(cs, "FIFO Send BUSY error"); - printk(KERN_WARNING "HFC S FIFO channel %d BUSY Error\n", bcs->channel); - } else { - count = bcs->tx_skb->len; - bcs->tx_cnt -= count; - if (PACKET_NOACK == bcs->tx_skb->pkt_type) - count = -1; - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - if (bcs->mode != L1_MODE_TRANS) { - WaitForBusy(cs); - WaitNoBusy(cs); - cs->BC_Read_Reg(cs, HFC_DATA, HFC_CIP | HFC_F1_INC | HFC_SEND | HFC_CHANNEL(bcs->channel)); - } - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (count >= 0)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - return; -} - -void -main_irq_hfc(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int z1, z2, rcnt; - u_char f1, f2, cip; - int receive, transmit, count = 5; - struct sk_buff *skb; - -Begin: - count--; - cip = HFC_CIP | HFC_F1 | HFC_REC | HFC_CHANNEL(bcs->channel); - if ((cip & 0xc3) != (cs->hw.hfc.cip & 0xc3)) { - cs->BC_Write_Reg(cs, HFC_STATUS, cip, cip); - WaitForBusy(cs); - } - WaitNoBusy(cs); - receive = 0; - if (bcs->mode == L1_MODE_HDLC) { - f1 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - cip = HFC_CIP | HFC_F2 | HFC_REC | HFC_CHANNEL(bcs->channel); - WaitNoBusy(cs); - f2 = cs->BC_Read_Reg(cs, HFC_DATA, cip); - if (f1 != f2) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc rec %d f1(%d) f2(%d)", - bcs->channel, f1, f2); - receive = 1; - } - } - if (receive || (bcs->mode == L1_MODE_TRANS)) { - WaitForBusy(cs); - z1 = ReadZReg(bcs, HFC_Z1 | HFC_REC | HFC_CHANNEL(bcs->channel)); - z2 = ReadZReg(bcs, HFC_Z2 | HFC_REC | HFC_CHANNEL(bcs->channel)); - rcnt = z1 - z2; - if (rcnt < 0) - rcnt += cs->hw.hfc.fifosize; - if ((bcs->mode == L1_MODE_HDLC) || (rcnt)) { - rcnt++; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfc rec %d z1(%x) z2(%x) cnt(%d)", - bcs->channel, z1, z2, rcnt); - /* sti(); */ - if ((skb = hfc_empty_fifo(bcs, rcnt))) { - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } - } - receive = 1; - } - if (bcs->tx_skb) { - transmit = 1; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - hfc_fill_fifo(bcs); - if (test_bit(BC_FLG_BUSY, &bcs->Flag)) - transmit = 0; - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - transmit = 1; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - hfc_fill_fifo(bcs); - if (test_bit(BC_FLG_BUSY, &bcs->Flag)) - transmit = 0; - } else { - transmit = 0; - schedule_event(bcs, B_XMTBUFREADY); - } - } - if ((receive || transmit) && count) - goto Begin; - return; -} - -static void -mode_hfc(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HFC 2BS0 mode %d bchan %d/%d", - mode, bc, bcs->channel); - bcs->mode = mode; - bcs->channel = bc; - - switch (mode) { - case (L1_MODE_NULL): - if (bc) { - cs->hw.hfc.ctmt &= ~1; - cs->hw.hfc.isac_spcr &= ~0x03; - } - else { - cs->hw.hfc.ctmt &= ~2; - cs->hw.hfc.isac_spcr &= ~0x0c; - } - break; - case (L1_MODE_TRANS): - cs->hw.hfc.ctmt &= ~(1 << bc); /* set HDLC mode */ - cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt); - hfc_clear_fifo(bcs); /* complete fifo clear */ - if (bc) { - cs->hw.hfc.ctmt |= 1; - cs->hw.hfc.isac_spcr &= ~0x03; - cs->hw.hfc.isac_spcr |= 0x02; - } else { - cs->hw.hfc.ctmt |= 2; - cs->hw.hfc.isac_spcr &= ~0x0c; - cs->hw.hfc.isac_spcr |= 0x08; - } - break; - case (L1_MODE_HDLC): - if (bc) { - cs->hw.hfc.ctmt &= ~1; - cs->hw.hfc.isac_spcr &= ~0x03; - cs->hw.hfc.isac_spcr |= 0x02; - } else { - cs->hw.hfc.ctmt &= ~2; - cs->hw.hfc.isac_spcr &= ~0x0c; - cs->hw.hfc.isac_spcr |= 0x08; - } - break; - } - cs->BC_Write_Reg(cs, HFC_STATUS, cs->hw.hfc.ctmt, cs->hw.hfc.ctmt); - cs->writeisac(cs, ISAC_SPCR, cs->hw.hfc.isac_spcr); - if (mode == L1_MODE_HDLC) - hfc_clear_fifo(bcs); -} - -static void -hfc_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); - } else { - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - mode_hfc(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - mode_hfc(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - - -static void -close_hfcstate(struct BCState *bcs) -{ - mode_hfc(bcs, 0, bcs->channel); - if (test_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); -} - -static int -open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_hfc(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hfcstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hfc_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -static void -init_send(struct BCState *bcs) -{ - int i; - - bcs->hw.hfc.send = kmalloc_array(32, sizeof(unsigned int), GFP_ATOMIC); - if (!bcs->hw.hfc.send) { - printk(KERN_WARNING - "HiSax: No memory for hfc.send\n"); - return; - } - for (i = 0; i < 32; i++) - bcs->hw.hfc.send[i] = 0x1fff; -} - -void -inithfc(struct IsdnCardState *cs) -{ - init_send(&cs->bcs[0]); - init_send(&cs->bcs[1]); - cs->BC_Send_Data = &hfc_fill_fifo; - cs->bcs[0].BC_SetStack = setstack_hfc; - cs->bcs[1].BC_SetStack = setstack_hfc; - cs->bcs[0].BC_Close = close_hfcstate; - cs->bcs[1].BC_Close = close_hfcstate; - mode_hfc(cs->bcs, 0, 0); - mode_hfc(cs->bcs + 1, 0, 0); -} - -void -releasehfc(struct IsdnCardState *cs) -{ - kfree(cs->bcs[0].hw.hfc.send); - cs->bcs[0].hw.hfc.send = NULL; - kfree(cs->bcs[1].hw.hfc.send); - cs->bcs[1].hw.hfc.send = NULL; -} diff --git a/drivers/isdn/hisax/hfc_2bs0.h b/drivers/isdn/hisax/hfc_2bs0.h deleted file mode 100644 index 1510096363dc..000000000000 --- a/drivers/isdn/hisax/hfc_2bs0.h +++ /dev/null @@ -1,60 +0,0 @@ -/* $Id: hfc_2bs0.h,v 1.5.2.2 2004/01/12 22:52:26 keil Exp $ - * - * specific defines for CCD's HFC 2BS0 - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define HFC_CTMT 0xe0 -#define HFC_CIRM 0xc0 -#define HFC_CIP 0x80 -#define HFC_Z1 0x00 -#define HFC_Z2 0x08 -#define HFC_Z_LOW 0x00 -#define HFC_Z_HIGH 0x04 -#define HFC_F1_INC 0x28 -#define HFC_FIFO_IN 0x2c -#define HFC_F1 0x30 -#define HFC_F2 0x34 -#define HFC_F2_INC 0x38 -#define HFC_FIFO_OUT 0x3c -#define HFC_B1 0x00 -#define HFC_B2 0x02 -#define HFC_REC 0x01 -#define HFC_SEND 0x00 -#define HFC_CHANNEL(ch) (ch ? HFC_B2 : HFC_B1) - -#define HFC_STATUS 0 -#define HFC_DATA 1 -#define HFC_DATA_NODEB 2 - -/* Status (READ) */ -#define HFC_BUSY 0x01 -#define HFC_TIMINT 0x02 -#define HFC_EXTINT 0x04 - -/* CTMT (Write) */ -#define HFC_CLTIMER 0x10 -#define HFC_TIM50MS 0x08 -#define HFC_TIMIRQE 0x04 -#define HFC_TRANSB2 0x02 -#define HFC_TRANSB1 0x01 - -/* CIRM (Write) */ -#define HFC_RESET 0x08 -#define HFC_MEM8K 0x10 -#define HFC_INTA 0x01 -#define HFC_INTB 0x02 -#define HFC_INTC 0x03 -#define HFC_INTD 0x04 -#define HFC_INTE 0x05 -#define HFC_INTF 0x06 - -extern void main_irq_hfc(struct BCState *bcs); -extern void inithfc(struct IsdnCardState *cs); -extern void releasehfc(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c deleted file mode 100644 index 71a8312592d6..000000000000 --- a/drivers/isdn/hisax/hfc_pci.c +++ /dev/null @@ -1,1755 +0,0 @@ -/* $Id: hfc_pci.c,v 1.48.2.4 2004/02/11 13:21:33 keil Exp $ - * - * low level driver for CCD's hfc-pci based cards - * - * Author Werner Cornelius - * based on existing driver for CCD hfc ISA cards - * Copyright by Werner Cornelius <werner@isdn4linux.de> - * by Karsten Keil <keil@isdn4linux.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 - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "hfc_pci.h" -#include "isdnl1.h" -#include <linux/pci.h> -#include <linux/sched.h> -#include <linux/interrupt.h> - -static const char *hfcpci_revision = "$Revision: 1.48.2.4 $"; - -/* table entry in the PCI devices list */ -typedef struct { - int vendor_id; - int device_id; - char *vendor_name; - char *card_name; -} PCI_ENTRY; - -#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ -#define CLKDEL_TE 0x0e /* CLKDEL in TE mode */ -#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ - -static const PCI_ENTRY id_list[] = -{ - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_2BD0, "CCD/Billion/Asuscom", "2BD0"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B000, "Billion", "B000"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B006, "Billion", "B006"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B007, "Billion", "B007"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B008, "Billion", "B008"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B009, "Billion", "B009"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00A, "Billion", "B00A"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00B, "Billion", "B00B"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B00C, "Billion", "B00C"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B100, "Seyeon", "B100"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B700, "Primux II S0", "B700"}, - {PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_B701, "Primux II S0 NT", "B701"}, - {PCI_VENDOR_ID_ABOCOM, PCI_DEVICE_ID_ABOCOM_2BD1, "Abocom/Magitek", "2BD1"}, - {PCI_VENDOR_ID_ASUSTEK, PCI_DEVICE_ID_ASUSTEK_0675, "Asuscom/Askey", "675"}, - {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_T_CONCEPT, "German telekom", "T-Concept"}, - {PCI_VENDOR_ID_BERKOM, PCI_DEVICE_ID_BERKOM_A1T, "German telekom", "A1T"}, - {PCI_VENDOR_ID_ANIGMA, PCI_DEVICE_ID_ANIGMA_MC145575, "Motorola MC145575", "MC145575"}, - {PCI_VENDOR_ID_ZOLTRIX, PCI_DEVICE_ID_ZOLTRIX_2BD0, "Zoltrix", "2BD0"}, - {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_E, "Digi International", "Digi DataFire Micro V IOM2 (Europe)"}, - {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E, "Digi International", "Digi DataFire Micro V (Europe)"}, - {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A, "Digi International", "Digi DataFire Micro V IOM2 (North America)"}, - {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A, "Digi International", "Digi DataFire Micro V (North America)"}, - {PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2, "Sitecom Europe", "DC-105 ISDN PCI"}, - {0, 0, NULL, NULL}, -}; - - -/******************************************/ -/* free hardware resources used by driver */ -/******************************************/ -static void -release_io_hfcpci(struct IsdnCardState *cs) -{ - printk(KERN_INFO "HiSax: release hfcpci at %p\n", - cs->hw.hfcpci.pci_io); - cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */ - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ - mdelay(10); - Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ - mdelay(10); - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, 0); /* disable memory mapped ports + busmaster */ - del_timer(&cs->hw.hfcpci.timer); - pci_free_consistent(cs->hw.hfcpci.dev, 0x8000, - cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma); - cs->hw.hfcpci.fifos = NULL; - iounmap(cs->hw.hfcpci.pci_io); -} - -/********************************************************************************/ -/* function called to reset the HFC PCI chip. A complete software reset of chip */ -/* and fifos is done. */ -/********************************************************************************/ -static void -reset_hfcpci(struct IsdnCardState *cs) -{ - pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */ - cs->hw.hfcpci.int_m2 = 0; /* interrupt output off ! */ - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - - printk(KERN_INFO "HFC_PCI: resetting card\n"); - pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO + PCI_ENA_MASTER); /* enable memory ports + busmaster */ - Write_hfc(cs, HFCPCI_CIRM, HFCPCI_RESET); /* Reset On */ - mdelay(10); - Write_hfc(cs, HFCPCI_CIRM, 0); /* Reset Off */ - mdelay(10); - if (Read_hfc(cs, HFCPCI_STATUS) & 2) - printk(KERN_WARNING "HFC-PCI init bit busy\n"); - - cs->hw.hfcpci.fifo_en = 0x30; /* only D fifos enabled */ - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - - cs->hw.hfcpci.trm = 0 + HFCPCI_BTRANS_THRESMASK; /* no echo connect , threshold */ - Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); - - Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_TE); /* ST-Bit delay for TE-Mode */ - cs->hw.hfcpci.sctrl_e = HFCPCI_AUTO_AWAKE; - Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); /* S/T Auto awake */ - cs->hw.hfcpci.bswapped = 0; /* no exchange */ - cs->hw.hfcpci.nt_mode = 0; /* we are in TE mode */ - cs->hw.hfcpci.ctmt = HFCPCI_TIM3_125 | HFCPCI_AUTO_TIMER; - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt); - - cs->hw.hfcpci.int_m1 = HFCPCI_INTS_DTRANS | HFCPCI_INTS_DREC | - HFCPCI_INTS_L1STATE | HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - - /* Clear already pending ints */ - Read_hfc(cs, HFCPCI_INT_S1); - - Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 2); /* HFC ST 2 */ - udelay(10); - Write_hfc(cs, HFCPCI_STATES, 2); /* HFC ST 2 */ - cs->hw.hfcpci.mst_m = HFCPCI_MASTER; /* HFC Master Mode */ - - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - cs->hw.hfcpci.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ - Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); - cs->hw.hfcpci.sctrl_r = 0; - Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r); - - /* Init GCI/IOM2 in master mode */ - /* Slots 0 and 1 are set for B-chan 1 and 2 */ - /* D- and monitor/CI channel are not enabled */ - /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ - /* STIO2 is used as data input, B1+B2 from IOM->ST */ - /* ST B-channel send disabled -> continuous 1s */ - /* The IOM slots are always enabled */ - cs->hw.hfcpci.conn = 0x36; /* set data flow directions */ - Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); - Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */ - Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */ - Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */ - Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */ - - /* Finally enable IRQ output */ - cs->hw.hfcpci.int_m2 = HFCPCI_IRQ_ENABLE; - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - Read_hfc(cs, HFCPCI_INT_S1); -} - -/***************************************************/ -/* Timer function called when kernel timer expires */ -/***************************************************/ -static void -hfcpci_Timer(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.hfcpci.timer); - cs->hw.hfcpci.timer.expires = jiffies + 75; - /* WD RESET */ -/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcpci.ctmt | 0x80); - add_timer(&cs->hw.hfcpci.timer); -*/ -} - - -/*********************************/ -/* schedule a new D-channel task */ -/*********************************/ -static void -sched_event_D_pci(struct IsdnCardState *cs, int event) -{ - test_and_set_bit(event, &cs->event); - schedule_work(&cs->tqueue); -} - -/*********************************/ -/* schedule a new b_channel task */ -/*********************************/ -static void -hfcpci_sched_event(struct BCState *bcs, int event) -{ - test_and_set_bit(event, &bcs->event); - schedule_work(&bcs->tqueue); -} - -/************************************************/ -/* select a b-channel entry matching and active */ -/************************************************/ -static -struct BCState * -Sel_BCS(struct IsdnCardState *cs, int channel) -{ - if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) - return (&cs->bcs[0]); - else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) - return (&cs->bcs[1]); - else - return (NULL); -} - -/***************************************/ -/* clear the desired B-channel rx fifo */ -/***************************************/ -static void hfcpci_clear_fifo_rx(struct IsdnCardState *cs, int fifo) -{ u_char fifo_state; - bzfifo_type *bzr; - - if (fifo) { - bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; - fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2RX; - } else { - bzr = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1; - fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1RX; - } - if (fifo_state) - cs->hw.hfcpci.fifo_en ^= fifo_state; - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - cs->hw.hfcpci.last_bfifo_cnt[fifo] = 0; - bzr->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; - bzr->za[MAX_B_FRAMES].z2 = bzr->za[MAX_B_FRAMES].z1; - bzr->f1 = MAX_B_FRAMES; - bzr->f2 = bzr->f1; /* init F pointers to remain constant */ - if (fifo_state) - cs->hw.hfcpci.fifo_en |= fifo_state; - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); -} - -/***************************************/ -/* clear the desired B-channel tx fifo */ -/***************************************/ -static void hfcpci_clear_fifo_tx(struct IsdnCardState *cs, int fifo) -{ u_char fifo_state; - bzfifo_type *bzt; - - if (fifo) { - bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2; - fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B2TX; - } else { - bzt = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1; - fifo_state = cs->hw.hfcpci.fifo_en & HFCPCI_FIFOEN_B1TX; - } - if (fifo_state) - cs->hw.hfcpci.fifo_en ^= fifo_state; - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - bzt->za[MAX_B_FRAMES].z1 = B_FIFO_SIZE + B_SUB_VAL - 1; - bzt->za[MAX_B_FRAMES].z2 = bzt->za[MAX_B_FRAMES].z1; - bzt->f1 = MAX_B_FRAMES; - bzt->f2 = bzt->f1; /* init F pointers to remain constant */ - if (fifo_state) - cs->hw.hfcpci.fifo_en |= fifo_state; - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); -} - -/*********************************************/ -/* read a complete B-frame out of the buffer */ -/*********************************************/ -static struct sk_buff -* -hfcpci_empty_fifo(struct BCState *bcs, bzfifo_type *bz, u_char *bdata, int count) -{ - u_char *ptr, *ptr1, new_f2; - struct sk_buff *skb; - struct IsdnCardState *cs = bcs->cs; - int maxlen, new_z2; - z_type *zp; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hfcpci_empty_fifo"); - zp = &bz->za[bz->f2]; /* point to Z-Regs */ - new_z2 = zp->z2 + count; /* new position in fifo */ - if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; - if ((count > HSCX_BUFMAX + 3) || (count < 4) || - (*(bdata + (zp->z1 - B_SUB_VAL)))) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcpci_empty_fifo: incoming packet invalid length %d or crc", count); -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - bz->za[new_f2].z2 = new_z2; - bz->f2 = new_f2; /* next buffer */ - skb = NULL; - } else if (!(skb = dev_alloc_skb(count - 3))) - printk(KERN_WARNING "HFCPCI: receive out of memory\n"); - else { - count -= 3; - ptr = skb_put(skb, count); - - if (zp->z2 + count <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = count; /* complete transfer */ - else - maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */ - - ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - count -= maxlen; - - if (count) { /* rest remaining */ - ptr += maxlen; - ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, count); /* rest */ - } - bz->za[new_f2].z2 = new_z2; - bz->f2 = new_f2; /* next buffer */ - - } - return (skb); -} - -/*******************************/ -/* D-channel receive procedure */ -/*******************************/ -static -int -receive_dmsg(struct IsdnCardState *cs) -{ - struct sk_buff *skb; - int maxlen; - int rcnt, total; - int count = 5; - u_char *ptr, *ptr1; - dfifo_type *df; - z_type *zp; - - df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_rx; - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_dmsg blocked"); - return (1); - } - while (((df->f1 & D_FREG_MASK) != (df->f2 & D_FREG_MASK)) && count--) { - zp = &df->za[df->f2 & D_FREG_MASK]; - rcnt = zp->z1 - zp->z2; - if (rcnt < 0) - rcnt += D_FIFO_SIZE; - rcnt++; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci recd f1(%d) f2(%d) z1(%x) z2(%x) cnt(%d)", - df->f1, df->f2, zp->z1, zp->z2, rcnt); - - if ((rcnt > MAX_DFRAME_LEN + 3) || (rcnt < 4) || - (df->data[zp->z1])) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "empty_fifo hfcpci packet inv. len %d or crc %d", rcnt, df->data[zp->z1]); -#ifdef ERROR_STATISTIC - cs->err_rx++; -#endif - df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ - df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + rcnt) & (D_FIFO_SIZE - 1); - } else if ((skb = dev_alloc_skb(rcnt - 3))) { - total = rcnt; - rcnt -= 3; - ptr = skb_put(skb, rcnt); - - if (zp->z2 + rcnt <= D_FIFO_SIZE) - maxlen = rcnt; /* complete transfer */ - else - maxlen = D_FIFO_SIZE - zp->z2; /* maximum */ - - ptr1 = df->data + zp->z2; /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - rcnt -= maxlen; - - if (rcnt) { /* rest remaining */ - ptr += maxlen; - ptr1 = df->data; /* start of buffer */ - memcpy(ptr, ptr1, rcnt); /* rest */ - } - df->f2 = ((df->f2 + 1) & MAX_D_FRAMES) | (MAX_D_FRAMES + 1); /* next buffer */ - df->za[df->f2 & D_FREG_MASK].z2 = (zp->z2 + total) & (D_FIFO_SIZE - 1); - - skb_queue_tail(&cs->rq, skb); - sched_event_D_pci(cs, D_RCVBUFREADY); - } else - printk(KERN_WARNING "HFC-PCI: D receive out of memory\n"); - } - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - return (1); -} - -/*******************************************************************************/ -/* check for transparent receive data and read max one threshold size if avail */ -/*******************************************************************************/ -static int -hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type *bz, u_char *bdata) -{ - unsigned short *z1r, *z2r; - int new_z2, fcnt, maxlen; - struct sk_buff *skb; - u_char *ptr, *ptr1; - - z1r = &bz->za[MAX_B_FRAMES].z1; /* pointer to z reg */ - z2r = z1r + 1; - - if (!(fcnt = *z1r - *z2r)) - return (0); /* no data avail */ - - if (fcnt <= 0) - fcnt += B_FIFO_SIZE; /* bytes actually buffered */ - if (fcnt > HFCPCI_BTRANS_THRESHOLD) - fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */ - - new_z2 = *z2r + fcnt; /* new position in fifo */ - if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - - if (!(skb = dev_alloc_skb(fcnt))) - printk(KERN_WARNING "HFCPCI: receive out of memory\n"); - else { - ptr = skb_put(skb, fcnt); - if (*z2r + fcnt <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = fcnt; /* complete transfer */ - else - maxlen = B_FIFO_SIZE + B_SUB_VAL - *z2r; /* maximum */ - - ptr1 = bdata + (*z2r - B_SUB_VAL); /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - fcnt -= maxlen; - - if (fcnt) { /* rest remaining */ - ptr += maxlen; - ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, fcnt); /* rest */ - } - skb_queue_tail(&bcs->rqueue, skb); - hfcpci_sched_event(bcs, B_RCVBUFREADY); - } - - *z2r = new_z2; /* new position */ - return (1); -} /* hfcpci_empty_fifo_trans */ - -/**********************************/ -/* B-channel main receive routine */ -/**********************************/ -static void -main_rec_hfcpci(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int rcnt, real_fifo; - int receive, count = 5; - struct sk_buff *skb; - bzfifo_type *bz; - u_char *bdata; - z_type *zp; - - - if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) { - bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; - bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2; - real_fifo = 1; - } else { - bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b1; - bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b1; - real_fifo = 0; - } -Begin: - count--; - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_data %d blocked", bcs->channel); - return; - } - if (bz->f1 != bz->f2) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci rec %d f1(%d) f2(%d)", - bcs->channel, bz->f1, bz->f2); - zp = &bz->za[bz->f2]; - - rcnt = zp->z1 - zp->z2; - if (rcnt < 0) - rcnt += B_FIFO_SIZE; - rcnt++; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci rec %d z1(%x) z2(%x) cnt(%d)", - bcs->channel, zp->z1, zp->z2, rcnt); - if ((skb = hfcpci_empty_fifo(bcs, bz, bdata, rcnt))) { - skb_queue_tail(&bcs->rqueue, skb); - hfcpci_sched_event(bcs, B_RCVBUFREADY); - } - rcnt = bz->f1 - bz->f2; - if (rcnt < 0) - rcnt += MAX_B_FRAMES + 1; - if (cs->hw.hfcpci.last_bfifo_cnt[real_fifo] > rcnt + 1) { - rcnt = 0; - hfcpci_clear_fifo_rx(cs, real_fifo); - } - cs->hw.hfcpci.last_bfifo_cnt[real_fifo] = rcnt; - if (rcnt > 1) - receive = 1; - else - receive = 0; - } else if (bcs->mode == L1_MODE_TRANS) - receive = hfcpci_empty_fifo_trans(bcs, bz, bdata); - else - receive = 0; - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - if (count && receive) - goto Begin; -} - -/**************************/ -/* D-channel send routine */ -/**************************/ -static void -hfcpci_fill_dfifo(struct IsdnCardState *cs) -{ - int fcnt; - int count, new_z1, maxlen; - dfifo_type *df; - u_char *src, *dst, new_f1; - - if (!cs->tx_skb) - return; - if (cs->tx_skb->len <= 0) - return; - - df = &((fifo_area *) (cs->hw.hfcpci.fifos))->d_chan.d_tx; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci_fill_Dfifo f1(%d) f2(%d) z1(f1)(%x)", - df->f1, df->f2, - df->za[df->f1 & D_FREG_MASK].z1); - fcnt = df->f1 - df->f2; /* frame count actually buffered */ - if (fcnt < 0) - fcnt += (MAX_D_FRAMES + 1); /* if wrap around */ - if (fcnt > (MAX_D_FRAMES - 1)) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci_fill_Dfifo more as 14 frames"); -#ifdef ERROR_STATISTIC - cs->err_tx++; -#endif - return; - } - /* now determine free bytes in FIFO buffer */ - count = df->za[df->f2 & D_FREG_MASK].z2 - df->za[df->f1 & D_FREG_MASK].z1 - 1; - if (count <= 0) - count += D_FIFO_SIZE; /* count now contains available bytes */ - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci_fill_Dfifo count(%u/%d)", - cs->tx_skb->len, count); - if (count < cs->tx_skb->len) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci_fill_Dfifo no fifo mem"); - return; - } - count = cs->tx_skb->len; /* get frame len */ - new_z1 = (df->za[df->f1 & D_FREG_MASK].z1 + count) & (D_FIFO_SIZE - 1); - new_f1 = ((df->f1 + 1) & D_FREG_MASK) | (D_FREG_MASK + 1); - src = cs->tx_skb->data; /* source pointer */ - dst = df->data + df->za[df->f1 & D_FREG_MASK].z1; - maxlen = D_FIFO_SIZE - df->za[df->f1 & D_FREG_MASK].z1; /* end fifo */ - if (maxlen > count) - maxlen = count; /* limit size */ - memcpy(dst, src, maxlen); /* first copy */ - - count -= maxlen; /* remaining bytes */ - if (count) { - dst = df->data; /* start of buffer */ - src += maxlen; /* new position */ - memcpy(dst, src, count); - } - df->za[new_f1 & D_FREG_MASK].z1 = new_z1; /* for next buffer */ - df->za[df->f1 & D_FREG_MASK].z1 = new_z1; /* new pos actual buffer */ - df->f1 = new_f1; /* next frame */ - - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; -} - -/**************************/ -/* B-channel send routine */ -/**************************/ -static void -hfcpci_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int maxlen, fcnt; - int count, new_z1; - bzfifo_type *bz; - u_char *bdata; - u_char new_f1, *src, *dst; - unsigned short *z1t, *z2t; - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - if ((bcs->channel) && (!cs->hw.hfcpci.bswapped)) { - bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b2; - bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b2; - } else { - bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txbz_b1; - bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.txdat_b1; - } - - if (bcs->mode == L1_MODE_TRANS) { - z1t = &bz->za[MAX_B_FRAMES].z1; - z2t = z1t + 1; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo_trans %d z1(%x) z2(%x)", - bcs->channel, *z1t, *z2t); - fcnt = *z2t - *z1t; - if (fcnt <= 0) - fcnt += B_FIFO_SIZE; /* fcnt contains available bytes in fifo */ - fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send */ - - while ((fcnt < 2 * HFCPCI_BTRANS_THRESHOLD) && (bcs->tx_skb)) { - if (bcs->tx_skb->len < B_FIFO_SIZE - fcnt) { - /* data is suitable for fifo */ - count = bcs->tx_skb->len; - - new_z1 = *z1t + count; /* new buffer Position */ - if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z1 -= B_FIFO_SIZE; /* buffer wrap */ - src = bcs->tx_skb->data; /* source pointer */ - dst = bdata + (*z1t - B_SUB_VAL); - maxlen = (B_FIFO_SIZE + B_SUB_VAL) - *z1t; /* end of fifo */ - if (maxlen > count) - maxlen = count; /* limit size */ - memcpy(dst, src, maxlen); /* first copy */ - - count -= maxlen; /* remaining bytes */ - if (count) { - dst = bdata; /* start of buffer */ - src += maxlen; /* new position */ - memcpy(dst, src, count); - } - bcs->tx_cnt -= bcs->tx_skb->len; - fcnt += bcs->tx_skb->len; - *z1t = new_z1; /* now send data */ - } else if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo_trans %d frame length %d discarded", - bcs->channel, bcs->tx_skb->len); - - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->tx_skb->len; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - - dev_consume_skb_any(bcs->tx_skb); - bcs->tx_skb = skb_dequeue(&bcs->squeue); /* fetch next data */ - } - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - return; - } - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo_hdlc %d f1(%d) f2(%d) z1(f1)(%x)", - bcs->channel, bz->f1, bz->f2, - bz->za[bz->f1].z1); - - fcnt = bz->f1 - bz->f2; /* frame count actually buffered */ - if (fcnt < 0) - fcnt += (MAX_B_FRAMES + 1); /* if wrap around */ - if (fcnt > (MAX_B_FRAMES - 1)) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_Bfifo more as 14 frames"); - return; - } - /* now determine free bytes in FIFO buffer */ - count = bz->za[bz->f2].z2 - bz->za[bz->f1].z1 - 1; - if (count <= 0) - count += B_FIFO_SIZE; /* count now contains available bytes */ - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo %d count(%u/%d),%lx", - bcs->channel, bcs->tx_skb->len, - count, current->state); - - if (count < bcs->tx_skb->len) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hfcpci_fill_fifo no fifo mem"); - return; - } - count = bcs->tx_skb->len; /* get frame len */ - new_z1 = bz->za[bz->f1].z1 + count; /* new buffer Position */ - if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z1 -= B_FIFO_SIZE; /* buffer wrap */ - - new_f1 = ((bz->f1 + 1) & MAX_B_FRAMES); - src = bcs->tx_skb->data; /* source pointer */ - dst = bdata + (bz->za[bz->f1].z1 - B_SUB_VAL); - maxlen = (B_FIFO_SIZE + B_SUB_VAL) - bz->za[bz->f1].z1; /* end fifo */ - if (maxlen > count) - maxlen = count; /* limit size */ - memcpy(dst, src, maxlen); /* first copy */ - - count -= maxlen; /* remaining bytes */ - if (count) { - dst = bdata; /* start of buffer */ - src += maxlen; /* new position */ - memcpy(dst, src, count); - } - bcs->tx_cnt -= bcs->tx_skb->len; - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->tx_skb->len; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - - bz->za[new_f1].z1 = new_z1; /* for next buffer */ - bz->f1 = new_f1; /* next frame */ - - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); -} - -/**********************************************/ -/* D-channel l1 state call for leased NT-mode */ -/**********************************************/ -static void -dch_nt_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - - switch (pr) { - case (PH_DATA | REQUEST): - case (PH_PULL | REQUEST): - case (PH_PULL | INDICATION): - st->l1.l1hw(st, pr, arg); - break; - case (PH_ACTIVATE | REQUEST): - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - break; - case (PH_TESTLOOP | REQUEST): - if (1 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B1"); - if (2 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B2"); - if (!(3 & (long) arg)) - debugl1(cs, "PH_TEST_LOOP DISABLED"); - st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); - break; - default: - if (cs->debug) - debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr); - break; - } -} - - - -/***********************/ -/* set/reset echo mode */ -/***********************/ -static int -hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) -{ - u_long flags; - int i = *(unsigned int *) ic->parm.num; - - if ((ic->arg == 98) && - (!(cs->hw.hfcpci.int_m1 & (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC + HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC)))) { - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCPCI_CLKDEL, CLKDEL_NT); /* ST-Bit delay for NT-Mode */ - Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 0); /* HFC ST G0 */ - udelay(10); - cs->hw.hfcpci.sctrl |= SCTRL_MODE_NT; - Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); /* set NT-mode */ - udelay(10); - Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 1); /* HFC ST G1 */ - udelay(10); - Write_hfc(cs, HFCPCI_STATES, 1 | HFCPCI_ACTIVATE | HFCPCI_DO_ACTION); - cs->dc.hfcpci.ph_state = 1; - cs->hw.hfcpci.nt_mode = 1; - cs->hw.hfcpci.nt_timer = 0; - cs->stlist->l2.l2l1 = dch_nt_l2l1; - spin_unlock_irqrestore(&cs->lock, flags); - debugl1(cs, "NT mode activated"); - return (0); - } - if ((cs->chanlimit > 1) || (cs->hw.hfcpci.bswapped) || - (cs->hw.hfcpci.nt_mode) || (ic->arg != 12)) - return (-EINVAL); - - spin_lock_irqsave(&cs->lock, flags); - if (i) { - cs->logecho = 1; - cs->hw.hfcpci.trm |= 0x20; /* enable echo chan */ - cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_B2REC; - cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2RX; - } else { - cs->logecho = 0; - cs->hw.hfcpci.trm &= ~0x20; /* disable echo chan */ - cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_B2REC; - cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2RX; - } - cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA; - cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA; - cs->hw.hfcpci.conn |= 0x10; /* B2-IOM -> B2-ST */ - cs->hw.hfcpci.ctmt &= ~2; - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt); - Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r); - Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); - Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); - Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); -} /* hfcpci_auxcmd */ - -/*****************************/ -/* E-channel receive routine */ -/*****************************/ -static void -receive_emsg(struct IsdnCardState *cs) -{ - int rcnt; - int receive, count = 5; - bzfifo_type *bz; - u_char *bdata; - z_type *zp; - u_char *ptr, *ptr1, new_f2; - int total, maxlen, new_z2; - u_char e_buffer[256]; - - bz = &((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxbz_b2; - bdata = ((fifo_area *) (cs->hw.hfcpci.fifos))->b_chans.rxdat_b2; -Begin: - count--; - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "echo_rec_data blocked"); - return; - } - if (bz->f1 != bz->f2) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci e_rec f1(%d) f2(%d)", - bz->f1, bz->f2); - zp = &bz->za[bz->f2]; - - rcnt = zp->z1 - zp->z2; - if (rcnt < 0) - rcnt += B_FIFO_SIZE; - rcnt++; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "hfcpci e_rec z1(%x) z2(%x) cnt(%d)", - zp->z1, zp->z2, rcnt); - new_z2 = zp->z2 + rcnt; /* new position in fifo */ - if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) - new_z2 -= B_FIFO_SIZE; /* buffer wrap */ - new_f2 = (bz->f2 + 1) & MAX_B_FRAMES; - if ((rcnt > 256 + 3) || (count < 4) || - (*(bdata + (zp->z1 - B_SUB_VAL)))) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcpci_empty_echan: incoming packet invalid length %d or crc", rcnt); - bz->za[new_f2].z2 = new_z2; - bz->f2 = new_f2; /* next buffer */ - } else { - total = rcnt; - rcnt -= 3; - ptr = e_buffer; - - if (zp->z2 <= B_FIFO_SIZE + B_SUB_VAL) - maxlen = rcnt; /* complete transfer */ - else - maxlen = B_FIFO_SIZE + B_SUB_VAL - zp->z2; /* maximum */ - - ptr1 = bdata + (zp->z2 - B_SUB_VAL); /* start of data */ - memcpy(ptr, ptr1, maxlen); /* copy data */ - rcnt -= maxlen; - - if (rcnt) { /* rest remaining */ - ptr += maxlen; - ptr1 = bdata; /* start of buffer */ - memcpy(ptr, ptr1, rcnt); /* rest */ - } - bz->za[new_f2].z2 = new_z2; - bz->f2 = new_f2; /* next buffer */ - if (cs->debug & DEB_DLOG_HEX) { - ptr = cs->dlog; - if ((total - 3) < MAX_DLOG_SPACE / 3 - 10) { - *ptr++ = 'E'; - *ptr++ = 'C'; - *ptr++ = 'H'; - *ptr++ = 'O'; - *ptr++ = ':'; - ptr += QuickHex(ptr, e_buffer, total - 3); - ptr--; - *ptr++ = '\n'; - *ptr = 0; - HiSax_putstatus(cs, NULL, cs->dlog); - } else - HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3); - } - } - - rcnt = bz->f1 - bz->f2; - if (rcnt < 0) - rcnt += MAX_B_FRAMES + 1; - if (rcnt > 1) - receive = 1; - else - receive = 0; - } else - receive = 0; - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - if (count && receive) - goto Begin; -} /* receive_emsg */ - -/*********************/ -/* Interrupt handler */ -/*********************/ -static irqreturn_t -hfcpci_interrupt(int intno, void *dev_id) -{ - u_long flags; - struct IsdnCardState *cs = dev_id; - u_char exval; - struct BCState *bcs; - int count = 15; - u_char val, stat; - - if (!(cs->hw.hfcpci.int_m2 & 0x08)) { - debugl1(cs, "HFC-PCI: int_m2 %x not initialised", cs->hw.hfcpci.int_m2); - return IRQ_NONE; /* not initialised */ - } - spin_lock_irqsave(&cs->lock, flags); - if (HFCPCI_ANYINT & (stat = Read_hfc(cs, HFCPCI_STATUS))) { - val = Read_hfc(cs, HFCPCI_INT_S1); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-PCI: stat(%02x) s1(%02x)", stat, val); - } else { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-PCI irq %x %s", val, - test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? - "locked" : "unlocked"); - val &= cs->hw.hfcpci.int_m1; - if (val & 0x40) { /* state machine irq */ - exval = Read_hfc(cs, HFCPCI_STATES) & 0xf; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcpci.ph_state, - exval); - cs->dc.hfcpci.ph_state = exval; - sched_event_D_pci(cs, D_L1STATECHANGE); - val &= ~0x40; - } - if (val & 0x80) { /* timer irq */ - if (cs->hw.hfcpci.nt_mode) { - if ((--cs->hw.hfcpci.nt_timer) < 0) - sched_event_D_pci(cs, D_L1STATECHANGE); - } - val &= ~0x80; - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER); - } - while (val) { - if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - cs->hw.hfcpci.int_s1 |= val; - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } - if (cs->hw.hfcpci.int_s1 & 0x18) { - exval = val; - val = cs->hw.hfcpci.int_s1; - cs->hw.hfcpci.int_s1 = exval; - } - if (val & 0x08) { - if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) { - if (cs->debug) - debugl1(cs, "hfcpci spurious 0x08 IRQ"); - } else - main_rec_hfcpci(bcs); - } - if (val & 0x10) { - if (cs->logecho) - receive_emsg(cs); - else if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcpci spurious 0x10 IRQ"); - } else - main_rec_hfcpci(bcs); - } - if (val & 0x01) { - if (!(bcs = Sel_BCS(cs, cs->hw.hfcpci.bswapped ? 1 : 0))) { - if (cs->debug) - debugl1(cs, "hfcpci spurious 0x01 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - hfcpci_sched_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x02) { - if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcpci spurious 0x02 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - hfcpci_sched_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x20) { /* receive dframe */ - receive_dmsg(cs); - } - if (val & 0x04) { /* dframe transmitted */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - sched_event_D_pci(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfcpci_fill_dfifo irq blocked"); - } - goto afterXPR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfcpci_fill_dfifo irq blocked"); - } - } else - sched_event_D_pci(cs, D_XMTBUFREADY); - } - afterXPR: - if (cs->hw.hfcpci.int_s1 && count--) { - val = cs->hw.hfcpci.int_s1; - cs->hw.hfcpci.int_s1 = 0; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-PCI irq %x loop %d", val, 15 - count); - } else - val = 0; - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -/********************************************************************/ -/* timer callback for D-chan busy resolution. Currently no function */ -/********************************************************************/ -static void -hfcpci_dbusy_timer(struct timer_list *t) -{ -} - -/*************************************/ -/* Layer 1 D-channel hardware access */ -/*************************************/ -static void -HFCPCI_l1hw(struct PStack *st, int pr, void *arg) -{ - u_long flags; - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfcpci_fill_dfifo blocked"); - - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfcpci_fill_dfifo blocked"); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - spin_lock_irqsave(&cs->lock, flags); - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCPCI_STATES, HFCPCI_LOAD_STATE | 3); /* HFC ST 3 */ - udelay(6); - Write_hfc(cs, HFCPCI_STATES, 3); /* HFC ST 2 */ - cs->hw.hfcpci.mst_m |= HFCPCI_MASTER; - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - Write_hfc(cs, HFCPCI_STATES, HFCPCI_ACTIVATE | HFCPCI_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCPCI_STATES, HFCPCI_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_DEACTIVATE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcpci.mst_m &= ~HFCPCI_MASTER; - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcpci.mst_m |= HFCPCI_MASTER; - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_TESTLOOP | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - switch ((long) arg) { - case (1): - Write_hfc(cs, HFCPCI_B1_SSL, 0x80); /* tx slot */ - Write_hfc(cs, HFCPCI_B1_RSL, 0x80); /* rx slot */ - cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~7) | 1; - Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); - break; - - case (2): - Write_hfc(cs, HFCPCI_B2_SSL, 0x81); /* tx slot */ - Write_hfc(cs, HFCPCI_B2_RSL, 0x81); /* rx slot */ - cs->hw.hfcpci.conn = (cs->hw.hfcpci.conn & ~0x38) | 0x08; - Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); - break; - - default: - spin_unlock_irqrestore(&cs->lock, flags); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcpci_l1hw loop invalid %4lx", (long) arg); - return; - } - cs->hw.hfcpci.trm |= 0x80; /* enable IOM-loop */ - Write_hfc(cs, HFCPCI_TRM, cs->hw.hfcpci.trm); - spin_unlock_irqrestore(&cs->lock, flags); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcpci_l1hw unknown pr %4x", pr); - break; - } -} - -/***********************************************/ -/* called during init setting l1 stack pointer */ -/***********************************************/ -static void -setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = HFCPCI_l1hw; -} - -/**************************************/ -/* send B-channel data if not blocked */ -/**************************************/ -static void -hfcpci_send_data(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcpci_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "send_data %d blocked", bcs->channel); -} - -/***************************************************************/ -/* activate/deactivate hardware for selected channels and mode */ -/***************************************************************/ -static void -mode_hfcpci(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int fifo2; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HFCPCI bchannel mode %d bchan %d/%d", - mode, bc, bcs->channel); - bcs->mode = mode; - bcs->channel = bc; - fifo2 = bc; - if (cs->chanlimit > 1) { - cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcpci.sctrl_e &= ~0x80; - } else { - if (bc) { - if (mode != L1_MODE_NULL) { - cs->hw.hfcpci.bswapped = 1; /* B1 and B2 exchanged */ - cs->hw.hfcpci.sctrl_e |= 0x80; - } else { - cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcpci.sctrl_e &= ~0x80; - } - fifo2 = 0; - } else { - cs->hw.hfcpci.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcpci.sctrl_e &= ~0x80; - } - } - switch (mode) { - case (L1_MODE_NULL): - if (bc) { - cs->hw.hfcpci.sctrl &= ~SCTRL_B2_ENA; - cs->hw.hfcpci.sctrl_r &= ~SCTRL_B2_ENA; - } else { - cs->hw.hfcpci.sctrl &= ~SCTRL_B1_ENA; - cs->hw.hfcpci.sctrl_r &= ~SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2; - cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - } else { - cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1; - cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - } - break; - case (L1_MODE_TRANS): - hfcpci_clear_fifo_rx(cs, fifo2); - hfcpci_clear_fifo_tx(cs, fifo2); - if (bc) { - cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; - } else { - cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2; - cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - cs->hw.hfcpci.ctmt |= 2; - cs->hw.hfcpci.conn &= ~0x18; - } else { - cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1; - cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - cs->hw.hfcpci.ctmt |= 1; - cs->hw.hfcpci.conn &= ~0x03; - } - break; - case (L1_MODE_HDLC): - hfcpci_clear_fifo_rx(cs, fifo2); - hfcpci_clear_fifo_tx(cs, fifo2); - if (bc) { - cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; - } else { - cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcpci.last_bfifo_cnt[1] = 0; - cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B2; - cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - cs->hw.hfcpci.ctmt &= ~2; - cs->hw.hfcpci.conn &= ~0x18; - } else { - cs->hw.hfcpci.last_bfifo_cnt[0] = 0; - cs->hw.hfcpci.fifo_en |= HFCPCI_FIFOEN_B1; - cs->hw.hfcpci.int_m1 |= (HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - cs->hw.hfcpci.ctmt &= ~1; - cs->hw.hfcpci.conn &= ~0x03; - } - break; - case (L1_MODE_EXTRN): - if (bc) { - cs->hw.hfcpci.conn |= 0x10; - cs->hw.hfcpci.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B2_ENA; - cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B2; - cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B2TRANS + HFCPCI_INTS_B2REC); - } else { - cs->hw.hfcpci.conn |= 0x02; - cs->hw.hfcpci.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcpci.sctrl_r |= SCTRL_B1_ENA; - cs->hw.hfcpci.fifo_en &= ~HFCPCI_FIFOEN_B1; - cs->hw.hfcpci.int_m1 &= ~(HFCPCI_INTS_B1TRANS + HFCPCI_INTS_B1REC); - } - break; - } - Write_hfc(cs, HFCPCI_SCTRL_E, cs->hw.hfcpci.sctrl_e); - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - Write_hfc(cs, HFCPCI_FIFO_EN, cs->hw.hfcpci.fifo_en); - Write_hfc(cs, HFCPCI_SCTRL, cs->hw.hfcpci.sctrl); - Write_hfc(cs, HFCPCI_SCTRL_R, cs->hw.hfcpci.sctrl_r); - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt); - Write_hfc(cs, HFCPCI_CONNECT, cs->hw.hfcpci.conn); -} - -/******************************/ -/* Layer2 -> Layer 1 Transfer */ -/******************************/ -static void -hfcpci_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - u_long flags; - struct sk_buff *skb = arg; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - spin_unlock_irqrestore(&bcs->cs->lock, flags); - printk(KERN_WARNING "hfc_l2l1: this shouldn't happen\n"); - break; - } -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - mode_hfcpci(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - mode_hfcpci(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -/******************************************/ -/* deactivate B-channel access and queues */ -/******************************************/ -static void -close_hfcpci(struct BCState *bcs) -{ - mode_hfcpci(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -/*************************************/ -/* init B-channel queues and control */ -/*************************************/ -static int -open_hfcpcistate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -/*********************************/ -/* inits the stack for B-channel */ -/*********************************/ -static int -setstack_2b(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hfcpcistate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hfcpci_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -/***************************/ -/* handle L1 state changes */ -/***************************/ -static void -hfcpci_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - u_long flags; -// struct PStack *stptr; - - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - if (!cs->hw.hfcpci.nt_mode) - switch (cs->dc.hfcpci.ph_state) { - case (0): - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - case (3): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (8): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (6): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (7): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - default: - break; - } else { - spin_lock_irqsave(&cs->lock, flags); - switch (cs->dc.hfcpci.ph_state) { - case (2): - if (cs->hw.hfcpci.nt_timer < 0) { - cs->hw.hfcpci.nt_timer = 0; - cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - /* Clear already pending ints */ - Read_hfc(cs, HFCPCI_INT_S1); - Write_hfc(cs, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE); - udelay(10); - Write_hfc(cs, HFCPCI_STATES, 4); - cs->dc.hfcpci.ph_state = 4; - } else { - cs->hw.hfcpci.int_m1 |= HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - cs->hw.hfcpci.ctmt &= ~HFCPCI_AUTO_TIMER; - cs->hw.hfcpci.ctmt |= HFCPCI_TIM3_125; - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER); - Write_hfc(cs, HFCPCI_CTMT, cs->hw.hfcpci.ctmt | HFCPCI_CLTIMER); - cs->hw.hfcpci.nt_timer = NT_T1_COUNT; - Write_hfc(cs, HFCPCI_STATES, 2 | HFCPCI_NT_G2_G3); /* allow G2 -> G3 transition */ - } - break; - case (1): - case (3): - case (4): - cs->hw.hfcpci.nt_timer = 0; - cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - break; - default: - break; - } - spin_unlock_irqrestore(&cs->lock, flags); - } - } - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -} - - -/********************************/ -/* called for card init message */ -/********************************/ -static void -inithfcpci(struct IsdnCardState *cs) -{ - cs->bcs[0].BC_SetStack = setstack_2b; - cs->bcs[1].BC_SetStack = setstack_2b; - cs->bcs[0].BC_Close = close_hfcpci; - cs->bcs[1].BC_Close = close_hfcpci; - timer_setup(&cs->dbusytimer, hfcpci_dbusy_timer, 0); - mode_hfcpci(cs->bcs, 0, 0); - mode_hfcpci(cs->bcs + 1, 0, 1); -} - - - -/*******************************************/ -/* handle card messages from control layer */ -/*******************************************/ -static int -hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCPCI: card_msg %x", mt); - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_hfcpci(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_hfcpci(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithfcpci(cs); - reset_hfcpci(cs); - spin_unlock_irqrestore(&cs->lock, flags); - msleep(80); /* Timeout 80ms */ - /* now switch timer interrupt off */ - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcpci.int_m1 &= ~HFCPCI_INTS_TIMER; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - /* reinit mode reg */ - Write_hfc(cs, HFCPCI_MST_MODE, cs->hw.hfcpci.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - - -/* this variable is used as card index when more than one cards are present */ -static struct pci_dev *dev_hfcpci = NULL; - -int -setup_hfcpci(struct IsdnCard *card) -{ - u_long flags; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - int i; - struct pci_dev *tmp_hfcpci = NULL; - - strcpy(tmp, hfcpci_revision); - printk(KERN_INFO "HiSax: HFC-PCI driver Rev. %s\n", HiSax_getrev(tmp)); - - cs->hw.hfcpci.int_s1 = 0; - cs->dc.hfcpci.ph_state = 0; - cs->hw.hfcpci.fifo = 255; - if (cs->typ != ISDN_CTYPE_HFC_PCI) - return (0); - - i = 0; - while (id_list[i].vendor_id) { - tmp_hfcpci = hisax_find_pci_device(id_list[i].vendor_id, - id_list[i].device_id, - dev_hfcpci); - i++; - if (tmp_hfcpci) { - dma_addr_t dma_mask = DMA_BIT_MASK(32) & ~0x7fffUL; - if (pci_enable_device(tmp_hfcpci)) - continue; - if (pci_set_dma_mask(tmp_hfcpci, dma_mask)) { - printk(KERN_WARNING - "HiSax hfc_pci: No suitable DMA available.\n"); - continue; - } - if (pci_set_consistent_dma_mask(tmp_hfcpci, dma_mask)) { - printk(KERN_WARNING - "HiSax hfc_pci: No suitable consistent DMA available.\n"); - continue; - } - pci_set_master(tmp_hfcpci); - if ((card->para[0]) && (card->para[0] != (tmp_hfcpci->resource[0].start & PCI_BASE_ADDRESS_IO_MASK))) - continue; - else - break; - } - } - - if (!tmp_hfcpci) { - printk(KERN_WARNING "HFC-PCI: No PCI card found\n"); - return (0); - } - - i--; - dev_hfcpci = tmp_hfcpci; /* old device */ - cs->hw.hfcpci.dev = dev_hfcpci; - cs->irq = dev_hfcpci->irq; - if (!cs->irq) { - printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.hfcpci.pci_io = ioremap(dev_hfcpci->resource[1].start, 256); - printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name); - - if (!cs->hw.hfcpci.pci_io) { - printk(KERN_WARNING "HFC-PCI: No IO-Mem for PCI card found\n"); - return (0); - } - - /* Allocate memory for FIFOS */ - cs->hw.hfcpci.fifos = pci_alloc_consistent(cs->hw.hfcpci.dev, - 0x8000, &cs->hw.hfcpci.dma); - if (!cs->hw.hfcpci.fifos) { - printk(KERN_WARNING "HFC-PCI: Error allocating FIFO memory!\n"); - return 0; - } - if (cs->hw.hfcpci.dma & 0x7fff) { - printk(KERN_WARNING - "HFC-PCI: Error DMA memory not on 32K boundary (%lx)\n", - (u_long)cs->hw.hfcpci.dma); - pci_free_consistent(cs->hw.hfcpci.dev, 0x8000, - cs->hw.hfcpci.fifos, cs->hw.hfcpci.dma); - return 0; - } - pci_write_config_dword(cs->hw.hfcpci.dev, 0x80, (u32)cs->hw.hfcpci.dma); - printk(KERN_INFO - "HFC-PCI: defined at mem %p fifo %p(%lx) IRQ %d HZ %d\n", - cs->hw.hfcpci.pci_io, - cs->hw.hfcpci.fifos, - (u_long)cs->hw.hfcpci.dma, - cs->irq, HZ); - - spin_lock_irqsave(&cs->lock, flags); - - pci_write_config_word(cs->hw.hfcpci.dev, PCI_COMMAND, PCI_ENA_MEMIO); /* enable memory mapped ports, disable busmaster */ - cs->hw.hfcpci.int_m2 = 0; /* disable alle interrupts */ - cs->hw.hfcpci.int_m1 = 0; - Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); - Write_hfc(cs, HFCPCI_INT_M2, cs->hw.hfcpci.int_m2); - /* At this point the needed PCI config is done */ - /* fifos are still not enabled */ - - INIT_WORK(&cs->tqueue, hfcpci_bh); - cs->setstack_d = setstack_hfcpci; - cs->BC_Send_Data = &hfcpci_send_data; - cs->readisac = NULL; - cs->writeisac = NULL; - cs->readisacfifo = NULL; - cs->writeisacfifo = NULL; - cs->BC_Read_Reg = NULL; - cs->BC_Write_Reg = NULL; - cs->irq_func = &hfcpci_interrupt; - cs->irq_flags |= IRQF_SHARED; - timer_setup(&cs->hw.hfcpci.timer, hfcpci_Timer, 0); - cs->cardmsg = &hfcpci_card_msg; - cs->auxcmd = &hfcpci_auxcmd; - - spin_unlock_irqrestore(&cs->lock, flags); - - return (1); -} diff --git a/drivers/isdn/hisax/hfc_pci.h b/drivers/isdn/hisax/hfc_pci.h deleted file mode 100644 index 4c3b3ba35726..000000000000 --- a/drivers/isdn/hisax/hfc_pci.h +++ /dev/null @@ -1,235 +0,0 @@ -/* $Id: hfc_pci.h,v 1.10.2.2 2004/01/12 22:52:26 keil Exp $ - * - * specific defines for CCD's HFC 2BDS0 PCI chips - * - * Author Werner Cornelius - * Copyright by Werner Cornelius <werner@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/*********************************************/ -/* thresholds for transparent B-channel mode */ -/* change mask and threshold simultaneously */ -/*********************************************/ -#define HFCPCI_BTRANS_THRESHOLD 128 -#define HFCPCI_BTRANS_THRESMASK 0x00 - - - -/* defines for PCI config */ - -#define PCI_ENA_MEMIO 0x02 -#define PCI_ENA_MASTER 0x04 - - -/* GCI/IOM bus monitor registers */ - -#define HCFPCI_C_I 0x08 -#define HFCPCI_TRxR 0x0C -#define HFCPCI_MON1_D 0x28 -#define HFCPCI_MON2_D 0x2C - - -/* GCI/IOM bus timeslot registers */ - -#define HFCPCI_B1_SSL 0x80 -#define HFCPCI_B2_SSL 0x84 -#define HFCPCI_AUX1_SSL 0x88 -#define HFCPCI_AUX2_SSL 0x8C -#define HFCPCI_B1_RSL 0x90 -#define HFCPCI_B2_RSL 0x94 -#define HFCPCI_AUX1_RSL 0x98 -#define HFCPCI_AUX2_RSL 0x9C - -/* GCI/IOM bus data registers */ - -#define HFCPCI_B1_D 0xA0 -#define HFCPCI_B2_D 0xA4 -#define HFCPCI_AUX1_D 0xA8 -#define HFCPCI_AUX2_D 0xAC - -/* GCI/IOM bus configuration registers */ - -#define HFCPCI_MST_EMOD 0xB4 -#define HFCPCI_MST_MODE 0xB8 -#define HFCPCI_CONNECT 0xBC - - -/* Interrupt and status registers */ - -#define HFCPCI_FIFO_EN 0x44 -#define HFCPCI_TRM 0x48 -#define HFCPCI_B_MODE 0x4C -#define HFCPCI_CHIP_ID 0x58 -#define HFCPCI_CIRM 0x60 -#define HFCPCI_CTMT 0x64 -#define HFCPCI_INT_M1 0x68 -#define HFCPCI_INT_M2 0x6C -#define HFCPCI_INT_S1 0x78 -#define HFCPCI_INT_S2 0x7C -#define HFCPCI_STATUS 0x70 - -/* S/T section registers */ - -#define HFCPCI_STATES 0xC0 -#define HFCPCI_SCTRL 0xC4 -#define HFCPCI_SCTRL_E 0xC8 -#define HFCPCI_SCTRL_R 0xCC -#define HFCPCI_SQ 0xD0 -#define HFCPCI_CLKDEL 0xDC -#define HFCPCI_B1_REC 0xF0 -#define HFCPCI_B1_SEND 0xF0 -#define HFCPCI_B2_REC 0xF4 -#define HFCPCI_B2_SEND 0xF4 -#define HFCPCI_D_REC 0xF8 -#define HFCPCI_D_SEND 0xF8 -#define HFCPCI_E_REC 0xFC - - -/* bits in status register (READ) */ -#define HFCPCI_PCI_PROC 0x02 -#define HFCPCI_NBUSY 0x04 -#define HFCPCI_TIMER_ELAP 0x10 -#define HFCPCI_STATINT 0x20 -#define HFCPCI_FRAMEINT 0x40 -#define HFCPCI_ANYINT 0x80 - -/* bits in CTMT (Write) */ -#define HFCPCI_CLTIMER 0x80 -#define HFCPCI_TIM3_125 0x04 -#define HFCPCI_TIM25 0x10 -#define HFCPCI_TIM50 0x14 -#define HFCPCI_TIM400 0x18 -#define HFCPCI_TIM800 0x1C -#define HFCPCI_AUTO_TIMER 0x20 -#define HFCPCI_TRANSB2 0x02 -#define HFCPCI_TRANSB1 0x01 - -/* bits in CIRM (Write) */ -#define HFCPCI_AUX_MSK 0x07 -#define HFCPCI_RESET 0x08 -#define HFCPCI_B1_REV 0x40 -#define HFCPCI_B2_REV 0x80 - -/* bits in INT_M1 and INT_S1 */ -#define HFCPCI_INTS_B1TRANS 0x01 -#define HFCPCI_INTS_B2TRANS 0x02 -#define HFCPCI_INTS_DTRANS 0x04 -#define HFCPCI_INTS_B1REC 0x08 -#define HFCPCI_INTS_B2REC 0x10 -#define HFCPCI_INTS_DREC 0x20 -#define HFCPCI_INTS_L1STATE 0x40 -#define HFCPCI_INTS_TIMER 0x80 - -/* bits in INT_M2 */ -#define HFCPCI_PROC_TRANS 0x01 -#define HFCPCI_GCI_I_CHG 0x02 -#define HFCPCI_GCI_MON_REC 0x04 -#define HFCPCI_IRQ_ENABLE 0x08 -#define HFCPCI_PMESEL 0x80 - -/* bits in STATES */ -#define HFCPCI_STATE_MSK 0x0F -#define HFCPCI_LOAD_STATE 0x10 -#define HFCPCI_ACTIVATE 0x20 -#define HFCPCI_DO_ACTION 0x40 -#define HFCPCI_NT_G2_G3 0x80 - -/* bits in HFCD_MST_MODE */ -#define HFCPCI_MASTER 0x01 -#define HFCPCI_SLAVE 0x00 -/* remaining bits are for codecs control */ - -/* bits in HFCD_SCTRL */ -#define SCTRL_B1_ENA 0x01 -#define SCTRL_B2_ENA 0x02 -#define SCTRL_MODE_TE 0x00 -#define SCTRL_MODE_NT 0x04 -#define SCTRL_LOW_PRIO 0x08 -#define SCTRL_SQ_ENA 0x10 -#define SCTRL_TEST 0x20 -#define SCTRL_NONE_CAP 0x40 -#define SCTRL_PWR_DOWN 0x80 - -/* bits in SCTRL_E */ -#define HFCPCI_AUTO_AWAKE 0x01 -#define HFCPCI_DBIT_1 0x04 -#define HFCPCI_IGNORE_COL 0x08 -#define HFCPCI_CHG_B1_B2 0x80 - -/****************************/ -/* bits in FIFO_EN register */ -/****************************/ -#define HFCPCI_FIFOEN_B1 0x03 -#define HFCPCI_FIFOEN_B2 0x0C -#define HFCPCI_FIFOEN_DTX 0x10 -#define HFCPCI_FIFOEN_B1TX 0x01 -#define HFCPCI_FIFOEN_B1RX 0x02 -#define HFCPCI_FIFOEN_B2TX 0x04 -#define HFCPCI_FIFOEN_B2RX 0x08 - - -/***********************************/ -/* definitions of fifo memory area */ -/***********************************/ -#define MAX_D_FRAMES 15 -#define MAX_B_FRAMES 31 -#define B_SUB_VAL 0x200 -#define B_FIFO_SIZE (0x2000 - B_SUB_VAL) -#define D_FIFO_SIZE 512 -#define D_FREG_MASK 0xF - -typedef struct { - unsigned short z1; /* Z1 pointer 16 Bit */ - unsigned short z2; /* Z2 pointer 16 Bit */ -} z_type; - -typedef struct { - u_char data[D_FIFO_SIZE]; /* FIFO data space */ - u_char fill1[0x20A0 - D_FIFO_SIZE]; /* reserved, do not use */ - u_char f1, f2; /* f pointers */ - u_char fill2[0x20C0 - 0x20A2]; /* reserved, do not use */ - z_type za[MAX_D_FRAMES + 1]; /* mask index with D_FREG_MASK for access */ - u_char fill3[0x4000 - 0x2100]; /* align 16K */ -} dfifo_type; - -typedef struct { - z_type za[MAX_B_FRAMES + 1]; /* only range 0x0..0x1F allowed */ - u_char f1, f2; /* f pointers */ - u_char fill[0x2100 - 0x2082]; /* alignment */ -} bzfifo_type; - - -typedef union { - struct { - dfifo_type d_tx; /* D-send channel */ - dfifo_type d_rx; /* D-receive channel */ - } d_chan; - struct { - u_char fill1[0x200]; - u_char txdat_b1[B_FIFO_SIZE]; - bzfifo_type txbz_b1; - - bzfifo_type txbz_b2; - u_char txdat_b2[B_FIFO_SIZE]; - - u_char fill2[D_FIFO_SIZE]; - - u_char rxdat_b1[B_FIFO_SIZE]; - bzfifo_type rxbz_b1; - - bzfifo_type rxbz_b2; - u_char rxdat_b2[B_FIFO_SIZE]; - } b_chans; - u_char fill[32768]; -} fifo_area; - - -#define Write_hfc(a, b, c) (writeb(c, (a->hw.hfcpci.pci_io) + b)) -#define Read_hfc(a, b) (readb((a->hw.hfcpci.pci_io) + b)) - -extern void main_irq_hcpci(struct BCState *bcs); -extern void releasehfcpci(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c deleted file mode 100644 index 12af628d9b2c..000000000000 --- a/drivers/isdn/hisax/hfc_sx.c +++ /dev/null @@ -1,1517 +0,0 @@ -/* $Id: hfc_sx.c,v 1.12.2.5 2004/02/11 13:21:33 keil Exp $ - * - * level driver for Cologne Chip Designs hfc-s+/sp based cards - * - * Author Werner Cornelius - * based on existing driver for CCD HFC PCI cards - * Copyright by Werner Cornelius <werner@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "hfc_sx.h" -#include "isdnl1.h" -#include <linux/interrupt.h> -#include <linux/isapnp.h> -#include <linux/slab.h> - -static const char *hfcsx_revision = "$Revision: 1.12.2.5 $"; - -/***************************************/ -/* IRQ-table for CCDs demo board */ -/* IRQs 6,5,10,11,12,15 are supported */ -/***************************************/ - -/* Teles 16.3c Vendor Id TAG2620, Version 1.0, Vendor version 2.1 - * - * Thanks to Uwe Wisniewski - * - * ISA-SLOT Signal PIN - * B25 IRQ3 92 IRQ_G - * B23 IRQ5 94 IRQ_A - * B4 IRQ2/9 95 IRQ_B - * D3 IRQ10 96 IRQ_C - * D4 IRQ11 97 IRQ_D - * D5 IRQ12 98 IRQ_E - * D6 IRQ15 99 IRQ_F - */ - -#undef CCD_DEMO_BOARD -#ifdef CCD_DEMO_BOARD -static u_char ccd_sp_irqtab[16] = { - 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 3, 4, 5, 0, 0, 6 -}; -#else /* Teles 16.3c */ -static u_char ccd_sp_irqtab[16] = { - 0, 0, 0, 7, 0, 1, 0, 0, 0, 2, 3, 4, 5, 0, 0, 6 -}; -#endif -#define NT_T1_COUNT 20 /* number of 3.125ms interrupts for G2 timeout */ - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -/******************************/ -/* In/Out access to registers */ -/******************************/ -static inline void -Write_hfc(struct IsdnCardState *cs, u_char regnum, u_char val) -{ - byteout(cs->hw.hfcsx.base + 1, regnum); - byteout(cs->hw.hfcsx.base, val); -} - -static inline u_char -Read_hfc(struct IsdnCardState *cs, u_char regnum) -{ - u_char ret; - - byteout(cs->hw.hfcsx.base + 1, regnum); - ret = bytein(cs->hw.hfcsx.base); - return (ret); -} - - -/**************************************************/ -/* select a fifo and remember which one for reuse */ -/**************************************************/ -static void -fifo_select(struct IsdnCardState *cs, u_char fifo) -{ - if (fifo == cs->hw.hfcsx.last_fifo) - return; /* still valid */ - - byteout(cs->hw.hfcsx.base + 1, HFCSX_FIF_SEL); - byteout(cs->hw.hfcsx.base, fifo); - while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */ - udelay(4); - byteout(cs->hw.hfcsx.base, fifo); - while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */ -} - -/******************************************/ -/* reset the specified fifo to defaults. */ -/* If its a send fifo init needed markers */ -/******************************************/ -static void -reset_fifo(struct IsdnCardState *cs, u_char fifo) -{ - fifo_select(cs, fifo); /* first select the fifo */ - byteout(cs->hw.hfcsx.base + 1, HFCSX_CIRM); - byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.cirm | 0x80); /* reset cmd */ - udelay(1); - while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */ -} - - -/*************************************************************/ -/* write_fifo writes the skb contents to the desired fifo */ -/* if no space is available or an error occurs 0 is returned */ -/* the skb is not released in any way. */ -/*************************************************************/ -static int -write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans_max) -{ - unsigned short *msp; - int fifo_size, count, z1, z2; - u_char f_msk, f1, f2, *src; - - if (skb->len <= 0) return (0); - if (fifo & 1) return (0); /* no write fifo */ - - fifo_select(cs, fifo); - if (fifo & 4) { - fifo_size = D_FIFO_SIZE; /* D-channel */ - f_msk = MAX_D_FRAMES; - if (trans_max) return (0); /* only HDLC */ - } - else { - fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */ - f_msk = MAX_B_FRAMES; - } - - z1 = Read_hfc(cs, HFCSX_FIF_Z1H); - z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); - - /* Check for transparent mode */ - if (trans_max) { - z2 = Read_hfc(cs, HFCSX_FIF_Z2H); - z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); - count = z2 - z1; - if (count <= 0) - count += fifo_size; /* free bytes */ - if (count < skb->len + 1) return (0); /* no room */ - count = fifo_size - count; /* bytes still not send */ - if (count > 2 * trans_max) return (0); /* delay to long */ - count = skb->len; - src = skb->data; - while (count--) - Write_hfc(cs, HFCSX_FIF_DWR, *src++); - return (1); /* success */ - } - - msp = ((struct hfcsx_extra *)(cs->hw.hfcsx.extra))->marker; - msp += (((fifo >> 1) & 3) * (MAX_B_FRAMES + 1)); - f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk; - f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk; - - count = f1 - f2; /* frame count actually buffered */ - if (count < 0) - count += (f_msk + 1); /* if wrap around */ - if (count > f_msk - 1) { - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_write_fifo %d more as %d frames", fifo, f_msk - 1); - return (0); - } - - *(msp + f1) = z1; /* remember marker */ - - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_write_fifo %d f1(%x) f2(%x) z1(f1)(%x)", - fifo, f1, f2, z1); - /* now determine free bytes in FIFO buffer */ - count = *(msp + f2) - z1; - if (count <= 0) - count += fifo_size; /* count now contains available bytes */ - - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_write_fifo %d count(%u/%d)", - fifo, skb->len, count); - if (count < skb->len) { - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_write_fifo %d no fifo mem", fifo); - return (0); - } - - count = skb->len; /* get frame len */ - src = skb->data; /* source pointer */ - while (count--) - Write_hfc(cs, HFCSX_FIF_DWR, *src++); - - Read_hfc(cs, HFCSX_FIF_INCF1); /* increment F1 */ - udelay(1); - while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */ - return (1); -} - -/***************************************************************/ -/* read_fifo reads data to an skb from the desired fifo */ -/* if no data is available or an error occurs NULL is returned */ -/* the skb is not released in any way. */ -/***************************************************************/ -static struct sk_buff * -read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max) -{ int fifo_size, count, z1, z2; - u_char f_msk, f1, f2, *dst; - struct sk_buff *skb; - - if (!(fifo & 1)) return (NULL); /* no read fifo */ - fifo_select(cs, fifo); - if (fifo & 4) { - fifo_size = D_FIFO_SIZE; /* D-channel */ - f_msk = MAX_D_FRAMES; - if (trans_max) return (NULL); /* only hdlc */ - } - else { - fifo_size = cs->hw.hfcsx.b_fifo_size; /* B-channel */ - f_msk = MAX_B_FRAMES; - } - - /* transparent mode */ - if (trans_max) { - z1 = Read_hfc(cs, HFCSX_FIF_Z1H); - z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); - z2 = Read_hfc(cs, HFCSX_FIF_Z2H); - z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); - /* now determine bytes in actual FIFO buffer */ - count = z1 - z2; - if (count <= 0) - count += fifo_size; /* count now contains buffered bytes */ - count++; - if (count > trans_max) - count = trans_max; /* limit length */ - skb = dev_alloc_skb(count); - if (skb) { - dst = skb_put(skb, count); - while (count--) - *dst++ = Read_hfc(cs, HFCSX_FIF_DRD); - return skb; - } else - return NULL; /* no memory */ - } - - do { - f1 = Read_hfc(cs, HFCSX_FIF_F1) & f_msk; - f2 = Read_hfc(cs, HFCSX_FIF_F2) & f_msk; - - if (f1 == f2) return (NULL); /* no frame available */ - - z1 = Read_hfc(cs, HFCSX_FIF_Z1H); - z1 = ((z1 << 8) | Read_hfc(cs, HFCSX_FIF_Z1L)); - z2 = Read_hfc(cs, HFCSX_FIF_Z2H); - z2 = ((z2 << 8) | Read_hfc(cs, HFCSX_FIF_Z2L)); - - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_read_fifo %d f1(%x) f2(%x) z1(f2)(%x) z2(f2)(%x)", - fifo, f1, f2, z1, z2); - /* now determine bytes in actual FIFO buffer */ - count = z1 - z2; - if (count <= 0) - count += fifo_size; /* count now contains buffered bytes */ - count++; - - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_read_fifo %d count %u)", - fifo, count); - - if ((count > fifo_size) || (count < 4)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcsx_read_fifo %d packet inv. len %d ", fifo , count); - while (count) { - count--; /* empty fifo */ - Read_hfc(cs, HFCSX_FIF_DRD); - } - skb = NULL; - } else - if ((skb = dev_alloc_skb(count - 3))) { - count -= 3; - dst = skb_put(skb, count); - - while (count--) - *dst++ = Read_hfc(cs, HFCSX_FIF_DRD); - - Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 1 */ - Read_hfc(cs, HFCSX_FIF_DRD); /* CRC 2 */ - if (Read_hfc(cs, HFCSX_FIF_DRD)) { - dev_kfree_skb_irq(skb); - if (cs->debug & L1_DEB_ISAC_FIFO) - debugl1(cs, "hfcsx_read_fifo %d crc error", fifo); - skb = NULL; - } - } else { - printk(KERN_WARNING "HFC-SX: receive out of memory\n"); - return (NULL); - } - - Read_hfc(cs, HFCSX_FIF_INCF2); /* increment F2 */ - udelay(1); - while (bytein(cs->hw.hfcsx.base + 1) & 1); /* wait for busy */ - udelay(1); - } while (!skb); /* retry in case of crc error */ - return (skb); -} - -/******************************************/ -/* free hardware resources used by driver */ -/******************************************/ -static void -release_io_hfcsx(struct IsdnCardState *cs) -{ - cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ - Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); - Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET); /* Reset On */ - msleep(30); /* Timeout 30ms */ - Write_hfc(cs, HFCSX_CIRM, 0); /* Reset Off */ - del_timer(&cs->hw.hfcsx.timer); - release_region(cs->hw.hfcsx.base, 2); /* release IO-Block */ - kfree(cs->hw.hfcsx.extra); - cs->hw.hfcsx.extra = NULL; -} - -/**********************************************************/ -/* set_fifo_size determines the size of the RAM and FIFOs */ -/* returning 0 -> need to reset the chip again. */ -/**********************************************************/ -static int set_fifo_size(struct IsdnCardState *cs) -{ - - if (cs->hw.hfcsx.b_fifo_size) return (1); /* already determined */ - - if ((cs->hw.hfcsx.chip >> 4) == 9) { - cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_32K; - return (1); - } - - cs->hw.hfcsx.b_fifo_size = B_FIFO_SIZE_8K; - cs->hw.hfcsx.cirm |= 0x10; /* only 8K of ram */ - return (0); - -} - -/********************************************************************************/ -/* function called to reset the HFC SX chip. A complete software reset of chip */ -/* and fifos is done. */ -/********************************************************************************/ -static void -reset_hfcsx(struct IsdnCardState *cs) -{ - cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */ - Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); - - printk(KERN_INFO "HFC_SX: resetting card\n"); - while (1) { - Write_hfc(cs, HFCSX_CIRM, HFCSX_RESET | cs->hw.hfcsx.cirm); /* Reset */ - mdelay(30); - Write_hfc(cs, HFCSX_CIRM, cs->hw.hfcsx.cirm); /* Reset Off */ - mdelay(20); - if (Read_hfc(cs, HFCSX_STATUS) & 2) - printk(KERN_WARNING "HFC-SX init bit busy\n"); - cs->hw.hfcsx.last_fifo = 0xff; /* invalidate */ - if (!set_fifo_size(cs)) continue; - break; - } - - cs->hw.hfcsx.trm = 0 + HFCSX_BTRANS_THRESMASK; /* no echo connect , threshold */ - Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); - - Write_hfc(cs, HFCSX_CLKDEL, 0x0e); /* ST-Bit delay for TE-Mode */ - cs->hw.hfcsx.sctrl_e = HFCSX_AUTO_AWAKE; - Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); /* S/T Auto awake */ - cs->hw.hfcsx.bswapped = 0; /* no exchange */ - cs->hw.hfcsx.nt_mode = 0; /* we are in TE mode */ - cs->hw.hfcsx.ctmt = HFCSX_TIM3_125 | HFCSX_AUTO_TIMER; - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); - - cs->hw.hfcsx.int_m1 = HFCSX_INTS_DTRANS | HFCSX_INTS_DREC | - HFCSX_INTS_L1STATE | HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - - /* Clear already pending ints */ - Read_hfc(cs, HFCSX_INT_S1); - - Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 2); /* HFC ST 2 */ - udelay(10); - Write_hfc(cs, HFCSX_STATES, 2); /* HFC ST 2 */ - cs->hw.hfcsx.mst_m = HFCSX_MASTER; /* HFC Master Mode */ - - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); - cs->hw.hfcsx.sctrl = 0x40; /* set tx_lo mode, error in datasheet ! */ - Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); - cs->hw.hfcsx.sctrl_r = 0; - Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); - - /* Init GCI/IOM2 in master mode */ - /* Slots 0 and 1 are set for B-chan 1 and 2 */ - /* D- and monitor/CI channel are not enabled */ - /* STIO1 is used as output for data, B1+B2 from ST->IOM+HFC */ - /* STIO2 is used as data input, B1+B2 from IOM->ST */ - /* ST B-channel send disabled -> continuous 1s */ - /* The IOM slots are always enabled */ - cs->hw.hfcsx.conn = 0x36; /* set data flow directions */ - Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); - Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* B1-Slot 0 STIO1 out enabled */ - Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* B2-Slot 1 STIO1 out enabled */ - Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* B1-Slot 0 STIO2 in enabled */ - Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* B2-Slot 1 STIO2 in enabled */ - - /* Finally enable IRQ output */ - cs->hw.hfcsx.int_m2 = HFCSX_IRQ_ENABLE; - Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); - Read_hfc(cs, HFCSX_INT_S2); -} - -/***************************************************/ -/* Timer function called when kernel timer expires */ -/***************************************************/ -static void -hfcsx_Timer(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.hfcsx.timer); - cs->hw.hfcsx.timer.expires = jiffies + 75; - /* WD RESET */ -/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcsx.ctmt | 0x80); - add_timer(&cs->hw.hfcsx.timer); -*/ -} - -/************************************************/ -/* select a b-channel entry matching and active */ -/************************************************/ -static -struct BCState * -Sel_BCS(struct IsdnCardState *cs, int channel) -{ - if (cs->bcs[0].mode && (cs->bcs[0].channel == channel)) - return (&cs->bcs[0]); - else if (cs->bcs[1].mode && (cs->bcs[1].channel == channel)) - return (&cs->bcs[1]); - else - return (NULL); -} - -/*******************************/ -/* D-channel receive procedure */ -/*******************************/ -static -int -receive_dmsg(struct IsdnCardState *cs) -{ - struct sk_buff *skb; - int count = 5; - - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_dmsg blocked"); - return (1); - } - - do { - skb = read_fifo(cs, HFCSX_SEL_D_RX, 0); - if (skb) { - skb_queue_tail(&cs->rq, skb); - schedule_event(cs, D_RCVBUFREADY); - } - } while (--count && skb); - - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - return (1); -} - -/**********************************/ -/* B-channel main receive routine */ -/**********************************/ -static void -main_rec_hfcsx(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int count = 5; - struct sk_buff *skb; - -Begin: - count--; - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "rec_data %d blocked", bcs->channel); - return; - } - skb = read_fifo(cs, ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? - HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX, - (bcs->mode == L1_MODE_TRANS) ? - HFCSX_BTRANS_THRESHOLD : 0); - - if (skb) { - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } - - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - if (count && skb) - goto Begin; - return; -} - -/**************************/ -/* D-channel send routine */ -/**************************/ -static void -hfcsx_fill_dfifo(struct IsdnCardState *cs) -{ - if (!cs->tx_skb) - return; - if (cs->tx_skb->len <= 0) - return; - - if (write_fifo(cs, cs->tx_skb, HFCSX_SEL_D_TX, 0)) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - } - return; -} - -/**************************/ -/* B-channel send routine */ -/**************************/ -static void -hfcsx_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - if (write_fifo(cs, bcs->tx_skb, - ((bcs->channel) && (!cs->hw.hfcsx.bswapped)) ? - HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX, - (bcs->mode == L1_MODE_TRANS) ? - HFCSX_BTRANS_THRESHOLD : 0)) { - - bcs->tx_cnt -= bcs->tx_skb->len; - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->tx_skb->len; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } -} - -/**********************************************/ -/* D-channel l1 state call for leased NT-mode */ -/**********************************************/ -static void -dch_nt_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - - switch (pr) { - case (PH_DATA | REQUEST): - case (PH_PULL | REQUEST): - case (PH_PULL | INDICATION): - st->l1.l1hw(st, pr, arg); - break; - case (PH_ACTIVATE | REQUEST): - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - break; - case (PH_TESTLOOP | REQUEST): - if (1 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B1"); - if (2 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B2"); - if (!(3 & (long) arg)) - debugl1(cs, "PH_TEST_LOOP DISABLED"); - st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); - break; - default: - if (cs->debug) - debugl1(cs, "dch_nt_l2l1 msg %04X unhandled", pr); - break; - } -} - - - -/***********************/ -/* set/reset echo mode */ -/***********************/ -static int -hfcsx_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) -{ - unsigned long flags; - int i = *(unsigned int *) ic->parm.num; - - if ((ic->arg == 98) && - (!(cs->hw.hfcsx.int_m1 & (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC + HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC)))) { - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 0); /* HFC ST G0 */ - udelay(10); - cs->hw.hfcsx.sctrl |= SCTRL_MODE_NT; - Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); /* set NT-mode */ - udelay(10); - Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 1); /* HFC ST G1 */ - udelay(10); - Write_hfc(cs, HFCSX_STATES, 1 | HFCSX_ACTIVATE | HFCSX_DO_ACTION); - cs->dc.hfcsx.ph_state = 1; - cs->hw.hfcsx.nt_mode = 1; - cs->hw.hfcsx.nt_timer = 0; - spin_unlock_irqrestore(&cs->lock, flags); - cs->stlist->l2.l2l1 = dch_nt_l2l1; - debugl1(cs, "NT mode activated"); - return (0); - } - if ((cs->chanlimit > 1) || (cs->hw.hfcsx.bswapped) || - (cs->hw.hfcsx.nt_mode) || (ic->arg != 12)) - return (-EINVAL); - - if (i) { - cs->logecho = 1; - cs->hw.hfcsx.trm |= 0x20; /* enable echo chan */ - cs->hw.hfcsx.int_m1 |= HFCSX_INTS_B2REC; - /* reset Channel !!!!! */ - } else { - cs->logecho = 0; - cs->hw.hfcsx.trm &= ~0x20; /* disable echo chan */ - cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_B2REC; - } - cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA; - cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA; - cs->hw.hfcsx.conn |= 0x10; /* B2-IOM -> B2-ST */ - cs->hw.hfcsx.ctmt &= ~2; - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); - Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); - Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); - Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); - Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); -} /* hfcsx_auxcmd */ - -/*****************************/ -/* E-channel receive routine */ -/*****************************/ -static void -receive_emsg(struct IsdnCardState *cs) -{ - int count = 5; - u_char *ptr; - struct sk_buff *skb; - - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - debugl1(cs, "echo_rec_data blocked"); - return; - } - do { - skb = read_fifo(cs, HFCSX_SEL_B2_RX, 0); - if (skb) { - if (cs->debug & DEB_DLOG_HEX) { - ptr = cs->dlog; - if ((skb->len) < MAX_DLOG_SPACE / 3 - 10) { - *ptr++ = 'E'; - *ptr++ = 'C'; - *ptr++ = 'H'; - *ptr++ = 'O'; - *ptr++ = ':'; - ptr += QuickHex(ptr, skb->data, skb->len); - ptr--; - *ptr++ = '\n'; - *ptr = 0; - HiSax_putstatus(cs, NULL, cs->dlog); - } else - HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len); - } - dev_kfree_skb_any(skb); - } - } while (--count && skb); - - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - return; -} /* receive_emsg */ - - -/*********************/ -/* Interrupt handler */ -/*********************/ -static irqreturn_t -hfcsx_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char exval; - struct BCState *bcs; - int count = 15; - u_long flags; - u_char val, stat; - - if (!(cs->hw.hfcsx.int_m2 & 0x08)) - return IRQ_NONE; /* not initialised */ - - spin_lock_irqsave(&cs->lock, flags); - if (HFCSX_ANYINT & (stat = Read_hfc(cs, HFCSX_STATUS))) { - val = Read_hfc(cs, HFCSX_INT_S1); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-SX: stat(%02x) s1(%02x)", stat, val); - } else { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-SX irq %x %s", val, - test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags) ? - "locked" : "unlocked"); - val &= cs->hw.hfcsx.int_m1; - if (val & 0x40) { /* state machine irq */ - exval = Read_hfc(cs, HFCSX_STATES) & 0xf; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state chg %d->%d", cs->dc.hfcsx.ph_state, - exval); - cs->dc.hfcsx.ph_state = exval; - schedule_event(cs, D_L1STATECHANGE); - val &= ~0x40; - } - if (val & 0x80) { /* timer irq */ - if (cs->hw.hfcsx.nt_mode) { - if ((--cs->hw.hfcsx.nt_timer) < 0) - schedule_event(cs, D_L1STATECHANGE); - } - val &= ~0x80; - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); - } - while (val) { - if (test_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - cs->hw.hfcsx.int_s1 |= val; - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } - if (cs->hw.hfcsx.int_s1 & 0x18) { - exval = val; - val = cs->hw.hfcsx.int_s1; - cs->hw.hfcsx.int_s1 = exval; - } - if (val & 0x08) { - if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) { - if (cs->debug) - debugl1(cs, "hfcsx spurious 0x08 IRQ"); - } else - main_rec_hfcsx(bcs); - } - if (val & 0x10) { - if (cs->logecho) - receive_emsg(cs); - else if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcsx spurious 0x10 IRQ"); - } else - main_rec_hfcsx(bcs); - } - if (val & 0x01) { - if (!(bcs = Sel_BCS(cs, cs->hw.hfcsx.bswapped ? 1 : 0))) { - if (cs->debug) - debugl1(cs, "hfcsx spurious 0x01 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - schedule_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x02) { - if (!(bcs = Sel_BCS(cs, 1))) { - if (cs->debug) - debugl1(cs, "hfcsx spurious 0x02 IRQ"); - } else { - if (bcs->tx_skb) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "fill_data %d blocked", bcs->channel); - } else { - schedule_event(bcs, B_XMTBUFREADY); - } - } - } - } - if (val & 0x20) { /* receive dframe */ - receive_dmsg(cs); - } - if (val & 0x04) { /* dframe transmitted */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfcsx_fill_dfifo irq blocked"); - } - goto afterXPR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else { - debugl1(cs, "hfcsx_fill_dfifo irq blocked"); - } - } else - schedule_event(cs, D_XMTBUFREADY); - } - afterXPR: - if (cs->hw.hfcsx.int_s1 && count--) { - val = cs->hw.hfcsx.int_s1; - cs->hw.hfcsx.int_s1 = 0; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFC-SX irq %x loop %d", val, 15 - count); - } else - val = 0; - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -/********************************************************************/ -/* timer callback for D-chan busy resolution. Currently no function */ -/********************************************************************/ -static void -hfcsx_dbusy_timer(struct timer_list *t) -{ -} - -/*************************************/ -/* Layer 1 D-channel hardware access */ -/*************************************/ -static void -HFCSX_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfcsx_fill_dfifo blocked"); - - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_dfifo(cs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "hfcsx_fill_dfifo blocked"); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCSX_STATES, HFCSX_LOAD_STATE | 3); /* HFC ST 3 */ - udelay(6); - Write_hfc(cs, HFCSX_STATES, 3); /* HFC ST 2 */ - cs->hw.hfcsx.mst_m |= HFCSX_MASTER; - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); - Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - Write_hfc(cs, HFCSX_STATES, HFCSX_ACTIVATE | HFCSX_DO_ACTION); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_DEACTIVATE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcsx.mst_m &= ~HFCSX_MASTER; - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcsx.mst_m |= HFCSX_MASTER; - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_TESTLOOP | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - switch ((long) arg) { - case (1): - Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */ - Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */ - cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~7) | 1; - Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); - break; - case (2): - Write_hfc(cs, HFCSX_B2_SSL, 0x81); /* tx slot */ - Write_hfc(cs, HFCSX_B2_RSL, 0x81); /* rx slot */ - cs->hw.hfcsx.conn = (cs->hw.hfcsx.conn & ~0x38) | 0x08; - Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); - break; - default: - spin_unlock_irqrestore(&cs->lock, flags); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcsx_l1hw loop invalid %4lx", (unsigned long)arg); - return; - } - cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */ - Write_hfc(cs, HFCSX_TRM, cs->hw.hfcsx.trm); - spin_unlock_irqrestore(&cs->lock, flags); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hfcsx_l1hw unknown pr %4x", pr); - break; - } -} - -/***********************************************/ -/* called during init setting l1 stack pointer */ -/***********************************************/ -static void -setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = HFCSX_l1hw; -} - -/**************************************/ -/* send B-channel data if not blocked */ -/**************************************/ -static void -hfcsx_send_data(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - - if (!test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - hfcsx_fill_fifo(bcs); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } else - debugl1(cs, "send_data %d blocked", bcs->channel); -} - -/***************************************************************/ -/* activate/deactivate hardware for selected channels and mode */ -/***************************************************************/ -static void -mode_hfcsx(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int fifo2; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HFCSX bchannel mode %d bchan %d/%d", - mode, bc, bcs->channel); - bcs->mode = mode; - bcs->channel = bc; - fifo2 = bc; - if (cs->chanlimit > 1) { - cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcsx.sctrl_e &= ~0x80; - } else { - if (bc) { - if (mode != L1_MODE_NULL) { - cs->hw.hfcsx.bswapped = 1; /* B1 and B2 exchanged */ - cs->hw.hfcsx.sctrl_e |= 0x80; - } else { - cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcsx.sctrl_e &= ~0x80; - } - fifo2 = 0; - } else { - cs->hw.hfcsx.bswapped = 0; /* B1 and B2 normal mode */ - cs->hw.hfcsx.sctrl_e &= ~0x80; - } - } - switch (mode) { - case (L1_MODE_NULL): - if (bc) { - cs->hw.hfcsx.sctrl &= ~SCTRL_B2_ENA; - cs->hw.hfcsx.sctrl_r &= ~SCTRL_B2_ENA; - } else { - cs->hw.hfcsx.sctrl &= ~SCTRL_B1_ENA; - cs->hw.hfcsx.sctrl_r &= ~SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); - } else { - cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); - } - break; - case (L1_MODE_TRANS): - if (bc) { - cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; - } else { - cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); - cs->hw.hfcsx.ctmt |= 2; - cs->hw.hfcsx.conn &= ~0x18; - } else { - cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); - cs->hw.hfcsx.ctmt |= 1; - cs->hw.hfcsx.conn &= ~0x03; - } - break; - case (L1_MODE_HDLC): - if (bc) { - cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; - } else { - cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; - } - if (fifo2) { - cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); - cs->hw.hfcsx.ctmt &= ~2; - cs->hw.hfcsx.conn &= ~0x18; - } else { - cs->hw.hfcsx.int_m1 |= (HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); - cs->hw.hfcsx.ctmt &= ~1; - cs->hw.hfcsx.conn &= ~0x03; - } - break; - case (L1_MODE_EXTRN): - if (bc) { - cs->hw.hfcsx.conn |= 0x10; - cs->hw.hfcsx.sctrl |= SCTRL_B2_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B2_ENA; - cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B2TRANS + HFCSX_INTS_B2REC); - } else { - cs->hw.hfcsx.conn |= 0x02; - cs->hw.hfcsx.sctrl |= SCTRL_B1_ENA; - cs->hw.hfcsx.sctrl_r |= SCTRL_B1_ENA; - cs->hw.hfcsx.int_m1 &= ~(HFCSX_INTS_B1TRANS + HFCSX_INTS_B1REC); - } - break; - } - Write_hfc(cs, HFCSX_SCTRL_E, cs->hw.hfcsx.sctrl_e); - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - Write_hfc(cs, HFCSX_SCTRL, cs->hw.hfcsx.sctrl); - Write_hfc(cs, HFCSX_SCTRL_R, cs->hw.hfcsx.sctrl_r); - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt); - Write_hfc(cs, HFCSX_CONNECT, cs->hw.hfcsx.conn); - if (mode != L1_MODE_EXTRN) { - reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_RX : HFCSX_SEL_B1_RX); - reset_fifo(cs, fifo2 ? HFCSX_SEL_B2_TX : HFCSX_SEL_B1_TX); - } -} - -/******************************/ -/* Layer2 -> Layer 1 Transfer */ -/******************************/ -static void -hfcsx_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "%s: this shouldn't happen\n", - __func__); - } else { -// test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - mode_hfcsx(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - mode_hfcsx(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -/******************************************/ -/* deactivate B-channel access and queues */ -/******************************************/ -static void -close_hfcsx(struct BCState *bcs) -{ - mode_hfcsx(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -/*************************************/ -/* init B-channel queues and control */ -/*************************************/ -static int -open_hfcsxstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -/*********************************/ -/* inits the stack for B-channel */ -/*********************************/ -static int -setstack_2b(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hfcsxstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hfcsx_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -/***************************/ -/* handle L1 state changes */ -/***************************/ -static void -hfcsx_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - u_long flags; - - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) { - if (!cs->hw.hfcsx.nt_mode) - switch (cs->dc.hfcsx.ph_state) { - case (0): - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - case (3): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (8): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (6): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (7): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - default: - break; - } else { - switch (cs->dc.hfcsx.ph_state) { - case (2): - spin_lock_irqsave(&cs->lock, flags); - if (cs->hw.hfcsx.nt_timer < 0) { - cs->hw.hfcsx.nt_timer = 0; - cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - /* Clear already pending ints */ - Read_hfc(cs, HFCSX_INT_S1); - - Write_hfc(cs, HFCSX_STATES, 4 | HFCSX_LOAD_STATE); - udelay(10); - Write_hfc(cs, HFCSX_STATES, 4); - cs->dc.hfcsx.ph_state = 4; - } else { - cs->hw.hfcsx.int_m1 |= HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - cs->hw.hfcsx.ctmt &= ~HFCSX_AUTO_TIMER; - cs->hw.hfcsx.ctmt |= HFCSX_TIM3_125; - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); - Write_hfc(cs, HFCSX_CTMT, cs->hw.hfcsx.ctmt | HFCSX_CLTIMER); - cs->hw.hfcsx.nt_timer = NT_T1_COUNT; - Write_hfc(cs, HFCSX_STATES, 2 | HFCSX_NT_G2_G3); /* allow G2 -> G3 transition */ - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (1): - case (3): - case (4): - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcsx.nt_timer = 0; - cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - spin_unlock_irqrestore(&cs->lock, flags); - break; - default: - break; - } - } - } - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -} - - -/********************************/ -/* called for card init message */ -/********************************/ -static void inithfcsx(struct IsdnCardState *cs) -{ - cs->setstack_d = setstack_hfcsx; - cs->BC_Send_Data = &hfcsx_send_data; - cs->bcs[0].BC_SetStack = setstack_2b; - cs->bcs[1].BC_SetStack = setstack_2b; - cs->bcs[0].BC_Close = close_hfcsx; - cs->bcs[1].BC_Close = close_hfcsx; - mode_hfcsx(cs->bcs, 0, 0); - mode_hfcsx(cs->bcs + 1, 0, 1); -} - - - -/*******************************************/ -/* handle card messages from control layer */ -/*******************************************/ -static int -hfcsx_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCSX: card_msg %x", mt); - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_hfcsx(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_hfcsx(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithfcsx(cs); - spin_unlock_irqrestore(&cs->lock, flags); - msleep(80); /* Timeout 80ms */ - /* now switch timer interrupt off */ - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcsx.int_m1 &= ~HFCSX_INTS_TIMER; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - /* reinit mode reg */ - Write_hfc(cs, HFCSX_MST_MODE, cs->hw.hfcsx.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id hfc_ids[] = { - { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620), - ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620), - (unsigned long) "Teles 16.3c2" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &hfc_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_hfcsx(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, hfcsx_revision); - printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp)); -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - break; - } else { - printk(KERN_ERR "HFC PnP: PnP error card found, no device\n"); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "HFC PnP: no ISAPnP card found\n"); - return (0); - } - } -#endif - cs->hw.hfcsx.base = card->para[1] & 0xfffe; - cs->irq = card->para[0]; - cs->hw.hfcsx.int_s1 = 0; - cs->dc.hfcsx.ph_state = 0; - cs->hw.hfcsx.fifo = 255; - if ((cs->typ == ISDN_CTYPE_HFC_SX) || - (cs->typ == ISDN_CTYPE_HFC_SP_PCMCIA)) { - if ((!cs->hw.hfcsx.base) || !request_region(cs->hw.hfcsx.base, 2, "HFCSX isdn")) { - printk(KERN_WARNING - "HiSax: HFC-SX io-base %#lx already in use\n", - cs->hw.hfcsx.base); - return (0); - } - byteout(cs->hw.hfcsx.base, cs->hw.hfcsx.base & 0xFF); - byteout(cs->hw.hfcsx.base + 1, - ((cs->hw.hfcsx.base >> 8) & 3) | 0x54); - udelay(10); - cs->hw.hfcsx.chip = Read_hfc(cs, HFCSX_CHIP_ID); - switch (cs->hw.hfcsx.chip >> 4) { - case 1: - tmp[0] = '+'; - break; - case 9: - tmp[0] = 'P'; - break; - default: - printk(KERN_WARNING - "HFC-SX: invalid chip id 0x%x\n", - cs->hw.hfcsx.chip >> 4); - release_region(cs->hw.hfcsx.base, 2); - return (0); - } - if (!ccd_sp_irqtab[cs->irq & 0xF]) { - printk(KERN_WARNING - "HFC_SX: invalid irq %d specified\n", cs->irq & 0xF); - release_region(cs->hw.hfcsx.base, 2); - return (0); - } - if (!(cs->hw.hfcsx.extra = - kmalloc(sizeof(struct hfcsx_extra), GFP_ATOMIC))) { - release_region(cs->hw.hfcsx.base, 2); - printk(KERN_WARNING "HFC-SX: unable to allocate memory\n"); - return (0); - } - printk(KERN_INFO "HFC-S%c chip detected at base 0x%x IRQ %d HZ %d\n", - tmp[0], (u_int) cs->hw.hfcsx.base, cs->irq, HZ); - cs->hw.hfcsx.int_m2 = 0; /* disable alle interrupts */ - cs->hw.hfcsx.int_m1 = 0; - Write_hfc(cs, HFCSX_INT_M1, cs->hw.hfcsx.int_m1); - Write_hfc(cs, HFCSX_INT_M2, cs->hw.hfcsx.int_m2); - } else - return (0); /* no valid card type */ - - timer_setup(&cs->dbusytimer, hfcsx_dbusy_timer, 0); - INIT_WORK(&cs->tqueue, hfcsx_bh); - cs->readisac = NULL; - cs->writeisac = NULL; - cs->readisacfifo = NULL; - cs->writeisacfifo = NULL; - cs->BC_Read_Reg = NULL; - cs->BC_Write_Reg = NULL; - cs->irq_func = &hfcsx_interrupt; - - cs->hw.hfcsx.b_fifo_size = 0; /* fifo size still unknown */ - cs->hw.hfcsx.cirm = ccd_sp_irqtab[cs->irq & 0xF]; /* RAM not evaluated */ - timer_setup(&cs->hw.hfcsx.timer, hfcsx_Timer, 0); - - reset_hfcsx(cs); - cs->cardmsg = &hfcsx_card_msg; - cs->auxcmd = &hfcsx_auxcmd; - return (1); -} diff --git a/drivers/isdn/hisax/hfc_sx.h b/drivers/isdn/hisax/hfc_sx.h deleted file mode 100644 index eee85dbb0883..000000000000 --- a/drivers/isdn/hisax/hfc_sx.h +++ /dev/null @@ -1,196 +0,0 @@ -/* $Id: hfc_sx.h,v 1.2.6.1 2001/09/23 22:24:48 kai Exp $ - * - * specific defines for CCD's HFC 2BDS0 S+,SP chips - * - * Author Werner Cornelius - * based on existing driver for CCD HFC PCI cards - * Copyright by Werner Cornelius <werner@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/*********************************************/ -/* thresholds for transparent B-channel mode */ -/* change mask and threshold simultaneously */ -/*********************************************/ -#define HFCSX_BTRANS_THRESHOLD 128 -#define HFCSX_BTRANS_THRESMASK 0x00 - -/* GCI/IOM bus monitor registers */ - -#define HFCSX_C_I 0x02 -#define HFCSX_TRxR 0x03 -#define HFCSX_MON1_D 0x0A -#define HFCSX_MON2_D 0x0B - - -/* GCI/IOM bus timeslot registers */ - -#define HFCSX_B1_SSL 0x20 -#define HFCSX_B2_SSL 0x21 -#define HFCSX_AUX1_SSL 0x22 -#define HFCSX_AUX2_SSL 0x23 -#define HFCSX_B1_RSL 0x24 -#define HFCSX_B2_RSL 0x25 -#define HFCSX_AUX1_RSL 0x26 -#define HFCSX_AUX2_RSL 0x27 - -/* GCI/IOM bus data registers */ - -#define HFCSX_B1_D 0x28 -#define HFCSX_B2_D 0x29 -#define HFCSX_AUX1_D 0x2A -#define HFCSX_AUX2_D 0x2B - -/* GCI/IOM bus configuration registers */ - -#define HFCSX_MST_EMOD 0x2D -#define HFCSX_MST_MODE 0x2E -#define HFCSX_CONNECT 0x2F - - -/* Interrupt and status registers */ - -#define HFCSX_TRM 0x12 -#define HFCSX_B_MODE 0x13 -#define HFCSX_CHIP_ID 0x16 -#define HFCSX_CIRM 0x18 -#define HFCSX_CTMT 0x19 -#define HFCSX_INT_M1 0x1A -#define HFCSX_INT_M2 0x1B -#define HFCSX_INT_S1 0x1E -#define HFCSX_INT_S2 0x1F -#define HFCSX_STATUS 0x1C - -/* S/T section registers */ - -#define HFCSX_STATES 0x30 -#define HFCSX_SCTRL 0x31 -#define HFCSX_SCTRL_E 0x32 -#define HFCSX_SCTRL_R 0x33 -#define HFCSX_SQ 0x34 -#define HFCSX_CLKDEL 0x37 -#define HFCSX_B1_REC 0x3C -#define HFCSX_B1_SEND 0x3C -#define HFCSX_B2_REC 0x3D -#define HFCSX_B2_SEND 0x3D -#define HFCSX_D_REC 0x3E -#define HFCSX_D_SEND 0x3E -#define HFCSX_E_REC 0x3F - -/****************/ -/* FIFO section */ -/****************/ -#define HFCSX_FIF_SEL 0x10 -#define HFCSX_FIF_Z1L 0x80 -#define HFCSX_FIF_Z1H 0x84 -#define HFCSX_FIF_Z2L 0x88 -#define HFCSX_FIF_Z2H 0x8C -#define HFCSX_FIF_INCF1 0xA8 -#define HFCSX_FIF_DWR 0xAC -#define HFCSX_FIF_F1 0xB0 -#define HFCSX_FIF_F2 0xB4 -#define HFCSX_FIF_INCF2 0xB8 -#define HFCSX_FIF_DRD 0xBC - -/* bits in status register (READ) */ -#define HFCSX_SX_PROC 0x02 -#define HFCSX_NBUSY 0x04 -#define HFCSX_TIMER_ELAP 0x10 -#define HFCSX_STATINT 0x20 -#define HFCSX_FRAMEINT 0x40 -#define HFCSX_ANYINT 0x80 - -/* bits in CTMT (Write) */ -#define HFCSX_CLTIMER 0x80 -#define HFCSX_TIM3_125 0x04 -#define HFCSX_TIM25 0x10 -#define HFCSX_TIM50 0x14 -#define HFCSX_TIM400 0x18 -#define HFCSX_TIM800 0x1C -#define HFCSX_AUTO_TIMER 0x20 -#define HFCSX_TRANSB2 0x02 -#define HFCSX_TRANSB1 0x01 - -/* bits in CIRM (Write) */ -#define HFCSX_IRQ_SELMSK 0x07 -#define HFCSX_IRQ_SELDIS 0x00 -#define HFCSX_RESET 0x08 -#define HFCSX_FIFO_RESET 0x80 - - -/* bits in INT_M1 and INT_S1 */ -#define HFCSX_INTS_B1TRANS 0x01 -#define HFCSX_INTS_B2TRANS 0x02 -#define HFCSX_INTS_DTRANS 0x04 -#define HFCSX_INTS_B1REC 0x08 -#define HFCSX_INTS_B2REC 0x10 -#define HFCSX_INTS_DREC 0x20 -#define HFCSX_INTS_L1STATE 0x40 -#define HFCSX_INTS_TIMER 0x80 - -/* bits in INT_M2 */ -#define HFCSX_PROC_TRANS 0x01 -#define HFCSX_GCI_I_CHG 0x02 -#define HFCSX_GCI_MON_REC 0x04 -#define HFCSX_IRQ_ENABLE 0x08 - -/* bits in STATES */ -#define HFCSX_STATE_MSK 0x0F -#define HFCSX_LOAD_STATE 0x10 -#define HFCSX_ACTIVATE 0x20 -#define HFCSX_DO_ACTION 0x40 -#define HFCSX_NT_G2_G3 0x80 - -/* bits in HFCD_MST_MODE */ -#define HFCSX_MASTER 0x01 -#define HFCSX_SLAVE 0x00 -/* remaining bits are for codecs control */ - -/* bits in HFCD_SCTRL */ -#define SCTRL_B1_ENA 0x01 -#define SCTRL_B2_ENA 0x02 -#define SCTRL_MODE_TE 0x00 -#define SCTRL_MODE_NT 0x04 -#define SCTRL_LOW_PRIO 0x08 -#define SCTRL_SQ_ENA 0x10 -#define SCTRL_TEST 0x20 -#define SCTRL_NONE_CAP 0x40 -#define SCTRL_PWR_DOWN 0x80 - -/* bits in SCTRL_E */ -#define HFCSX_AUTO_AWAKE 0x01 -#define HFCSX_DBIT_1 0x04 -#define HFCSX_IGNORE_COL 0x08 -#define HFCSX_CHG_B1_B2 0x80 - -/**********************************/ -/* definitions for FIFO selection */ -/**********************************/ -#define HFCSX_SEL_D_RX 5 -#define HFCSX_SEL_D_TX 4 -#define HFCSX_SEL_B1_RX 1 -#define HFCSX_SEL_B1_TX 0 -#define HFCSX_SEL_B2_RX 3 -#define HFCSX_SEL_B2_TX 2 - -#define MAX_D_FRAMES 15 -#define MAX_B_FRAMES 31 -#define B_SUB_VAL_32K 0x0200 -#define B_FIFO_SIZE_32K (0x2000 - B_SUB_VAL_32K) -#define B_SUB_VAL_8K 0x1A00 -#define B_FIFO_SIZE_8K (0x2000 - B_SUB_VAL_8K) -#define D_FIFO_SIZE 512 -#define D_FREG_MASK 0xF - -/************************************************************/ -/* structure holding additional dynamic data -> send marker */ -/************************************************************/ -struct hfcsx_extra { - unsigned short marker[2 * (MAX_B_FRAMES + 1) + (MAX_D_FRAMES + 1)]; -}; - -extern void main_irq_hfcsx(struct BCState *bcs); -extern void releasehfcsx(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c deleted file mode 100644 index b6e58c11c288..000000000000 --- a/drivers/isdn/hisax/hfc_usb.c +++ /dev/null @@ -1,1594 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * hfc_usb.c - * - * $Id: hfc_usb.c,v 2.3.2.24 2007/10/14 08:40:29 mbachem Exp $ - * - * modular HiSax ISDN driver for Colognechip HFC-S USB chip - * - * Authors : Peter Sprenger (sprenger@moving-bytes.de) - * Martin Bachem (m.bachem@gmx.de, info@colognechip.com) - * - * based on the first hfc_usb driver of - * Werner Cornelius (werner@isdn-development.de) - * - * See Version Histroy at the bottom of this file - */ - -#include <linux/types.h> -#include <linux/stddef.h> -#include <linux/timer.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/kernel_stat.h> -#include <linux/usb.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/moduleparam.h> -#include <linux/slab.h> -#include "hisax.h" -#include "hisax_if.h" -#include "hfc_usb.h" - -static const char *hfcusb_revision = - "$Revision: 2.3.2.24 $ $Date: 2007/10/14 08:40:29 $ "; - -/* Hisax debug support - * debug flags defined in hfc_usb.h as HFCUSB_DBG_[*] - */ -#define __debug_variable hfc_debug -#include "hisax_debug.h" -static u_int debug; -module_param(debug, uint, 0); -static int hfc_debug; - - -/* private vendor specific data */ -typedef struct { - __u8 led_scheme; // led display scheme - signed short led_bits[8]; // array of 8 possible LED bitmask settings - char *vend_name; // device name -} hfcsusb_vdata; - -/* VID/PID device list */ -static const struct usb_device_id hfcusb_idtab[] = { - { - USB_DEVICE(0x0959, 0x2bd0), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_OFF, {4, 0, 2, 1}, - "ISDN USB TA (Cologne Chip HFC-S USB based)"}), - }, - { - USB_DEVICE(0x0675, 0x1688), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {1, 2, 0, 0}, - "DrayTek miniVigor 128 USB ISDN TA"}), - }, - { - USB_DEVICE(0x07b0, 0x0007), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Billion tiny USB ISDN TA 128"}), - }, - { - USB_DEVICE(0x0742, 0x2008), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {4, 0, 2, 1}, - "Stollmann USB TA"}), - }, - { - USB_DEVICE(0x0742, 0x2009), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {4, 0, 2, 1}, - "Aceex USB ISDN TA"}), - }, - { - USB_DEVICE(0x0742, 0x200A), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {4, 0, 2, 1}, - "OEM USB ISDN TA"}), - }, - { - USB_DEVICE(0x08e3, 0x0301), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {2, 0, 1, 4}, - "Olitec USB RNIS"}), - }, - { - USB_DEVICE(0x07fa, 0x0846), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Bewan Modem RNIS USB"}), - }, - { - USB_DEVICE(0x07fa, 0x0847), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Djinn Numeris USB"}), - }, - { - USB_DEVICE(0x07b0, 0x0006), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {0x80, -64, -32, -16}, - "Twister ISDN TA"}), - }, - { - USB_DEVICE(0x071d, 0x1005), - .driver_info = (unsigned long) &((hfcsusb_vdata) - {LED_SCHEME1, {0x02, 0, 0x01, 0x04}, - "Eicon DIVA USB 4.0"}), - }, - { } -}; - -/* structure defining input+output fifos (interrupt/bulk mode) */ -struct usb_fifo; /* forward definition */ -typedef struct iso_urb_struct { - struct urb *purb; - __u8 buffer[ISO_BUFFER_SIZE]; /* buffer incoming/outgoing data */ - struct usb_fifo *owner_fifo; /* pointer to owner fifo */ -} iso_urb_struct; - -struct hfcusb_data; /* forward definition */ - -typedef struct usb_fifo { - int fifonum; /* fifo index attached to this structure */ - int active; /* fifo is currently active */ - struct hfcusb_data *hfc; /* pointer to main structure */ - int pipe; /* address of endpoint */ - __u8 usb_packet_maxlen; /* maximum length for usb transfer */ - unsigned int max_size; /* maximum size of receive/send packet */ - __u8 intervall; /* interrupt interval */ - struct sk_buff *skbuff; /* actual used buffer */ - struct urb *urb; /* transfer structure for usb routines */ - __u8 buffer[128]; /* buffer incoming/outgoing data */ - int bit_line; /* how much bits are in the fifo? */ - - volatile __u8 usb_transfer_mode; /* switched between ISO and INT */ - iso_urb_struct iso[2]; /* need two urbs to have one always for pending */ - struct hisax_if *hif; /* hisax interface */ - int delete_flg; /* only delete skbuff once */ - int last_urblen; /* remember length of last packet */ -} usb_fifo; - -/* structure holding all data for one device */ -typedef struct hfcusb_data { - /* HiSax Interface for loadable Layer1 drivers */ - struct hisax_d_if d_if; /* see hisax_if.h */ - struct hisax_b_if b_if[2]; /* see hisax_if.h */ - int protocol; - - struct usb_device *dev; /* our device */ - int if_used; /* used interface number */ - int alt_used; /* used alternate config */ - int ctrl_paksize; /* control pipe packet size */ - int ctrl_in_pipe, /* handles for control pipe */ - ctrl_out_pipe; - int cfg_used; /* configuration index used */ - int vend_idx; /* vendor found */ - int b_mode[2]; /* B-channel mode */ - int l1_activated; /* layer 1 activated */ - int disc_flag; /* TRUE if device was disonnected to avoid some USB actions */ - int packet_size, iso_packet_size; - - /* control pipe background handling */ - ctrl_buft ctrl_buff[HFC_CTRL_BUFSIZE]; /* buffer holding queued data */ - volatile int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; /* input/output pointer + count */ - struct urb *ctrl_urb; /* transfer structure for control channel */ - - struct usb_ctrlrequest ctrl_write; /* buffer for control write request */ - struct usb_ctrlrequest ctrl_read; /* same for read request */ - - __u8 old_led_state, led_state; - - volatile __u8 threshold_mask; /* threshold actually reported */ - volatile __u8 bch_enables; /* or mask for sctrl_r and sctrl register values */ - - usb_fifo fifos[HFCUSB_NUM_FIFOS]; /* structure holding all fifo data */ - - volatile __u8 l1_state; /* actual l1 state */ - struct timer_list t3_timer; /* timer 3 for activation/deactivation */ - struct timer_list t4_timer; /* timer 4 for activation/deactivation */ -} hfcusb_data; - - -static void collect_rx_frame(usb_fifo *fifo, __u8 *data, int len, - int finish); - -static inline const char * -symbolic(struct hfcusb_symbolic_list list[], const int num) -{ - int i; - for (i = 0; list[i].name != NULL; i++) - if (list[i].num == num) - return (list[i].name); - return "<unknown ERROR>"; -} - -static void -ctrl_start_transfer(hfcusb_data *hfc) -{ - if (hfc->ctrl_cnt) { - hfc->ctrl_urb->pipe = hfc->ctrl_out_pipe; - hfc->ctrl_urb->setup_packet = (u_char *)&hfc->ctrl_write; - hfc->ctrl_urb->transfer_buffer = NULL; - hfc->ctrl_urb->transfer_buffer_length = 0; - hfc->ctrl_write.wIndex = - cpu_to_le16(hfc->ctrl_buff[hfc->ctrl_out_idx].hfc_reg); - hfc->ctrl_write.wValue = - cpu_to_le16(hfc->ctrl_buff[hfc->ctrl_out_idx].reg_val); - - usb_submit_urb(hfc->ctrl_urb, GFP_ATOMIC); /* start transfer */ - } -} /* ctrl_start_transfer */ - -static int -queue_control_request(hfcusb_data *hfc, __u8 reg, __u8 val, int action) -{ - ctrl_buft *buf; - - if (hfc->ctrl_cnt >= HFC_CTRL_BUFSIZE) - return (1); /* no space left */ - buf = &hfc->ctrl_buff[hfc->ctrl_in_idx]; /* pointer to new index */ - buf->hfc_reg = reg; - buf->reg_val = val; - buf->action = action; - if (++hfc->ctrl_in_idx >= HFC_CTRL_BUFSIZE) - hfc->ctrl_in_idx = 0; /* pointer wrap */ - if (++hfc->ctrl_cnt == 1) - ctrl_start_transfer(hfc); - return (0); -} - -static void -ctrl_complete(struct urb *urb) -{ - hfcusb_data *hfc = (hfcusb_data *) urb->context; - - urb->dev = hfc->dev; - if (hfc->ctrl_cnt) { - hfc->ctrl_cnt--; /* decrement actual count */ - if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE) - hfc->ctrl_out_idx = 0; /* pointer wrap */ - - ctrl_start_transfer(hfc); /* start next transfer */ - } -} - -/* write led data to auxport & invert if necessary */ -static void -write_led(hfcusb_data *hfc, __u8 led_state) -{ - if (led_state != hfc->old_led_state) { - hfc->old_led_state = led_state; - queue_control_request(hfc, HFCUSB_P_DATA, led_state, 1); - } -} - -static void -set_led_bit(hfcusb_data *hfc, signed short led_bits, int on) -{ - if (on) { - if (led_bits < 0) - hfc->led_state &= ~abs(led_bits); - else - hfc->led_state |= led_bits; - } else { - if (led_bits < 0) - hfc->led_state |= abs(led_bits); - else - hfc->led_state &= ~led_bits; - } -} - -/* handle LED requests */ -static void -handle_led(hfcusb_data *hfc, int event) -{ - hfcsusb_vdata *driver_info = - (hfcsusb_vdata *) hfcusb_idtab[hfc->vend_idx].driver_info; - - /* if no scheme -> no LED action */ - if (driver_info->led_scheme == LED_OFF) - return; - - switch (event) { - case LED_POWER_ON: - set_led_bit(hfc, driver_info->led_bits[0], 1); - set_led_bit(hfc, driver_info->led_bits[1], 0); - set_led_bit(hfc, driver_info->led_bits[2], 0); - set_led_bit(hfc, driver_info->led_bits[3], 0); - break; - case LED_POWER_OFF: - set_led_bit(hfc, driver_info->led_bits[0], 0); - set_led_bit(hfc, driver_info->led_bits[1], 0); - set_led_bit(hfc, driver_info->led_bits[2], 0); - set_led_bit(hfc, driver_info->led_bits[3], 0); - break; - case LED_S0_ON: - set_led_bit(hfc, driver_info->led_bits[1], 1); - break; - case LED_S0_OFF: - set_led_bit(hfc, driver_info->led_bits[1], 0); - break; - case LED_B1_ON: - set_led_bit(hfc, driver_info->led_bits[2], 1); - break; - case LED_B1_OFF: - set_led_bit(hfc, driver_info->led_bits[2], 0); - break; - case LED_B2_ON: - set_led_bit(hfc, driver_info->led_bits[3], 1); - break; - case LED_B2_OFF: - set_led_bit(hfc, driver_info->led_bits[3], 0); - break; - } - write_led(hfc, hfc->led_state); -} - -/* ISDN l1 timer T3 expires */ -static void -l1_timer_expire_t3(struct timer_list *t) -{ - hfcusb_data *hfc = from_timer(hfc, t, t3_timer); - hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION, - NULL); - - DBG(HFCUSB_DBG_STATES, - "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T3 expire)"); - - hfc->l1_activated = 0; - handle_led(hfc, LED_S0_OFF); - /* deactivate : */ - queue_control_request(hfc, HFCUSB_STATES, 0x10, 1); - queue_control_request(hfc, HFCUSB_STATES, 3, 1); -} - -/* ISDN l1 timer T4 expires */ -static void -l1_timer_expire_t4(struct timer_list *t) -{ - hfcusb_data *hfc = from_timer(hfc, t, t4_timer); - hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION, - NULL); - - DBG(HFCUSB_DBG_STATES, - "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T4 expire)"); - - hfc->l1_activated = 0; - handle_led(hfc, LED_S0_OFF); -} - -/* S0 state changed */ -static void -s0_state_handler(hfcusb_data *hfc, __u8 state) -{ - __u8 old_state; - - old_state = hfc->l1_state; - if (state == old_state || state < 1 || state > 8) - return; - - DBG(HFCUSB_DBG_STATES, "HFC-S USB: S0 statechange(%d -> %d)", - old_state, state); - - if (state < 4 || state == 7 || state == 8) { - if (timer_pending(&hfc->t3_timer)) - del_timer(&hfc->t3_timer); - DBG(HFCUSB_DBG_STATES, "HFC-S USB: T3 deactivated"); - } - if (state >= 7) { - if (timer_pending(&hfc->t4_timer)) - del_timer(&hfc->t4_timer); - DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 deactivated"); - } - - if (state == 7 && !hfc->l1_activated) { - hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, - PH_ACTIVATE | INDICATION, NULL); - DBG(HFCUSB_DBG_STATES, "HFC-S USB: PH_ACTIVATE | INDICATION sent"); - hfc->l1_activated = 1; - handle_led(hfc, LED_S0_ON); - } else if (state <= 3 /* && activated */) { - if (old_state == 7 || old_state == 8) { - DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 activated"); - if (!timer_pending(&hfc->t4_timer)) { - hfc->t4_timer.expires = - jiffies + (HFC_TIMER_T4 * HZ) / 1000; - add_timer(&hfc->t4_timer); - } - } else { - hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, - PH_DEACTIVATE | INDICATION, - NULL); - DBG(HFCUSB_DBG_STATES, - "HFC-S USB: PH_DEACTIVATE | INDICATION sent"); - hfc->l1_activated = 0; - handle_led(hfc, LED_S0_OFF); - } - } - hfc->l1_state = state; -} - -static void -fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, - void *buf, int num_packets, int packet_size, int interval, - usb_complete_t complete, void *context) -{ - int k; - - usb_fill_int_urb(urb, dev, pipe, buf, packet_size * num_packets, - complete, context, interval); - - urb->number_of_packets = num_packets; - urb->transfer_flags = URB_ISO_ASAP; - urb->actual_length = 0; - for (k = 0; k < num_packets; k++) { - urb->iso_frame_desc[k].offset = packet_size * k; - urb->iso_frame_desc[k].length = packet_size; - urb->iso_frame_desc[k].actual_length = 0; - } -} - -/* allocs urbs and start isoc transfer with two pending urbs to avoid - * gaps in the transfer chain - */ -static int -start_isoc_chain(usb_fifo *fifo, int num_packets_per_urb, - usb_complete_t complete, int packet_size) -{ - int i, k, errcode; - - DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting ISO-URBs for fifo:%d\n", - fifo->fifonum); - - /* allocate Memory for Iso out Urbs */ - for (i = 0; i < 2; i++) { - if (!(fifo->iso[i].purb)) { - fifo->iso[i].purb = - usb_alloc_urb(num_packets_per_urb, GFP_KERNEL); - if (!(fifo->iso[i].purb)) { - printk(KERN_INFO - "alloc urb for fifo %i failed!!!", - fifo->fifonum); - } - fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo; - - /* Init the first iso */ - if (ISO_BUFFER_SIZE >= - (fifo->usb_packet_maxlen * - num_packets_per_urb)) { - fill_isoc_urb(fifo->iso[i].purb, - fifo->hfc->dev, fifo->pipe, - fifo->iso[i].buffer, - num_packets_per_urb, - fifo->usb_packet_maxlen, - fifo->intervall, complete, - &fifo->iso[i]); - memset(fifo->iso[i].buffer, 0, - sizeof(fifo->iso[i].buffer)); - /* defining packet delimeters in fifo->buffer */ - for (k = 0; k < num_packets_per_urb; k++) { - fifo->iso[i].purb-> - iso_frame_desc[k].offset = - k * packet_size; - fifo->iso[i].purb-> - iso_frame_desc[k].length = - packet_size; - } - } else { - printk(KERN_INFO - "HFC-S USB: ISO Buffer size to small!\n"); - } - } - fifo->bit_line = BITLINE_INF; - - errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL); - fifo->active = (errcode >= 0) ? 1 : 0; - if (errcode < 0) - printk(KERN_INFO "HFC-S USB: usb_submit_urb URB nr:%d, error(%i): '%s'\n", - i, errcode, symbolic(urb_errlist, errcode)); - } - return (fifo->active); -} - -/* stops running iso chain and frees their pending urbs */ -static void -stop_isoc_chain(usb_fifo *fifo) -{ - int i; - - for (i = 0; i < 2; i++) { - if (fifo->iso[i].purb) { - DBG(HFCUSB_DBG_INIT, - "HFC-S USB: Stopping iso chain for fifo %i.%i", - fifo->fifonum, i); - usb_kill_urb(fifo->iso[i].purb); - usb_free_urb(fifo->iso[i].purb); - fifo->iso[i].purb = NULL; - } - } - - usb_kill_urb(fifo->urb); - usb_free_urb(fifo->urb); - fifo->urb = NULL; - fifo->active = 0; -} - -/* defines how much ISO packets are handled in one URB */ -static int iso_packets[8] = -{ ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, - ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D -}; - -static void -tx_iso_complete(struct urb *urb) -{ - iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; - usb_fifo *fifo = context_iso_urb->owner_fifo; - hfcusb_data *hfc = fifo->hfc; - int k, tx_offset, num_isoc_packets, sink, len, current_len, - errcode; - int frame_complete, transp_mode, fifon, status; - __u8 threshbit; - - fifon = fifo->fifonum; - status = urb->status; - - tx_offset = 0; - - /* ISO transfer only partially completed, - look at individual frame status for details */ - if (status == -EXDEV) { - DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete with -EXDEV" - ", urb->status %d, fifonum %d\n", - status, fifon); - - for (k = 0; k < iso_packets[fifon]; ++k) { - errcode = urb->iso_frame_desc[k].status; - if (errcode) - DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete " - "packet %i, status: %i\n", - k, errcode); - } - - // clear status, so go on with ISO transfers - status = 0; - } - - if (fifo->active && !status) { - transp_mode = 0; - if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS) - transp_mode = 1; - - /* is FifoFull-threshold set for our channel? */ - threshbit = (hfc->threshold_mask & (1 << fifon)); - num_isoc_packets = iso_packets[fifon]; - - /* predict dataflow to avoid fifo overflow */ - if (fifon >= HFCUSB_D_TX) { - sink = (threshbit) ? SINK_DMIN : SINK_DMAX; - } else { - sink = (threshbit) ? SINK_MIN : SINK_MAX; - } - fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe, - context_iso_urb->buffer, num_isoc_packets, - fifo->usb_packet_maxlen, fifo->intervall, - tx_iso_complete, urb->context); - memset(context_iso_urb->buffer, 0, - sizeof(context_iso_urb->buffer)); - frame_complete = 0; - - /* Generate next ISO Packets */ - for (k = 0; k < num_isoc_packets; ++k) { - if (fifo->skbuff) { - len = fifo->skbuff->len; - /* we lower data margin every msec */ - fifo->bit_line -= sink; - current_len = (0 - fifo->bit_line) / 8; - /* maximum 15 byte for every ISO packet makes our life easier */ - if (current_len > 14) - current_len = 14; - current_len = - (len <= - current_len) ? len : current_len; - /* how much bit do we put on the line? */ - fifo->bit_line += current_len * 8; - - context_iso_urb->buffer[tx_offset] = 0; - if (current_len == len) { - if (!transp_mode) { - /* here frame completion */ - context_iso_urb-> - buffer[tx_offset] = 1; - /* add 2 byte flags and 16bit CRC at end of ISDN frame */ - fifo->bit_line += 32; - } - frame_complete = 1; - } - - memcpy(context_iso_urb->buffer + - tx_offset + 1, fifo->skbuff->data, - current_len); - skb_pull(fifo->skbuff, current_len); - - /* define packet delimeters within the URB buffer */ - urb->iso_frame_desc[k].offset = tx_offset; - urb->iso_frame_desc[k].length = - current_len + 1; - - tx_offset += (current_len + 1); - } else { - urb->iso_frame_desc[k].offset = - tx_offset++; - - urb->iso_frame_desc[k].length = 1; - fifo->bit_line -= sink; /* we lower data margin every msec */ - - if (fifo->bit_line < BITLINE_INF) { - fifo->bit_line = BITLINE_INF; - } - } - - if (frame_complete) { - fifo->delete_flg = 1; - fifo->hif->l1l2(fifo->hif, - PH_DATA | CONFIRM, - (void *) (unsigned long) fifo->skbuff-> - truesize); - if (fifo->skbuff && fifo->delete_flg) { - dev_kfree_skb_any(fifo->skbuff); - fifo->skbuff = NULL; - fifo->delete_flg = 0; - } - frame_complete = 0; - } - } - errcode = usb_submit_urb(urb, GFP_ATOMIC); - if (errcode < 0) { - printk(KERN_INFO - "HFC-S USB: error submitting ISO URB: %d\n", - errcode); - } - } else { - if (status && !hfc->disc_flag) { - printk(KERN_INFO - "HFC-S USB: tx_iso_complete: error(%i): '%s', fifonum=%d\n", - status, symbolic(urb_errlist, status), fifon); - } - } -} - -static void -rx_iso_complete(struct urb *urb) -{ - iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; - usb_fifo *fifo = context_iso_urb->owner_fifo; - hfcusb_data *hfc = fifo->hfc; - int k, len, errcode, offset, num_isoc_packets, fifon, maxlen, - status; - unsigned int iso_status; - __u8 *buf; - static __u8 eof[8]; - - fifon = fifo->fifonum; - status = urb->status; - - if (urb->status == -EOVERFLOW) { - DBG(HFCUSB_DBG_VERBOSE_USB, - "HFC-USB: ignoring USB DATAOVERRUN fifo(%i)", fifon); - status = 0; - } - - /* ISO transfer only partially completed, - look at individual frame status for details */ - if (status == -EXDEV) { - DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: rx_iso_complete with -EXDEV " - "urb->status %d, fifonum %d\n", - status, fifon); - status = 0; - } - - if (fifo->active && !status) { - num_isoc_packets = iso_packets[fifon]; - maxlen = fifo->usb_packet_maxlen; - for (k = 0; k < num_isoc_packets; ++k) { - len = urb->iso_frame_desc[k].actual_length; - offset = urb->iso_frame_desc[k].offset; - buf = context_iso_urb->buffer + offset; - iso_status = urb->iso_frame_desc[k].status; - - if (iso_status && !hfc->disc_flag) - DBG(HFCUSB_DBG_VERBOSE_USB, - "HFC-S USB: rx_iso_complete " - "ISO packet %i, status: %i\n", - k, iso_status); - - if (fifon == HFCUSB_D_RX) { - DBG(HFCUSB_DBG_VERBOSE_USB, - "HFC-S USB: ISO-D-RX lst_urblen:%2d " - "act_urblen:%2d max-urblen:%2d EOF:0x%0x", - fifo->last_urblen, len, maxlen, - eof[5]); - - DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len); - } - - if (fifo->last_urblen != maxlen) { - /* the threshold mask is in the 2nd status byte */ - hfc->threshold_mask = buf[1]; - /* care for L1 state only for D-Channel - to avoid overlapped iso completions */ - if (fifon == HFCUSB_D_RX) { - /* the S0 state is in the upper half - of the 1st status byte */ - s0_state_handler(hfc, buf[0] >> 4); - } - eof[fifon] = buf[0] & 1; - if (len > 2) - collect_rx_frame(fifo, buf + 2, - len - 2, - (len < maxlen) ? - eof[fifon] : 0); - } else { - collect_rx_frame(fifo, buf, len, - (len < - maxlen) ? eof[fifon] : - 0); - } - fifo->last_urblen = len; - } - - fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe, - context_iso_urb->buffer, num_isoc_packets, - fifo->usb_packet_maxlen, fifo->intervall, - rx_iso_complete, urb->context); - errcode = usb_submit_urb(urb, GFP_ATOMIC); - if (errcode < 0) { - printk(KERN_ERR - "HFC-S USB: error submitting ISO URB: %d\n", - errcode); - } - } else { - if (status && !hfc->disc_flag) { - printk(KERN_ERR - "HFC-S USB: rx_iso_complete : " - "urb->status %d, fifonum %d\n", - status, fifon); - } - } -} - -/* collect rx data from INT- and ISO-URBs */ -static void -collect_rx_frame(usb_fifo *fifo, __u8 *data, int len, int finish) -{ - hfcusb_data *hfc = fifo->hfc; - int transp_mode, fifon; - - fifon = fifo->fifonum; - transp_mode = 0; - if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS) - transp_mode = 1; - - if (!fifo->skbuff) { - fifo->skbuff = dev_alloc_skb(fifo->max_size + 3); - if (!fifo->skbuff) { - printk(KERN_ERR - "HFC-S USB: cannot allocate buffer for fifo(%d)\n", - fifon); - return; - } - } - if (len) { - if (fifo->skbuff->len + len < fifo->max_size) { - skb_put_data(fifo->skbuff, data, len); - } else { - DBG(HFCUSB_DBG_FIFO_ERR, - "HCF-USB: got frame exceeded fifo->max_size(%d) fifo(%d)", - fifo->max_size, fifon); - DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff); - skb_trim(fifo->skbuff, 0); - } - } - if (transp_mode && fifo->skbuff->len >= 128) { - fifo->hif->l1l2(fifo->hif, PH_DATA | INDICATION, - fifo->skbuff); - fifo->skbuff = NULL; - return; - } - /* we have a complete hdlc packet */ - if (finish) { - if (fifo->skbuff->len > 3 && - !fifo->skbuff->data[fifo->skbuff->len - 1]) { - - if (fifon == HFCUSB_D_RX) { - DBG(HFCUSB_DBG_DCHANNEL, - "HFC-S USB: D-RX len(%d)", fifo->skbuff->len); - DBG_SKB(HFCUSB_DBG_DCHANNEL, fifo->skbuff); - } - - /* remove CRC & status */ - skb_trim(fifo->skbuff, fifo->skbuff->len - 3); - if (fifon == HFCUSB_PCM_RX) { - fifo->hif->l1l2(fifo->hif, - PH_DATA_E | INDICATION, - fifo->skbuff); - } else - fifo->hif->l1l2(fifo->hif, - PH_DATA | INDICATION, - fifo->skbuff); - fifo->skbuff = NULL; /* buffer was freed from upper layer */ - } else { - DBG(HFCUSB_DBG_FIFO_ERR, - "HFC-S USB: ERROR frame len(%d) fifo(%d)", - fifo->skbuff->len, fifon); - DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff); - skb_trim(fifo->skbuff, 0); - } - } -} - -static void -rx_int_complete(struct urb *urb) -{ - int len; - int status; - __u8 *buf, maxlen, fifon; - usb_fifo *fifo = (usb_fifo *) urb->context; - hfcusb_data *hfc = fifo->hfc; - static __u8 eof[8]; - - urb->dev = hfc->dev; /* security init */ - - fifon = fifo->fifonum; - if ((!fifo->active) || (urb->status)) { - DBG(HFCUSB_DBG_INIT, "HFC-S USB: RX-Fifo %i is going down (%i)", - fifon, urb->status); - - fifo->urb->interval = 0; /* cancel automatic rescheduling */ - if (fifo->skbuff) { - dev_kfree_skb_any(fifo->skbuff); - fifo->skbuff = NULL; - } - return; - } - len = urb->actual_length; - buf = fifo->buffer; - maxlen = fifo->usb_packet_maxlen; - - if (fifon == HFCUSB_D_RX) { - DBG(HFCUSB_DBG_VERBOSE_USB, - "HFC-S USB: INT-D-RX lst_urblen:%2d " - "act_urblen:%2d max-urblen:%2d EOF:0x%0x", - fifo->last_urblen, len, maxlen, - eof[5]); - DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len); - } - - if (fifo->last_urblen != fifo->usb_packet_maxlen) { - /* the threshold mask is in the 2nd status byte */ - hfc->threshold_mask = buf[1]; - /* the S0 state is in the upper half of the 1st status byte */ - s0_state_handler(hfc, buf[0] >> 4); - eof[fifon] = buf[0] & 1; - /* if we have more than the 2 status bytes -> collect data */ - if (len > 2) - collect_rx_frame(fifo, buf + 2, - urb->actual_length - 2, - (len < maxlen) ? eof[fifon] : 0); - } else { - collect_rx_frame(fifo, buf, urb->actual_length, - (len < maxlen) ? eof[fifon] : 0); - } - fifo->last_urblen = urb->actual_length; - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) { - printk(KERN_INFO - "HFC-S USB: %s error resubmitting URB fifo(%d)\n", - __func__, fifon); - } -} - -/* start initial INT-URB for certain fifo */ -static void -start_int_fifo(usb_fifo *fifo) -{ - int errcode; - - DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting RX INT-URB for fifo:%d\n", - fifo->fifonum); - - if (!fifo->urb) { - fifo->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!fifo->urb) - return; - } - usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe, - fifo->buffer, fifo->usb_packet_maxlen, - rx_int_complete, fifo, fifo->intervall); - fifo->active = 1; /* must be marked active */ - errcode = usb_submit_urb(fifo->urb, GFP_KERNEL); - if (errcode) { - printk(KERN_ERR "HFC-S USB: submit URB error(%s): status:%i\n", - __func__, errcode); - fifo->active = 0; - fifo->skbuff = NULL; - } -} - -static void -setup_bchannel(hfcusb_data *hfc, int channel, int mode) -{ - __u8 val, idx_table[2] = { 0, 2 }; - - if (hfc->disc_flag) { - return; - } - DBG(HFCUSB_DBG_STATES, "HFC-S USB: setting channel %d to mode %d", - channel, mode); - hfc->b_mode[channel] = mode; - - /* setup CON_HDLC */ - val = 0; - if (mode != L1_MODE_NULL) - val = 8; /* enable fifo? */ - if (mode == L1_MODE_TRANS) - val |= 2; /* set transparent bit */ - - /* set FIFO to transmit register */ - queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel], 1); - queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1); - /* reset fifo */ - queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1); - /* set FIFO to receive register */ - queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel] + 1, 1); - queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1); - /* reset fifo */ - queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1); - - val = 0x40; - if (hfc->b_mode[0]) - val |= 1; - if (hfc->b_mode[1]) - val |= 2; - queue_control_request(hfc, HFCUSB_SCTRL, val, 1); - - val = 0; - if (hfc->b_mode[0]) - val |= 1; - if (hfc->b_mode[1]) - val |= 2; - queue_control_request(hfc, HFCUSB_SCTRL_R, val, 1); - - if (mode == L1_MODE_NULL) { - if (channel) - handle_led(hfc, LED_B2_OFF); - else - handle_led(hfc, LED_B1_OFF); - } else { - if (channel) - handle_led(hfc, LED_B2_ON); - else - handle_led(hfc, LED_B1_ON); - } -} - -static void -hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg) -{ - usb_fifo *fifo = my_hisax_if->priv; - hfcusb_data *hfc = fifo->hfc; - - switch (pr) { - case PH_ACTIVATE | REQUEST: - if (fifo->fifonum == HFCUSB_D_TX) { - DBG(HFCUSB_DBG_STATES, - "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST"); - - if (hfc->l1_state != 3 - && hfc->l1_state != 7) { - hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, - PH_DEACTIVATE | - INDICATION, - NULL); - DBG(HFCUSB_DBG_STATES, - "HFC-S USB: PH_DEACTIVATE | INDICATION sent (not state 3 or 7)"); - } else { - if (hfc->l1_state == 7) { /* l1 already active */ - hfc->d_if.ifc.l1l2(&hfc-> - d_if. - ifc, - PH_ACTIVATE - | - INDICATION, - NULL); - DBG(HFCUSB_DBG_STATES, - "HFC-S USB: PH_ACTIVATE | INDICATION sent again ;)"); - } else { - /* force sending sending INFO1 */ - queue_control_request(hfc, - HFCUSB_STATES, - 0x14, - 1); - mdelay(1); - /* start l1 activation */ - queue_control_request(hfc, - HFCUSB_STATES, - 0x04, - 1); - if (!timer_pending - (&hfc->t3_timer)) { - hfc->t3_timer. - expires = - jiffies + - (HFC_TIMER_T3 * - HZ) / 1000; - add_timer(&hfc-> - t3_timer); - } - } - } - } else { - DBG(HFCUSB_DBG_STATES, - "HFC_USB: hfc_usb_d_l2l1 B-chan: PH_ACTIVATE | REQUEST"); - setup_bchannel(hfc, - (fifo->fifonum == - HFCUSB_B1_TX) ? 0 : 1, - (long) arg); - fifo->hif->l1l2(fifo->hif, - PH_ACTIVATE | INDICATION, - NULL); - } - break; - case PH_DEACTIVATE | REQUEST: - if (fifo->fifonum == HFCUSB_D_TX) { - DBG(HFCUSB_DBG_STATES, - "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST"); - } else { - DBG(HFCUSB_DBG_STATES, - "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST"); - setup_bchannel(hfc, - (fifo->fifonum == - HFCUSB_B1_TX) ? 0 : 1, - (int) L1_MODE_NULL); - fifo->hif->l1l2(fifo->hif, - PH_DEACTIVATE | INDICATION, - NULL); - } - break; - case PH_DATA | REQUEST: - if (fifo->skbuff && fifo->delete_flg) { - dev_kfree_skb_any(fifo->skbuff); - fifo->skbuff = NULL; - fifo->delete_flg = 0; - } - fifo->skbuff = arg; /* we have a new buffer */ - break; - default: - DBG(HFCUSB_DBG_STATES, - "HFC_USB: hfc_usb_d_l2l1: unknown state : %#x", pr); - break; - } -} - -/* initial init HFC-S USB chip registers, HiSax interface, USB URBs */ -static int -hfc_usb_init(hfcusb_data *hfc) -{ - usb_fifo *fifo; - int i; - u_char b; - struct hisax_b_if *p_b_if[2]; - - /* check the chip id */ - if (read_usb(hfc, HFCUSB_CHIP_ID, &b) != 1) { - printk(KERN_INFO "HFC-USB: cannot read chip id\n"); - return (1); - } - if (b != HFCUSB_CHIPID) { - printk(KERN_INFO "HFC-S USB: Invalid chip id 0x%02x\n", b); - return (1); - } - - /* first set the needed config, interface and alternate */ - usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used); - - /* do Chip reset */ - write_usb(hfc, HFCUSB_CIRM, 8); - /* aux = output, reset off */ - write_usb(hfc, HFCUSB_CIRM, 0x10); - - /* set USB_SIZE to match wMaxPacketSize for INT or BULK transfers */ - write_usb(hfc, HFCUSB_USB_SIZE, - (hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4)); - - /* set USB_SIZE_I to match wMaxPacketSize for ISO transfers */ - write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size); - - /* enable PCM/GCI master mode */ - write_usb(hfc, HFCUSB_MST_MODE1, 0); /* set default values */ - write_usb(hfc, HFCUSB_MST_MODE0, 1); /* enable master mode */ - - /* init the fifos */ - write_usb(hfc, HFCUSB_F_THRES, - (HFCUSB_TX_THRESHOLD / - 8) | ((HFCUSB_RX_THRESHOLD / 8) << 4)); - - fifo = hfc->fifos; - for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { - write_usb(hfc, HFCUSB_FIFO, i); /* select the desired fifo */ - fifo[i].skbuff = NULL; /* init buffer pointer */ - fifo[i].max_size = - (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN; - fifo[i].last_urblen = 0; - /* set 2 bit for D- & E-channel */ - write_usb(hfc, HFCUSB_HDLC_PAR, - ((i <= HFCUSB_B2_RX) ? 0 : 2)); - /* rx hdlc, enable IFF for D-channel */ - write_usb(hfc, HFCUSB_CON_HDLC, - ((i == HFCUSB_D_TX) ? 0x09 : 0x08)); - write_usb(hfc, HFCUSB_INC_RES_F, 2); /* reset the fifo */ - } - - write_usb(hfc, HFCUSB_CLKDEL, 0x0f); /* clock delay value */ - write_usb(hfc, HFCUSB_STATES, 3 | 0x10); /* set deactivated mode */ - write_usb(hfc, HFCUSB_STATES, 3); /* enable state machine */ - - write_usb(hfc, HFCUSB_SCTRL_R, 0); /* disable both B receivers */ - write_usb(hfc, HFCUSB_SCTRL, 0x40); /* disable B transmitters + capacitive mode */ - - /* set both B-channel to not connected */ - hfc->b_mode[0] = L1_MODE_NULL; - hfc->b_mode[1] = L1_MODE_NULL; - - hfc->l1_activated = 0; - hfc->disc_flag = 0; - hfc->led_state = 0; - hfc->old_led_state = 0; - - /* init the t3 timer */ - timer_setup(&hfc->t3_timer, l1_timer_expire_t3, 0); - - /* init the t4 timer */ - timer_setup(&hfc->t4_timer, l1_timer_expire_t4, 0); - - /* init the background machinery for control requests */ - hfc->ctrl_read.bRequestType = 0xc0; - hfc->ctrl_read.bRequest = 1; - hfc->ctrl_read.wLength = cpu_to_le16(1); - hfc->ctrl_write.bRequestType = 0x40; - hfc->ctrl_write.bRequest = 0; - hfc->ctrl_write.wLength = 0; - usb_fill_control_urb(hfc->ctrl_urb, - hfc->dev, - hfc->ctrl_out_pipe, - (u_char *)&hfc->ctrl_write, - NULL, 0, ctrl_complete, hfc); - /* Init All Fifos */ - for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { - hfc->fifos[i].iso[0].purb = NULL; - hfc->fifos[i].iso[1].purb = NULL; - hfc->fifos[i].active = 0; - } - /* register Modul to upper Hisax Layers */ - hfc->d_if.owner = THIS_MODULE; - hfc->d_if.ifc.priv = &hfc->fifos[HFCUSB_D_TX]; - hfc->d_if.ifc.l2l1 = hfc_usb_l2l1; - for (i = 0; i < 2; i++) { - hfc->b_if[i].ifc.priv = &hfc->fifos[HFCUSB_B1_TX + i * 2]; - hfc->b_if[i].ifc.l2l1 = hfc_usb_l2l1; - p_b_if[i] = &hfc->b_if[i]; - } - /* default Prot: EURO ISDN, should be a module_param */ - hfc->protocol = 2; - i = hisax_register(&hfc->d_if, p_b_if, "hfc_usb", hfc->protocol); - if (i) { - printk(KERN_INFO "HFC-S USB: hisax_register -> %d\n", i); - return i; - } - -#ifdef CONFIG_HISAX_DEBUG - hfc_debug = debug; -#endif - - for (i = 0; i < 4; i++) - hfc->fifos[i].hif = &p_b_if[i / 2]->ifc; - for (i = 4; i < 8; i++) - hfc->fifos[i].hif = &hfc->d_if.ifc; - - /* 3 (+1) INT IN + 3 ISO OUT */ - if (hfc->cfg_used == CNF_3INT3ISO || hfc->cfg_used == CNF_4INT3ISO) { - start_int_fifo(hfc->fifos + HFCUSB_D_RX); - if (hfc->fifos[HFCUSB_PCM_RX].pipe) - start_int_fifo(hfc->fifos + HFCUSB_PCM_RX); - start_int_fifo(hfc->fifos + HFCUSB_B1_RX); - start_int_fifo(hfc->fifos + HFCUSB_B2_RX); - } - /* 3 (+1) ISO IN + 3 ISO OUT */ - if (hfc->cfg_used == CNF_3ISO3ISO || hfc->cfg_used == CNF_4ISO3ISO) { - start_isoc_chain(hfc->fifos + HFCUSB_D_RX, ISOC_PACKETS_D, - rx_iso_complete, 16); - if (hfc->fifos[HFCUSB_PCM_RX].pipe) - start_isoc_chain(hfc->fifos + HFCUSB_PCM_RX, - ISOC_PACKETS_D, rx_iso_complete, - 16); - start_isoc_chain(hfc->fifos + HFCUSB_B1_RX, ISOC_PACKETS_B, - rx_iso_complete, 16); - start_isoc_chain(hfc->fifos + HFCUSB_B2_RX, ISOC_PACKETS_B, - rx_iso_complete, 16); - } - - start_isoc_chain(hfc->fifos + HFCUSB_D_TX, ISOC_PACKETS_D, - tx_iso_complete, 1); - start_isoc_chain(hfc->fifos + HFCUSB_B1_TX, ISOC_PACKETS_B, - tx_iso_complete, 1); - start_isoc_chain(hfc->fifos + HFCUSB_B2_TX, ISOC_PACKETS_B, - tx_iso_complete, 1); - - handle_led(hfc, LED_POWER_ON); - - return (0); -} - -/* initial callback for each plugged USB device */ -static int -hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - hfcusb_data *context; - struct usb_host_interface *iface = intf->cur_altsetting; - struct usb_host_interface *iface_used = NULL; - struct usb_host_endpoint *ep; - int ifnum = iface->desc.bInterfaceNumber; - int i, idx, alt_idx, probe_alt_setting, vend_idx, cfg_used, *vcf, - attr, cfg_found, cidx, ep_addr; - int cmptbl[16], small_match, iso_packet_size, packet_size, - alt_used = 0; - hfcsusb_vdata *driver_info; - - vend_idx = 0xffff; - for (i = 0; hfcusb_idtab[i].idVendor; i++) { - if ((le16_to_cpu(dev->descriptor.idVendor) == hfcusb_idtab[i].idVendor) - && (le16_to_cpu(dev->descriptor.idProduct) == hfcusb_idtab[i].idProduct)) { - vend_idx = i; - continue; - } - } - - printk(KERN_INFO - "HFC-S USB: probing interface(%d) actalt(%d) minor(%d)\n", - ifnum, iface->desc.bAlternateSetting, intf->minor); - - if (vend_idx != 0xffff) { - /* if vendor and product ID is OK, start probing alternate settings */ - alt_idx = 0; - small_match = 0xffff; - - /* default settings */ - iso_packet_size = 16; - packet_size = 64; - - while (alt_idx < intf->num_altsetting) { - iface = intf->altsetting + alt_idx; - probe_alt_setting = iface->desc.bAlternateSetting; - cfg_used = 0; - - /* check for config EOL element */ - while (validconf[cfg_used][0]) { - cfg_found = 1; - vcf = validconf[cfg_used]; - /* first endpoint descriptor */ - ep = iface->endpoint; - - memcpy(cmptbl, vcf, 16 * sizeof(int)); - - /* check for all endpoints in this alternate setting */ - for (i = 0; i < iface->desc.bNumEndpoints; - i++) { - ep_addr = - ep->desc.bEndpointAddress; - /* get endpoint base */ - idx = ((ep_addr & 0x7f) - 1) * 2; - if (ep_addr & 0x80) - idx++; - attr = ep->desc.bmAttributes; - if (cmptbl[idx] == EP_NUL) { - cfg_found = 0; - } - if (attr == USB_ENDPOINT_XFER_INT - && cmptbl[idx] == EP_INT) - cmptbl[idx] = EP_NUL; - if (attr == USB_ENDPOINT_XFER_BULK - && cmptbl[idx] == EP_BLK) - cmptbl[idx] = EP_NUL; - if (attr == USB_ENDPOINT_XFER_ISOC - && cmptbl[idx] == EP_ISO) - cmptbl[idx] = EP_NUL; - - /* check if all INT endpoints match minimum interval */ - if ((attr == USB_ENDPOINT_XFER_INT) - && (ep->desc.bInterval < vcf[17])) { - cfg_found = 0; - } - ep++; - } - for (i = 0; i < 16; i++) { - /* all entries must be EP_NOP or EP_NUL for a valid config */ - if (cmptbl[i] != EP_NOP - && cmptbl[i] != EP_NUL) - cfg_found = 0; - } - if (cfg_found) { - if (cfg_used < small_match) { - small_match = cfg_used; - alt_used = - probe_alt_setting; - iface_used = iface; - } - } - cfg_used++; - } - alt_idx++; - } /* (alt_idx < intf->num_altsetting) */ - - /* found a valid USB Ta Endpint config */ - if (small_match != 0xffff) { - iface = iface_used; - if (!(context = kzalloc(sizeof(hfcusb_data), GFP_KERNEL))) - return (-ENOMEM); /* got no mem */ - - ep = iface->endpoint; - vcf = validconf[small_match]; - - for (i = 0; i < iface->desc.bNumEndpoints; i++) { - ep_addr = ep->desc.bEndpointAddress; - /* get endpoint base */ - idx = ((ep_addr & 0x7f) - 1) * 2; - if (ep_addr & 0x80) - idx++; - cidx = idx & 7; - attr = ep->desc.bmAttributes; - - /* init Endpoints */ - if (vcf[idx] != EP_NOP - && vcf[idx] != EP_NUL) { - switch (attr) { - case USB_ENDPOINT_XFER_INT: - context-> - fifos[cidx]. - pipe = - usb_rcvintpipe - (dev, - ep->desc. - bEndpointAddress); - context-> - fifos[cidx]. - usb_transfer_mode - = USB_INT; - packet_size = - le16_to_cpu(ep->desc.wMaxPacketSize); - break; - case USB_ENDPOINT_XFER_BULK: - if (ep_addr & 0x80) - context-> - fifos - [cidx]. - pipe = - usb_rcvbulkpipe - (dev, - ep-> - desc. - bEndpointAddress); - else - context-> - fifos - [cidx]. - pipe = - usb_sndbulkpipe - (dev, - ep-> - desc. - bEndpointAddress); - context-> - fifos[cidx]. - usb_transfer_mode - = USB_BULK; - packet_size = - le16_to_cpu(ep->desc.wMaxPacketSize); - break; - case USB_ENDPOINT_XFER_ISOC: - if (ep_addr & 0x80) - context-> - fifos - [cidx]. - pipe = - usb_rcvisocpipe - (dev, - ep-> - desc. - bEndpointAddress); - else - context-> - fifos - [cidx]. - pipe = - usb_sndisocpipe - (dev, - ep-> - desc. - bEndpointAddress); - context-> - fifos[cidx]. - usb_transfer_mode - = USB_ISOC; - iso_packet_size = - le16_to_cpu(ep->desc.wMaxPacketSize); - break; - default: - context-> - fifos[cidx]. - pipe = 0; - } /* switch attribute */ - - if (context->fifos[cidx].pipe) { - context->fifos[cidx]. - fifonum = cidx; - context->fifos[cidx].hfc = - context; - context->fifos[cidx].usb_packet_maxlen = - le16_to_cpu(ep->desc.wMaxPacketSize); - context->fifos[cidx]. - intervall = - ep->desc.bInterval; - context->fifos[cidx]. - skbuff = NULL; - } - } - ep++; - } - context->dev = dev; /* save device */ - context->if_used = ifnum; /* save used interface */ - context->alt_used = alt_used; /* and alternate config */ - context->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */ - context->cfg_used = vcf[16]; /* store used config */ - context->vend_idx = vend_idx; /* store found vendor */ - context->packet_size = packet_size; - context->iso_packet_size = iso_packet_size; - - /* create the control pipes needed for register access */ - context->ctrl_in_pipe = - usb_rcvctrlpipe(context->dev, 0); - context->ctrl_out_pipe = - usb_sndctrlpipe(context->dev, 0); - - driver_info = (hfcsusb_vdata *) - hfcusb_idtab[vend_idx].driver_info; - - context->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); - - if (!context->ctrl_urb) { - pr_warn("%s: No memory for control urb\n", - driver_info->vend_name); - kfree(context); - return -ENOMEM; - } - - pr_info("HFC-S USB: detected \"%s\"\n", - driver_info->vend_name); - - DBG(HFCUSB_DBG_INIT, - "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d), E-Channel(%d)", - conf_str[small_match], context->if_used, - context->alt_used, - validconf[small_match][18]); - - /* init the chip and register the driver */ - if (hfc_usb_init(context)) { - usb_kill_urb(context->ctrl_urb); - usb_free_urb(context->ctrl_urb); - context->ctrl_urb = NULL; - kfree(context); - return (-EIO); - } - usb_set_intfdata(intf, context); - return (0); - } - } else { - printk(KERN_INFO - "HFC-S USB: no valid vendor found in USB descriptor\n"); - } - return (-EIO); -} - -/* callback for unplugged USB device */ -static void -hfc_usb_disconnect(struct usb_interface *intf) -{ - hfcusb_data *context = usb_get_intfdata(intf); - int i; - - handle_led(context, LED_POWER_OFF); - schedule_timeout(HZ / 100); - - printk(KERN_INFO "HFC-S USB: device disconnect\n"); - context->disc_flag = 1; - usb_set_intfdata(intf, NULL); - - if (timer_pending(&context->t3_timer)) - del_timer(&context->t3_timer); - if (timer_pending(&context->t4_timer)) - del_timer(&context->t4_timer); - - /* tell all fifos to terminate */ - for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { - if (context->fifos[i].usb_transfer_mode == USB_ISOC) { - if (context->fifos[i].active > 0) { - stop_isoc_chain(&context->fifos[i]); - DBG(HFCUSB_DBG_INIT, - "HFC-S USB: %s stopping ISOC chain Fifo(%i)", - __func__, i); - } - } else { - if (context->fifos[i].active > 0) { - context->fifos[i].active = 0; - DBG(HFCUSB_DBG_INIT, - "HFC-S USB: %s unlinking URB for Fifo(%i)", - __func__, i); - } - usb_kill_urb(context->fifos[i].urb); - usb_free_urb(context->fifos[i].urb); - context->fifos[i].urb = NULL; - } - context->fifos[i].active = 0; - } - usb_kill_urb(context->ctrl_urb); - usb_free_urb(context->ctrl_urb); - context->ctrl_urb = NULL; - hisax_unregister(&context->d_if); - kfree(context); /* free our structure again */ -} - -static struct usb_driver hfc_drv = { - .name = "hfc_usb", - .id_table = hfcusb_idtab, - .probe = hfc_usb_probe, - .disconnect = hfc_usb_disconnect, - .disable_hub_initiated_lpm = 1, -}; - -static void __exit -hfc_usb_mod_exit(void) -{ - usb_deregister(&hfc_drv); /* release our driver */ - printk(KERN_INFO "HFC-S USB: module removed\n"); -} - -static int __init -hfc_usb_mod_init(void) -{ - char revstr[30], datestr[30], dummy[30]; -#ifndef CONFIG_HISAX_DEBUG - hfc_debug = debug; -#endif - sscanf(hfcusb_revision, - "%s %s $ %s %s %s $ ", dummy, revstr, - dummy, datestr, dummy); - printk(KERN_INFO - "HFC-S USB: driver module revision %s date %s loaded, (debug=%i)\n", - revstr, datestr, debug); - if (usb_register(&hfc_drv)) { - printk(KERN_INFO - "HFC-S USB: Unable to register HFC-S USB module at usb stack\n"); - return (-1); /* unable to register */ - } - return (0); -} - -module_init(hfc_usb_mod_init); -module_exit(hfc_usb_mod_exit); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(usb, hfcusb_idtab); diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h deleted file mode 100644 index 9a212330e8a8..000000000000 --- a/drivers/isdn/hisax/hfc_usb.h +++ /dev/null @@ -1,208 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * hfc_usb.h - * - * $Id: hfc_usb.h,v 1.1.2.5 2007/08/20 14:36:03 mbachem Exp $ - */ - -#ifndef __HFC_USB_H__ -#define __HFC_USB_H__ - -#define DRIVER_AUTHOR "Peter Sprenger (sprenger@moving-byters.de)" -#define DRIVER_DESC "HFC-S USB based HiSAX ISDN driver" - - -#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */ -#define HFC_TIMER_T3 8000 /* timeout for l1 activation timer */ -#define HFC_TIMER_T4 500 /* time for state change interval */ - -#define HFCUSB_L1_STATECHANGE 0 /* L1 state changed */ -#define HFCUSB_L1_DRX 1 /* D-frame received */ -#define HFCUSB_L1_ERX 2 /* E-frame received */ -#define HFCUSB_L1_DTX 4 /* D-frames completed */ - -#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */ - -#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */ -#define HFCUSB_TX_THRESHOLD 64 /* threshold for fifo report bit tx */ - -#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */ -#define HFCUSB_CIRM 0x00 /* cirm register index */ -#define HFCUSB_USB_SIZE 0x07 /* int length register */ -#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */ -#define HFCUSB_F_CROSS 0x0b /* bit order register */ -#define HFCUSB_CLKDEL 0x37 /* bit delay register */ -#define HFCUSB_CON_HDLC 0xfa /* channel connect register */ -#define HFCUSB_HDLC_PAR 0xfb -#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */ -#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */ -#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */ -#define HFCUSB_F_THRES 0x0c /* threshold register */ -#define HFCUSB_FIFO 0x0f /* fifo select register */ -#define HFCUSB_F_USAGE 0x1a /* fifo usage register */ -#define HFCUSB_MST_MODE0 0x14 -#define HFCUSB_MST_MODE1 0x15 -#define HFCUSB_P_DATA 0x1f -#define HFCUSB_INC_RES_F 0x0e -#define HFCUSB_STATES 0x30 - -#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */ - - -/* fifo registers */ -#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */ -#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */ -#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */ -#define HFCUSB_B2_TX 2 -#define HFCUSB_B2_RX 3 -#define HFCUSB_D_TX 4 -#define HFCUSB_D_RX 5 -#define HFCUSB_PCM_TX 6 -#define HFCUSB_PCM_RX 7 - -/* - * used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just - * supports ISO out, while the Cologne Chip EVAL TA just supports BULK out - */ -#define USB_INT 0 -#define USB_BULK 1 -#define USB_ISOC 2 - -#define ISOC_PACKETS_D 8 -#define ISOC_PACKETS_B 8 -#define ISO_BUFFER_SIZE 128 - -/* Fifo flow Control for TX ISO */ -#define SINK_MAX 68 -#define SINK_MIN 48 -#define SINK_DMIN 12 -#define SINK_DMAX 18 -#define BITLINE_INF (-64 * 8) - -/* HFC-S USB register access by Control-URSs */ -#define write_usb(a, b, c) usb_control_msg((a)->dev, (a)->ctrl_out_pipe, 0, 0x40, (c), (b), NULL, 0, HFC_CTRL_TIMEOUT) -#define read_usb(a, b, c) usb_control_msg((a)->dev, (a)->ctrl_in_pipe, 1, 0xC0, 0, (b), (c), 1, HFC_CTRL_TIMEOUT) -#define HFC_CTRL_BUFSIZE 32 - -/* entry and size of output/input control buffer */ -typedef struct { - __u8 hfc_reg; /* register number */ - __u8 reg_val; /* value to be written (or read) */ - int action; /* data for action handler */ -} ctrl_buft; - -/* Debugging Flags */ -#define HFCUSB_DBG_INIT 0x0001 -#define HFCUSB_DBG_STATES 0x0002 -#define HFCUSB_DBG_DCHANNEL 0x0080 -#define HFCUSB_DBG_FIFO_ERR 0x4000 -#define HFCUSB_DBG_VERBOSE_USB 0x8000 - -/* - * URB error codes: - * Used to represent a list of values and their respective symbolic names - */ -struct hfcusb_symbolic_list { - const int num; - const char *name; -}; - -static struct hfcusb_symbolic_list urb_errlist[] = { - {-ENOMEM, "No memory for allocation of internal structures"}, - {-ENOSPC, "The host controller's bandwidth is already consumed"}, - {-ENOENT, "URB was canceled by unlink_urb"}, - {-EXDEV, "ISO transfer only partially completed"}, - {-EAGAIN, "Too match scheduled for the future"}, - {-ENXIO, "URB already queued"}, - {-EFBIG, "Too much ISO frames requested"}, - {-ENOSR, "Buffer error (overrun)"}, - {-EPIPE, "Specified endpoint is stalled (device not responding)"}, - {-EOVERFLOW, "Babble (bad cable?)"}, - {-EPROTO, "Bit-stuff error (bad cable?)"}, - {-EILSEQ, "CRC/Timeout"}, - {-ETIMEDOUT, "NAK (device does not respond)"}, - {-ESHUTDOWN, "Device unplugged"}, - {-1, NULL} -}; - - -/* - * device dependent information to support different - * ISDN Ta's using the HFC-S USB chip - */ - -/* USB descriptor need to contain one of the following EndPoint combination: */ -#define CNF_4INT3ISO 1 // 4 INT IN, 3 ISO OUT -#define CNF_3INT3ISO 2 // 3 INT IN, 3 ISO OUT -#define CNF_4ISO3ISO 3 // 4 ISO IN, 3 ISO OUT -#define CNF_3ISO3ISO 4 // 3 ISO IN, 3 ISO OUT - -#define EP_NUL 1 // Endpoint at this position not allowed -#define EP_NOP 2 // all type of endpoints allowed at this position -#define EP_ISO 3 // Isochron endpoint mandatory at this position -#define EP_BLK 4 // Bulk endpoint mandatory at this position -#define EP_INT 5 // Interrupt endpoint mandatory at this position - -/* - * List of all supported endpoint configuration sets, used to find the - * best matching endpoint configuration within a devices' USB descriptor. - * We need at least 3 RX endpoints, and 3 TX endpoints, either - * INT-in and ISO-out, or ISO-in and ISO-out) - * with 4 RX endpoints even E-Channel logging is possible - */ -static int validconf[][19] = { - // INT in, ISO out config - {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT, - EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL, - CNF_4INT3ISO, 2, 1}, - {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL, - EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL, - CNF_3INT3ISO, 2, 0}, - // ISO in, ISO out config - {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, - EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO, - CNF_4ISO3ISO, 2, 1}, - {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, - EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL, - CNF_3ISO3ISO, 2, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // EOL element -}; - -#ifdef CONFIG_HISAX_DEBUG -// string description of chosen config -static char *conf_str[] = { - "4 Interrupt IN + 3 Isochron OUT", - "3 Interrupt IN + 3 Isochron OUT", - "4 Isochron IN + 3 Isochron OUT", - "3 Isochron IN + 3 Isochron OUT" -}; -#endif - -typedef struct { - int vendor; // vendor id - int prod_id; // product id - char *vend_name; // vendor string - __u8 led_scheme; // led display scheme - signed short led_bits[8]; // array of 8 possible LED bitmask settings -} vendor_data; - -#define LED_OFF 0 // no LED support -#define LED_SCHEME1 1 // LED standard scheme -#define LED_SCHEME2 2 // not used yet... - -#define LED_POWER_ON 1 -#define LED_POWER_OFF 2 -#define LED_S0_ON 3 -#define LED_S0_OFF 4 -#define LED_B1_ON 5 -#define LED_B1_OFF 6 -#define LED_B1_DATA 7 -#define LED_B2_ON 8 -#define LED_B2_OFF 9 -#define LED_B2_DATA 10 - -#define LED_NORMAL 0 // LEDs are normal -#define LED_INVERTED 1 // LEDs are inverted - - -#endif // __HFC_USB_H__ diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c deleted file mode 100644 index 91b5219499ca..000000000000 --- a/drivers/isdn/hisax/hfcscard.c +++ /dev/null @@ -1,261 +0,0 @@ -/* $Id: hfcscard.c,v 1.10.2.4 2004/01/14 16:04:48 keil Exp $ - * - * low level stuff for hfcs based cards (Teles3c, ACER P10) - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include <linux/isapnp.h> -#include "hisax.h" -#include "hfc_2bds0.h" -#include "isdnl1.h" - -static const char *hfcs_revision = "$Revision: 1.10.2.4 $"; - -static irqreturn_t -hfcs_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, stat; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if ((HFCD_ANYINT | HFCD_BUSY_NBUSY) & - (stat = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_STAT))) { - val = cs->BC_Read_Reg(cs, HFCD_DATA, HFCD_INT_S1); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCS: stat(%02x) s1(%02x)", stat, val); - hfc2bds0_interrupt(cs, val); - } else { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCS: irq_no_irq stat(%02x)", stat); - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -hfcs_Timer(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.hfcD.timer); - cs->hw.hfcD.timer.expires = jiffies + 75; - /* WD RESET */ -/* WriteReg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt | 0x80); - add_timer(&cs->hw.hfcD.timer); -*/ -} - -static void -release_io_hfcs(struct IsdnCardState *cs) -{ - release2bds0(cs); - del_timer(&cs->hw.hfcD.timer); - if (cs->hw.hfcD.addr) - release_region(cs->hw.hfcD.addr, 2); -} - -static void -reset_hfcs(struct IsdnCardState *cs) -{ - printk(KERN_INFO "HFCS: resetting card\n"); - cs->hw.hfcD.cirm = HFCD_RESET; - if (cs->typ == ISDN_CTYPE_TELES3C) - cs->hw.hfcD.cirm |= HFCD_MEM8K; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset On */ - mdelay(10); - cs->hw.hfcD.cirm = 0; - if (cs->typ == ISDN_CTYPE_TELES3C) - cs->hw.hfcD.cirm |= HFCD_MEM8K; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); /* Reset Off */ - mdelay(10); - if (cs->typ == ISDN_CTYPE_TELES3C) - cs->hw.hfcD.cirm |= HFCD_INTB; - else if (cs->typ == ISDN_CTYPE_ACERP10) - cs->hw.hfcD.cirm |= HFCD_INTA; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CIRM, cs->hw.hfcD.cirm); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CLKDEL, 0x0e); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_TEST, HFCD_AUTO_AWAKE); /* S/T Auto awake */ - cs->hw.hfcD.ctmt = HFCD_TIM25 | HFCD_AUTO_TIMER; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); - cs->hw.hfcD.int_m2 = HFCD_IRQ_ENABLE; - cs->hw.hfcD.int_m1 = HFCD_INTS_B1TRANS | HFCD_INTS_B2TRANS | - HFCD_INTS_DTRANS | HFCD_INTS_B1REC | HFCD_INTS_B2REC | - HFCD_INTS_DREC | HFCD_INTS_L1STATE; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M1, cs->hw.hfcD.int_m1); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_INT_M2, cs->hw.hfcD.int_m2); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, HFCD_LOAD_STATE | 2); /* HFC ST 2 */ - udelay(10); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_STATES, 2); /* HFC ST 2 */ - cs->hw.hfcD.mst_m = HFCD_MASTER; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); /* HFC Master */ - cs->hw.hfcD.sctrl = 0; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_SCTRL, cs->hw.hfcD.sctrl); -} - -static int -hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - int delay; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "HFCS: card_msg %x", mt); - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_hfcs(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_hfcs(cs); - return (0); - case CARD_INIT: - delay = (75 * HZ) / 100 + 1; - mod_timer(&cs->hw.hfcD.timer, jiffies + delay); - spin_lock_irqsave(&cs->lock, flags); - reset_hfcs(cs); - init2bds0(cs); - spin_unlock_irqrestore(&cs->lock, flags); - delay = (80 * HZ) / 1000 + 1; - msleep(80); - spin_lock_irqsave(&cs->lock, flags); - cs->hw.hfcD.ctmt |= HFCD_TIM800; - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_CTMT, cs->hw.hfcD.ctmt); - cs->BC_Write_Reg(cs, HFCD_DATA, HFCD_MST_MODE, cs->hw.hfcD.mst_m); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id hfc_ids[] = { - { ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), - ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), - (unsigned long) "Acer P10" }, - { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), - ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), - (unsigned long) "Billion 2" }, - { ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), - ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), - (unsigned long) "Billion 1" }, - { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), - ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), - (unsigned long) "IStar PnP" }, - { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), - ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), - (unsigned long) "Teles 16.3c" }, - { ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), - ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), - (unsigned long) "Tornado Tipa C" }, - { ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), - ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), - (unsigned long) "Genius Speed Surfer" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &hfc_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_hfcs(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, hfcs_revision); - printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp)); - -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - break; - } else { - printk(KERN_ERR "HFC PnP: PnP error card found, no device\n"); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "HFC PnP: no ISAPnP card found\n"); - return (0); - } - } -#endif - cs->hw.hfcD.addr = card->para[1] & 0xfffe; - cs->irq = card->para[0]; - cs->hw.hfcD.cip = 0; - cs->hw.hfcD.int_s1 = 0; - cs->hw.hfcD.send = NULL; - cs->bcs[0].hw.hfc.send = NULL; - cs->bcs[1].hw.hfc.send = NULL; - cs->hw.hfcD.dfifosize = 512; - cs->dc.hfcd.ph_state = 0; - cs->hw.hfcD.fifo = 255; - if (cs->typ == ISDN_CTYPE_TELES3C) { - cs->hw.hfcD.bfifosize = 1024 + 512; - } else if (cs->typ == ISDN_CTYPE_ACERP10) { - cs->hw.hfcD.bfifosize = 7 * 1024 + 512; - } else - return (0); - if (!request_region(cs->hw.hfcD.addr, 2, "HFCS isdn")) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.hfcD.addr, - cs->hw.hfcD.addr + 2); - return (0); - } - printk(KERN_INFO - "HFCS: defined at 0x%x IRQ %d HZ %d\n", - cs->hw.hfcD.addr, - cs->irq, HZ); - if (cs->typ == ISDN_CTYPE_TELES3C) { - /* Teles 16.3c IO ADR is 0x200 | YY0U (YY Bit 15/14 address) */ - outb(0x00, cs->hw.hfcD.addr); - outb(0x56, cs->hw.hfcD.addr | 1); - } else if (cs->typ == ISDN_CTYPE_ACERP10) { - /* Acer P10 IO ADR is 0x300 */ - outb(0x00, cs->hw.hfcD.addr); - outb(0x57, cs->hw.hfcD.addr | 1); - } - set_cs_func(cs); - timer_setup(&cs->hw.hfcD.timer, hfcs_Timer, 0); - cs->cardmsg = &hfcs_card_msg; - cs->irq_func = &hfcs_interrupt; - return (1); -} diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h deleted file mode 100644 index 40080e06421c..000000000000 --- a/drivers/isdn/hisax/hisax.h +++ /dev/null @@ -1,1352 +0,0 @@ -/* $Id: hisax.h,v 2.64.2.4 2004/02/11 13:21:33 keil Exp $ - * - * Basic declarations, defines and prototypes - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/major.h> -#include <asm/io.h> -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/mman.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/timer.h> -#include <linux/wait.h> -#include <linux/isdnif.h> -#include <linux/tty.h> -#include <linux/serial_reg.h> -#include <linux/netdevice.h> - -#define ERROR_STATISTIC - -#define REQUEST 0 -#define CONFIRM 1 -#define INDICATION 2 -#define RESPONSE 3 - -#define HW_ENABLE 0x0000 -#define HW_RESET 0x0004 -#define HW_POWERUP 0x0008 -#define HW_ACTIVATE 0x0010 -#define HW_DEACTIVATE 0x0018 - -#define HW_INFO1 0x0010 -#define HW_INFO2 0x0020 -#define HW_INFO3 0x0030 -#define HW_INFO4 0x0040 -#define HW_INFO4_P8 0x0040 -#define HW_INFO4_P10 0x0048 -#define HW_RSYNC 0x0060 -#define HW_TESTLOOP 0x0070 -#define CARD_RESET 0x00F0 -#define CARD_INIT 0x00F2 -#define CARD_RELEASE 0x00F3 -#define CARD_TEST 0x00F4 -#define CARD_AUX_IND 0x00F5 - -#define PH_ACTIVATE 0x0100 -#define PH_DEACTIVATE 0x0110 -#define PH_DATA 0x0120 -#define PH_PULL 0x0130 -#define PH_TESTLOOP 0x0140 -#define PH_PAUSE 0x0150 -#define MPH_ACTIVATE 0x0180 -#define MPH_DEACTIVATE 0x0190 -#define MPH_INFORMATION 0x01A0 - -#define DL_ESTABLISH 0x0200 -#define DL_RELEASE 0x0210 -#define DL_DATA 0x0220 -#define DL_FLUSH 0x0224 -#define DL_UNIT_DATA 0x0230 - -#define MDL_BC_RELEASE 0x0278 // Formula-n enter:now -#define MDL_BC_ASSIGN 0x027C // Formula-n enter:now -#define MDL_ASSIGN 0x0280 -#define MDL_REMOVE 0x0284 -#define MDL_ERROR 0x0288 -#define MDL_INFO_SETUP 0x02E0 -#define MDL_INFO_CONN 0x02E4 -#define MDL_INFO_REL 0x02E8 - -#define CC_SETUP 0x0300 -#define CC_RESUME 0x0304 -#define CC_MORE_INFO 0x0310 -#define CC_IGNORE 0x0320 -#define CC_REJECT 0x0324 -#define CC_SETUP_COMPL 0x0330 -#define CC_PROCEEDING 0x0340 -#define CC_ALERTING 0x0344 -#define CC_PROGRESS 0x0348 -#define CC_CONNECT 0x0350 -#define CC_CHARGE 0x0354 -#define CC_NOTIFY 0x0358 -#define CC_DISCONNECT 0x0360 -#define CC_RELEASE 0x0368 -#define CC_SUSPEND 0x0370 -#define CC_PROCEED_SEND 0x0374 -#define CC_REDIR 0x0378 -#define CC_T302 0x0382 -#define CC_T303 0x0383 -#define CC_T304 0x0384 -#define CC_T305 0x0385 -#define CC_T308_1 0x0388 -#define CC_T308_2 0x038A -#define CC_T309 0x0309 -#define CC_T310 0x0390 -#define CC_T313 0x0393 -#define CC_T318 0x0398 -#define CC_T319 0x0399 -#define CC_TSPID 0x03A0 -#define CC_NOSETUP_RSP 0x03E0 -#define CC_SETUP_ERR 0x03E1 -#define CC_SUSPEND_ERR 0x03E2 -#define CC_RESUME_ERR 0x03E3 -#define CC_CONNECT_ERR 0x03E4 -#define CC_RELEASE_ERR 0x03E5 -#define CC_RESTART 0x03F4 -#define CC_TDSS1_IO 0x13F4 /* DSS1 IO user timer */ -#define CC_TNI1_IO 0x13F5 /* NI1 IO user timer */ - -/* define maximum number of possible waiting incoming calls */ -#define MAX_WAITING_CALLS 2 - - -#ifdef __KERNEL__ - -extern const char *CardType[]; -extern int nrcards; - -extern const char *l1_revision; -extern const char *l2_revision; -extern const char *l3_revision; -extern const char *lli_revision; -extern const char *tei_revision; - -/* include l3dss1 & ni1 specific process structures, but no other defines */ -#ifdef CONFIG_HISAX_EURO -#define l3dss1_process -#include "l3dss1.h" -#undef l3dss1_process -#endif /* CONFIG_HISAX_EURO */ - -#ifdef CONFIG_HISAX_NI1 -#define l3ni1_process -#include "l3ni1.h" -#undef l3ni1_process -#endif /* CONFIG_HISAX_NI1 */ - -#define MAX_DFRAME_LEN 260 -#define MAX_DFRAME_LEN_L1 300 -#define HSCX_BUFMAX 4096 -#define MAX_DATA_SIZE (HSCX_BUFMAX - 4) -#define MAX_DATA_MEM (HSCX_BUFMAX + 64) -#define RAW_BUFMAX (((HSCX_BUFMAX * 6) / 5) + 5) -#define MAX_HEADER_LEN 4 -#define MAX_WINDOW 8 -#define MAX_MON_FRAME 32 -#define MAX_DLOG_SPACE 2048 -#define MAX_BLOG_SPACE 256 - -/* #define I4L_IRQ_FLAG SA_INTERRUPT */ -#define I4L_IRQ_FLAG 0 - -/* - * Statemachine - */ - -struct FsmInst; - -typedef void (*FSMFNPTR)(struct FsmInst *, int, void *); - -struct Fsm { - FSMFNPTR *jumpmatrix; - int state_count, event_count; - char **strEvent, **strState; -}; - -struct FsmInst { - struct Fsm *fsm; - int state; - int debug; - void *userdata; - int userint; - void (*printdebug) (struct FsmInst *, char *, ...); -}; - -struct FsmNode { - int state, event; - void (*routine) (struct FsmInst *, int, void *); -}; - -struct FsmTimer { - struct FsmInst *fi; - struct timer_list tl; - int event; - void *arg; -}; - -struct L3Timer { - struct l3_process *pc; - struct timer_list tl; - int event; -}; - -#define FLG_L1_ACTIVATING 1 -#define FLG_L1_ACTIVATED 2 -#define FLG_L1_DEACTTIMER 3 -#define FLG_L1_ACTTIMER 4 -#define FLG_L1_T3RUN 5 -#define FLG_L1_PULL_REQ 6 -#define FLG_L1_UINT 7 - -struct Layer1 { - void *hardware; - struct BCState *bcs; - struct PStack **stlistp; - unsigned long Flags; - struct FsmInst l1m; - struct FsmTimer timer; - void (*l1l2) (struct PStack *, int, void *); - void (*l1hw) (struct PStack *, int, void *); - void (*l1tei) (struct PStack *, int, void *); - int mode, bc; - int delay; -}; - -#define GROUP_TEI 127 -#define TEI_SAPI 63 -#define CTRL_SAPI 0 -#define PACKET_NOACK 7 - -/* Layer2 Flags */ - -#define FLG_LAPB 0 -#define FLG_LAPD 1 -#define FLG_ORIG 2 -#define FLG_MOD128 3 -#define FLG_PEND_REL 4 -#define FLG_L3_INIT 5 -#define FLG_T200_RUN 6 -#define FLG_ACK_PEND 7 -#define FLG_REJEXC 8 -#define FLG_OWN_BUSY 9 -#define FLG_PEER_BUSY 10 -#define FLG_DCHAN_BUSY 11 -#define FLG_L1_ACTIV 12 -#define FLG_ESTAB_PEND 13 -#define FLG_PTP 14 -#define FLG_FIXED_TEI 15 -#define FLG_L2BLOCK 16 - -struct Layer2 { - int tei; - int sap; - int maxlen; - u_long flag; - spinlock_t lock; - u_int vs, va, vr; - int rc; - unsigned int window; - unsigned int sow; - struct sk_buff *windowar[MAX_WINDOW]; - struct sk_buff_head i_queue; - struct sk_buff_head ui_queue; - void (*l2l1) (struct PStack *, int, void *); - void (*l2l3) (struct PStack *, int, void *); - void (*l2tei) (struct PStack *, int, void *); - struct FsmInst l2m; - struct FsmTimer t200, t203; - int T200, N200, T203; - int debug; - char debug_id[16]; -}; - -struct Layer3 { - void (*l3l4) (struct PStack *, int, void *); - void (*l3ml3) (struct PStack *, int, void *); - void (*l3l2) (struct PStack *, int, void *); - struct FsmInst l3m; - struct FsmTimer l3m_timer; - struct sk_buff_head squeue; - struct l3_process *proc; - struct l3_process *global; - int N303; - int debug; - char debug_id[8]; -}; - -struct LLInterface { - void (*l4l3) (struct PStack *, int, void *); - int (*l4l3_proto) (struct PStack *, isdn_ctrl *); - void *userdata; - u_long flag; -}; - -#define FLG_LLI_L1WAKEUP 1 -#define FLG_LLI_L2WAKEUP 2 - -struct Management { - int ri; - struct FsmInst tei_m; - struct FsmTimer t202; - int T202, N202, debug; - void (*layer) (struct PStack *, int, void *); -}; - -#define NO_CAUSE 254 - -struct Param { - u_char cause; - u_char loc; - u_char diag[6]; - int bchannel; - int chargeinfo; - int spv; /* SPV Flag */ - setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ - u_char moderate; /* transfer mode and rate (bearer octet 4) */ -}; - - -struct PStack { - struct PStack *next; - struct Layer1 l1; - struct Layer2 l2; - struct Layer3 l3; - struct LLInterface lli; - struct Management ma; - int protocol; /* EDSS1, 1TR6 or NI1 */ - - /* protocol specific data fields */ - union - { u_char uuuu; /* only as dummy */ -#ifdef CONFIG_HISAX_EURO - dss1_stk_priv dss1; /* private dss1 data */ -#endif /* CONFIG_HISAX_EURO */ -#ifdef CONFIG_HISAX_NI1 - ni1_stk_priv ni1; /* private ni1 data */ -#endif /* CONFIG_HISAX_NI1 */ - } prot; -}; - -struct l3_process { - int callref; - int state; - struct L3Timer timer; - int N303; - int debug; - struct Param para; - struct Channel *chan; - struct PStack *st; - struct l3_process *next; - ulong redir_result; - - /* protocol specific data fields */ - union - { u_char uuuu; /* only when euro not defined, avoiding empty union */ -#ifdef CONFIG_HISAX_EURO - dss1_proc_priv dss1; /* private dss1 data */ -#endif /* CONFIG_HISAX_EURO */ -#ifdef CONFIG_HISAX_NI1 - ni1_proc_priv ni1; /* private ni1 data */ -#endif /* CONFIG_HISAX_NI1 */ - } prot; -}; - -struct hscx_hw { - int hscx; - int rcvidx; - int count; /* Current skb sent count */ - u_char *rcvbuf; /* B-Channel receive Buffer */ - u_char tsaxr0; - u_char tsaxr1; -}; - -struct w6692B_hw { - int bchan; - int rcvidx; - int count; /* Current skb sent count */ - u_char *rcvbuf; /* B-Channel receive Buffer */ -}; - -struct isar_reg { - unsigned long Flags; - volatile u_char bstat; - volatile u_char iis; - volatile u_char cmsb; - volatile u_char clsb; - volatile u_char par[8]; -}; - -struct isar_hw { - int dpath; - int rcvidx; - int txcnt; - int mml; - u_char state; - u_char cmd; - u_char mod; - u_char newcmd; - u_char newmod; - char try_mod; - struct timer_list ftimer; - u_char *rcvbuf; /* B-Channel receive Buffer */ - u_char conmsg[16]; - struct isar_reg *reg; -}; - -struct hdlc_stat_reg { -#ifdef __BIG_ENDIAN - u_char fill; - u_char mode; - u_char xml; - u_char cmd; -#else - u_char cmd; - u_char xml; - u_char mode; - u_char fill; -#endif -} __attribute__((packed)); - -struct hdlc_hw { - union { - u_int ctrl; - struct hdlc_stat_reg sr; - } ctrl; - u_int stat; - int rcvidx; - int count; /* Current skb sent count */ - u_char *rcvbuf; /* B-Channel receive Buffer */ -}; - -struct hfcB_hw { - unsigned int *send; - int f1; - int f2; -}; - -struct tiger_hw { - u_int *send; - u_int *s_irq; - u_int *s_end; - u_int *sendp; - u_int *rec; - int free; - u_char *rcvbuf; - u_char *sendbuf; - u_char *sp; - int sendcnt; - u_int s_tot; - u_int r_bitcnt; - u_int r_tot; - u_int r_err; - u_int r_fcs; - u_char r_state; - u_char r_one; - u_char r_val; - u_char s_state; -}; - -struct amd7930_hw { - u_char *tx_buff; - u_char *rv_buff; - int rv_buff_in; - int rv_buff_out; - struct sk_buff *rv_skb; - struct hdlc_state *hdlc_state; - struct work_struct tq_rcv; - struct work_struct tq_xmt; -}; - -#define BC_FLG_INIT 1 -#define BC_FLG_ACTIV 2 -#define BC_FLG_BUSY 3 -#define BC_FLG_NOFRAME 4 -#define BC_FLG_HALF 5 -#define BC_FLG_EMPTY 6 -#define BC_FLG_ORIG 7 -#define BC_FLG_DLEETX 8 -#define BC_FLG_LASTDLE 9 -#define BC_FLG_FIRST 10 -#define BC_FLG_LASTDATA 11 -#define BC_FLG_NMD_DATA 12 -#define BC_FLG_FTI_RUN 13 -#define BC_FLG_LL_OK 14 -#define BC_FLG_LL_CONN 15 -#define BC_FLG_FTI_FTS 16 -#define BC_FLG_FRH_WAIT 17 - -#define L1_MODE_NULL 0 -#define L1_MODE_TRANS 1 -#define L1_MODE_HDLC 2 -#define L1_MODE_EXTRN 3 -#define L1_MODE_HDLC_56K 4 -#define L1_MODE_MODEM 7 -#define L1_MODE_V32 8 -#define L1_MODE_FAX 9 - -struct BCState { - int channel; - int mode; - u_long Flag; - struct IsdnCardState *cs; - int tx_cnt; /* B-Channel transmit counter */ - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ - struct sk_buff_head rqueue; /* B-Channel receive Queue */ - struct sk_buff_head squeue; /* B-Channel send Queue */ - int ackcnt; - spinlock_t aclock; - struct PStack *st; - u_char *blog; - u_char *conmsg; - struct timer_list transbusy; - struct work_struct tqueue; - u_long event; - int (*BC_SetStack) (struct PStack *, struct BCState *); - void (*BC_Close) (struct BCState *); -#ifdef ERROR_STATISTIC - int err_crc; - int err_tx; - int err_rdo; - int err_inv; -#endif - union { - struct hscx_hw hscx; - struct hdlc_hw hdlc; - struct isar_hw isar; - struct hfcB_hw hfc; - struct tiger_hw tiger; - struct amd7930_hw amd7930; - struct w6692B_hw w6692; - struct hisax_b_if *b_if; - } hw; -}; - -struct Channel { - struct PStack *b_st, *d_st; - struct IsdnCardState *cs; - struct BCState *bcs; - int chan; - int incoming; - struct FsmInst fi; - struct FsmTimer drel_timer, dial_timer; - int debug; - int l2_protocol, l2_active_protocol; - int l3_protocol; - int data_open; - struct l3_process *proc; - setup_parm setup; /* from isdnif.h numbers and Serviceindicator */ - u_long Flags; /* for remembering action done in l4 */ - int leased; -}; - -struct elsa_hw { - struct pci_dev *dev; - unsigned long base; - unsigned int cfg; - unsigned int ctrl; - unsigned int ale; - unsigned int isac; - unsigned int itac; - unsigned int hscx; - unsigned int trig; - unsigned int timer; - unsigned int counter; - unsigned int status; - struct timer_list tl; - unsigned int MFlag; - struct BCState *bcs; - u_char *transbuf; - u_char *rcvbuf; - unsigned int transp; - unsigned int rcvp; - unsigned int transcnt; - unsigned int rcvcnt; - u_char IER; - u_char FCR; - u_char LCR; - u_char MCR; - u_char ctrl_reg; -}; - -struct teles3_hw { - unsigned int cfg_reg; - signed int isac; - signed int hscx[2]; - signed int isacfifo; - signed int hscxfifo[2]; -}; - -struct teles0_hw { - unsigned int cfg_reg; - void __iomem *membase; - unsigned long phymem; -}; - -struct avm_hw { - unsigned int cfg_reg; - unsigned int isac; - unsigned int hscx[2]; - unsigned int isacfifo; - unsigned int hscxfifo[2]; - unsigned int counter; - struct pci_dev *dev; -}; - -struct ix1_hw { - unsigned int cfg_reg; - unsigned int isac_ale; - unsigned int isac; - unsigned int hscx_ale; - unsigned int hscx; -}; - -struct diva_hw { - unsigned long cfg_reg; - unsigned long pci_cfg; - unsigned int ctrl; - unsigned long isac_adr; - unsigned int isac; - unsigned long hscx_adr; - unsigned int hscx; - unsigned int status; - struct timer_list tl; - u_char ctrl_reg; - struct pci_dev *dev; -}; - -struct asus_hw { - unsigned int cfg_reg; - unsigned int adr; - unsigned int isac; - unsigned int hscx; - unsigned int u7; - unsigned int pots; -}; - - -struct hfc_hw { - unsigned int addr; - unsigned int fifosize; - unsigned char cirm; - unsigned char ctmt; - unsigned char cip; - u_char isac_spcr; - struct timer_list timer; -}; - -struct sedl_hw { - unsigned int cfg_reg; - unsigned int adr; - unsigned int isac; - unsigned int hscx; - unsigned int reset_on; - unsigned int reset_off; - struct isar_reg isar; - unsigned int chip; - unsigned int bus; - struct pci_dev *dev; -}; - -struct spt_hw { - unsigned int cfg_reg; - unsigned int isac; - unsigned int hscx[2]; - unsigned char res_irq; -}; - -struct mic_hw { - unsigned int cfg_reg; - unsigned int adr; - unsigned int isac; - unsigned int hscx; -}; - -struct njet_hw { - unsigned long base; - unsigned int isac; - unsigned int auxa; - unsigned char auxd; - unsigned char dmactrl; - unsigned char ctrl_reg; - unsigned char irqmask0; - unsigned char irqstat0; - unsigned char last_is0; - struct pci_dev *dev; -}; - -struct hfcPCI_hw { - unsigned char cirm; - unsigned char ctmt; - unsigned char conn; - unsigned char mst_m; - unsigned char int_m1; - unsigned char int_m2; - unsigned char int_s1; - unsigned char sctrl; - unsigned char sctrl_r; - unsigned char sctrl_e; - unsigned char trm; - unsigned char stat; - unsigned char fifo; - unsigned char fifo_en; - unsigned char bswapped; - unsigned char nt_mode; - int nt_timer; - struct pci_dev *dev; - void __iomem *pci_io; /* start of PCI IO memory */ - dma_addr_t dma; /* dma handle for Fifos */ - void *fifos; /* FIFO memory */ - int last_bfifo_cnt[2]; /* marker saving last b-fifo frame count */ - struct timer_list timer; -}; - -struct hfcSX_hw { - unsigned long base; - unsigned char cirm; - unsigned char ctmt; - unsigned char conn; - unsigned char mst_m; - unsigned char int_m1; - unsigned char int_m2; - unsigned char int_s1; - unsigned char sctrl; - unsigned char sctrl_r; - unsigned char sctrl_e; - unsigned char trm; - unsigned char stat; - unsigned char fifo; - unsigned char bswapped; - unsigned char nt_mode; - unsigned char chip; - int b_fifo_size; - unsigned char last_fifo; - void *extra; - int nt_timer; - struct timer_list timer; -}; - -struct hfcD_hw { - unsigned int addr; - unsigned int bfifosize; - unsigned int dfifosize; - unsigned char cirm; - unsigned char ctmt; - unsigned char cip; - unsigned char conn; - unsigned char mst_m; - unsigned char int_m1; - unsigned char int_m2; - unsigned char int_s1; - unsigned char sctrl; - unsigned char stat; - unsigned char fifo; - unsigned char f1; - unsigned char f2; - unsigned int *send; - struct timer_list timer; -}; - -struct isurf_hw { - unsigned int reset; - unsigned long phymem; - void __iomem *isac; - void __iomem *isar; - struct isar_reg isar_r; -}; - -struct saphir_hw { - struct pci_dev *dev; - unsigned int cfg_reg; - unsigned int ale; - unsigned int isac; - unsigned int hscx; - struct timer_list timer; -}; - -struct bkm_hw { - struct pci_dev *dev; - unsigned long base; - /* A4T stuff */ - unsigned long isac_adr; - unsigned int isac_ale; - unsigned long jade_adr; - unsigned int jade_ale; - /* Scitel Quadro stuff */ - unsigned long plx_adr; - unsigned long data_adr; -}; - -struct gazel_hw { - struct pci_dev *dev; - unsigned int cfg_reg; - unsigned int pciaddr[2]; - signed int ipac; - signed int isac; - signed int hscx[2]; - signed int isacfifo; - signed int hscxfifo[2]; - unsigned char timeslot; - unsigned char iom2; -}; - -struct w6692_hw { - struct pci_dev *dev; - unsigned int iobase; - struct timer_list timer; -}; - -struct arcofi_msg { - struct arcofi_msg *next; - u_char receive; - u_char len; - u_char msg[10]; -}; - -struct isac_chip { - int ph_state; - u_char *mon_tx; - u_char *mon_rx; - int mon_txp; - int mon_txc; - int mon_rxp; - struct arcofi_msg *arcofi_list; - struct timer_list arcofitimer; - wait_queue_head_t arcofi_wait; - u_char arcofi_bc; - u_char arcofi_state; - u_char mocr; - u_char adf2; -}; - -struct hfcd_chip { - int ph_state; -}; - -struct hfcpci_chip { - int ph_state; -}; - -struct hfcsx_chip { - int ph_state; -}; - -struct w6692_chip { - int ph_state; -}; - -struct amd7930_chip { - u_char lmr1; - u_char ph_state; - u_char old_state; - u_char flg_t3; - unsigned int tx_xmtlen; - struct timer_list timer3; - void (*ph_command) (struct IsdnCardState *, u_char, char *); - void (*setIrqMask) (struct IsdnCardState *, u_char); -}; - -struct icc_chip { - int ph_state; - u_char *mon_tx; - u_char *mon_rx; - int mon_txp; - int mon_txc; - int mon_rxp; - struct arcofi_msg *arcofi_list; - struct timer_list arcofitimer; - wait_queue_head_t arcofi_wait; - u_char arcofi_bc; - u_char arcofi_state; - u_char mocr; - u_char adf2; -}; - -#define HW_IOM1 0 -#define HW_IPAC 1 -#define HW_ISAR 2 -#define HW_ARCOFI 3 -#define FLG_TWO_DCHAN 4 -#define FLG_L1_DBUSY 5 -#define FLG_DBUSY_TIMER 6 -#define FLG_LOCK_ATOMIC 7 -#define FLG_ARCOFI_TIMER 8 -#define FLG_ARCOFI_ERROR 9 -#define FLG_HW_L1_UINT 10 - -struct IsdnCardState { - spinlock_t lock; - u_char typ; - u_char subtyp; - int protocol; - u_int irq; - u_long irq_flags; - u_long HW_Flags; - int *busy_flag; - int chanlimit; /* limited number of B-chans to use */ - int logecho; /* log echo if supported by card */ - union { - struct elsa_hw elsa; - struct teles0_hw teles0; - struct teles3_hw teles3; - struct avm_hw avm; - struct ix1_hw ix1; - struct diva_hw diva; - struct asus_hw asus; - struct hfc_hw hfc; - struct sedl_hw sedl; - struct spt_hw spt; - struct mic_hw mic; - struct njet_hw njet; - struct hfcD_hw hfcD; - struct hfcPCI_hw hfcpci; - struct hfcSX_hw hfcsx; - struct ix1_hw niccy; - struct isurf_hw isurf; - struct saphir_hw saphir; - struct bkm_hw ax; - struct gazel_hw gazel; - struct w6692_hw w6692; - struct hisax_d_if *hisax_d_if; - } hw; - int myid; - isdn_if iif; - spinlock_t statlock; - u_char *status_buf; - u_char *status_read; - u_char *status_write; - u_char *status_end; - u_char (*readisac) (struct IsdnCardState *, u_char); - void (*writeisac) (struct IsdnCardState *, u_char, u_char); - void (*readisacfifo) (struct IsdnCardState *, u_char *, int); - void (*writeisacfifo) (struct IsdnCardState *, u_char *, int); - u_char (*BC_Read_Reg) (struct IsdnCardState *, int, u_char); - void (*BC_Write_Reg) (struct IsdnCardState *, int, u_char, u_char); - void (*BC_Send_Data) (struct BCState *); - int (*cardmsg) (struct IsdnCardState *, int, void *); - void (*setstack_d) (struct PStack *, struct IsdnCardState *); - void (*DC_Close) (struct IsdnCardState *); - irq_handler_t irq_func; - int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *); - struct Channel channel[2 + MAX_WAITING_CALLS]; - struct BCState bcs[2 + MAX_WAITING_CALLS]; - struct PStack *stlist; - struct sk_buff_head rq, sq; /* D-channel queues */ - int cardnr; - char *dlog; - int debug; - union { - struct isac_chip isac; - struct hfcd_chip hfcd; - struct hfcpci_chip hfcpci; - struct hfcsx_chip hfcsx; - struct w6692_chip w6692; - struct amd7930_chip amd7930; - struct icc_chip icc; - } dc; - u_char *rcvbuf; - int rcvidx; - struct sk_buff *tx_skb; - int tx_cnt; - u_long event; - struct work_struct tqueue; - struct timer_list dbusytimer; - unsigned int irq_cnt; -#ifdef ERROR_STATISTIC - int err_crc; - int err_tx; - int err_rx; -#endif -}; - - -#define schedule_event(s, ev) do { test_and_set_bit(ev, &s->event); schedule_work(&s->tqueue); } while (0) - -#define MON0_RX 1 -#define MON1_RX 2 -#define MON0_TX 4 -#define MON1_TX 8 - - -#ifdef ISDN_CHIP_ISAC -#undef ISDN_CHIP_ISAC -#endif - -#ifdef CONFIG_HISAX_16_0 -#define CARD_TELES0 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_TELES0 0 -#endif - -#ifdef CONFIG_HISAX_16_3 -#define CARD_TELES3 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_TELES3 0 -#endif - -#ifdef CONFIG_HISAX_TELESPCI -#define CARD_TELESPCI 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_TELESPCI 0 -#endif - -#ifdef CONFIG_HISAX_AVM_A1 -#define CARD_AVM_A1 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_AVM_A1 0 -#endif - -#ifdef CONFIG_HISAX_AVM_A1_PCMCIA -#define CARD_AVM_A1_PCMCIA 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_AVM_A1_PCMCIA 0 -#endif - -#ifdef CONFIG_HISAX_FRITZPCI -#define CARD_FRITZPCI 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_FRITZPCI 0 -#endif - -#ifdef CONFIG_HISAX_ELSA -#define CARD_ELSA 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_ELSA 0 -#endif - -#ifdef CONFIG_HISAX_IX1MICROR2 -#define CARD_IX1MICROR2 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_IX1MICROR2 0 -#endif - -#ifdef CONFIG_HISAX_DIEHLDIVA -#define CARD_DIEHLDIVA 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_DIEHLDIVA 0 -#endif - -#ifdef CONFIG_HISAX_ASUSCOM -#define CARD_ASUSCOM 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_ASUSCOM 0 -#endif - -#ifdef CONFIG_HISAX_TELEINT -#define CARD_TELEINT 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_TELEINT 0 -#endif - -#ifdef CONFIG_HISAX_SEDLBAUER -#define CARD_SEDLBAUER 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_SEDLBAUER 0 -#endif - -#ifdef CONFIG_HISAX_SPORTSTER -#define CARD_SPORTSTER 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_SPORTSTER 0 -#endif - -#ifdef CONFIG_HISAX_MIC -#define CARD_MIC 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_MIC 0 -#endif - -#ifdef CONFIG_HISAX_NETJET -#define CARD_NETJET_S 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_NETJET_S 0 -#endif - -#ifdef CONFIG_HISAX_HFCS -#define CARD_HFCS 1 -#else -#define CARD_HFCS 0 -#endif - -#ifdef CONFIG_HISAX_HFC_PCI -#define CARD_HFC_PCI 1 -#else -#define CARD_HFC_PCI 0 -#endif - -#ifdef CONFIG_HISAX_HFC_SX -#define CARD_HFC_SX 1 -#else -#define CARD_HFC_SX 0 -#endif - -#ifdef CONFIG_HISAX_NICCY -#define CARD_NICCY 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_NICCY 0 -#endif - -#ifdef CONFIG_HISAX_ISURF -#define CARD_ISURF 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_ISURF 0 -#endif - -#ifdef CONFIG_HISAX_S0BOX -#define CARD_S0BOX 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_S0BOX 0 -#endif - -#ifdef CONFIG_HISAX_HSTSAPHIR -#define CARD_HSTSAPHIR 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_HSTSAPHIR 0 -#endif - -#ifdef CONFIG_HISAX_BKM_A4T -#define CARD_BKM_A4T 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_BKM_A4T 0 -#endif - -#ifdef CONFIG_HISAX_SCT_QUADRO -#define CARD_SCT_QUADRO 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_SCT_QUADRO 0 -#endif - -#ifdef CONFIG_HISAX_GAZEL -#define CARD_GAZEL 1 -#ifndef ISDN_CHIP_ISAC -#define ISDN_CHIP_ISAC 1 -#endif -#else -#define CARD_GAZEL 0 -#endif - -#ifdef CONFIG_HISAX_W6692 -#define CARD_W6692 1 -#ifndef ISDN_CHIP_W6692 -#define ISDN_CHIP_W6692 1 -#endif -#else -#define CARD_W6692 0 -#endif - -#ifdef CONFIG_HISAX_NETJET_U -#define CARD_NETJET_U 1 -#ifndef ISDN_CHIP_ICC -#define ISDN_CHIP_ICC 1 -#endif -#ifndef HISAX_UINTERFACE -#define HISAX_UINTERFACE 1 -#endif -#else -#define CARD_NETJET_U 0 -#endif - -#ifdef CONFIG_HISAX_ENTERNOW_PCI -#define CARD_FN_ENTERNOW_PCI 1 -#else -#define CARD_FN_ENTERNOW_PCI 0 -#endif - -#define TEI_PER_CARD 1 - -/* L1 Debug */ -#define L1_DEB_WARN 0x01 -#define L1_DEB_INTSTAT 0x02 -#define L1_DEB_ISAC 0x04 -#define L1_DEB_ISAC_FIFO 0x08 -#define L1_DEB_HSCX 0x10 -#define L1_DEB_HSCX_FIFO 0x20 -#define L1_DEB_LAPD 0x40 -#define L1_DEB_IPAC 0x80 -#define L1_DEB_RECEIVE_FRAME 0x100 -#define L1_DEB_MONITOR 0x200 -#define DEB_DLOG_HEX 0x400 -#define DEB_DLOG_VERBOSE 0x800 - -#define L2FRAME_DEBUG - -#ifdef L2FRAME_DEBUG -extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir); -#endif - -#include "hisax_cfg.h" - -void init_bcstate(struct IsdnCardState *cs, int bc); - -void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs); -void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st); -void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st); - -void setstack_l1_B(struct PStack *st); - -void setstack_tei(struct PStack *st); -void setstack_manager(struct PStack *st); - -void setstack_isdnl2(struct PStack *st, char *debug_id); -void releasestack_isdnl2(struct PStack *st); -void setstack_transl2(struct PStack *st); -void releasestack_transl2(struct PStack *st); -void lli_writewakeup(struct PStack *st, int len); - -void setstack_l3dc(struct PStack *st, struct Channel *chanp); -void setstack_l3bc(struct PStack *st, struct Channel *chanp); -void releasestack_isdnl3(struct PStack *st); - -u_char *findie(u_char *p, int size, u_char ie, int wanted_set); -int getcallref(u_char *p); -int newcallref(void); - -int FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount); -void FsmFree(struct Fsm *fsm); -int FsmEvent(struct FsmInst *fi, int event, void *arg); -void FsmChangeState(struct FsmInst *fi, int newstate); -void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft); -int FsmAddTimer(struct FsmTimer *ft, int millisec, int event, - void *arg, int where); -void FsmRestartTimer(struct FsmTimer *ft, int millisec, int event, - void *arg, int where); -void FsmDelTimer(struct FsmTimer *ft, int where); -int jiftime(char *s, long mark); - -int HiSax_command(isdn_ctrl *ic); -int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb); -__printf(3, 4) -void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...); -__printf(3, 0) -void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, va_list args); -void HiSax_reportcard(int cardnr, int sel); -int QuickHex(char *txt, u_char *p, int cnt); -void LogFrame(struct IsdnCardState *cs, u_char *p, int size); -void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir); -void iecpy(u_char *dest, u_char *iestart, int ieoffset); -#endif /* __KERNEL__ */ - -/* - * Busywait delay for `jiffs' jiffies - */ -#define HZDELAY(jiffs) do { \ - int tout = jiffs; \ - \ - while (tout--) { \ - int loops = USEC_PER_SEC / HZ; \ - while (loops--) \ - udelay(1); \ - } \ - } while (0) - -int ll_run(struct IsdnCardState *cs, int addfeatures); -int CallcNew(void); -void CallcFree(void); -int CallcNewChan(struct IsdnCardState *cs); -void CallcFreeChan(struct IsdnCardState *cs); -int Isdnl1New(void); -void Isdnl1Free(void); -int Isdnl2New(void); -void Isdnl2Free(void); -int Isdnl3New(void); -void Isdnl3Free(void); -void init_tei(struct IsdnCardState *cs, int protocol); -void release_tei(struct IsdnCardState *cs); -char *HiSax_getrev(const char *revision); -int TeiNew(void); -void TeiFree(void); - -#ifdef CONFIG_PCI - -#include <linux/pci.h> - -/* adaptation wrapper for old usage - * WARNING! This is unfit for use in a PCI hotplug environment, - * as the returned PCI device can disappear at any moment in time. - * Callers should be converted to use pci_get_device() instead. - */ -static inline struct pci_dev *hisax_find_pci_device(unsigned int vendor, - unsigned int device, - struct pci_dev *from) -{ - struct pci_dev *pdev; - - pci_dev_get(from); - pdev = pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from); - pci_dev_put(pdev); - return pdev; -} - -#endif diff --git a/drivers/isdn/hisax/hisax_cfg.h b/drivers/isdn/hisax/hisax_cfg.h deleted file mode 100644 index 487dcfe9e718..000000000000 --- a/drivers/isdn/hisax/hisax_cfg.h +++ /dev/null @@ -1,66 +0,0 @@ -/* $Id: hisax_cfg.h,v 1.1.2.1 2004/01/24 20:47:23 keil Exp $ - * define of the basic HiSax configuration structures - * and pcmcia interface - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define ISDN_CTYPE_16_0 1 -#define ISDN_CTYPE_8_0 2 -#define ISDN_CTYPE_16_3 3 -#define ISDN_CTYPE_PNP 4 -#define ISDN_CTYPE_A1 5 -#define ISDN_CTYPE_ELSA 6 -#define ISDN_CTYPE_ELSA_PNP 7 -#define ISDN_CTYPE_TELESPCMCIA 8 -#define ISDN_CTYPE_IX1MICROR2 9 -#define ISDN_CTYPE_ELSA_PCMCIA 10 -#define ISDN_CTYPE_DIEHLDIVA 11 -#define ISDN_CTYPE_ASUSCOM 12 -#define ISDN_CTYPE_TELEINT 13 -#define ISDN_CTYPE_TELES3C 14 -#define ISDN_CTYPE_SEDLBAUER 15 -#define ISDN_CTYPE_SPORTSTER 16 -#define ISDN_CTYPE_MIC 17 -#define ISDN_CTYPE_ELSA_PCI 18 -#define ISDN_CTYPE_COMPAQ_ISA 19 -#define ISDN_CTYPE_NETJET_S 20 -#define ISDN_CTYPE_TELESPCI 21 -#define ISDN_CTYPE_SEDLBAUER_PCMCIA 22 -#define ISDN_CTYPE_AMD7930 23 -#define ISDN_CTYPE_NICCY 24 -#define ISDN_CTYPE_S0BOX 25 -#define ISDN_CTYPE_A1_PCMCIA 26 -#define ISDN_CTYPE_FRITZPCI 27 -#define ISDN_CTYPE_SEDLBAUER_FAX 28 -#define ISDN_CTYPE_ISURF 29 -#define ISDN_CTYPE_ACERP10 30 -#define ISDN_CTYPE_HSTSAPHIR 31 -#define ISDN_CTYPE_BKM_A4T 32 -#define ISDN_CTYPE_SCT_QUADRO 33 -#define ISDN_CTYPE_GAZEL 34 -#define ISDN_CTYPE_HFC_PCI 35 -#define ISDN_CTYPE_W6692 36 -#define ISDN_CTYPE_HFC_SX 37 -#define ISDN_CTYPE_NETJET_U 38 -#define ISDN_CTYPE_HFC_SP_PCMCIA 39 -#define ISDN_CTYPE_DYNAMIC 40 -#define ISDN_CTYPE_ENTERNOW 41 -#define ISDN_CTYPE_COUNT 41 - -typedef struct IsdnCardState IsdnCardState_t; -typedef struct IsdnCard IsdnCard_t; - -struct IsdnCard { - int typ; - int protocol; /* EDSS1, 1TR6 or NI1 */ - unsigned long para[4]; - IsdnCardState_t *cs; -}; - -typedef int (*hisax_setup_func_t)(struct IsdnCard *card); - -extern void HiSax_closecard(int); -extern int hisax_init_pcmcia(void *, int *, IsdnCard_t *); diff --git a/drivers/isdn/hisax/hisax_debug.h b/drivers/isdn/hisax/hisax_debug.h deleted file mode 100644 index 7b3093d0856a..000000000000 --- a/drivers/isdn/hisax/hisax_debug.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Common debugging macros for use with the hisax driver - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> - * 2001 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. - * - * How to use: - * - * Before including this file, you need to - * #define __debug_variable my_debug - * where my_debug is a variable in your code which - * determines the debug bitmask. - * - * If CONFIG_HISAX_DEBUG is not set, all macros evaluate to nothing - * - */ - -#ifndef __HISAX_DEBUG_H__ -#define __HISAX_DEBUG_H__ - - -#ifdef CONFIG_HISAX_DEBUG - -#define DBG(level, format, arg...) do { \ - if (level & __debug_variable) \ - printk(KERN_DEBUG "%s: " format "\n" , __func__ , ## arg); \ - } while (0) - -#define DBG_PACKET(level, data, count) \ - if (level & __debug_variable) dump_packet(__func__, data, count) - -#define DBG_SKB(level, skb) \ - if ((level & __debug_variable) && skb) dump_packet(__func__, skb->data, skb->len) - - -static void __attribute__((unused)) -dump_packet(const char *name, const u_char *data, int pkt_len) -{ -#define DUMP_HDR_SIZE 20 -#define DUMP_TLR_SIZE 8 - if (pkt_len) { - int i, len1, len2; - - printk(KERN_DEBUG "%s: length=%d,data=", name, pkt_len); - - if (pkt_len > DUMP_HDR_SIZE + DUMP_TLR_SIZE) { - len1 = DUMP_HDR_SIZE; - len2 = DUMP_TLR_SIZE; - } else { - len1 = pkt_len > DUMP_HDR_SIZE ? DUMP_HDR_SIZE : pkt_len; - len2 = 0; - } - for (i = 0; i < len1; ++i) { - printk("%.2x", data[i]); - } - if (len2) { - printk(".."); - for (i = pkt_len-DUMP_TLR_SIZE; i < pkt_len; ++i) { - printk("%.2x", data[i]); - } - } - printk("\n"); - } -#undef DUMP_HDR_SIZE -#undef DUMP_TLR_SIZE -} - -#else - -#define DBG(level, format, arg...) do {} while (0) -#define DBG_PACKET(level, data, count) do {} while (0) -#define DBG_SKB(level, skb) do {} while (0) - -#endif - -#endif diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c deleted file mode 100644 index 7a7137d8664b..000000000000 --- a/drivers/isdn/hisax/hisax_fcpcipnp.c +++ /dev/null @@ -1,1024 +0,0 @@ -/* - * Driver for AVM Fritz!PCI, Fritz!PCI v2, Fritz!PnP ISDN cards - * - * Author Kai Germaschewski - * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de> - * 2001 by Karsten Keil <keil@isdn4linux.de> - * - * based upon Karsten Keil's original avm_pci.c driver - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Wizard Computersysteme GmbH, Bremervoerde and - * SoHaNet Technology GmbH, Berlin - * for supporting the development of this driver - */ - - -/* TODO: - * - * o POWER PC - * o clean up debugging - * o tx_skb at PH_DEACTIVATE time - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/isapnp.h> -#include <linux/kmod.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/delay.h> - -#include <asm/io.h> - -#include "hisax_fcpcipnp.h" - -// debugging cruft -#define __debug_variable debug -#include "hisax_debug.h" - -#ifdef CONFIG_HISAX_DEBUG -static int debug = 0; -/* static int hdlcfifosize = 32; */ -module_param(debug, int, 0); -/* module_param(hdlcfifosize, int, 0); */ -#endif - -MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>"); -MODULE_DESCRIPTION("AVM Fritz!PCI/PnP ISDN driver"); - -static const struct pci_device_id fcpci_ids[] = { - { .vendor = PCI_VENDOR_ID_AVM, - .device = PCI_DEVICE_ID_AVM_A1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (unsigned long) "Fritz!Card PCI", - }, - { .vendor = PCI_VENDOR_ID_AVM, - .device = PCI_DEVICE_ID_AVM_A1_V2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = (unsigned long) "Fritz!Card PCI v2" }, - {} -}; - -MODULE_DEVICE_TABLE(pci, fcpci_ids); - -#ifdef CONFIG_PNP -static struct pnp_device_id fcpnp_ids[] = { - { - .id = "AVM0900", - .driver_data = (unsigned long) "Fritz!Card PnP", - }, - { .id = "" } -}; - -MODULE_DEVICE_TABLE(pnp, fcpnp_ids); -#endif - -static int protocol = 2; /* EURO-ISDN Default */ -module_param(protocol, int, 0); -MODULE_LICENSE("GPL"); - -// ---------------------------------------------------------------------- - -#define AVM_INDEX 0x04 -#define AVM_DATA 0x10 - -#define AVM_IDX_HDLC_1 0x00 -#define AVM_IDX_HDLC_2 0x01 -#define AVM_IDX_ISAC_FIFO 0x02 -#define AVM_IDX_ISAC_REG_LOW 0x04 -#define AVM_IDX_ISAC_REG_HIGH 0x06 - -#define AVM_STATUS0 0x02 - -#define AVM_STATUS0_IRQ_ISAC 0x01 -#define AVM_STATUS0_IRQ_HDLC 0x02 -#define AVM_STATUS0_IRQ_TIMER 0x04 -#define AVM_STATUS0_IRQ_MASK 0x07 - -#define AVM_STATUS0_RESET 0x01 -#define AVM_STATUS0_DIS_TIMER 0x02 -#define AVM_STATUS0_RES_TIMER 0x04 -#define AVM_STATUS0_ENA_IRQ 0x08 -#define AVM_STATUS0_TESTBIT 0x10 - -#define AVM_STATUS1 0x03 -#define AVM_STATUS1_ENA_IOM 0x80 - -#define HDLC_FIFO 0x0 -#define HDLC_STATUS 0x4 -#define HDLC_CTRL 0x4 - -#define HDLC_MODE_ITF_FLG 0x01 -#define HDLC_MODE_TRANS 0x02 -#define HDLC_MODE_CCR_7 0x04 -#define HDLC_MODE_CCR_16 0x08 -#define HDLC_MODE_TESTLOOP 0x80 - -#define HDLC_INT_XPR 0x80 -#define HDLC_INT_XDU 0x40 -#define HDLC_INT_RPR 0x20 -#define HDLC_INT_MASK 0xE0 - -#define HDLC_STAT_RME 0x01 -#define HDLC_STAT_RDO 0x10 -#define HDLC_STAT_CRCVFRRAB 0x0E -#define HDLC_STAT_CRCVFR 0x06 -#define HDLC_STAT_RML_MASK 0xff00 - -#define HDLC_CMD_XRS 0x80 -#define HDLC_CMD_XME 0x01 -#define HDLC_CMD_RRS 0x20 -#define HDLC_CMD_XML_MASK 0xff00 - -#define AVM_HDLC_FIFO_1 0x10 -#define AVM_HDLC_FIFO_2 0x18 - -#define AVM_HDLC_STATUS_1 0x14 -#define AVM_HDLC_STATUS_2 0x1c - -#define AVM_ISACSX_INDEX 0x04 -#define AVM_ISACSX_DATA 0x08 - -// ---------------------------------------------------------------------- -// Fritz!PCI - -static unsigned char fcpci_read_isac(struct isac *isac, unsigned char offset) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned char idx = (offset > 0x2f) ? - AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW; - unsigned char val; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outb(idx, adapter->io + AVM_INDEX); - val = inb(adapter->io + AVM_DATA + (offset & 0xf)); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - DBG(0x1000, " port %#x, value %#x", - offset, val); - return val; -} - -static void fcpci_write_isac(struct isac *isac, unsigned char offset, - unsigned char value) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned char idx = (offset > 0x2f) ? - AVM_IDX_ISAC_REG_HIGH : AVM_IDX_ISAC_REG_LOW; - unsigned long flags; - - DBG(0x1000, " port %#x, value %#x", - offset, value); - spin_lock_irqsave(&adapter->hw_lock, flags); - outb(idx, adapter->io + AVM_INDEX); - outb(value, adapter->io + AVM_DATA + (offset & 0xf)); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static void fcpci_read_isac_fifo(struct isac *isac, unsigned char *data, - int size) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX); - insb(adapter->io + AVM_DATA, data, size); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static void fcpci_write_isac_fifo(struct isac *isac, unsigned char *data, - int size) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outb(AVM_IDX_ISAC_FIFO, adapter->io + AVM_INDEX); - outsb(adapter->io + AVM_DATA, data, size); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static u32 fcpci_read_hdlc_status(struct fritz_adapter *adapter, int nr) -{ - u32 val; - int idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outl(idx, adapter->io + AVM_INDEX); - val = inl(adapter->io + AVM_DATA + HDLC_STATUS); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - return val; -} - -static void __fcpci_write_ctrl(struct fritz_bcs *bcs, int which) -{ - struct fritz_adapter *adapter = bcs->adapter; - int idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1; - - DBG(0x40, "hdlc %c wr%x ctrl %x", - 'A' + bcs->channel, which, bcs->ctrl.ctrl); - - outl(idx, adapter->io + AVM_INDEX); - outl(bcs->ctrl.ctrl, adapter->io + AVM_DATA + HDLC_CTRL); -} - -static void fcpci_write_ctrl(struct fritz_bcs *bcs, int which) -{ - struct fritz_adapter *adapter = bcs->adapter; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - __fcpci_write_ctrl(bcs, which); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -// ---------------------------------------------------------------------- -// Fritz!PCI v2 - -static unsigned char fcpci2_read_isac(struct isac *isac, unsigned char offset) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned char val; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outl(offset, adapter->io + AVM_ISACSX_INDEX); - val = inl(adapter->io + AVM_ISACSX_DATA); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - DBG(0x1000, " port %#x, value %#x", - offset, val); - - return val; -} - -static void fcpci2_write_isac(struct isac *isac, unsigned char offset, - unsigned char value) -{ - struct fritz_adapter *adapter = isac->priv; - unsigned long flags; - - DBG(0x1000, " port %#x, value %#x", - offset, value); - spin_lock_irqsave(&adapter->hw_lock, flags); - outl(offset, adapter->io + AVM_ISACSX_INDEX); - outl(value, adapter->io + AVM_ISACSX_DATA); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static void fcpci2_read_isac_fifo(struct isac *isac, unsigned char *data, - int size) -{ - struct fritz_adapter *adapter = isac->priv; - int i; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outl(0, adapter->io + AVM_ISACSX_INDEX); - for (i = 0; i < size; i++) - data[i] = inl(adapter->io + AVM_ISACSX_DATA); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static void fcpci2_write_isac_fifo(struct isac *isac, unsigned char *data, - int size) -{ - struct fritz_adapter *adapter = isac->priv; - int i; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outl(0, adapter->io + AVM_ISACSX_INDEX); - for (i = 0; i < size; i++) - outl(data[i], adapter->io + AVM_ISACSX_DATA); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -static u32 fcpci2_read_hdlc_status(struct fritz_adapter *adapter, int nr) -{ - int offset = nr ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1; - - return inl(adapter->io + offset); -} - -static void fcpci2_write_ctrl(struct fritz_bcs *bcs, int which) -{ - struct fritz_adapter *adapter = bcs->adapter; - int offset = bcs->channel ? AVM_HDLC_STATUS_2 : AVM_HDLC_STATUS_1; - - DBG(0x40, "hdlc %c wr%x ctrl %x", - 'A' + bcs->channel, which, bcs->ctrl.ctrl); - - outl(bcs->ctrl.ctrl, adapter->io + offset); -} - -// ---------------------------------------------------------------------- -// Fritz!PnP (ISAC access as for Fritz!PCI) - -static u32 fcpnp_read_hdlc_status(struct fritz_adapter *adapter, int nr) -{ - unsigned char idx = nr ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1; - u32 val; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - outb(idx, adapter->io + AVM_INDEX); - val = inb(adapter->io + AVM_DATA + HDLC_STATUS); - if (val & HDLC_INT_RPR) - val |= inb(adapter->io + AVM_DATA + HDLC_STATUS + 1) << 8; - spin_unlock_irqrestore(&adapter->hw_lock, flags); - return val; -} - -static void __fcpnp_write_ctrl(struct fritz_bcs *bcs, int which) -{ - struct fritz_adapter *adapter = bcs->adapter; - unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1; - - DBG(0x40, "hdlc %c wr%x ctrl %x", - 'A' + bcs->channel, which, bcs->ctrl.ctrl); - - outb(idx, adapter->io + AVM_INDEX); - if (which & 4) - outb(bcs->ctrl.sr.mode, - adapter->io + AVM_DATA + HDLC_STATUS + 2); - if (which & 2) - outb(bcs->ctrl.sr.xml, - adapter->io + AVM_DATA + HDLC_STATUS + 1); - if (which & 1) - outb(bcs->ctrl.sr.cmd, - adapter->io + AVM_DATA + HDLC_STATUS + 0); -} - -static void fcpnp_write_ctrl(struct fritz_bcs *bcs, int which) -{ - struct fritz_adapter *adapter = bcs->adapter; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - __fcpnp_write_ctrl(bcs, which); - spin_unlock_irqrestore(&adapter->hw_lock, flags); -} - -// ---------------------------------------------------------------------- - -static inline void B_L1L2(struct fritz_bcs *bcs, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if; - - DBG(2, "pr %#x", pr); - ifc->l1l2(ifc, pr, arg); -} - -static void hdlc_fill_fifo(struct fritz_bcs *bcs) -{ - struct fritz_adapter *adapter = bcs->adapter; - struct sk_buff *skb = bcs->tx_skb; - int count; - unsigned long flags; - unsigned char *p; - - DBG(0x40, "hdlc_fill_fifo"); - - BUG_ON(skb->len == 0); - - bcs->ctrl.sr.cmd &= ~HDLC_CMD_XME; - if (bcs->tx_skb->len > bcs->fifo_size) { - count = bcs->fifo_size; - } else { - count = bcs->tx_skb->len; - if (bcs->mode != L1_MODE_TRANS) - bcs->ctrl.sr.cmd |= HDLC_CMD_XME; - } - DBG(0x40, "hdlc_fill_fifo %d/%d", count, bcs->tx_skb->len); - p = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt += count; - bcs->ctrl.sr.xml = ((count == bcs->fifo_size) ? 0 : count); - - switch (adapter->type) { - case AVM_FRITZ_PCI: - spin_lock_irqsave(&adapter->hw_lock, flags); - // sets the correct AVM_INDEX, too - __fcpci_write_ctrl(bcs, 3); - outsl(adapter->io + AVM_DATA + HDLC_FIFO, - p, (count + 3) / 4); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - break; - case AVM_FRITZ_PCIV2: - fcpci2_write_ctrl(bcs, 3); - outsl(adapter->io + - (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1), - p, (count + 3) / 4); - break; - case AVM_FRITZ_PNP: - spin_lock_irqsave(&adapter->hw_lock, flags); - // sets the correct AVM_INDEX, too - __fcpnp_write_ctrl(bcs, 3); - outsb(adapter->io + AVM_DATA, p, count); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - break; - } -} - -static inline void hdlc_empty_fifo(struct fritz_bcs *bcs, int count) -{ - struct fritz_adapter *adapter = bcs->adapter; - unsigned char *p; - unsigned char idx = bcs->channel ? AVM_IDX_HDLC_2 : AVM_IDX_HDLC_1; - - DBG(0x10, "hdlc_empty_fifo %d", count); - if (bcs->rcvidx + count > HSCX_BUFMAX) { - DBG(0x10, "hdlc_empty_fifo: incoming packet too large"); - return; - } - p = bcs->rcvbuf + bcs->rcvidx; - bcs->rcvidx += count; - switch (adapter->type) { - case AVM_FRITZ_PCI: - spin_lock(&adapter->hw_lock); - outl(idx, adapter->io + AVM_INDEX); - insl(adapter->io + AVM_DATA + HDLC_FIFO, - p, (count + 3) / 4); - spin_unlock(&adapter->hw_lock); - break; - case AVM_FRITZ_PCIV2: - insl(adapter->io + - (bcs->channel ? AVM_HDLC_FIFO_2 : AVM_HDLC_FIFO_1), - p, (count + 3) / 4); - break; - case AVM_FRITZ_PNP: - spin_lock(&adapter->hw_lock); - outb(idx, adapter->io + AVM_INDEX); - insb(adapter->io + AVM_DATA, p, count); - spin_unlock(&adapter->hw_lock); - break; - } -} - -static inline void hdlc_rpr_irq(struct fritz_bcs *bcs, u32 stat) -{ - struct fritz_adapter *adapter = bcs->adapter; - struct sk_buff *skb; - int len; - - if (stat & HDLC_STAT_RDO) { - DBG(0x10, "RDO"); - bcs->ctrl.sr.xml = 0; - bcs->ctrl.sr.cmd |= HDLC_CMD_RRS; - adapter->write_ctrl(bcs, 1); - bcs->ctrl.sr.cmd &= ~HDLC_CMD_RRS; - adapter->write_ctrl(bcs, 1); - bcs->rcvidx = 0; - return; - } - - len = (stat & HDLC_STAT_RML_MASK) >> 8; - if (len == 0) - len = bcs->fifo_size; - - hdlc_empty_fifo(bcs, len); - - if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) { - if (((stat & HDLC_STAT_CRCVFRRAB) == HDLC_STAT_CRCVFR) || - (bcs->mode == L1_MODE_TRANS)) { - skb = dev_alloc_skb(bcs->rcvidx); - if (!skb) { - printk(KERN_WARNING "HDLC: receive out of memory\n"); - } else { - skb_put_data(skb, bcs->rcvbuf, bcs->rcvidx); - DBG_SKB(1, skb); - B_L1L2(bcs, PH_DATA | INDICATION, skb); - } - bcs->rcvidx = 0; - } else { - DBG(0x10, "ch%d invalid frame %#x", - bcs->channel, stat); - bcs->rcvidx = 0; - } - } -} - -static inline void hdlc_xdu_irq(struct fritz_bcs *bcs) -{ - struct fritz_adapter *adapter = bcs->adapter; - - - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - bcs->ctrl.sr.xml = 0; - bcs->ctrl.sr.cmd |= HDLC_CMD_XRS; - adapter->write_ctrl(bcs, 1); - bcs->ctrl.sr.cmd &= ~HDLC_CMD_XRS; - - if (!bcs->tx_skb) { - DBG(0x10, "XDU without skb"); - adapter->write_ctrl(bcs, 1); - return; - } - /* only hdlc restarts the frame, transparent mode must continue */ - if (bcs->mode == L1_MODE_HDLC) { - skb_push(bcs->tx_skb, bcs->tx_cnt); - bcs->tx_cnt = 0; - } -} - -static inline void hdlc_xpr_irq(struct fritz_bcs *bcs) -{ - struct sk_buff *skb; - - skb = bcs->tx_skb; - if (!skb) - return; - - if (skb->len) { - hdlc_fill_fifo(bcs); - return; - } - bcs->tx_cnt = 0; - bcs->tx_skb = NULL; - B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long)skb->truesize); - dev_kfree_skb_irq(skb); -} - -static void hdlc_irq_one(struct fritz_bcs *bcs, u32 stat) -{ - DBG(0x10, "ch%d stat %#x", bcs->channel, stat); - if (stat & HDLC_INT_RPR) { - DBG(0x10, "RPR"); - hdlc_rpr_irq(bcs, stat); - } - if (stat & HDLC_INT_XDU) { - DBG(0x10, "XDU"); - hdlc_xdu_irq(bcs); - hdlc_xpr_irq(bcs); - return; - } - if (stat & HDLC_INT_XPR) { - DBG(0x10, "XPR"); - hdlc_xpr_irq(bcs); - } -} - -static inline void hdlc_irq(struct fritz_adapter *adapter) -{ - int nr; - u32 stat; - - for (nr = 0; nr < 2; nr++) { - stat = adapter->read_hdlc_status(adapter, nr); - DBG(0x10, "HDLC %c stat %#x", 'A' + nr, stat); - if (stat & HDLC_INT_MASK) - hdlc_irq_one(&adapter->bcs[nr], stat); - } -} - -static void modehdlc(struct fritz_bcs *bcs, int mode) -{ - struct fritz_adapter *adapter = bcs->adapter; - - DBG(0x40, "hdlc %c mode %d --> %d", - 'A' + bcs->channel, bcs->mode, mode); - - if (bcs->mode == mode) - return; - - bcs->fifo_size = 32; - bcs->ctrl.ctrl = 0; - bcs->ctrl.sr.cmd = HDLC_CMD_XRS | HDLC_CMD_RRS; - switch (mode) { - case L1_MODE_NULL: - bcs->ctrl.sr.mode = HDLC_MODE_TRANS; - adapter->write_ctrl(bcs, 5); - break; - case L1_MODE_TRANS: - case L1_MODE_HDLC: - bcs->rcvidx = 0; - bcs->tx_cnt = 0; - bcs->tx_skb = NULL; - if (mode == L1_MODE_TRANS) { - bcs->ctrl.sr.mode = HDLC_MODE_TRANS; - } else { - bcs->ctrl.sr.mode = HDLC_MODE_ITF_FLG; - } - adapter->write_ctrl(bcs, 5); - bcs->ctrl.sr.cmd = HDLC_CMD_XRS; - adapter->write_ctrl(bcs, 1); - bcs->ctrl.sr.cmd = 0; - break; - } - bcs->mode = mode; -} - -static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg) -{ - struct fritz_bcs *bcs = ifc->priv; - struct sk_buff *skb = arg; - int mode; - - DBG(0x10, "pr %#x", pr); - - switch (pr) { - case PH_DATA | REQUEST: - BUG_ON(bcs->tx_skb); - bcs->tx_skb = skb; - DBG_SKB(1, skb); - hdlc_fill_fifo(bcs); - break; - case PH_ACTIVATE | REQUEST: - mode = (long) arg; - DBG(4, "B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode); - modehdlc(bcs, mode); - B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL); - break; - case PH_DEACTIVATE | REQUEST: - DBG(4, "B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1); - modehdlc(bcs, L1_MODE_NULL); - B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL); - break; - } -} - -// ---------------------------------------------------------------------- - -static irqreturn_t -fcpci2_irq(int intno, void *dev) -{ - struct fritz_adapter *adapter = dev; - unsigned char val; - - val = inb(adapter->io + AVM_STATUS0); - if (!(val & AVM_STATUS0_IRQ_MASK)) - /* hopefully a shared IRQ reqest */ - return IRQ_NONE; - DBG(2, "STATUS0 %#x", val); - if (val & AVM_STATUS0_IRQ_ISAC) - isacsx_irq(&adapter->isac); - if (val & AVM_STATUS0_IRQ_HDLC) - hdlc_irq(adapter); - if (val & AVM_STATUS0_IRQ_ISAC) - isacsx_irq(&adapter->isac); - return IRQ_HANDLED; -} - -static irqreturn_t -fcpci_irq(int intno, void *dev) -{ - struct fritz_adapter *adapter = dev; - unsigned char sval; - - sval = inb(adapter->io + 2); - if ((sval & AVM_STATUS0_IRQ_MASK) == AVM_STATUS0_IRQ_MASK) - /* possibly a shared IRQ reqest */ - return IRQ_NONE; - DBG(2, "sval %#x", sval); - if (!(sval & AVM_STATUS0_IRQ_ISAC)) - isac_irq(&adapter->isac); - - if (!(sval & AVM_STATUS0_IRQ_HDLC)) - hdlc_irq(adapter); - return IRQ_HANDLED; -} - -// ---------------------------------------------------------------------- - -static inline void fcpci2_init(struct fritz_adapter *adapter) -{ - outb(AVM_STATUS0_RES_TIMER, adapter->io + AVM_STATUS0); - outb(AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0); - -} - -static inline void fcpci_init(struct fritz_adapter *adapter) -{ - outb(AVM_STATUS0_DIS_TIMER | AVM_STATUS0_RES_TIMER | - AVM_STATUS0_ENA_IRQ, adapter->io + AVM_STATUS0); - - outb(AVM_STATUS1_ENA_IOM | adapter->irq, - adapter->io + AVM_STATUS1); - mdelay(10); -} - -// ---------------------------------------------------------------------- - -static int fcpcipnp_setup(struct fritz_adapter *adapter) -{ - u32 val = 0; - int retval; - - DBG(1, ""); - - isac_init(&adapter->isac); // FIXME is this okay now - - retval = -EBUSY; - if (!request_region(adapter->io, 32, "fcpcipnp")) - goto err; - - switch (adapter->type) { - case AVM_FRITZ_PCIV2: - case AVM_FRITZ_PCI: - val = inl(adapter->io); - break; - case AVM_FRITZ_PNP: - val = inb(adapter->io); - val |= inb(adapter->io + 1) << 8; - break; - } - - DBG(1, "stat %#x Class %X Rev %d", - val, val & 0xff, (val >> 8) & 0xff); - - spin_lock_init(&adapter->hw_lock); - adapter->isac.priv = adapter; - switch (adapter->type) { - case AVM_FRITZ_PCIV2: - adapter->isac.read_isac = &fcpci2_read_isac; - adapter->isac.write_isac = &fcpci2_write_isac; - adapter->isac.read_isac_fifo = &fcpci2_read_isac_fifo; - adapter->isac.write_isac_fifo = &fcpci2_write_isac_fifo; - - adapter->read_hdlc_status = &fcpci2_read_hdlc_status; - adapter->write_ctrl = &fcpci2_write_ctrl; - break; - case AVM_FRITZ_PCI: - adapter->isac.read_isac = &fcpci_read_isac; - adapter->isac.write_isac = &fcpci_write_isac; - adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo; - adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo; - - adapter->read_hdlc_status = &fcpci_read_hdlc_status; - adapter->write_ctrl = &fcpci_write_ctrl; - break; - case AVM_FRITZ_PNP: - adapter->isac.read_isac = &fcpci_read_isac; - adapter->isac.write_isac = &fcpci_write_isac; - adapter->isac.read_isac_fifo = &fcpci_read_isac_fifo; - adapter->isac.write_isac_fifo = &fcpci_write_isac_fifo; - - adapter->read_hdlc_status = &fcpnp_read_hdlc_status; - adapter->write_ctrl = &fcpnp_write_ctrl; - break; - } - - // Reset - outb(0, adapter->io + AVM_STATUS0); - mdelay(10); - outb(AVM_STATUS0_RESET, adapter->io + AVM_STATUS0); - mdelay(10); - outb(0, adapter->io + AVM_STATUS0); - mdelay(10); - - switch (adapter->type) { - case AVM_FRITZ_PCIV2: - retval = request_irq(adapter->irq, fcpci2_irq, IRQF_SHARED, - "fcpcipnp", adapter); - break; - case AVM_FRITZ_PCI: - retval = request_irq(adapter->irq, fcpci_irq, IRQF_SHARED, - "fcpcipnp", adapter); - break; - case AVM_FRITZ_PNP: - retval = request_irq(adapter->irq, fcpci_irq, 0, - "fcpcipnp", adapter); - break; - } - if (retval) - goto err_region; - - switch (adapter->type) { - case AVM_FRITZ_PCIV2: - fcpci2_init(adapter); - isacsx_setup(&adapter->isac); - break; - case AVM_FRITZ_PCI: - case AVM_FRITZ_PNP: - fcpci_init(adapter); - isac_setup(&adapter->isac); - break; - } - val = adapter->read_hdlc_status(adapter, 0); - DBG(0x20, "HDLC A STA %x", val); - val = adapter->read_hdlc_status(adapter, 1); - DBG(0x20, "HDLC B STA %x", val); - - adapter->bcs[0].mode = -1; - adapter->bcs[1].mode = -1; - modehdlc(&adapter->bcs[0], L1_MODE_NULL); - modehdlc(&adapter->bcs[1], L1_MODE_NULL); - - return 0; - -err_region: - release_region(adapter->io, 32); -err: - return retval; -} - -static void fcpcipnp_release(struct fritz_adapter *adapter) -{ - DBG(1, ""); - - outb(0, adapter->io + AVM_STATUS0); - free_irq(adapter->irq, adapter); - release_region(adapter->io, 32); -} - -// ---------------------------------------------------------------------- - -static struct fritz_adapter *new_adapter(void) -{ - struct fritz_adapter *adapter; - struct hisax_b_if *b_if[2]; - int i; - - adapter = kzalloc(sizeof(struct fritz_adapter), GFP_KERNEL); - if (!adapter) - return NULL; - - adapter->isac.hisax_d_if.owner = THIS_MODULE; - adapter->isac.hisax_d_if.ifc.priv = &adapter->isac; - adapter->isac.hisax_d_if.ifc.l2l1 = isac_d_l2l1; - - for (i = 0; i < 2; i++) { - adapter->bcs[i].adapter = adapter; - adapter->bcs[i].channel = i; - adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; - adapter->bcs[i].b_if.ifc.l2l1 = fritz_b_l2l1; - } - - for (i = 0; i < 2; i++) - b_if[i] = &adapter->bcs[i].b_if; - - if (hisax_register(&adapter->isac.hisax_d_if, b_if, "fcpcipnp", - protocol) != 0) { - kfree(adapter); - adapter = NULL; - } - - return adapter; -} - -static void delete_adapter(struct fritz_adapter *adapter) -{ - hisax_unregister(&adapter->isac.hisax_d_if); - kfree(adapter); -} - -static int fcpci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - struct fritz_adapter *adapter; - int retval; - - retval = -ENOMEM; - adapter = new_adapter(); - if (!adapter) - goto err; - - pci_set_drvdata(pdev, adapter); - - if (pdev->device == PCI_DEVICE_ID_AVM_A1_V2) - adapter->type = AVM_FRITZ_PCIV2; - else - adapter->type = AVM_FRITZ_PCI; - - retval = pci_enable_device(pdev); - if (retval) - goto err_free; - - adapter->io = pci_resource_start(pdev, 1); - adapter->irq = pdev->irq; - - printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at %s\n", - (char *) ent->driver_data, pci_name(pdev)); - - retval = fcpcipnp_setup(adapter); - if (retval) - goto err_free; - - return 0; - -err_free: - delete_adapter(adapter); -err: - return retval; -} - -#ifdef CONFIG_PNP -static int fcpnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) -{ - struct fritz_adapter *adapter; - int retval; - - if (!pdev) - return (-ENODEV); - - retval = -ENOMEM; - adapter = new_adapter(); - if (!adapter) - goto err; - - pnp_set_drvdata(pdev, adapter); - - adapter->type = AVM_FRITZ_PNP; - - pnp_disable_dev(pdev); - retval = pnp_activate_dev(pdev); - if (retval < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev(%s) ret(%d)\n", __func__, - (char *)dev_id->driver_data, retval); - goto err_free; - } - adapter->io = pnp_port_start(pdev, 0); - adapter->irq = pnp_irq(pdev, 0); - if (!adapter->io || adapter->irq == -1) - goto err_free; - - printk(KERN_INFO "hisax_fcpcipnp: found adapter %s at IO %#x irq %d\n", - (char *) dev_id->driver_data, adapter->io, adapter->irq); - - retval = fcpcipnp_setup(adapter); - if (retval) - goto err_free; - - return 0; - -err_free: - delete_adapter(adapter); -err: - return retval; -} - -static void fcpnp_remove(struct pnp_dev *pdev) -{ - struct fritz_adapter *adapter = pnp_get_drvdata(pdev); - - if (adapter) { - fcpcipnp_release(adapter); - delete_adapter(adapter); - } - pnp_disable_dev(pdev); -} - -static struct pnp_driver fcpnp_driver = { - .name = "fcpnp", - .probe = fcpnp_probe, - .remove = fcpnp_remove, - .id_table = fcpnp_ids, -}; -#endif - -static void fcpci_remove(struct pci_dev *pdev) -{ - struct fritz_adapter *adapter = pci_get_drvdata(pdev); - - fcpcipnp_release(adapter); - pci_disable_device(pdev); - delete_adapter(adapter); -} - -static struct pci_driver fcpci_driver = { - .name = "fcpci", - .probe = fcpci_probe, - .remove = fcpci_remove, - .id_table = fcpci_ids, -}; - -static int __init hisax_fcpcipnp_init(void) -{ - int retval; - - printk(KERN_INFO "hisax_fcpcipnp: Fritz!Card PCI/PCIv2/PnP ISDN driver v0.0.1\n"); - - retval = pci_register_driver(&fcpci_driver); - if (retval) - return retval; -#ifdef CONFIG_PNP - retval = pnp_register_driver(&fcpnp_driver); - if (retval < 0) { - pci_unregister_driver(&fcpci_driver); - return retval; - } -#endif - return 0; -} - -static void __exit hisax_fcpcipnp_exit(void) -{ -#ifdef CONFIG_PNP - pnp_unregister_driver(&fcpnp_driver); -#endif - pci_unregister_driver(&fcpci_driver); -} - -module_init(hisax_fcpcipnp_init); -module_exit(hisax_fcpcipnp_exit); diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.h b/drivers/isdn/hisax/hisax_fcpcipnp.h deleted file mode 100644 index 1f64e9937aa1..000000000000 --- a/drivers/isdn/hisax/hisax_fcpcipnp.h +++ /dev/null @@ -1,58 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include "hisax_if.h" -#include "hisax_isac.h" -#include <linux/pci.h> - -#define HSCX_BUFMAX 4096 - -enum { - AVM_FRITZ_PCI, - AVM_FRITZ_PNP, - AVM_FRITZ_PCIV2, -}; - -struct hdlc_stat_reg { -#ifdef __BIG_ENDIAN - u_char fill; - u_char mode; - u_char xml; - u_char cmd; -#else - u_char cmd; - u_char xml; - u_char mode; - u_char fill; -#endif -} __attribute__((packed)); - -struct fritz_bcs { - struct hisax_b_if b_if; - struct fritz_adapter *adapter; - int mode; - int channel; - - union { - u_int ctrl; - struct hdlc_stat_reg sr; - } ctrl; - u_int stat; - int rcvidx; - int fifo_size; - u_char rcvbuf[HSCX_BUFMAX]; /* B-Channel receive Buffer */ - - int tx_cnt; /* B-Channel transmit counter */ - struct sk_buff *tx_skb; /* B-Channel transmit Buffer */ -}; - -struct fritz_adapter { - int type; - spinlock_t hw_lock; - unsigned int io; - unsigned int irq; - struct isac isac; - - struct fritz_bcs bcs[2]; - - u32 (*read_hdlc_status) (struct fritz_adapter *adapter, int nr); - void (*write_ctrl) (struct fritz_bcs *bcs, int which); -}; diff --git a/drivers/isdn/hisax/hisax_if.h b/drivers/isdn/hisax/hisax_if.h deleted file mode 100644 index 7098d6bd5ff2..000000000000 --- a/drivers/isdn/hisax/hisax_if.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Interface between low level (hardware) drivers and - * HiSax protocol stack - * - * Author Kai Germaschewski - * Copyright 2001 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. - * - */ - -#ifndef __HISAX_IF_H__ -#define __HISAX_IF_H__ - -#include <linux/skbuff.h> - -#define REQUEST 0 -#define CONFIRM 1 -#define INDICATION 2 -#define RESPONSE 3 - -#define PH_ACTIVATE 0x0100 -#define PH_DEACTIVATE 0x0110 -#define PH_DATA 0x0120 -#define PH_PULL 0x0130 -#define PH_DATA_E 0x0140 - -#define L1_MODE_NULL 0 -#define L1_MODE_TRANS 1 -#define L1_MODE_HDLC 2 -#define L1_MODE_EXTRN 3 -#define L1_MODE_HDLC_56K 4 -#define L1_MODE_MODEM 7 -#define L1_MODE_V32 8 -#define L1_MODE_FAX 9 - -struct hisax_if { - void *priv; // private to driver - void (*l1l2)(struct hisax_if *, int pr, void *arg); - void (*l2l1)(struct hisax_if *, int pr, void *arg); -}; - -struct hisax_b_if { - struct hisax_if ifc; - - // private to hisax - struct BCState *bcs; -}; - -struct hisax_d_if { - struct hisax_if ifc; - - // private to hisax - struct module *owner; - struct IsdnCardState *cs; - struct hisax_b_if *b_if[2]; - struct sk_buff_head erq; - unsigned long ph_state; -}; - -int hisax_register(struct hisax_d_if *hisax_if, struct hisax_b_if *b_if[], - char *name, int protocol); -void hisax_unregister(struct hisax_d_if *hisax_if); - -#endif diff --git a/drivers/isdn/hisax/hisax_isac.c b/drivers/isdn/hisax/hisax_isac.c deleted file mode 100644 index 0f36375478c5..000000000000 --- a/drivers/isdn/hisax/hisax_isac.c +++ /dev/null @@ -1,895 +0,0 @@ -/* - * Driver for ISAC-S and ISAC-SX - * ISDN Subscriber Access Controller for Terminals - * - * Author Kai Germaschewski - * Copyright 2001 by Kai Germaschewski <kai.germaschewski@gmx.de> - * 2001 by Karsten Keil <keil@isdn4linux.de> - * - * based upon Karsten Keil's original isac.c driver - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Wizard Computersysteme GmbH, Bremervoerde and - * SoHaNet Technology GmbH, Berlin - * for supporting the development of this driver - */ - -/* TODO: - * specifically handle level vs edge triggered? - */ - -#include <linux/module.h> -#include <linux/gfp.h> -#include <linux/init.h> -#include <linux/netdevice.h> -#include "hisax_isac.h" - -// debugging cruft - -#define __debug_variable debug -#include "hisax_debug.h" - -#ifdef CONFIG_HISAX_DEBUG -static int debug = 1; -module_param(debug, int, 0); - -static char *ISACVer[] = { - "2086/2186 V1.1", - "2085 B1", - "2085 B2", - "2085 V2.3" -}; -#endif - -MODULE_AUTHOR("Kai Germaschewski <kai.germaschewski@gmx.de>/Karsten Keil <kkeil@suse.de>"); -MODULE_DESCRIPTION("ISAC/ISAC-SX driver"); -MODULE_LICENSE("GPL"); - -#define DBG_WARN 0x0001 -#define DBG_IRQ 0x0002 -#define DBG_L1M 0x0004 -#define DBG_PR 0x0008 -#define DBG_RFIFO 0x0100 -#define DBG_RPACKET 0x0200 -#define DBG_XFIFO 0x1000 -#define DBG_XPACKET 0x2000 - -// we need to distinguish ISAC-S and ISAC-SX -#define TYPE_ISAC 0x00 -#define TYPE_ISACSX 0x01 - -// registers etc. -#define ISAC_MASK 0x20 -#define ISAC_ISTA 0x20 -#define ISAC_ISTA_EXI 0x01 -#define ISAC_ISTA_SIN 0x02 -#define ISAC_ISTA_CISQ 0x04 -#define ISAC_ISTA_XPR 0x10 -#define ISAC_ISTA_RSC 0x20 -#define ISAC_ISTA_RPF 0x40 -#define ISAC_ISTA_RME 0x80 - -#define ISAC_STAR 0x21 -#define ISAC_CMDR 0x21 -#define ISAC_CMDR_XRES 0x01 -#define ISAC_CMDR_XME 0x02 -#define ISAC_CMDR_XTF 0x08 -#define ISAC_CMDR_RRES 0x40 -#define ISAC_CMDR_RMC 0x80 - -#define ISAC_EXIR 0x24 -#define ISAC_EXIR_MOS 0x04 -#define ISAC_EXIR_XDU 0x40 -#define ISAC_EXIR_XMR 0x80 - -#define ISAC_ADF2 0x39 -#define ISAC_SPCR 0x30 -#define ISAC_ADF1 0x38 - -#define ISAC_CIR0 0x31 -#define ISAC_CIX0 0x31 -#define ISAC_CIR0_CIC0 0x02 -#define ISAC_CIR0_CIC1 0x01 - -#define ISAC_CIR1 0x33 -#define ISAC_CIX1 0x33 -#define ISAC_STCR 0x37 -#define ISAC_MODE 0x22 - -#define ISAC_RSTA 0x27 -#define ISAC_RSTA_RDO 0x40 -#define ISAC_RSTA_CRC 0x20 -#define ISAC_RSTA_RAB 0x10 - -#define ISAC_RBCL 0x25 -#define ISAC_RBCH 0x2A -#define ISAC_TIMR 0x23 -#define ISAC_SQXR 0x3b -#define ISAC_MOSR 0x3a -#define ISAC_MOCR 0x3a -#define ISAC_MOR0 0x32 -#define ISAC_MOX0 0x32 -#define ISAC_MOR1 0x34 -#define ISAC_MOX1 0x34 - -#define ISAC_RBCH_XAC 0x80 - -#define ISAC_CMD_TIM 0x0 -#define ISAC_CMD_RES 0x1 -#define ISAC_CMD_SSP 0x2 -#define ISAC_CMD_SCP 0x3 -#define ISAC_CMD_AR8 0x8 -#define ISAC_CMD_AR10 0x9 -#define ISAC_CMD_ARL 0xa -#define ISAC_CMD_DI 0xf - -#define ISACSX_MASK 0x60 -#define ISACSX_ISTA 0x60 -#define ISACSX_ISTA_ICD 0x01 -#define ISACSX_ISTA_CIC 0x10 - -#define ISACSX_MASKD 0x20 -#define ISACSX_ISTAD 0x20 -#define ISACSX_ISTAD_XDU 0x04 -#define ISACSX_ISTAD_XMR 0x08 -#define ISACSX_ISTAD_XPR 0x10 -#define ISACSX_ISTAD_RFO 0x20 -#define ISACSX_ISTAD_RPF 0x40 -#define ISACSX_ISTAD_RME 0x80 - -#define ISACSX_CMDRD 0x21 -#define ISACSX_CMDRD_XRES 0x01 -#define ISACSX_CMDRD_XME 0x02 -#define ISACSX_CMDRD_XTF 0x08 -#define ISACSX_CMDRD_RRES 0x40 -#define ISACSX_CMDRD_RMC 0x80 - -#define ISACSX_MODED 0x22 - -#define ISACSX_RBCLD 0x26 - -#define ISACSX_RSTAD 0x28 -#define ISACSX_RSTAD_RAB 0x10 -#define ISACSX_RSTAD_CRC 0x20 -#define ISACSX_RSTAD_RDO 0x40 -#define ISACSX_RSTAD_VFR 0x80 - -#define ISACSX_CIR0 0x2e -#define ISACSX_CIR0_CIC0 0x08 -#define ISACSX_CIX0 0x2e - -#define ISACSX_TR_CONF0 0x30 - -#define ISACSX_TR_CONF2 0x32 - -static struct Fsm l1fsm; - -enum { - ST_L1_RESET, - ST_L1_F3_PDOWN, - ST_L1_F3_PUP, - ST_L1_F3_PEND_DEACT, - ST_L1_F4, - ST_L1_F5, - ST_L1_F6, - ST_L1_F7, - ST_L1_F8, -}; - -#define L1_STATE_COUNT (ST_L1_F8 + 1) - -static char *strL1State[] = -{ - "ST_L1_RESET", - "ST_L1_F3_PDOWN", - "ST_L1_F3_PUP", - "ST_L1_F3_PEND_DEACT", - "ST_L1_F4", - "ST_L1_F5", - "ST_L1_F6", - "ST_L1_F7", - "ST_L1_F8", -}; - -enum { - EV_PH_DR, // 0000 - EV_PH_RES, // 0001 - EV_PH_TMA, // 0010 - EV_PH_SLD, // 0011 - EV_PH_RSY, // 0100 - EV_PH_DR6, // 0101 - EV_PH_EI, // 0110 - EV_PH_PU, // 0111 - EV_PH_AR, // 1000 - EV_PH_9, // 1001 - EV_PH_ARL, // 1010 - EV_PH_CVR, // 1011 - EV_PH_AI8, // 1100 - EV_PH_AI10, // 1101 - EV_PH_AIL, // 1110 - EV_PH_DC, // 1111 - EV_PH_ACTIVATE_REQ, - EV_PH_DEACTIVATE_REQ, - EV_TIMER3, -}; - -#define L1_EVENT_COUNT (EV_TIMER3 + 1) - -static char *strL1Event[] = -{ - "EV_PH_DR", // 0000 - "EV_PH_RES", // 0001 - "EV_PH_TMA", // 0010 - "EV_PH_SLD", // 0011 - "EV_PH_RSY", // 0100 - "EV_PH_DR6", // 0101 - "EV_PH_EI", // 0110 - "EV_PH_PU", // 0111 - "EV_PH_AR", // 1000 - "EV_PH_9", // 1001 - "EV_PH_ARL", // 1010 - "EV_PH_CVR", // 1011 - "EV_PH_AI8", // 1100 - "EV_PH_AI10", // 1101 - "EV_PH_AIL", // 1110 - "EV_PH_DC", // 1111 - "EV_PH_ACTIVATE_REQ", - "EV_PH_DEACTIVATE_REQ", - "EV_TIMER3", -}; - -static inline void D_L1L2(struct isac *isac, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &isac->hisax_d_if; - - DBG(DBG_PR, "pr %#x", pr); - ifc->l1l2(ifc, pr, arg); -} - -static void ph_command(struct isac *isac, unsigned int command) -{ - DBG(DBG_L1M, "ph_command %#x", command); - switch (isac->type) { - case TYPE_ISAC: - isac->write_isac(isac, ISAC_CIX0, (command << 2) | 3); - break; - case TYPE_ISACSX: - isac->write_isac(isac, ISACSX_CIX0, (command << 4) | (7 << 1)); - break; - } -} - -// ---------------------------------------------------------------------- - -static void l1_di(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_RESET); - ph_command(isac, ISAC_CMD_DI); -} - -static void l1_di_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_RESET); - D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); - ph_command(isac, ISAC_CMD_DI); -} - -static void l1_go_f3pdown(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F3_PDOWN); -} - -static void l1_go_f3pend_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_F3_PEND_DEACT); - D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); - ph_command(isac, ISAC_CMD_DI); -} - -static void l1_go_f3pend(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_F3_PEND_DEACT); - ph_command(isac, ISAC_CMD_DI); -} - -static void l1_go_f4(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F4); -} - -static void l1_go_f5(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F5); -} - -static void l1_go_f6(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F6); -} - -static void l1_go_f6_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_F6); - D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); -} - -static void l1_go_f7_act_ind(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmDelTimer(&isac->timer, 0); - FsmChangeState(fi, ST_L1_F7); - ph_command(isac, ISAC_CMD_AR8); - D_L1L2(isac, PH_ACTIVATE | INDICATION, NULL); -} - -static void l1_go_f8(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F8); -} - -static void l1_go_f8_deact_ind(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmChangeState(fi, ST_L1_F8); - D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); -} - -static void l1_ar8(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - FsmRestartTimer(&isac->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); - ph_command(isac, ISAC_CMD_AR8); -} - -static void l1_timer3(struct FsmInst *fi, int event, void *arg) -{ - struct isac *isac = fi->userdata; - - ph_command(isac, ISAC_CMD_DI); - D_L1L2(isac, PH_DEACTIVATE | INDICATION, NULL); -} - -// state machines according to data sheet PSB 2186 / 3186 - -static struct FsmNode L1FnList[] __initdata = -{ - {ST_L1_RESET, EV_PH_RES, l1_di}, - {ST_L1_RESET, EV_PH_EI, l1_di}, - {ST_L1_RESET, EV_PH_DC, l1_go_f3pdown}, - {ST_L1_RESET, EV_PH_AR, l1_go_f6}, - {ST_L1_RESET, EV_PH_AI8, l1_go_f7_act_ind}, - - {ST_L1_F3_PDOWN, EV_PH_RES, l1_di}, - {ST_L1_F3_PDOWN, EV_PH_EI, l1_di}, - {ST_L1_F3_PDOWN, EV_PH_AR, l1_go_f6}, - {ST_L1_F3_PDOWN, EV_PH_RSY, l1_go_f5}, - {ST_L1_F3_PDOWN, EV_PH_PU, l1_go_f4}, - {ST_L1_F3_PDOWN, EV_PH_AI8, l1_go_f7_act_ind}, - {ST_L1_F3_PDOWN, EV_PH_ACTIVATE_REQ, l1_ar8}, - {ST_L1_F3_PDOWN, EV_TIMER3, l1_timer3}, - - {ST_L1_F3_PEND_DEACT, EV_PH_RES, l1_di}, - {ST_L1_F3_PEND_DEACT, EV_PH_EI, l1_di}, - {ST_L1_F3_PEND_DEACT, EV_PH_DC, l1_go_f3pdown}, - {ST_L1_F3_PEND_DEACT, EV_PH_RSY, l1_go_f5}, - {ST_L1_F3_PEND_DEACT, EV_PH_AR, l1_go_f6}, - {ST_L1_F3_PEND_DEACT, EV_PH_AI8, l1_go_f7_act_ind}, - - {ST_L1_F4, EV_PH_RES, l1_di}, - {ST_L1_F4, EV_PH_EI, l1_di}, - {ST_L1_F4, EV_PH_RSY, l1_go_f5}, - {ST_L1_F4, EV_PH_AI8, l1_go_f7_act_ind}, - {ST_L1_F4, EV_TIMER3, l1_timer3}, - {ST_L1_F4, EV_PH_DC, l1_go_f3pdown}, - - {ST_L1_F5, EV_PH_RES, l1_di}, - {ST_L1_F5, EV_PH_EI, l1_di}, - {ST_L1_F5, EV_PH_AR, l1_go_f6}, - {ST_L1_F5, EV_PH_AI8, l1_go_f7_act_ind}, - {ST_L1_F5, EV_TIMER3, l1_timer3}, - {ST_L1_F5, EV_PH_DR, l1_go_f3pend}, - {ST_L1_F5, EV_PH_DC, l1_go_f3pdown}, - - {ST_L1_F6, EV_PH_RES, l1_di}, - {ST_L1_F6, EV_PH_EI, l1_di}, - {ST_L1_F6, EV_PH_RSY, l1_go_f8}, - {ST_L1_F6, EV_PH_AI8, l1_go_f7_act_ind}, - {ST_L1_F6, EV_PH_DR6, l1_go_f3pend}, - {ST_L1_F6, EV_TIMER3, l1_timer3}, - {ST_L1_F6, EV_PH_DC, l1_go_f3pdown}, - - {ST_L1_F7, EV_PH_RES, l1_di_deact_ind}, - {ST_L1_F7, EV_PH_EI, l1_di_deact_ind}, - {ST_L1_F7, EV_PH_AR, l1_go_f6_deact_ind}, - {ST_L1_F7, EV_PH_RSY, l1_go_f8_deact_ind}, - {ST_L1_F7, EV_PH_DR, l1_go_f3pend_deact_ind}, - - {ST_L1_F8, EV_PH_RES, l1_di}, - {ST_L1_F8, EV_PH_EI, l1_di}, - {ST_L1_F8, EV_PH_AR, l1_go_f6}, - {ST_L1_F8, EV_PH_DR, l1_go_f3pend}, - {ST_L1_F8, EV_PH_AI8, l1_go_f7_act_ind}, - {ST_L1_F8, EV_TIMER3, l1_timer3}, - {ST_L1_F8, EV_PH_DC, l1_go_f3pdown}, -}; - -static void l1m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - char buf[256]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - DBG(DBG_L1M, "%s", buf); - va_end(args); -} - -static void isac_version(struct isac *cs) -{ - int val; - - val = cs->read_isac(cs, ISAC_RBCH); - DBG(1, "ISAC version (%x): %s", val, ISACVer[(val >> 5) & 3]); -} - -static void isac_empty_fifo(struct isac *isac, int count) -{ - // this also works for isacsx, since - // CMDR(D) register works the same - u_char *ptr; - - DBG(DBG_IRQ, "count %d", count); - - if ((isac->rcvidx + count) >= MAX_DFRAME_LEN_L1) { - DBG(DBG_WARN, "overrun %d", isac->rcvidx + count); - isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC); - isac->rcvidx = 0; - return; - } - ptr = isac->rcvbuf + isac->rcvidx; - isac->rcvidx += count; - isac->read_isac_fifo(isac, ptr, count); - isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC); - DBG_PACKET(DBG_RFIFO, ptr, count); -} - -static void isac_fill_fifo(struct isac *isac) -{ - // this also works for isacsx, since - // CMDR(D) register works the same - - int count; - unsigned char cmd; - u_char *ptr; - - BUG_ON(!isac->tx_skb); - - count = isac->tx_skb->len; - BUG_ON(count <= 0); - - DBG(DBG_IRQ, "count %d", count); - - if (count > 0x20) { - count = 0x20; - cmd = ISAC_CMDR_XTF; - } else { - cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME; - } - - ptr = isac->tx_skb->data; - skb_pull(isac->tx_skb, count); - isac->tx_cnt += count; - DBG_PACKET(DBG_XFIFO, ptr, count); - isac->write_isac_fifo(isac, ptr, count); - isac->write_isac(isac, ISAC_CMDR, cmd); -} - -static void isac_retransmit(struct isac *isac) -{ - if (!isac->tx_skb) { - DBG(DBG_WARN, "no skb"); - return; - } - skb_push(isac->tx_skb, isac->tx_cnt); - isac->tx_cnt = 0; -} - - -static inline void isac_cisq_interrupt(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISAC_CIR0); - DBG(DBG_IRQ, "CIR0 %#x", val); - if (val & ISAC_CIR0_CIC0) { - DBG(DBG_IRQ, "CODR0 %#x", (val >> 2) & 0xf); - FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL); - } - if (val & ISAC_CIR0_CIC1) { - val = isac->read_isac(isac, ISAC_CIR1); - DBG(DBG_WARN, "ISAC CIR1 %#x", val); - } -} - -static inline void isac_rme_interrupt(struct isac *isac) -{ - unsigned char val; - int count; - struct sk_buff *skb; - - val = isac->read_isac(isac, ISAC_RSTA); - if ((val & (ISAC_RSTA_RDO | ISAC_RSTA_CRC | ISAC_RSTA_RAB)) - != ISAC_RSTA_CRC) { - DBG(DBG_WARN, "RSTA %#x, dropped", val); - isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_RMC); - goto out; - } - - count = isac->read_isac(isac, ISAC_RBCL) & 0x1f; - DBG(DBG_IRQ, "RBCL %#x", count); - if (count == 0) - count = 0x20; - - isac_empty_fifo(isac, count); - count = isac->rcvidx; - if (count < 1) { - DBG(DBG_WARN, "count %d < 1", count); - goto out; - } - - skb = alloc_skb(count, GFP_ATOMIC); - if (!skb) { - DBG(DBG_WARN, "no memory, dropping\n"); - goto out; - } - skb_put_data(skb, isac->rcvbuf, count); - DBG_SKB(DBG_RPACKET, skb); - D_L1L2(isac, PH_DATA | INDICATION, skb); -out: - isac->rcvidx = 0; -} - -static inline void isac_xpr_interrupt(struct isac *isac) -{ - if (!isac->tx_skb) - return; - - if (isac->tx_skb->len > 0) { - isac_fill_fifo(isac); - return; - } - dev_kfree_skb_irq(isac->tx_skb); - isac->tx_cnt = 0; - isac->tx_skb = NULL; - D_L1L2(isac, PH_DATA | CONFIRM, NULL); -} - -static inline void isac_exi_interrupt(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISAC_EXIR); - DBG(2, "EXIR %#x", val); - - if (val & ISAC_EXIR_XMR) { - DBG(DBG_WARN, "ISAC XMR"); - isac_retransmit(isac); - } - if (val & ISAC_EXIR_XDU) { - DBG(DBG_WARN, "ISAC XDU"); - isac_retransmit(isac); - } - if (val & ISAC_EXIR_MOS) { /* MOS */ - DBG(DBG_WARN, "MOS"); - val = isac->read_isac(isac, ISAC_MOSR); - DBG(2, "ISAC MOSR %#x", val); - } -} - -void isac_irq(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISAC_ISTA); - DBG(DBG_IRQ, "ISTA %#x", val); - - if (val & ISAC_ISTA_EXI) { - DBG(DBG_IRQ, "EXI"); - isac_exi_interrupt(isac); - } - if (val & ISAC_ISTA_XPR) { - DBG(DBG_IRQ, "XPR"); - isac_xpr_interrupt(isac); - } - if (val & ISAC_ISTA_RME) { - DBG(DBG_IRQ, "RME"); - isac_rme_interrupt(isac); - } - if (val & ISAC_ISTA_RPF) { - DBG(DBG_IRQ, "RPF"); - isac_empty_fifo(isac, 0x20); - } - if (val & ISAC_ISTA_CISQ) { - DBG(DBG_IRQ, "CISQ"); - isac_cisq_interrupt(isac); - } - if (val & ISAC_ISTA_RSC) { - DBG(DBG_WARN, "RSC"); - } - if (val & ISAC_ISTA_SIN) { - DBG(DBG_WARN, "SIN"); - } - isac->write_isac(isac, ISAC_MASK, 0xff); - isac->write_isac(isac, ISAC_MASK, 0x00); -} - -// ====================================================================== - -static inline void isacsx_cic_interrupt(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISACSX_CIR0); - DBG(DBG_IRQ, "CIR0 %#x", val); - if (val & ISACSX_CIR0_CIC0) { - DBG(DBG_IRQ, "CODR0 %#x", val >> 4); - FsmEvent(&isac->l1m, val >> 4, NULL); - } -} - -static inline void isacsx_rme_interrupt(struct isac *isac) -{ - int count; - struct sk_buff *skb; - unsigned char val; - - val = isac->read_isac(isac, ISACSX_RSTAD); - if ((val & (ISACSX_RSTAD_VFR | - ISACSX_RSTAD_RDO | - ISACSX_RSTAD_CRC | - ISACSX_RSTAD_RAB)) - != (ISACSX_RSTAD_VFR | ISACSX_RSTAD_CRC)) { - DBG(DBG_WARN, "RSTAD %#x, dropped", val); - isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC); - goto out; - } - - count = isac->read_isac(isac, ISACSX_RBCLD) & 0x1f; - DBG(DBG_IRQ, "RBCLD %#x", count); - if (count == 0) - count = 0x20; - - isac_empty_fifo(isac, count); - // strip trailing status byte - count = isac->rcvidx - 1; - if (count < 1) { - DBG(DBG_WARN, "count %d < 1", count); - goto out; - } - - skb = dev_alloc_skb(count); - if (!skb) { - DBG(DBG_WARN, "no memory, dropping"); - goto out; - } - skb_put_data(skb, isac->rcvbuf, count); - DBG_SKB(DBG_RPACKET, skb); - D_L1L2(isac, PH_DATA | INDICATION, skb); -out: - isac->rcvidx = 0; -} - -static inline void isacsx_xpr_interrupt(struct isac *isac) -{ - if (!isac->tx_skb) - return; - - if (isac->tx_skb->len > 0) { - isac_fill_fifo(isac); - return; - } - dev_kfree_skb_irq(isac->tx_skb); - isac->tx_skb = NULL; - isac->tx_cnt = 0; - D_L1L2(isac, PH_DATA | CONFIRM, NULL); -} - -static inline void isacsx_icd_interrupt(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISACSX_ISTAD); - DBG(DBG_IRQ, "ISTAD %#x", val); - if (val & ISACSX_ISTAD_XDU) { - DBG(DBG_WARN, "ISTAD XDU"); - isac_retransmit(isac); - } - if (val & ISACSX_ISTAD_XMR) { - DBG(DBG_WARN, "ISTAD XMR"); - isac_retransmit(isac); - } - if (val & ISACSX_ISTAD_XPR) { - DBG(DBG_IRQ, "ISTAD XPR"); - isacsx_xpr_interrupt(isac); - } - if (val & ISACSX_ISTAD_RFO) { - DBG(DBG_WARN, "ISTAD RFO"); - isac->write_isac(isac, ISACSX_CMDRD, ISACSX_CMDRD_RMC); - } - if (val & ISACSX_ISTAD_RME) { - DBG(DBG_IRQ, "ISTAD RME"); - isacsx_rme_interrupt(isac); - } - if (val & ISACSX_ISTAD_RPF) { - DBG(DBG_IRQ, "ISTAD RPF"); - isac_empty_fifo(isac, 0x20); - } -} - -void isacsx_irq(struct isac *isac) -{ - unsigned char val; - - val = isac->read_isac(isac, ISACSX_ISTA); - DBG(DBG_IRQ, "ISTA %#x", val); - - if (val & ISACSX_ISTA_ICD) - isacsx_icd_interrupt(isac); - if (val & ISACSX_ISTA_CIC) - isacsx_cic_interrupt(isac); -} - -void isac_init(struct isac *isac) -{ - isac->tx_skb = NULL; - isac->l1m.fsm = &l1fsm; - isac->l1m.state = ST_L1_RESET; -#ifdef CONFIG_HISAX_DEBUG - isac->l1m.debug = 1; -#else - isac->l1m.debug = 0; -#endif - isac->l1m.userdata = isac; - isac->l1m.printdebug = l1m_debug; - FsmInitTimer(&isac->l1m, &isac->timer); -} - -void isac_setup(struct isac *isac) -{ - int val, eval; - - isac->type = TYPE_ISAC; - isac_version(isac); - - ph_command(isac, ISAC_CMD_RES); - - isac->write_isac(isac, ISAC_MASK, 0xff); - isac->mocr = 0xaa; - if (test_bit(ISAC_IOM1, &isac->flags)) { - /* IOM 1 Mode */ - isac->write_isac(isac, ISAC_ADF2, 0x0); - isac->write_isac(isac, ISAC_SPCR, 0xa); - isac->write_isac(isac, ISAC_ADF1, 0x2); - isac->write_isac(isac, ISAC_STCR, 0x70); - isac->write_isac(isac, ISAC_MODE, 0xc9); - } else { - /* IOM 2 Mode */ - if (!isac->adf2) - isac->adf2 = 0x80; - isac->write_isac(isac, ISAC_ADF2, isac->adf2); - isac->write_isac(isac, ISAC_SQXR, 0x2f); - isac->write_isac(isac, ISAC_SPCR, 0x00); - isac->write_isac(isac, ISAC_STCR, 0x70); - isac->write_isac(isac, ISAC_MODE, 0xc9); - isac->write_isac(isac, ISAC_TIMR, 0x00); - isac->write_isac(isac, ISAC_ADF1, 0x00); - } - val = isac->read_isac(isac, ISAC_STAR); - DBG(2, "ISAC STAR %x", val); - val = isac->read_isac(isac, ISAC_MODE); - DBG(2, "ISAC MODE %x", val); - val = isac->read_isac(isac, ISAC_ADF2); - DBG(2, "ISAC ADF2 %x", val); - val = isac->read_isac(isac, ISAC_ISTA); - DBG(2, "ISAC ISTA %x", val); - if (val & 0x01) { - eval = isac->read_isac(isac, ISAC_EXIR); - DBG(2, "ISAC EXIR %x", eval); - } - val = isac->read_isac(isac, ISAC_CIR0); - DBG(2, "ISAC CIR0 %x", val); - FsmEvent(&isac->l1m, (val >> 2) & 0xf, NULL); - - isac->write_isac(isac, ISAC_MASK, 0x0); - // RESET Receiver and Transmitter - isac->write_isac(isac, ISAC_CMDR, ISAC_CMDR_XRES | ISAC_CMDR_RRES); -} - -void isacsx_setup(struct isac *isac) -{ - isac->type = TYPE_ISACSX; - // clear LDD - isac->write_isac(isac, ISACSX_TR_CONF0, 0x00); - // enable transmitter - isac->write_isac(isac, ISACSX_TR_CONF2, 0x00); - // transparent mode 0, RAC, stop/go - isac->write_isac(isac, ISACSX_MODED, 0xc9); - // all HDLC IRQ unmasked - isac->write_isac(isac, ISACSX_MASKD, 0x03); - // unmask ICD, CID IRQs - isac->write_isac(isac, ISACSX_MASK, - ~(ISACSX_ISTA_ICD | ISACSX_ISTA_CIC)); -} - -void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) -{ - struct isac *isac = hisax_d_if->priv; - struct sk_buff *skb = arg; - - DBG(DBG_PR, "pr %#x", pr); - - switch (pr) { - case PH_ACTIVATE | REQUEST: - FsmEvent(&isac->l1m, EV_PH_ACTIVATE_REQ, NULL); - break; - case PH_DEACTIVATE | REQUEST: - FsmEvent(&isac->l1m, EV_PH_DEACTIVATE_REQ, NULL); - break; - case PH_DATA | REQUEST: - DBG(DBG_PR, "PH_DATA REQUEST len %d", skb->len); - DBG_SKB(DBG_XPACKET, skb); - if (isac->l1m.state != ST_L1_F7) { - DBG(1, "L1 wrong state %d\n", isac->l1m.state); - dev_kfree_skb(skb); - break; - } - BUG_ON(isac->tx_skb); - - isac->tx_skb = skb; - isac_fill_fifo(isac); - break; - } -} - -static int __init hisax_isac_init(void) -{ - printk(KERN_INFO "hisax_isac: ISAC-S/ISAC-SX ISDN driver v0.1.0\n"); - - l1fsm.state_count = L1_STATE_COUNT; - l1fsm.event_count = L1_EVENT_COUNT; - l1fsm.strState = strL1State; - l1fsm.strEvent = strL1Event; - return FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList)); -} - -static void __exit hisax_isac_exit(void) -{ - FsmFree(&l1fsm); -} - -EXPORT_SYMBOL(isac_init); -EXPORT_SYMBOL(isac_d_l2l1); - -EXPORT_SYMBOL(isacsx_setup); -EXPORT_SYMBOL(isacsx_irq); - -EXPORT_SYMBOL(isac_setup); -EXPORT_SYMBOL(isac_irq); - -module_init(hisax_isac_init); -module_exit(hisax_isac_exit); diff --git a/drivers/isdn/hisax/hisax_isac.h b/drivers/isdn/hisax/hisax_isac.h deleted file mode 100644 index d7301da97991..000000000000 --- a/drivers/isdn/hisax/hisax_isac.h +++ /dev/null @@ -1,46 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __HISAX_ISAC_H__ -#define __HISAX_ISAC_H__ - -#include <linux/kernel.h> -#include "fsm.h" -#include "hisax_if.h" - -#define TIMER3_VALUE 7000 -#define MAX_DFRAME_LEN_L1 300 - -#define ISAC_IOM1 0 - -struct isac { - void *priv; - - u_long flags; - struct hisax_d_if hisax_d_if; - struct FsmInst l1m; - struct FsmTimer timer; - u_char mocr; - u_char adf2; - int type; - - u_char rcvbuf[MAX_DFRAME_LEN_L1]; - int rcvidx; - - struct sk_buff *tx_skb; - int tx_cnt; - - u_char (*read_isac) (struct isac *, u_char); - void (*write_isac) (struct isac *, u_char, u_char); - void (*read_isac_fifo) (struct isac *, u_char *, int); - void (*write_isac_fifo)(struct isac *, u_char *, int); -}; - -void isac_init(struct isac *isac); -void isac_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg); - -void isac_setup(struct isac *isac); -void isac_irq(struct isac *isac); - -void isacsx_setup(struct isac *isac); -void isacsx_irq(struct isac *isac); - -#endif diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c deleted file mode 100644 index 3e305fec0ed9..000000000000 --- a/drivers/isdn/hisax/hscx.c +++ /dev/null @@ -1,277 +0,0 @@ -/* $Id: hscx.c,v 1.24.2.4 2004/01/24 20:47:23 keil Exp $ - * - * HSCX specific routines - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "hscx.h" -#include "isac.h" -#include "isdnl1.h" -#include <linux/interrupt.h> -#include <linux/slab.h> - -static char *HSCXVer[] = -{"A1", "?1", "A2", "?3", "A3", "V2.1", "?6", "?7", - "?8", "?9", "?10", "?11", "?12", "?13", "?14", "???"}; - -int -HscxVersion(struct IsdnCardState *cs, char *s) -{ - int verA, verB; - - verA = cs->BC_Read_Reg(cs, 0, HSCX_VSTR) & 0xf; - verB = cs->BC_Read_Reg(cs, 1, HSCX_VSTR) & 0xf; - printk(KERN_INFO "%s HSCX version A: %s B: %s\n", s, - HSCXVer[verA], HSCXVer[verB]); - if ((verA == 0) | (verA == 0xf) | (verB == 0) | (verB == 0xf)) - return (1); - else - return (0); -} - -void -modehscx(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int hscx = bcs->hw.hscx.hscx; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "hscx %c mode %d ichan %d", - 'A' + hscx, mode, bc); - bcs->mode = mode; - bcs->channel = bc; - cs->BC_Write_Reg(cs, hscx, HSCX_XAD1, 0xFF); - cs->BC_Write_Reg(cs, hscx, HSCX_XAD2, 0xFF); - cs->BC_Write_Reg(cs, hscx, HSCX_RAH2, 0xFF); - cs->BC_Write_Reg(cs, hscx, HSCX_XBCH, 0x0); - cs->BC_Write_Reg(cs, hscx, HSCX_RLCR, 0x0); - cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, - test_bit(HW_IPAC, &cs->HW_Flags) ? 0x82 : 0x85); - cs->BC_Write_Reg(cs, hscx, HSCX_CCR2, 0x30); - cs->BC_Write_Reg(cs, hscx, HSCX_XCCR, 7); - cs->BC_Write_Reg(cs, hscx, HSCX_RCCR, 7); - - /* Switch IOM 1 SSI */ - if (test_bit(HW_IOM1, &cs->HW_Flags) && (hscx == 0)) - bc = 1 - bc; - - if (bc == 0) { - cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, - test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0); - cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, - test_bit(HW_IOM1, &cs->HW_Flags) ? 0x7 : bcs->hw.hscx.tsaxr0); - } else { - cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, bcs->hw.hscx.tsaxr1); - cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, bcs->hw.hscx.tsaxr1); - } - switch (mode) { - case (L1_MODE_NULL): - cs->BC_Write_Reg(cs, hscx, HSCX_TSAX, 0x1f); - cs->BC_Write_Reg(cs, hscx, HSCX_TSAR, 0x1f); - cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x84); - break; - case (L1_MODE_TRANS): - cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0xe4); - break; - case (L1_MODE_HDLC): - cs->BC_Write_Reg(cs, hscx, HSCX_CCR1, - test_bit(HW_IPAC, &cs->HW_Flags) ? 0x8a : 0x8d); - cs->BC_Write_Reg(cs, hscx, HSCX_MODE, 0x8c); - break; - } - if (mode) - cs->BC_Write_Reg(cs, hscx, HSCX_CMDR, 0x41); - cs->BC_Write_Reg(cs, hscx, HSCX_ISTA, 0x00); -} - -void -hscx_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - u_long flags; - struct sk_buff *skb = arg; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.hscx.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n"); - } else { - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->hw.hscx.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - modehscx(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - modehscx(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_hscxstate(struct BCState *bcs) -{ - modehscx(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - kfree(bcs->blog); - bcs->blog = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -int -open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for hscx.rcvbuf\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - return (1); - } - if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for bcs->blog\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - return (2); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.hscx.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_hscx(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_hscxstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = hscx_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -void -clear_pending_hscx_ints(struct IsdnCardState *cs) -{ - int val, eval; - - val = cs->BC_Read_Reg(cs, 1, HSCX_ISTA); - debugl1(cs, "HSCX B ISTA %x", val); - if (val & 0x01) { - eval = cs->BC_Read_Reg(cs, 1, HSCX_EXIR); - debugl1(cs, "HSCX B EXIR %x", eval); - } - if (val & 0x02) { - eval = cs->BC_Read_Reg(cs, 0, HSCX_EXIR); - debugl1(cs, "HSCX A EXIR %x", eval); - } - val = cs->BC_Read_Reg(cs, 0, HSCX_ISTA); - debugl1(cs, "HSCX A ISTA %x", val); - val = cs->BC_Read_Reg(cs, 1, HSCX_STAR); - debugl1(cs, "HSCX B STAR %x", val); - val = cs->BC_Read_Reg(cs, 0, HSCX_STAR); - debugl1(cs, "HSCX A STAR %x", val); - /* disable all IRQ */ - cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0xFF); - cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0xFF); -} - -void -inithscx(struct IsdnCardState *cs) -{ - cs->bcs[0].BC_SetStack = setstack_hscx; - cs->bcs[1].BC_SetStack = setstack_hscx; - cs->bcs[0].BC_Close = close_hscxstate; - cs->bcs[1].BC_Close = close_hscxstate; - cs->bcs[0].hw.hscx.hscx = 0; - cs->bcs[1].hw.hscx.hscx = 1; - cs->bcs[0].hw.hscx.tsaxr0 = 0x2f; - cs->bcs[0].hw.hscx.tsaxr1 = 3; - cs->bcs[1].hw.hscx.tsaxr0 = 0x2f; - cs->bcs[1].hw.hscx.tsaxr1 = 3; - modehscx(cs->bcs, 0, 0); - modehscx(cs->bcs + 1, 0, 0); -} - -void -inithscxisac(struct IsdnCardState *cs, int part) -{ - if (part & 1) { - clear_pending_isac_ints(cs); - clear_pending_hscx_ints(cs); - initisac(cs); - inithscx(cs); - } - if (part & 2) { - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - cs->BC_Write_Reg(cs, 0, HSCX_MASK, 0); - cs->BC_Write_Reg(cs, 1, HSCX_MASK, 0); - /* RESET Receiver and Transmitter */ - cs->writeisac(cs, ISAC_CMDR, 0x41); - } -} diff --git a/drivers/isdn/hisax/hscx.h b/drivers/isdn/hisax/hscx.h deleted file mode 100644 index 1148b4bbe711..000000000000 --- a/drivers/isdn/hisax/hscx.h +++ /dev/null @@ -1,41 +0,0 @@ -/* $Id: hscx.h,v 1.8.2.2 2004/01/12 22:52:26 keil Exp $ - * - * HSCX specific defines - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* All Registers original Siemens Spec */ - -#define HSCX_ISTA 0x20 -#define HSCX_CCR1 0x2f -#define HSCX_CCR2 0x2c -#define HSCX_TSAR 0x31 -#define HSCX_TSAX 0x30 -#define HSCX_XCCR 0x32 -#define HSCX_RCCR 0x33 -#define HSCX_MODE 0x22 -#define HSCX_CMDR 0x21 -#define HSCX_EXIR 0x24 -#define HSCX_XAD1 0x24 -#define HSCX_XAD2 0x25 -#define HSCX_RAH2 0x27 -#define HSCX_RSTA 0x27 -#define HSCX_TIMR 0x23 -#define HSCX_STAR 0x21 -#define HSCX_RBCL 0x25 -#define HSCX_XBCH 0x2d -#define HSCX_VSTR 0x2e -#define HSCX_RLCR 0x2e -#define HSCX_MASK 0x20 - -extern int HscxVersion(struct IsdnCardState *cs, char *s); -extern void modehscx(struct BCState *bcs, int mode, int bc); -extern void clear_pending_hscx_ints(struct IsdnCardState *cs); -extern void inithscx(struct IsdnCardState *cs); -extern void inithscxisac(struct IsdnCardState *cs, int part); diff --git a/drivers/isdn/hisax/hscx_irq.c b/drivers/isdn/hisax/hscx_irq.c deleted file mode 100644 index 0d7e783c8bef..000000000000 --- a/drivers/isdn/hisax/hscx_irq.c +++ /dev/null @@ -1,294 +0,0 @@ -/* $Id: hscx_irq.c,v 1.18.2.3 2004/02/11 13:21:34 keil Exp $ - * - * low level b-channel stuff for Siemens HSCX - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This is an include file for fast inline IRQ stuff - * - */ - - -static inline void -waitforCEC(struct IsdnCardState *cs, int hscx) -{ - int to = 50; - - while ((READHSCX(cs, hscx, HSCX_STAR) & 0x04) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: waitforCEC timeout\n"); -} - - -static inline void -waitforXFW(struct IsdnCardState *cs, int hscx) -{ - int to = 50; - - while (((READHSCX(cs, hscx, HSCX_STAR) & 0x44) != 0x40) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: waitforXFW timeout\n"); -} - -static inline void -WriteHSCXCMDR(struct IsdnCardState *cs, int hscx, u_char data) -{ - waitforCEC(cs, hscx); - WRITEHSCX(cs, hscx, HSCX_CMDR, data); -} - - - -static void -hscx_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct IsdnCardState *cs = bcs->cs; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hscx_empty_fifo"); - - if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "hscx_empty_fifo: incoming packet too large"); - WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); - bcs->hw.hscx.rcvidx = 0; - return; - } - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - bcs->hw.hscx.rcvidx += count; - READHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); - WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x80); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "hscx_empty_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -hscx_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int more, count; - int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32; - u_char *ptr; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "hscx_fill_fifo"); - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->tx_skb->len > fifo_size) { - more = !0; - count = fifo_size; - } else - count = bcs->tx_skb->len; - - waitforXFW(cs, bcs->hw.hscx.hscx); - ptr = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.hscx.count += count; - WRITEHSCXFIFO(cs, bcs->hw.hscx.hscx, ptr, count); - WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, more ? 0x8 : 0xa); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "hscx_fill_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -hscx_interrupt(struct IsdnCardState *cs, u_char val, u_char hscx) -{ - u_char r; - struct BCState *bcs = cs->bcs + hscx; - struct sk_buff *skb; - int fifo_size = test_bit(HW_IPAC, &cs->HW_Flags) ? 64 : 32; - int count; - - if (!test_bit(BC_FLG_INIT, &bcs->Flag)) - return; - - if (val & 0x80) { /* RME */ - r = READHSCX(cs, hscx, HSCX_RSTA); - if ((r & 0xf0) != 0xa0) { - if (!(r & 0x80)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX invalid frame"); -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - } - if ((r & 0x40) && bcs->mode) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX RDO mode=%d", - bcs->mode); -#ifdef ERROR_STATISTIC - bcs->err_rdo++; -#endif - } - if (!(r & 0x20)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX CRC error"); -#ifdef ERROR_STATISTIC - bcs->err_crc++; -#endif - } - WriteHSCXCMDR(cs, hscx, 0x80); - } else { - count = READHSCX(cs, hscx, HSCX_RBCL) & ( - test_bit(HW_IPAC, &cs->HW_Flags) ? 0x3f : 0x1f); - if (count == 0) - count = fifo_size; - hscx_empty_fifo(bcs, count); - if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "HX Frame %d", count); - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "HSCX: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - count); - skb_queue_tail(&bcs->rqueue, skb); - } - } - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - if (val & 0x40) { /* RPF */ - hscx_empty_fifo(bcs, fifo_size); - if (bcs->mode == L1_MODE_TRANS) { - /* receive audio data */ - if (!(skb = dev_alloc_skb(fifo_size))) - printk(KERN_WARNING "HiSax: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - fifo_size); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - } - if (val & 0x10) { /* XPR */ - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - hscx_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hscx.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hscx.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - hscx_fill_fifo(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -} - -static void -hscx_int_main(struct IsdnCardState *cs, u_char val) -{ - - u_char exval; - struct BCState *bcs; - - if (val & 0x01) { - bcs = cs->bcs + 1; - exval = READHSCX(cs, 1, HSCX_EXIR); - if (exval & 0x40) { - if (bcs->mode == 1) - hscx_fill_fifo(bcs); - else { -#ifdef ERROR_STATISTIC - bcs->err_tx++; -#endif - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX B EXIR %x Lost TX", exval); - } - } else if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX B EXIR %x", exval); - } - if (val & 0xf8) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX B interrupt %x", val); - hscx_interrupt(cs, val, 1); - } - if (val & 0x02) { - bcs = cs->bcs; - exval = READHSCX(cs, 0, HSCX_EXIR); - if (exval & 0x40) { - if (bcs->mode == L1_MODE_TRANS) - hscx_fill_fifo(bcs); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ -#ifdef ERROR_STATISTIC - bcs->err_tx++; -#endif - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - WriteHSCXCMDR(cs, bcs->hw.hscx.hscx, 0x01); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "HSCX A EXIR %x Lost TX", exval); - } - } else if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX A EXIR %x", exval); - } - if (val & 0x04) { - exval = READHSCX(cs, 0, HSCX_ISTA); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX A interrupt %x", exval); - hscx_interrupt(cs, exval, 0); - } -} diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c deleted file mode 100644 index 831dd1bb81ef..000000000000 --- a/drivers/isdn/hisax/icc.c +++ /dev/null @@ -1,680 +0,0 @@ -/* $Id: icc.c,v 1.8.2.3 2004/01/13 14:31:25 keil Exp $ - * - * ICC specific routines - * - * Author Matt Henderson & Guy Ellis - * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * 1999.6.25 Initial implementation of routines for Siemens ISDN - * Communication Controller PEB 2070 based on the ISAC routines - * written by Karsten Keil. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "icc.h" -// #include "arcofi.h" -#include "isdnl1.h" -#include <linux/interrupt.h> -#include <linux/slab.h> - -#define DBUSY_TIMER_VALUE 80 -#define ARCOFI_USE 0 - -static char *ICCVer[] = -{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"}; - -void -ICCVersion(struct IsdnCardState *cs, char *s) -{ - int val; - - val = cs->readisac(cs, ICC_RBCH); - printk(KERN_INFO "%s ICC version (%x): %s\n", s, val, ICCVer[(val >> 5) & 3]); -} - -static void -ph_command(struct IsdnCardState *cs, unsigned int command) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_command %x", command); - cs->writeisac(cs, ICC_CIX0, (command << 2) | 3); -} - - -static void -icc_new_ph(struct IsdnCardState *cs) -{ - switch (cs->dc.icc.ph_state) { - case (ICC_IND_EI1): - ph_command(cs, ICC_CMD_DI); - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - case (ICC_IND_DC): - l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); - break; - case (ICC_IND_DR): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (ICC_IND_PU): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (ICC_IND_FJ): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (ICC_IND_AR): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (ICC_IND_AI): - l1_msg(cs, HW_INFO4 | INDICATION, NULL); - break; - default: - break; - } -} - -static void -icc_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - struct PStack *stptr; - - if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { - if (cs->debug) - debugl1(cs, "D-Channel Busy cleared"); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); - stptr = stptr->next; - } - } - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) - icc_new_ph(cs); - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -#if ARCOFI_USE - if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) - return; - if (test_and_clear_bit(D_RX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_RX_END, NULL); - if (test_and_clear_bit(D_TX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_TX_END, NULL); -#endif -} - -static void -icc_empty_fifo(struct IsdnCardState *cs, int count) -{ - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "icc_empty_fifo"); - - if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "icc_empty_fifo overrun %d", - cs->rcvidx + count); - cs->writeisac(cs, ICC_CMDR, 0x80); - cs->rcvidx = 0; - return; - } - ptr = cs->rcvbuf + cs->rcvidx; - cs->rcvidx += count; - cs->readisacfifo(cs, ptr, count); - cs->writeisac(cs, ICC_CMDR, 0x80); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "icc_empty_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -static void -icc_fill_fifo(struct IsdnCardState *cs) -{ - int count, more; - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "icc_fill_fifo"); - - if (!cs->tx_skb) - return; - - count = cs->tx_skb->len; - if (count <= 0) - return; - - more = 0; - if (count > 32) { - more = !0; - count = 32; - } - ptr = cs->tx_skb->data; - skb_pull(cs->tx_skb, count); - cs->tx_cnt += count; - cs->writeisacfifo(cs, ptr, count); - cs->writeisac(cs, ICC_CMDR, more ? 0x8 : 0xa); - if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - debugl1(cs, "icc_fill_fifo dbusytimer running"); - del_timer(&cs->dbusytimer); - } - cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); - add_timer(&cs->dbusytimer); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "icc_fill_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -void -icc_interrupt(struct IsdnCardState *cs, u_char val) -{ - u_char exval, v1; - struct sk_buff *skb; - unsigned int count; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ICC interrupt %x", val); - if (val & 0x80) { /* RME */ - exval = cs->readisac(cs, ICC_RSTA); - if ((exval & 0x70) != 0x20) { - if (exval & 0x40) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC RDO"); -#ifdef ERROR_STATISTIC - cs->err_rx++; -#endif - } - if (!(exval & 0x20)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC CRC error"); -#ifdef ERROR_STATISTIC - cs->err_crc++; -#endif - } - cs->writeisac(cs, ICC_CMDR, 0x80); - } else { - count = cs->readisac(cs, ICC_RBCL) & 0x1f; - if (count == 0) - count = 32; - icc_empty_fifo(cs, count); - if ((count = cs->rcvidx) > 0) { - cs->rcvidx = 0; - if (!(skb = alloc_skb(count, GFP_ATOMIC))) - printk(KERN_WARNING "HiSax: D receive out of memory\n"); - else { - skb_put_data(skb, cs->rcvbuf, count); - skb_queue_tail(&cs->rq, skb); - } - } - } - cs->rcvidx = 0; - schedule_event(cs, D_RCVBUFREADY); - } - if (val & 0x40) { /* RPF */ - icc_empty_fifo(cs, 32); - } - if (val & 0x20) { /* RSC */ - /* never */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC RSC interrupt"); - } - if (val & 0x10) { /* XPR */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - icc_fill_fifo(cs); - goto afterXPR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - icc_fill_fifo(cs); - } else - schedule_event(cs, D_XMTBUFREADY); - } -afterXPR: - if (val & 0x04) { /* CISQ */ - exval = cs->readisac(cs, ICC_CIR0); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ICC CIR0 %02X", exval); - if (exval & 2) { - cs->dc.icc.ph_state = (exval >> 2) & 0xf; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state change %x", cs->dc.icc.ph_state); - schedule_event(cs, D_L1STATECHANGE); - } - if (exval & 1) { - exval = cs->readisac(cs, ICC_CIR1); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ICC CIR1 %02X", exval); - } - } - if (val & 0x02) { /* SIN */ - /* never */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC SIN interrupt"); - } - if (val & 0x01) { /* EXI */ - exval = cs->readisac(cs, ICC_EXIR); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC EXIR %02x", exval); - if (exval & 0x80) { /* XMR */ - debugl1(cs, "ICC XMR"); - printk(KERN_WARNING "HiSax: ICC XMR\n"); - } - if (exval & 0x40) { /* XDU */ - debugl1(cs, "ICC XDU"); - printk(KERN_WARNING "HiSax: ICC XDU\n"); -#ifdef ERROR_STATISTIC - cs->err_tx++; -#endif - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { /* Restart frame */ - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; - icc_fill_fifo(cs); - } else { - printk(KERN_WARNING "HiSax: ICC XDU no skb\n"); - debugl1(cs, "ICC XDU no skb"); - } - } - if (exval & 0x04) { /* MOS */ - v1 = cs->readisac(cs, ICC_MOSR); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ICC MOSR %02x", v1); -#if ARCOFI_USE - if (v1 & 0x08) { - if (!cs->dc.icc.mon_rx) { - if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC MON RX out of memory!"); - cs->dc.icc.mocr &= 0xf0; - cs->dc.icc.mocr |= 0x0a; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - goto afterMONR0; - } else - cs->dc.icc.mon_rxp = 0; - } - if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { - cs->dc.icc.mocr &= 0xf0; - cs->dc.icc.mocr |= 0x0a; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mon_rxp = 0; - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC MON RX overflow!"); - goto afterMONR0; - } - cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR0); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ICC MOR0 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]); - if (cs->dc.icc.mon_rxp == 1) { - cs->dc.icc.mocr |= 0x04; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - } - } - afterMONR0: - if (v1 & 0x80) { - if (!cs->dc.icc.mon_rx) { - if (!(cs->dc.icc.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC))) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC MON RX out of memory!"); - cs->dc.icc.mocr &= 0x0f; - cs->dc.icc.mocr |= 0xa0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - goto afterMONR1; - } else - cs->dc.icc.mon_rxp = 0; - } - if (cs->dc.icc.mon_rxp >= MAX_MON_FRAME) { - cs->dc.icc.mocr &= 0x0f; - cs->dc.icc.mocr |= 0xa0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mon_rxp = 0; - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ICC MON RX overflow!"); - goto afterMONR1; - } - cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp++] = cs->readisac(cs, ICC_MOR1); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ICC MOR1 %02x", cs->dc.icc.mon_rx[cs->dc.icc.mon_rxp - 1]); - cs->dc.icc.mocr |= 0x40; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - } - afterMONR1: - if (v1 & 0x04) { - cs->dc.icc.mocr &= 0xf0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mocr |= 0x0a; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - schedule_event(cs, D_RX_MON0); - } - if (v1 & 0x40) { - cs->dc.icc.mocr &= 0x0f; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mocr |= 0xa0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - schedule_event(cs, D_RX_MON1); - } - if (v1 & 0x02) { - if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && - (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && - !(v1 & 0x08))) { - cs->dc.icc.mocr &= 0xf0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mocr |= 0x0a; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - if (cs->dc.icc.mon_txc && - (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) - schedule_event(cs, D_TX_MON0); - goto AfterMOX0; - } - if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { - schedule_event(cs, D_TX_MON0); - goto AfterMOX0; - } - cs->writeisac(cs, ICC_MOX0, - cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ICC %02x -> MOX0", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]); - } - AfterMOX0: - if (v1 & 0x20) { - if ((!cs->dc.icc.mon_tx) || (cs->dc.icc.mon_txc && - (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc) && - !(v1 & 0x80))) { - cs->dc.icc.mocr &= 0x0f; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - cs->dc.icc.mocr |= 0xa0; - cs->writeisac(cs, ICC_MOCR, cs->dc.icc.mocr); - if (cs->dc.icc.mon_txc && - (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) - schedule_event(cs, D_TX_MON1); - goto AfterMOX1; - } - if (cs->dc.icc.mon_txc && (cs->dc.icc.mon_txp >= cs->dc.icc.mon_txc)) { - schedule_event(cs, D_TX_MON1); - goto AfterMOX1; - } - cs->writeisac(cs, ICC_MOX1, - cs->dc.icc.mon_tx[cs->dc.icc.mon_txp++]); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ICC %02x -> MOX1", cs->dc.icc.mon_tx[cs->dc.icc.mon_txp - 1]); - } - AfterMOX1: ; -#endif - } - } -} - -static void -ICC_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - int val; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - icc_fill_fifo(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - icc_fill_fifo(cs); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - if ((cs->dc.icc.ph_state == ICC_IND_EI1) || - (cs->dc.icc.ph_state == ICC_IND_DR)) - ph_command(cs, ICC_CMD_DI); - else - ph_command(cs, ICC_CMD_RES); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, ICC_CMD_DI); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO1 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, ICC_CMD_AR); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, ICC_CMD_AI); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_TESTLOOP | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - val = 0; - if (1 & (long) arg) - val |= 0x0c; - if (2 & (long) arg) - val |= 0x3; - if (test_bit(HW_IOM1, &cs->HW_Flags)) { - /* IOM 1 Mode */ - if (!val) { - cs->writeisac(cs, ICC_SPCR, 0xa); - cs->writeisac(cs, ICC_ADF1, 0x2); - } else { - cs->writeisac(cs, ICC_SPCR, val); - cs->writeisac(cs, ICC_ADF1, 0xa); - } - } else { - /* IOM 2 Mode */ - cs->writeisac(cs, ICC_SPCR, val); - if (val) - cs->writeisac(cs, ICC_ADF1, 0x8); - else - cs->writeisac(cs, ICC_ADF1, 0x0); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_DEACTIVATE | RESPONSE): - skb_queue_purge(&cs->rq); - skb_queue_purge(&cs->sq); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - } - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "icc_l1hw unknown %04x", pr); - break; - } -} - -static void -setstack_icc(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = ICC_l1hw; -} - -static void -DC_Close_icc(struct IsdnCardState *cs) { - kfree(cs->dc.icc.mon_rx); - cs->dc.icc.mon_rx = NULL; - kfree(cs->dc.icc.mon_tx); - cs->dc.icc.mon_tx = NULL; -} - -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, dbusytimer); - struct PStack *stptr; - int rbch, star; - - if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbch = cs->readisac(cs, ICC_RBCH); - star = cs->readisac(cs, ICC_STAR); - if (cs->debug) - debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", - rbch, star); - if (rbch & ICC_RBCH_XAC) { /* D-Channel Busy */ - test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); - stptr = stptr->next; - } - } else { - /* discard frame; reset transceiver */ - test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } else { - printk(KERN_WARNING "HiSax: ICC D-Channel Busy no skb\n"); - debugl1(cs, "D-Channel Busy no skb"); - } - cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */ - cs->irq_func(cs->irq, cs); - } - } -} - -void -initicc(struct IsdnCardState *cs) -{ - cs->setstack_d = setstack_icc; - cs->DC_Close = DC_Close_icc; - cs->dc.icc.mon_tx = NULL; - cs->dc.icc.mon_rx = NULL; - cs->writeisac(cs, ICC_MASK, 0xff); - cs->dc.icc.mocr = 0xaa; - if (test_bit(HW_IOM1, &cs->HW_Flags)) { - /* IOM 1 Mode */ - cs->writeisac(cs, ICC_ADF2, 0x0); - cs->writeisac(cs, ICC_SPCR, 0xa); - cs->writeisac(cs, ICC_ADF1, 0x2); - cs->writeisac(cs, ICC_STCR, 0x70); - cs->writeisac(cs, ICC_MODE, 0xc9); - } else { - /* IOM 2 Mode */ - if (!cs->dc.icc.adf2) - cs->dc.icc.adf2 = 0x80; - cs->writeisac(cs, ICC_ADF2, cs->dc.icc.adf2); - cs->writeisac(cs, ICC_SQXR, 0xa0); - cs->writeisac(cs, ICC_SPCR, 0x20); - cs->writeisac(cs, ICC_STCR, 0x70); - cs->writeisac(cs, ICC_MODE, 0xca); - cs->writeisac(cs, ICC_TIMR, 0x00); - cs->writeisac(cs, ICC_ADF1, 0x20); - } - ph_command(cs, ICC_CMD_RES); - cs->writeisac(cs, ICC_MASK, 0x0); - ph_command(cs, ICC_CMD_DI); -} - -void -clear_pending_icc_ints(struct IsdnCardState *cs) -{ - int val, eval; - - val = cs->readisac(cs, ICC_STAR); - debugl1(cs, "ICC STAR %x", val); - val = cs->readisac(cs, ICC_MODE); - debugl1(cs, "ICC MODE %x", val); - val = cs->readisac(cs, ICC_ADF2); - debugl1(cs, "ICC ADF2 %x", val); - val = cs->readisac(cs, ICC_ISTA); - debugl1(cs, "ICC ISTA %x", val); - if (val & 0x01) { - eval = cs->readisac(cs, ICC_EXIR); - debugl1(cs, "ICC EXIR %x", eval); - } - val = cs->readisac(cs, ICC_CIR0); - debugl1(cs, "ICC CIR0 %x", val); - cs->dc.icc.ph_state = (val >> 2) & 0xf; - schedule_event(cs, D_L1STATECHANGE); - /* Disable all IRQ */ - cs->writeisac(cs, ICC_MASK, 0xFF); -} - -void setup_icc(struct IsdnCardState *cs) -{ - INIT_WORK(&cs->tqueue, icc_bh); - timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0); -} diff --git a/drivers/isdn/hisax/icc.h b/drivers/isdn/hisax/icc.h deleted file mode 100644 index f367df5d3669..000000000000 --- a/drivers/isdn/hisax/icc.h +++ /dev/null @@ -1,72 +0,0 @@ -/* $Id: icc.h,v 1.4.2.2 2004/01/12 22:52:26 keil Exp $ - * - * ICC specific routines - * - * Author Matt Henderson & Guy Ellis - * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * 1999.7.14 Initial implementation of routines for Siemens ISDN - * Communication Controller PEB 2070 based on the ISAC routines - * written by Karsten Keil. - */ - -/* All Registers original Siemens Spec */ - -#define ICC_MASK 0x20 -#define ICC_ISTA 0x20 -#define ICC_STAR 0x21 -#define ICC_CMDR 0x21 -#define ICC_EXIR 0x24 -#define ICC_ADF2 0x39 -#define ICC_SPCR 0x30 -#define ICC_ADF1 0x38 -#define ICC_CIR0 0x31 -#define ICC_CIX0 0x31 -#define ICC_CIR1 0x33 -#define ICC_CIX1 0x33 -#define ICC_STCR 0x37 -#define ICC_MODE 0x22 -#define ICC_RSTA 0x27 -#define ICC_RBCL 0x25 -#define ICC_RBCH 0x2A -#define ICC_TIMR 0x23 -#define ICC_SQXR 0x3b -#define ICC_MOSR 0x3a -#define ICC_MOCR 0x3a -#define ICC_MOR0 0x32 -#define ICC_MOX0 0x32 -#define ICC_MOR1 0x34 -#define ICC_MOX1 0x34 - -#define ICC_RBCH_XAC 0x80 - -#define ICC_CMD_TIM 0x0 -#define ICC_CMD_RES 0x1 -#define ICC_CMD_DU 0x3 -#define ICC_CMD_EI1 0x4 -#define ICC_CMD_SSP 0x5 -#define ICC_CMD_DT 0x6 -#define ICC_CMD_AR 0x8 -#define ICC_CMD_ARL 0xA -#define ICC_CMD_AI 0xC -#define ICC_CMD_DI 0xF - -#define ICC_IND_DR 0x0 -#define ICC_IND_FJ 0x2 -#define ICC_IND_EI1 0x4 -#define ICC_IND_INT 0x6 -#define ICC_IND_PU 0x7 -#define ICC_IND_AR 0x8 -#define ICC_IND_ARL 0xA -#define ICC_IND_AI 0xC -#define ICC_IND_AIL 0xE -#define ICC_IND_DC 0xF - -extern void ICCVersion(struct IsdnCardState *cs, char *s); -extern void initicc(struct IsdnCardState *cs); -extern void icc_interrupt(struct IsdnCardState *cs, u_char val); -extern void clear_pending_icc_ints(struct IsdnCardState *cs); -extern void setup_icc(struct IsdnCardState *); diff --git a/drivers/isdn/hisax/ipac.h b/drivers/isdn/hisax/ipac.h deleted file mode 100644 index 4f937f02ee34..000000000000 --- a/drivers/isdn/hisax/ipac.h +++ /dev/null @@ -1,29 +0,0 @@ -/* $Id: ipac.h,v 1.7.2.2 2004/01/12 22:52:26 keil Exp $ - * - * IPAC specific defines - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* All Registers original Siemens Spec */ - -#define IPAC_CONF 0xC0 -#define IPAC_MASK 0xC1 -#define IPAC_ISTA 0xC1 -#define IPAC_ID 0xC2 -#define IPAC_ACFG 0xC3 -#define IPAC_AOE 0xC4 -#define IPAC_ARX 0xC5 -#define IPAC_ATX 0xC5 -#define IPAC_PITA1 0xC6 -#define IPAC_PITA2 0xC7 -#define IPAC_POTA1 0xC8 -#define IPAC_POTA2 0xC9 -#define IPAC_PCFG 0xCA -#define IPAC_SCFG 0xCB -#define IPAC_TIMR2 0xCC diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c deleted file mode 100644 index c7086c1534bd..000000000000 --- a/drivers/isdn/hisax/ipacx.c +++ /dev/null @@ -1,913 +0,0 @@ -/* - * - * IPACX specific routines - * - * Author Joerg Petersohn - * Derived from hisax_isac.c, isac.c, hscx.c and others - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include "hisax_if.h" -#include "hisax.h" -#include "isdnl1.h" -#include "ipacx.h" - -#define DBUSY_TIMER_VALUE 80 -#define TIMER3_VALUE 7000 -#define MAX_DFRAME_LEN_L1 300 -#define B_FIFO_SIZE 64 -#define D_FIFO_SIZE 32 - - -// ipacx interrupt mask values -#define _MASK_IMASK 0x2E // global mask -#define _MASKB_IMASK 0x0B -#define _MASKD_IMASK 0x03 // all on - -//---------------------------------------------------------- -// local function declarations -//---------------------------------------------------------- -static void ph_command(struct IsdnCardState *cs, unsigned int command); -static inline void cic_int(struct IsdnCardState *cs); -static void dch_l2l1(struct PStack *st, int pr, void *arg); -static void dbusy_timer_handler(struct timer_list *t); -static void dch_empty_fifo(struct IsdnCardState *cs, int count); -static void dch_fill_fifo(struct IsdnCardState *cs); -static inline void dch_int(struct IsdnCardState *cs); -static void dch_setstack(struct PStack *st, struct IsdnCardState *cs); -static void dch_init(struct IsdnCardState *cs); -static void bch_l2l1(struct PStack *st, int pr, void *arg); -static void bch_empty_fifo(struct BCState *bcs, int count); -static void bch_fill_fifo(struct BCState *bcs); -static void bch_int(struct IsdnCardState *cs, u_char hscx); -static void bch_mode(struct BCState *bcs, int mode, int bc); -static void bch_close_state(struct BCState *bcs); -static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs); -static int bch_setstack(struct PStack *st, struct BCState *bcs); -static void bch_init(struct IsdnCardState *cs, int hscx); -static void clear_pending_ints(struct IsdnCardState *cs); - -//---------------------------------------------------------- -// Issue Layer 1 command to chip -//---------------------------------------------------------- -static void -ph_command(struct IsdnCardState *cs, unsigned int command) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_command (%#x) in (%#x)", command, - cs->dc.isac.ph_state); -//################################### -// printk(KERN_INFO "ph_command (%#x)\n", command); -//################################### - cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E); -} - -//---------------------------------------------------------- -// Transceiver interrupt handler -//---------------------------------------------------------- -static inline void -cic_int(struct IsdnCardState *cs) -{ - u_char event; - - event = cs->readisac(cs, IPACX_CIR0) >> 4; - if (cs->debug & L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event); -//######################################### -// printk(KERN_INFO "cic_int(%x)\n", event); -//######################################### - cs->dc.isac.ph_state = event; - schedule_event(cs, D_L1STATECHANGE); -} - -//========================================================== -// D channel functions -//========================================================== - -//---------------------------------------------------------- -// Command entry point -//---------------------------------------------------------- -static void -dch_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_char cda1_cr; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - dch_fill_fifo(cs); - } - break; - - case (PH_PULL | INDICATION): - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - break; - } - if (cs->debug & DEB_DLOG_HEX) LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - dch_fill_fifo(cs); - break; - - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG - if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - - case (HW_RESET | REQUEST): - case (HW_ENABLE | REQUEST): - if ((cs->dc.isac.ph_state == IPACX_IND_RES) || - (cs->dc.isac.ph_state == IPACX_IND_DR) || - (cs->dc.isac.ph_state == IPACX_IND_DC)) - ph_command(cs, IPACX_CMD_TIM); - else - ph_command(cs, IPACX_CMD_RES); - break; - - case (HW_INFO3 | REQUEST): - ph_command(cs, IPACX_CMD_AR8); - break; - - case (HW_TESTLOOP | REQUEST): - cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1 - cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1 - cda1_cr = cs->readisac(cs, IPACX_CDA1_CR); - (void) cs->readisac(cs, IPACX_CDA2_CR); - if ((long)arg & 1) { // loop B1 - cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x0a); - } - else { // B1 off - cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x0a); - } - if ((long)arg & 2) { // loop B2 - cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr | 0x14); - } - else { // B2 off - cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr & ~0x14); - } - break; - - case (HW_DEACTIVATE | RESPONSE): - skb_queue_purge(&cs->rq); - skb_queue_purge(&cs->sq); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - } - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - break; - - default: - if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr); - break; - } -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, dbusytimer); - struct PStack *st; - int rbchd, stard; - - if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbchd = cs->readisac(cs, IPACX_RBCHD); - stard = cs->readisac(cs, IPACX_STARD); - if (cs->debug) - debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard); - if (!(stard & 0x40)) { // D-Channel Busy - set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - for (st = cs->stlist; st; st = st->next) { - st->l1.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on - } - } else { - // seems we lost an interrupt; reset transceiver */ - clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } else { - printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n"); - debugl1(cs, "D-Channel Busy no skb"); - } - cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR - } - } -} - -//---------------------------------------------------------- -// Fill buffer from receive FIFO -//---------------------------------------------------------- -static void -dch_empty_fifo(struct IsdnCardState *cs, int count) -{ - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "dch_empty_fifo()"); - - // message too large, remove - if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "dch_empty_fifo() incoming message too large"); - cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC - cs->rcvidx = 0; - return; - } - - ptr = cs->rcvbuf + cs->rcvidx; - cs->rcvidx += count; - - cs->readisacfifo(cs, ptr, count); - cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC - - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "dch_empty_fifo() cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -//---------------------------------------------------------- -// Fill transmit FIFO -//---------------------------------------------------------- -static void -dch_fill_fifo(struct IsdnCardState *cs) -{ - int count; - u_char cmd, *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "dch_fill_fifo()"); - - if (!cs->tx_skb) return; - count = cs->tx_skb->len; - if (count <= 0) return; - - if (count > D_FIFO_SIZE) { - count = D_FIFO_SIZE; - cmd = 0x08; // XTF - } else { - cmd = 0x0A; // XTF | XME - } - - ptr = cs->tx_skb->data; - skb_pull(cs->tx_skb, count); - cs->tx_cnt += count; - cs->writeisacfifo(cs, ptr, count); - cs->writeisac(cs, IPACX_CMDRD, cmd); - - // set timeout for transmission contol - if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - debugl1(cs, "dch_fill_fifo dbusytimer running"); - del_timer(&cs->dbusytimer); - } - cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); - add_timer(&cs->dbusytimer); - - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "dch_fill_fifo() cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -//---------------------------------------------------------- -// D channel interrupt handler -//---------------------------------------------------------- -static inline void -dch_int(struct IsdnCardState *cs) -{ - struct sk_buff *skb; - u_char istad, rstad; - int count; - - istad = cs->readisac(cs, IPACX_ISTAD); -//############################################## -// printk(KERN_WARNING "dch_int(istad=%02x)\n", istad); -//############################################## - - if (istad & 0x80) { // RME - rstad = cs->readisac(cs, IPACX_RSTAD); - if ((rstad & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB) - if (!(rstad & 0x80)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "dch_int(): invalid frame"); - if ((rstad & 0x40)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "dch_int(): RDO"); - if (!(rstad & 0x20)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "dch_int(): CRC error"); - cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC - } else { // received frame ok - count = cs->readisac(cs, IPACX_RBCLD); - if (count) count--; // RSTAB is last byte - count &= D_FIFO_SIZE - 1; - if (count == 0) count = D_FIFO_SIZE; - dch_empty_fifo(cs, count); - if ((count = cs->rcvidx) > 0) { - cs->rcvidx = 0; - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n"); - else { - skb_put_data(skb, cs->rcvbuf, count); - skb_queue_tail(&cs->rq, skb); - } - } - } - cs->rcvidx = 0; - schedule_event(cs, D_RCVBUFREADY); - } - - if (istad & 0x40) { // RPF - dch_empty_fifo(cs, D_FIFO_SIZE); - } - - if (istad & 0x20) { // RFO - if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): RFO"); - cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES - } - - if (istad & 0x10) { // XPR - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - dch_fill_fifo(cs); - goto afterXPR; - } - else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_skb = NULL; - cs->tx_cnt = 0; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - dch_fill_fifo(cs); - } - else { - schedule_event(cs, D_XMTBUFREADY); - } - } -afterXPR: - - if (istad & 0x0C) { // XDU or XMR - if (cs->debug & L1_DEB_WARN) debugl1(cs, "dch_int(): XDU"); - if (cs->tx_skb) { - skb_push(cs->tx_skb, cs->tx_cnt); // retransmit - cs->tx_cnt = 0; - dch_fill_fifo(cs); - } else { - printk(KERN_WARNING "HiSax: ISAC XDU no skb\n"); - debugl1(cs, "ISAC XDU no skb"); - } - } -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -dch_setstack(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = dch_l2l1; -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -dch_init(struct IsdnCardState *cs) -{ - printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n"); - - cs->setstack_d = dch_setstack; - - timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0); - - cs->writeisac(cs, IPACX_TR_CONF0, 0x00); // clear LDD - cs->writeisac(cs, IPACX_TR_CONF2, 0x00); // enable transmitter - cs->writeisac(cs, IPACX_MODED, 0xC9); // transparent mode 0, RAC, stop/go - cs->writeisac(cs, IPACX_MON_CR, 0x00); // disable monitor channel -} - - -//========================================================== -// B channel functions -//========================================================== - -//---------------------------------------------------------- -// Entry point for commands -//---------------------------------------------------------- -static void -bch_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.hscx.count = 0; - bch_fill_fifo(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n"); - } else { - set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->hw.hscx.count = 0; - bch_fill_fifo(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - set_bit(BC_FLG_ACTIV, &bcs->Flag); - bch_mode(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - clear_bit(BC_FLG_ACTIV, &bcs->Flag); - clear_bit(BC_FLG_BUSY, &bcs->Flag); - bch_mode(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -//---------------------------------------------------------- -// Read B channel fifo to receive buffer -//---------------------------------------------------------- -static void -bch_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr, hscx; - struct IsdnCardState *cs; - int cnt; - - cs = bcs->cs; - hscx = bcs->hw.hscx.hscx; - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "bch_empty_fifo()"); - - // message too large, remove - if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_empty_fifo() incoming packet too large"); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC - bcs->hw.hscx.rcvidx = 0; - return; - } - - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - cnt = count; - while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC - - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - bcs->hw.hscx.rcvidx += count; - - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -//---------------------------------------------------------- -// Fill buffer to transmit FIFO -//---------------------------------------------------------- -static void -bch_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs; - int more, count, cnt; - u_char *ptr, *p, hscx; - - cs = bcs->cs; - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "bch_fill_fifo()"); - - if (!bcs->tx_skb) return; - if (bcs->tx_skb->len <= 0) return; - - hscx = bcs->hw.hscx.hscx; - more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->tx_skb->len > B_FIFO_SIZE) { - more = 1; - count = B_FIFO_SIZE; - } else { - count = bcs->tx_skb->len; - } - cnt = count; - - p = ptr = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.hscx.count += count; - while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a)); - - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "%s() B-%d cnt %d", __func__, hscx, count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -//---------------------------------------------------------- -// B channel interrupt handler -//---------------------------------------------------------- -static void -bch_int(struct IsdnCardState *cs, u_char hscx) -{ - u_char istab; - struct BCState *bcs; - struct sk_buff *skb; - int count; - u_char rstab; - - bcs = cs->bcs + hscx; - istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB); -//############################################## -// printk(KERN_WARNING "bch_int(istab=%02x)\n", istab); -//############################################## - if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return; - - if (istab & 0x80) { // RME - rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB); - if ((rstab & 0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB) - if (!(rstab & 0x80)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: invalid frame", hscx); - if ((rstab & 0x40) && (bcs->mode != L1_MODE_NULL)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode); - if (!(rstab & 0x20)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: CRC error", hscx); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80); // RMC - } - else { // received frame ok - count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) & (B_FIFO_SIZE - 1); - if (count == 0) count = B_FIFO_SIZE; - bch_empty_fifo(bcs, count); - if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "bch_int Frame %d", count); - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - count); - skb_queue_tail(&bcs->rqueue, skb); - } - } - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - - if (istab & 0x40) { // RPF - bch_empty_fifo(bcs, B_FIFO_SIZE); - - if (bcs->mode == L1_MODE_TRANS) { // queue every chunk - // receive transparent audio data - if (!(skb = dev_alloc_skb(B_FIFO_SIZE))) - printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - B_FIFO_SIZE); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - } - - if (istab & 0x20) { // RFO - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d: RFO error", hscx); - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40); // RRES - } - - if (istab & 0x10) { // XPR - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - bch_fill_fifo(bcs); - goto afterXPR; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hscx.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hscx.count = 0; - bcs->tx_skb = NULL; - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - set_bit(BC_FLG_BUSY, &bcs->Flag); - bch_fill_fifo(bcs); - } else { - clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -afterXPR: - - if (istab & 0x04) { // XDU - if (bcs->mode == L1_MODE_TRANS) { - bch_fill_fifo(bcs); - } - else { - if (bcs->tx_skb) { // restart transmitting the whole frame - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01); // XRES - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "bch_int() B-%d XDU error", hscx); - } - } -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -bch_mode(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int hscx = bcs->hw.hscx.hscx; - - bc = bc ? 1 : 0; // in case bc is greater than 1 - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "mode_bch() switch B-%d mode %d chan %d", hscx, mode, bc); - bcs->mode = mode; - bcs->channel = bc; - - // map controller to according timeslot - if (!hscx) - { - cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc); - cs->writeisac(cs, IPACX_BCHA_CR, 0x88); - } - else - { - cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc); - cs->writeisac(cs, IPACX_BCHB_CR, 0x88); - } - - switch (mode) { - case (L1_MODE_NULL): - cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0); // rec off - cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x30); // std adj. - cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF); // ints off - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments - break; - case (L1_MODE_TRANS): - cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88); // ext transp mode - cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x00); // xxx00000 - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments - cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK); - break; - case (L1_MODE_HDLC): - cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8); // transp mode 0 - cs->BC_Write_Reg(cs, hscx, IPACX_EXMB, 0x01); // idle=hdlc flags crc enabled - cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41); // validate adjustments - cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK); - break; - } -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -bch_close_state(struct BCState *bcs) -{ - bch_mode(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - kfree(bcs->blog); - bcs->blog = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static int -bch_open_state(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax open_bchstate(): No memory for hscx.rcvbuf\n"); - clear_bit(BC_FLG_INIT, &bcs->Flag); - return (1); - } - if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax open_bchstate: No memory for bcs->blog\n"); - clear_bit(BC_FLG_INIT, &bcs->Flag); - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - return (2); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.hscx.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static int -bch_setstack(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (bch_open_state(st->l1.hardware, bcs)) return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = bch_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -//---------------------------------------------------------- -//---------------------------------------------------------- -static void -bch_init(struct IsdnCardState *cs, int hscx) -{ - cs->bcs[hscx].BC_SetStack = bch_setstack; - cs->bcs[hscx].BC_Close = bch_close_state; - cs->bcs[hscx].hw.hscx.hscx = hscx; - cs->bcs[hscx].cs = cs; - bch_mode(cs->bcs + hscx, 0, hscx); -} - - -//========================================================== -// Shared functions -//========================================================== - -//---------------------------------------------------------- -// Main interrupt handler -//---------------------------------------------------------- -void -interrupt_ipacx(struct IsdnCardState *cs) -{ - u_char ista; - - while ((ista = cs->readisac(cs, IPACX_ISTA))) { -//################################################# -// printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista); -//################################################# - if (ista & 0x80) bch_int(cs, 0); // B channel interrupts - if (ista & 0x40) bch_int(cs, 1); - - if (ista & 0x01) dch_int(cs); // D channel - if (ista & 0x10) cic_int(cs); // Layer 1 state - } -} - -//---------------------------------------------------------- -// Clears chip interrupt status -//---------------------------------------------------------- -static void -clear_pending_ints(struct IsdnCardState *cs) -{ - int ista; - - // all interrupts off - cs->writeisac(cs, IPACX_MASK, 0xff); - cs->writeisac(cs, IPACX_MASKD, 0xff); - cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff); - cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff); - - ista = cs->readisac(cs, IPACX_ISTA); - if (ista & 0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB); - if (ista & 0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB); - if (ista & 0x10) cs->readisac(cs, IPACX_CIR0); - if (ista & 0x01) cs->readisac(cs, IPACX_ISTAD); -} - -//---------------------------------------------------------- -// Does chip configuration work -// Work to do depends on bit mask in part -//---------------------------------------------------------- -void -init_ipacx(struct IsdnCardState *cs, int part) -{ - if (part & 1) { // initialise chip -//################################################## -// printk(KERN_INFO "init_ipacx(%x)\n", part); -//################################################## - clear_pending_ints(cs); - bch_init(cs, 0); - bch_init(cs, 1); - dch_init(cs); - } - if (part & 2) { // reenable all interrupts and start chip - cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK); - cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK); - cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK); - cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register - - // reset HDLC Transmitters/receivers - cs->writeisac(cs, IPACX_CMDRD, 0x41); - cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41); - cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41); - ph_command(cs, IPACX_CMD_RES); - } -} - -//----------------- end of file ----------------------- diff --git a/drivers/isdn/hisax/ipacx.h b/drivers/isdn/hisax/ipacx.h deleted file mode 100644 index e8a22e8f34b6..000000000000 --- a/drivers/isdn/hisax/ipacx.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * - * IPACX specific defines - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* All Registers original Siemens Spec */ - -#ifndef INCLUDE_IPACX_H -#define INCLUDE_IPACX_H - -/* D-channel registers */ -#define IPACX_RFIFOD 0x00 /* RD */ -#define IPACX_XFIFOD 0x00 /* WR */ -#define IPACX_ISTAD 0x20 /* RD */ -#define IPACX_MASKD 0x20 /* WR */ -#define IPACX_STARD 0x21 /* RD */ -#define IPACX_CMDRD 0x21 /* WR */ -#define IPACX_MODED 0x22 /* RD/WR */ -#define IPACX_EXMD1 0x23 /* RD/WR */ -#define IPACX_TIMR1 0x24 /* RD/WR */ -#define IPACX_SAP1 0x25 /* WR */ -#define IPACX_SAP2 0x26 /* WR */ -#define IPACX_RBCLD 0x26 /* RD */ -#define IPACX_RBCHD 0x27 /* RD */ -#define IPACX_TEI1 0x27 /* WR */ -#define IPACX_TEI2 0x28 /* WR */ -#define IPACX_RSTAD 0x28 /* RD */ -#define IPACX_TMD 0x29 /* RD/WR */ -#define IPACX_CIR0 0x2E /* RD */ -#define IPACX_CIX0 0x2E /* WR */ -#define IPACX_CIR1 0x2F /* RD */ -#define IPACX_CIX1 0x2F /* WR */ - -/* Transceiver registers */ -#define IPACX_TR_CONF0 0x30 /* RD/WR */ -#define IPACX_TR_CONF1 0x31 /* RD/WR */ -#define IPACX_TR_CONF2 0x32 /* RD/WR */ -#define IPACX_TR_STA 0x33 /* RD */ -#define IPACX_TR_CMD 0x34 /* RD/WR */ -#define IPACX_SQRR1 0x35 /* RD */ -#define IPACX_SQXR1 0x35 /* WR */ -#define IPACX_SQRR2 0x36 /* RD */ -#define IPACX_SQXR2 0x36 /* WR */ -#define IPACX_SQRR3 0x37 /* RD */ -#define IPACX_SQXR3 0x37 /* WR */ -#define IPACX_ISTATR 0x38 /* RD */ -#define IPACX_MASKTR 0x39 /* RD/WR */ -#define IPACX_TR_MODE 0x3A /* RD/WR */ -#define IPACX_ACFG1 0x3C /* RD/WR */ -#define IPACX_ACFG2 0x3D /* RD/WR */ -#define IPACX_AOE 0x3E /* RD/WR */ -#define IPACX_ARX 0x3F /* RD */ -#define IPACX_ATX 0x3F /* WR */ - -/* IOM: Timeslot, DPS, CDA */ -#define IPACX_CDA10 0x40 /* RD/WR */ -#define IPACX_CDA11 0x41 /* RD/WR */ -#define IPACX_CDA20 0x42 /* RD/WR */ -#define IPACX_CDA21 0x43 /* RD/WR */ -#define IPACX_CDA_TSDP10 0x44 /* RD/WR */ -#define IPACX_CDA_TSDP11 0x45 /* RD/WR */ -#define IPACX_CDA_TSDP20 0x46 /* RD/WR */ -#define IPACX_CDA_TSDP21 0x47 /* RD/WR */ -#define IPACX_BCHA_TSDP_BC1 0x48 /* RD/WR */ -#define IPACX_BCHA_TSDP_BC2 0x49 /* RD/WR */ -#define IPACX_BCHB_TSDP_BC1 0x4A /* RD/WR */ -#define IPACX_BCHB_TSDP_BC2 0x4B /* RD/WR */ -#define IPACX_TR_TSDP_BC1 0x4C /* RD/WR */ -#define IPACX_TR_TSDP_BC2 0x4D /* RD/WR */ -#define IPACX_CDA1_CR 0x4E /* RD/WR */ -#define IPACX_CDA2_CR 0x4F /* RD/WR */ - -/* IOM: Contol, Sync transfer, Monitor */ -#define IPACX_TR_CR 0x50 /* RD/WR */ -#define IPACX_TRC_CR 0x50 /* RD/WR */ -#define IPACX_BCHA_CR 0x51 /* RD/WR */ -#define IPACX_BCHB_CR 0x52 /* RD/WR */ -#define IPACX_DCI_CR 0x53 /* RD/WR */ -#define IPACX_DCIC_CR 0x53 /* RD/WR */ -#define IPACX_MON_CR 0x54 /* RD/WR */ -#define IPACX_SDS1_CR 0x55 /* RD/WR */ -#define IPACX_SDS2_CR 0x56 /* RD/WR */ -#define IPACX_IOM_CR 0x57 /* RD/WR */ -#define IPACX_STI 0x58 /* RD */ -#define IPACX_ASTI 0x58 /* WR */ -#define IPACX_MSTI 0x59 /* RD/WR */ -#define IPACX_SDS_CONF 0x5A /* RD/WR */ -#define IPACX_MCDA 0x5B /* RD */ -#define IPACX_MOR 0x5C /* RD */ -#define IPACX_MOX 0x5C /* WR */ -#define IPACX_MOSR 0x5D /* RD */ -#define IPACX_MOCR 0x5E /* RD/WR */ -#define IPACX_MSTA 0x5F /* RD */ -#define IPACX_MCONF 0x5F /* WR */ - -/* Interrupt and general registers */ -#define IPACX_ISTA 0x60 /* RD */ -#define IPACX_MASK 0x60 /* WR */ -#define IPACX_AUXI 0x61 /* RD */ -#define IPACX_AUXM 0x61 /* WR */ -#define IPACX_MODE1 0x62 /* RD/WR */ -#define IPACX_MODE2 0x63 /* RD/WR */ -#define IPACX_ID 0x64 /* RD */ -#define IPACX_SRES 0x64 /* WR */ -#define IPACX_TIMR2 0x65 /* RD/WR */ - -/* B-channel registers */ -#define IPACX_OFF_B1 0x70 -#define IPACX_OFF_B2 0x80 - -#define IPACX_ISTAB 0x00 /* RD */ -#define IPACX_MASKB 0x00 /* WR */ -#define IPACX_STARB 0x01 /* RD */ -#define IPACX_CMDRB 0x01 /* WR */ -#define IPACX_MODEB 0x02 /* RD/WR */ -#define IPACX_EXMB 0x03 /* RD/WR */ -#define IPACX_RAH1 0x05 /* WR */ -#define IPACX_RAH2 0x06 /* WR */ -#define IPACX_RBCLB 0x06 /* RD */ -#define IPACX_RBCHB 0x07 /* RD */ -#define IPACX_RAL1 0x07 /* WR */ -#define IPACX_RAL2 0x08 /* WR */ -#define IPACX_RSTAB 0x08 /* RD */ -#define IPACX_TMB 0x09 /* RD/WR */ -#define IPACX_RFIFOB 0x0A /*- RD */ -#define IPACX_XFIFOB 0x0A /*- WR */ - -/* Layer 1 Commands */ -#define IPACX_CMD_TIM 0x0 -#define IPACX_CMD_RES 0x1 -#define IPACX_CMD_SSP 0x2 -#define IPACX_CMD_SCP 0x3 -#define IPACX_CMD_AR8 0x8 -#define IPACX_CMD_AR10 0x9 -#define IPACX_CMD_ARL 0xa -#define IPACX_CMD_DI 0xf - -/* Layer 1 Indications */ -#define IPACX_IND_DR 0x0 -#define IPACX_IND_RES 0x1 -#define IPACX_IND_TMA 0x2 -#define IPACX_IND_SLD 0x3 -#define IPACX_IND_RSY 0x4 -#define IPACX_IND_DR6 0x5 -#define IPACX_IND_PU 0x7 -#define IPACX_IND_AR 0x8 -#define IPACX_IND_ARL 0xa -#define IPACX_IND_CVR 0xb -#define IPACX_IND_AI8 0xc -#define IPACX_IND_AI10 0xd -#define IPACX_IND_AIL 0xe -#define IPACX_IND_DC 0xf - -extern void init_ipacx(struct IsdnCardState *, int); -extern void interrupt_ipacx(struct IsdnCardState *); -extern void setup_isac(struct IsdnCardState *); - -#endif diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c deleted file mode 100644 index bd40e0671ded..000000000000 --- a/drivers/isdn/hisax/isac.c +++ /dev/null @@ -1,681 +0,0 @@ -/* $Id: isac.c,v 1.31.2.3 2004/01/13 14:31:25 keil Exp $ - * - * ISAC specific routines - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.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 - * - */ - -#include "hisax.h" -#include "isac.h" -#include "arcofi.h" -#include "isdnl1.h" -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/init.h> - -#define DBUSY_TIMER_VALUE 80 -#define ARCOFI_USE 1 - -static char *ISACVer[] = -{"2086/2186 V1.1", "2085 B1", "2085 B2", - "2085 V2.3"}; - -void ISACVersion(struct IsdnCardState *cs, char *s) -{ - int val; - - val = cs->readisac(cs, ISAC_RBCH); - printk(KERN_INFO "%s ISAC version (%x): %s\n", s, val, ISACVer[(val >> 5) & 3]); -} - -static void -ph_command(struct IsdnCardState *cs, unsigned int command) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_command %x", command); - cs->writeisac(cs, ISAC_CIX0, (command << 2) | 3); -} - - -static void -isac_new_ph(struct IsdnCardState *cs) -{ - switch (cs->dc.isac.ph_state) { - case (ISAC_IND_RS): - case (ISAC_IND_EI): - ph_command(cs, ISAC_CMD_DUI); - l1_msg(cs, HW_RESET | INDICATION, NULL); - break; - case (ISAC_IND_DID): - l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); - break; - case (ISAC_IND_DR): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (ISAC_IND_PU): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (ISAC_IND_RSY): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (ISAC_IND_ARD): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (ISAC_IND_AI8): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - case (ISAC_IND_AI10): - l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL); - break; - default: - break; - } -} - -static void -isac_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - struct PStack *stptr; - - if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { - if (cs->debug) - debugl1(cs, "D-Channel Busy cleared"); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); - stptr = stptr->next; - } - } - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) - isac_new_ph(cs); - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -#if ARCOFI_USE - if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) - return; - if (test_and_clear_bit(D_RX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_RX_END, NULL); - if (test_and_clear_bit(D_TX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_TX_END, NULL); -#endif -} - -static void -isac_empty_fifo(struct IsdnCardState *cs, int count) -{ - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "isac_empty_fifo"); - - if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isac_empty_fifo overrun %d", - cs->rcvidx + count); - cs->writeisac(cs, ISAC_CMDR, 0x80); - cs->rcvidx = 0; - return; - } - ptr = cs->rcvbuf + cs->rcvidx; - cs->rcvidx += count; - cs->readisacfifo(cs, ptr, count); - cs->writeisac(cs, ISAC_CMDR, 0x80); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "isac_empty_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -static void -isac_fill_fifo(struct IsdnCardState *cs) -{ - int count, more; - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "isac_fill_fifo"); - - if (!cs->tx_skb) - return; - - count = cs->tx_skb->len; - if (count <= 0) - return; - - more = 0; - if (count > 32) { - more = !0; - count = 32; - } - ptr = cs->tx_skb->data; - skb_pull(cs->tx_skb, count); - cs->tx_cnt += count; - cs->writeisacfifo(cs, ptr, count); - cs->writeisac(cs, ISAC_CMDR, more ? 0x8 : 0xa); - if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - debugl1(cs, "isac_fill_fifo dbusytimer running"); - del_timer(&cs->dbusytimer); - } - cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000); - add_timer(&cs->dbusytimer); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "isac_fill_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -void -isac_interrupt(struct IsdnCardState *cs, u_char val) -{ - u_char exval, v1; - struct sk_buff *skb; - unsigned int count; - - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC interrupt %x", val); - if (val & 0x80) { /* RME */ - exval = cs->readisac(cs, ISAC_RSTA); - if ((exval & 0x70) != 0x20) { - if (exval & 0x40) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC RDO"); -#ifdef ERROR_STATISTIC - cs->err_rx++; -#endif - } - if (!(exval & 0x20)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC CRC error"); -#ifdef ERROR_STATISTIC - cs->err_crc++; -#endif - } - cs->writeisac(cs, ISAC_CMDR, 0x80); - } else { - count = cs->readisac(cs, ISAC_RBCL) & 0x1f; - if (count == 0) - count = 32; - isac_empty_fifo(cs, count); - count = cs->rcvidx; - if (count > 0) { - cs->rcvidx = 0; - skb = alloc_skb(count, GFP_ATOMIC); - if (!skb) - printk(KERN_WARNING "HiSax: D receive out of memory\n"); - else { - skb_put_data(skb, cs->rcvbuf, count); - skb_queue_tail(&cs->rq, skb); - } - } - } - cs->rcvidx = 0; - schedule_event(cs, D_RCVBUFREADY); - } - if (val & 0x40) { /* RPF */ - isac_empty_fifo(cs, 32); - } - if (val & 0x20) { /* RSC */ - /* never */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC RSC interrupt"); - } - if (val & 0x10) { /* XPR */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - isac_fill_fifo(cs); - goto afterXPR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - cs->tx_skb = skb_dequeue(&cs->sq); - if (cs->tx_skb) { - cs->tx_cnt = 0; - isac_fill_fifo(cs); - } else - schedule_event(cs, D_XMTBUFREADY); - } -afterXPR: - if (val & 0x04) { /* CISQ */ - exval = cs->readisac(cs, ISAC_CIR0); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC CIR0 %02X", exval); - if (exval & 2) { - cs->dc.isac.ph_state = (exval >> 2) & 0xf; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state change %x", cs->dc.isac.ph_state); - schedule_event(cs, D_L1STATECHANGE); - } - if (exval & 1) { - exval = cs->readisac(cs, ISAC_CIR1); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC CIR1 %02X", exval); - } - } - if (val & 0x02) { /* SIN */ - /* never */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC SIN interrupt"); - } - if (val & 0x01) { /* EXI */ - exval = cs->readisac(cs, ISAC_EXIR); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC EXIR %02x", exval); - if (exval & 0x80) { /* XMR */ - debugl1(cs, "ISAC XMR"); - printk(KERN_WARNING "HiSax: ISAC XMR\n"); - } - if (exval & 0x40) { /* XDU */ - debugl1(cs, "ISAC XDU"); - printk(KERN_WARNING "HiSax: ISAC XDU\n"); -#ifdef ERROR_STATISTIC - cs->err_tx++; -#endif - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { /* Restart frame */ - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; - isac_fill_fifo(cs); - } else { - printk(KERN_WARNING "HiSax: ISAC XDU no skb\n"); - debugl1(cs, "ISAC XDU no skb"); - } - } - if (exval & 0x04) { /* MOS */ - v1 = cs->readisac(cs, ISAC_MOSR); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ISAC MOSR %02x", v1); -#if ARCOFI_USE - if (v1 & 0x08) { - if (!cs->dc.isac.mon_rx) { - cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); - if (!cs->dc.isac.mon_rx) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC MON RX out of memory!"); - cs->dc.isac.mocr &= 0xf0; - cs->dc.isac.mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - goto afterMONR0; - } else - cs->dc.isac.mon_rxp = 0; - } - if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) { - cs->dc.isac.mocr &= 0xf0; - cs->dc.isac.mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mon_rxp = 0; - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC MON RX overflow!"); - goto afterMONR0; - } - cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR0); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ISAC MOR0 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]); - if (cs->dc.isac.mon_rxp == 1) { - cs->dc.isac.mocr |= 0x04; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - } - } - afterMONR0: - if (v1 & 0x80) { - if (!cs->dc.isac.mon_rx) { - cs->dc.isac.mon_rx = kmalloc(MAX_MON_FRAME, GFP_ATOMIC); - if (!cs->dc.isac.mon_rx) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC MON RX out of memory!"); - cs->dc.isac.mocr &= 0x0f; - cs->dc.isac.mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - goto afterMONR1; - } else - cs->dc.isac.mon_rxp = 0; - } - if (cs->dc.isac.mon_rxp >= MAX_MON_FRAME) { - cs->dc.isac.mocr &= 0x0f; - cs->dc.isac.mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mon_rxp = 0; - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "ISAC MON RX overflow!"); - goto afterMONR1; - } - cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp++] = cs->readisac(cs, ISAC_MOR1); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ISAC MOR1 %02x", cs->dc.isac.mon_rx[cs->dc.isac.mon_rxp - 1]); - cs->dc.isac.mocr |= 0x40; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - } - afterMONR1: - if (v1 & 0x04) { - cs->dc.isac.mocr &= 0xf0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - schedule_event(cs, D_RX_MON0); - } - if (v1 & 0x40) { - cs->dc.isac.mocr &= 0x0f; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - schedule_event(cs, D_RX_MON1); - } - if (v1 & 0x02) { - if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && - (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && - !(v1 & 0x08))) { - cs->dc.isac.mocr &= 0xf0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mocr |= 0x0a; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - if (cs->dc.isac.mon_txc && - (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) - schedule_event(cs, D_TX_MON0); - goto AfterMOX0; - } - if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) { - schedule_event(cs, D_TX_MON0); - goto AfterMOX0; - } - cs->writeisac(cs, ISAC_MOX0, - cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ISAC %02x -> MOX0", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]); - } - AfterMOX0: - if (v1 & 0x20) { - if ((!cs->dc.isac.mon_tx) || (cs->dc.isac.mon_txc && - (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc) && - !(v1 & 0x80))) { - cs->dc.isac.mocr &= 0x0f; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - cs->dc.isac.mocr |= 0xa0; - cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr); - if (cs->dc.isac.mon_txc && - (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) - schedule_event(cs, D_TX_MON1); - goto AfterMOX1; - } - if (cs->dc.isac.mon_txc && (cs->dc.isac.mon_txp >= cs->dc.isac.mon_txc)) { - schedule_event(cs, D_TX_MON1); - goto AfterMOX1; - } - cs->writeisac(cs, ISAC_MOX1, - cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]); - if (cs->debug & L1_DEB_MONITOR) - debugl1(cs, "ISAC %02x -> MOX1", cs->dc.isac.mon_tx[cs->dc.isac.mon_txp - 1]); - } - AfterMOX1:; -#endif - } - } -} - -static void -ISAC_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - int val; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - isac_fill_fifo(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - } else { - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - isac_fill_fifo(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - if ((cs->dc.isac.ph_state == ISAC_IND_EI) || - (cs->dc.isac.ph_state == ISAC_IND_DR) || - (cs->dc.isac.ph_state == ISAC_IND_RS)) - ph_command(cs, ISAC_CMD_TIM); - else - ph_command(cs, ISAC_CMD_RS); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, ISAC_CMD_TIM); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, ISAC_CMD_AR8); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_TESTLOOP | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - val = 0; - if (1 & (long) arg) - val |= 0x0c; - if (2 & (long) arg) - val |= 0x3; - if (test_bit(HW_IOM1, &cs->HW_Flags)) { - /* IOM 1 Mode */ - if (!val) { - cs->writeisac(cs, ISAC_SPCR, 0xa); - cs->writeisac(cs, ISAC_ADF1, 0x2); - } else { - cs->writeisac(cs, ISAC_SPCR, val); - cs->writeisac(cs, ISAC_ADF1, 0xa); - } - } else { - /* IOM 2 Mode */ - cs->writeisac(cs, ISAC_SPCR, val); - if (val) - cs->writeisac(cs, ISAC_ADF1, 0x8); - else - cs->writeisac(cs, ISAC_ADF1, 0x0); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_DEACTIVATE | RESPONSE): - skb_queue_purge(&cs->rq); - skb_queue_purge(&cs->sq); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - } - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isac_l1hw unknown %04x", pr); - break; - } -} - -static void -setstack_isac(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = ISAC_l1hw; -} - -static void -DC_Close_isac(struct IsdnCardState *cs) -{ - kfree(cs->dc.isac.mon_rx); - cs->dc.isac.mon_rx = NULL; - kfree(cs->dc.isac.mon_tx); - cs->dc.isac.mon_tx = NULL; -} - -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, dbusytimer); - struct PStack *stptr; - int rbch, star; - - if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbch = cs->readisac(cs, ISAC_RBCH); - star = cs->readisac(cs, ISAC_STAR); - if (cs->debug) - debugl1(cs, "D-Channel Busy RBCH %02x STAR %02x", - rbch, star); - if (rbch & ISAC_RBCH_XAC) { /* D-Channel Busy */ - test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); - stptr = stptr->next; - } - } else { - /* discard frame; reset transceiver */ - test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } else { - printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n"); - debugl1(cs, "D-Channel Busy no skb"); - } - cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */ - cs->irq_func(cs->irq, cs); - } - } -} - -void initisac(struct IsdnCardState *cs) -{ - cs->setstack_d = setstack_isac; - cs->DC_Close = DC_Close_isac; - cs->dc.isac.mon_tx = NULL; - cs->dc.isac.mon_rx = NULL; - cs->writeisac(cs, ISAC_MASK, 0xff); - cs->dc.isac.mocr = 0xaa; - if (test_bit(HW_IOM1, &cs->HW_Flags)) { - /* IOM 1 Mode */ - cs->writeisac(cs, ISAC_ADF2, 0x0); - cs->writeisac(cs, ISAC_SPCR, 0xa); - cs->writeisac(cs, ISAC_ADF1, 0x2); - cs->writeisac(cs, ISAC_STCR, 0x70); - cs->writeisac(cs, ISAC_MODE, 0xc9); - } else { - /* IOM 2 Mode */ - if (!cs->dc.isac.adf2) - cs->dc.isac.adf2 = 0x80; - cs->writeisac(cs, ISAC_ADF2, cs->dc.isac.adf2); - cs->writeisac(cs, ISAC_SQXR, 0x2f); - cs->writeisac(cs, ISAC_SPCR, 0x00); - cs->writeisac(cs, ISAC_STCR, 0x70); - cs->writeisac(cs, ISAC_MODE, 0xc9); - cs->writeisac(cs, ISAC_TIMR, 0x00); - cs->writeisac(cs, ISAC_ADF1, 0x00); - } - ph_command(cs, ISAC_CMD_RS); - cs->writeisac(cs, ISAC_MASK, 0x0); -} - -void clear_pending_isac_ints(struct IsdnCardState *cs) -{ - int val, eval; - - val = cs->readisac(cs, ISAC_STAR); - debugl1(cs, "ISAC STAR %x", val); - val = cs->readisac(cs, ISAC_MODE); - debugl1(cs, "ISAC MODE %x", val); - val = cs->readisac(cs, ISAC_ADF2); - debugl1(cs, "ISAC ADF2 %x", val); - val = cs->readisac(cs, ISAC_ISTA); - debugl1(cs, "ISAC ISTA %x", val); - if (val & 0x01) { - eval = cs->readisac(cs, ISAC_EXIR); - debugl1(cs, "ISAC EXIR %x", eval); - } - val = cs->readisac(cs, ISAC_CIR0); - debugl1(cs, "ISAC CIR0 %x", val); - cs->dc.isac.ph_state = (val >> 2) & 0xf; - schedule_event(cs, D_L1STATECHANGE); - /* Disable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0xFF); -} - -void setup_isac(struct IsdnCardState *cs) -{ - INIT_WORK(&cs->tqueue, isac_bh); - timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0); -} diff --git a/drivers/isdn/hisax/isac.h b/drivers/isdn/hisax/isac.h deleted file mode 100644 index 04f16b91b822..000000000000 --- a/drivers/isdn/hisax/isac.h +++ /dev/null @@ -1,70 +0,0 @@ -/* $Id: isac.h,v 1.9.2.2 2004/01/12 22:52:27 keil Exp $ - * - * ISAC specific defines - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* All Registers original Siemens Spec */ - -#define ISAC_MASK 0x20 -#define ISAC_ISTA 0x20 -#define ISAC_STAR 0x21 -#define ISAC_CMDR 0x21 -#define ISAC_EXIR 0x24 -#define ISAC_ADF2 0x39 -#define ISAC_SPCR 0x30 -#define ISAC_ADF1 0x38 -#define ISAC_CIR0 0x31 -#define ISAC_CIX0 0x31 -#define ISAC_CIR1 0x33 -#define ISAC_CIX1 0x33 -#define ISAC_STCR 0x37 -#define ISAC_MODE 0x22 -#define ISAC_RSTA 0x27 -#define ISAC_RBCL 0x25 -#define ISAC_RBCH 0x2A -#define ISAC_TIMR 0x23 -#define ISAC_SQXR 0x3b -#define ISAC_MOSR 0x3a -#define ISAC_MOCR 0x3a -#define ISAC_MOR0 0x32 -#define ISAC_MOX0 0x32 -#define ISAC_MOR1 0x34 -#define ISAC_MOX1 0x34 - -#define ISAC_RBCH_XAC 0x80 - -#define ISAC_CMD_TIM 0x0 -#define ISAC_CMD_RS 0x1 -#define ISAC_CMD_SCZ 0x4 -#define ISAC_CMD_SSZ 0x2 -#define ISAC_CMD_AR8 0x8 -#define ISAC_CMD_AR10 0x9 -#define ISAC_CMD_ARL 0xA -#define ISAC_CMD_DUI 0xF - -#define ISAC_IND_RS 0x1 -#define ISAC_IND_PU 0x7 -#define ISAC_IND_DR 0x0 -#define ISAC_IND_SD 0x2 -#define ISAC_IND_DIS 0x3 -#define ISAC_IND_EI 0x6 -#define ISAC_IND_RSY 0x4 -#define ISAC_IND_ARD 0x8 -#define ISAC_IND_TI 0xA -#define ISAC_IND_ATI 0xB -#define ISAC_IND_AI8 0xC -#define ISAC_IND_AI10 0xD -#define ISAC_IND_DID 0xF - -extern void ISACVersion(struct IsdnCardState *, char *); -extern void setup_isac(struct IsdnCardState *); -extern void initisac(struct IsdnCardState *); -extern void isac_interrupt(struct IsdnCardState *, u_char); -extern void clear_pending_isac_ints(struct IsdnCardState *); diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c deleted file mode 100644 index 82c1879f5664..000000000000 --- a/drivers/isdn/hisax/isar.c +++ /dev/null @@ -1,1910 +0,0 @@ -/* $Id: isar.c,v 1.22.2.6 2004/02/11 13:21:34 keil Exp $ - * - * isar.c ISAR (Siemens PSB 7110) specific routines - * - * Author Karsten Keil (keil@isdn4linux.de) - * - * This file is (c) under GNU General Public License - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isar.h" -#include "isdnl1.h" -#include <linux/interrupt.h> -#include <linux/slab.h> - -#define DBG_LOADFIRM 0 -#define DUMP_MBOXFRAME 2 - -#define DLE 0x10 -#define ETX 0x03 - -#define FAXMODCNT 13 -static const u_char faxmodulation[] = {3, 24, 48, 72, 73, 74, 96, 97, 98, 121, 122, 145, 146}; -static u_int modmask = 0x1fff; -static int frm_extra_delay = 2; -static int para_TOA = 6; -static const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL"}; - -static void isar_setup(struct IsdnCardState *cs); -static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para); -static void ll_deliver_faxstat(struct BCState *bcs, u_char status); - -static inline int -waitforHIA(struct IsdnCardState *cs, int timeout) -{ - - while ((cs->BC_Read_Reg(cs, 0, ISAR_HIA) & 1) && timeout) { - udelay(1); - timeout--; - } - if (!timeout) - printk(KERN_WARNING "HiSax: ISAR waitforHIA timeout\n"); - return (timeout); -} - - -static int -sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len, - u_char *msg) -{ - int i; - - if (!waitforHIA(cs, 4000)) - return (0); -#if DUMP_MBOXFRAME - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "sendmsg(%02x,%02x,%d)", his, creg, len); -#endif - cs->BC_Write_Reg(cs, 0, ISAR_CTRL_H, creg); - cs->BC_Write_Reg(cs, 0, ISAR_CTRL_L, len); - cs->BC_Write_Reg(cs, 0, ISAR_WADR, 0); - if (msg && len) { - cs->BC_Write_Reg(cs, 1, ISAR_MBOX, msg[0]); - for (i = 1; i < len; i++) - cs->BC_Write_Reg(cs, 2, ISAR_MBOX, msg[i]); -#if DUMP_MBOXFRAME > 1 - if (cs->debug & L1_DEB_HSCX_FIFO) { - char tmp[256], *t; - - i = len; - while (i > 0) { - t = tmp; - t += sprintf(t, "sendmbox cnt %d", len); - QuickHex(t, &msg[len-i], (i > 64) ? 64 : i); - debugl1(cs, "%s", tmp); - i -= 64; - } - } -#endif - } - cs->BC_Write_Reg(cs, 1, ISAR_HIS, his); - waitforHIA(cs, 10000); - return (1); -} - -/* Call only with IRQ disabled !!! */ -static inline void -rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg) -{ - int i; - - cs->BC_Write_Reg(cs, 1, ISAR_RADR, 0); - if (msg && ireg->clsb) { - msg[0] = cs->BC_Read_Reg(cs, 1, ISAR_MBOX); - for (i = 1; i < ireg->clsb; i++) - msg[i] = cs->BC_Read_Reg(cs, 2, ISAR_MBOX); -#if DUMP_MBOXFRAME > 1 - if (cs->debug & L1_DEB_HSCX_FIFO) { - char tmp[256], *t; - - i = ireg->clsb; - while (i > 0) { - t = tmp; - t += sprintf(t, "rcv_mbox cnt %d", ireg->clsb); - QuickHex(t, &msg[ireg->clsb - i], (i > 64) ? 64 : i); - debugl1(cs, "%s", tmp); - i -= 64; - } - } -#endif - } - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); -} - -/* Call only with IRQ disabled !!! */ -static inline void -get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg) -{ - ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS); - ireg->cmsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_H); - ireg->clsb = cs->BC_Read_Reg(cs, 1, ISAR_CTRL_L); -#if DUMP_MBOXFRAME - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "irq_stat(%02x,%02x,%d)", ireg->iis, ireg->cmsb, - ireg->clsb); -#endif -} - -static int -waitrecmsg(struct IsdnCardState *cs, u_char *len, - u_char *msg, int maxdelay) -{ - int timeout = 0; - struct isar_reg *ir = cs->bcs[0].hw.isar.reg; - - - while ((!(cs->BC_Read_Reg(cs, 0, ISAR_IRQBIT) & ISAR_IRQSTA)) && - (timeout++ < maxdelay)) - udelay(1); - if (timeout > maxdelay) { - printk(KERN_WARNING"isar recmsg IRQSTA timeout\n"); - return (0); - } - get_irq_infos(cs, ir); - rcv_mbox(cs, ir, msg); - *len = ir->clsb; - return (1); -} - -int -ISARVersion(struct IsdnCardState *cs, char *s) -{ - int ver; - u_char msg[] = ISAR_MSG_HWVER; - u_char tmp[64]; - u_char len; - u_long flags; - int debug; - - cs->cardmsg(cs, CARD_RESET, NULL); - spin_lock_irqsave(&cs->lock, flags); - /* disable ISAR IRQ */ - cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); - debug = cs->debug; - cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO); - if (!sendmsg(cs, ISAR_HIS_VNR, 0, 3, msg)) { - spin_unlock_irqrestore(&cs->lock, flags); - return (-1); - } - if (!waitrecmsg(cs, &len, tmp, 100000)) { - spin_unlock_irqrestore(&cs->lock, flags); - return (-2); - } - cs->debug = debug; - if (cs->bcs[0].hw.isar.reg->iis == ISAR_IIS_VNR) { - if (len == 1) { - ver = tmp[0] & 0xf; - printk(KERN_INFO "%s ISAR version %d\n", s, ver); - } else - ver = -3; - } else - ver = -4; - spin_unlock_irqrestore(&cs->lock, flags); - return (ver); -} - -static int -isar_load_firmware(struct IsdnCardState *cs, u_char __user *buf) -{ - int cfu_ret, ret, size, cnt, debug; - u_char len, nom, noc; - u_short sadr, left, *sp; - u_char __user *p = buf; - u_char *msg, *tmpmsg, *mp, tmp[64]; - u_long flags; - struct isar_reg *ireg = cs->bcs[0].hw.isar.reg; - - struct {u_short sadr; - u_short len; - u_short d_key; - } blk_head; - -#define BLK_HEAD_SIZE 6 - if (1 != (ret = ISARVersion(cs, "Testing"))) { - printk(KERN_ERR"isar_load_firmware wrong isar version %d\n", ret); - return (1); - } - debug = cs->debug; -#if DBG_LOADFIRM < 2 - cs->debug &= ~(L1_DEB_HSCX | L1_DEB_HSCX_FIFO); -#endif - - cfu_ret = copy_from_user(&size, p, sizeof(int)); - if (cfu_ret) { - printk(KERN_ERR "isar_load_firmware copy_from_user ret %d\n", cfu_ret); - return -EFAULT; - } - p += sizeof(int); - printk(KERN_DEBUG"isar_load_firmware size: %d\n", size); - cnt = 0; - /* disable ISAR IRQ */ - cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); - if (!(msg = kmalloc(256, GFP_KERNEL))) { - printk(KERN_ERR"isar_load_firmware no buffer\n"); - return (1); - } - if (!(tmpmsg = kmalloc(256, GFP_KERNEL))) { - printk(KERN_ERR"isar_load_firmware no tmp buffer\n"); - kfree(msg); - return (1); - } - spin_lock_irqsave(&cs->lock, flags); - /* disable ISAR IRQ */ - cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); - spin_unlock_irqrestore(&cs->lock, flags); - while (cnt < size) { - if ((ret = copy_from_user(&blk_head, p, BLK_HEAD_SIZE))) { - printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); - goto reterror; - } -#ifdef __BIG_ENDIAN - sadr = (blk_head.sadr & 0xff) * 256 + blk_head.sadr / 256; - blk_head.sadr = sadr; - sadr = (blk_head.len & 0xff) * 256 + blk_head.len / 256; - blk_head.len = sadr; - sadr = (blk_head.d_key & 0xff) * 256 + blk_head.d_key / 256; - blk_head.d_key = sadr; -#endif /* __BIG_ENDIAN */ - cnt += BLK_HEAD_SIZE; - p += BLK_HEAD_SIZE; - printk(KERN_DEBUG"isar firmware block (%#x,%5d,%#x)\n", - blk_head.sadr, blk_head.len, blk_head.d_key & 0xff); - sadr = blk_head.sadr; - left = blk_head.len; - spin_lock_irqsave(&cs->lock, flags); - if (!sendmsg(cs, ISAR_HIS_DKEY, blk_head.d_key & 0xff, 0, NULL)) { - printk(KERN_ERR"isar sendmsg dkey failed\n"); - ret = 1; goto reterr_unlock; - } - if (!waitrecmsg(cs, &len, tmp, 100000)) { - printk(KERN_ERR"isar waitrecmsg dkey failed\n"); - ret = 1; goto reterr_unlock; - } - if ((ireg->iis != ISAR_IIS_DKEY) || ireg->cmsb || len) { - printk(KERN_ERR"isar wrong dkey response (%x,%x,%x)\n", - ireg->iis, ireg->cmsb, len); - ret = 1; goto reterr_unlock; - } - spin_unlock_irqrestore(&cs->lock, flags); - while (left > 0) { - if (left > 126) - noc = 126; - else - noc = left; - nom = 2 * noc; - mp = msg; - *mp++ = sadr / 256; - *mp++ = sadr % 256; - left -= noc; - *mp++ = noc; - if ((ret = copy_from_user(tmpmsg, p, nom))) { - printk(KERN_ERR"isar_load_firmware copy_from_user ret %d\n", ret); - goto reterror; - } - p += nom; - cnt += nom; - nom += 3; - sp = (u_short *)tmpmsg; -#if DBG_LOADFIRM - printk(KERN_DEBUG"isar: load %3d words at %04x left %d\n", - noc, sadr, left); -#endif - sadr += noc; - while (noc) { -#ifdef __BIG_ENDIAN - *mp++ = *sp % 256; - *mp++ = *sp / 256; -#else - *mp++ = *sp / 256; - *mp++ = *sp % 256; -#endif /* __BIG_ENDIAN */ - sp++; - noc--; - } - spin_lock_irqsave(&cs->lock, flags); - if (!sendmsg(cs, ISAR_HIS_FIRM, 0, nom, msg)) { - printk(KERN_ERR"isar sendmsg prog failed\n"); - ret = 1; goto reterr_unlock; - } - if (!waitrecmsg(cs, &len, tmp, 100000)) { - printk(KERN_ERR"isar waitrecmsg prog failed\n"); - ret = 1; goto reterr_unlock; - } - if ((ireg->iis != ISAR_IIS_FIRM) || ireg->cmsb || len) { - printk(KERN_ERR"isar wrong prog response (%x,%x,%x)\n", - ireg->iis, ireg->cmsb, len); - ret = 1; goto reterr_unlock; - } - spin_unlock_irqrestore(&cs->lock, flags); - } - printk(KERN_DEBUG"isar firmware block %5d words loaded\n", - blk_head.len); - } - /* 10ms delay */ - cnt = 10; - while (cnt--) - udelay(1000); - msg[0] = 0xff; - msg[1] = 0xfe; - ireg->bstat = 0; - spin_lock_irqsave(&cs->lock, flags); - if (!sendmsg(cs, ISAR_HIS_STDSP, 0, 2, msg)) { - printk(KERN_ERR"isar sendmsg start dsp failed\n"); - ret = 1; goto reterr_unlock; - } - if (!waitrecmsg(cs, &len, tmp, 100000)) { - printk(KERN_ERR"isar waitrecmsg start dsp failed\n"); - ret = 1; goto reterr_unlock; - } - if ((ireg->iis != ISAR_IIS_STDSP) || ireg->cmsb || len) { - printk(KERN_ERR"isar wrong start dsp response (%x,%x,%x)\n", - ireg->iis, ireg->cmsb, len); - ret = 1; goto reterr_unlock; - } else - printk(KERN_DEBUG"isar start dsp success\n"); - /* NORMAL mode entered */ - /* Enable IRQs of ISAR */ - cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, ISAR_IRQSTA); - spin_unlock_irqrestore(&cs->lock, flags); - cnt = 1000; /* max 1s */ - while ((!ireg->bstat) && cnt) { - udelay(1000); - cnt--; - } - if (!cnt) { - printk(KERN_ERR"isar no general status event received\n"); - ret = 1; goto reterror; - } else { - printk(KERN_DEBUG"isar general status event %x\n", - ireg->bstat); - } - /* 10ms delay */ - cnt = 10; - while (cnt--) - udelay(1000); - spin_lock_irqsave(&cs->lock, flags); - ireg->iis = 0; - if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { - printk(KERN_ERR"isar sendmsg self tst failed\n"); - ret = 1; goto reterr_unlock; - } - cnt = 10000; /* max 100 ms */ - spin_unlock_irqrestore(&cs->lock, flags); - while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { - udelay(10); - cnt--; - } - udelay(1000); - if (!cnt) { - printk(KERN_ERR"isar no self tst response\n"); - ret = 1; goto reterror; - } - if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1) - && (ireg->par[0] == 0)) { - printk(KERN_DEBUG"isar selftest OK\n"); - } else { - printk(KERN_DEBUG"isar selftest not OK %x/%x/%x\n", - ireg->cmsb, ireg->clsb, ireg->par[0]); - ret = 1; goto reterror; - } - spin_lock_irqsave(&cs->lock, flags); - ireg->iis = 0; - if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_SWVER, 0, NULL)) { - printk(KERN_ERR"isar RQST SVN failed\n"); - ret = 1; goto reterr_unlock; - } - spin_unlock_irqrestore(&cs->lock, flags); - cnt = 30000; /* max 300 ms */ - while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { - udelay(10); - cnt--; - } - udelay(1000); - if (!cnt) { - printk(KERN_ERR"isar no SVN response\n"); - ret = 1; goto reterror; - } else { - if ((ireg->cmsb == ISAR_CTRL_SWVER) && (ireg->clsb == 1)) - printk(KERN_DEBUG"isar software version %#x\n", - ireg->par[0]); - else { - printk(KERN_ERR"isar wrong swver response (%x,%x) cnt(%d)\n", - ireg->cmsb, ireg->clsb, cnt); - ret = 1; goto reterror; - } - } - spin_lock_irqsave(&cs->lock, flags); - cs->debug = debug; - isar_setup(cs); - - ret = 0; -reterr_unlock: - spin_unlock_irqrestore(&cs->lock, flags); -reterror: - cs->debug = debug; - if (ret) - /* disable ISAR IRQ */ - cs->BC_Write_Reg(cs, 0, ISAR_IRQBIT, 0); - kfree(msg); - kfree(tmpmsg); - return (ret); -} - -#define B_LL_NOCARRIER 8 -#define B_LL_CONNECT 9 -#define B_LL_OK 10 - -static void -isar_bh(struct work_struct *work) -{ - struct BCState *bcs = container_of(work, struct BCState, tqueue); - - BChannel_bh(work); - if (test_and_clear_bit(B_LL_NOCARRIER, &bcs->event)) - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_NOCARR); - if (test_and_clear_bit(B_LL_CONNECT, &bcs->event)) - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); - if (test_and_clear_bit(B_LL_OK, &bcs->event)) - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_OK); -} - -static void -send_DLE_ETX(struct BCState *bcs) -{ - u_char dleetx[2] = {DLE, ETX}; - struct sk_buff *skb; - - if ((skb = dev_alloc_skb(2))) { - skb_put_data(skb, dleetx, 2); - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } else { - printk(KERN_WARNING "HiSax: skb out of memory\n"); - } -} - -static inline int -dle_count(unsigned char *buf, int len) -{ - int count = 0; - - while (len--) - if (*buf++ == DLE) - count++; - return count; -} - -static inline void -insert_dle(unsigned char *dest, unsigned char *src, int count) { - /* <DLE> in input stream have to be flagged as <DLE><DLE> */ - while (count--) { - *dest++ = *src; - if (*src++ == DLE) - *dest++ = DLE; - } -} - -static void -isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) -{ - u_char *ptr; - struct sk_buff *skb; - struct isar_reg *ireg = bcs->hw.isar.reg; - - if (!ireg->clsb) { - debugl1(cs, "isar zero len frame"); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - return; - } - switch (bcs->mode) { - case L1_MODE_NULL: - debugl1(cs, "isar mode 0 spurious IIS_RDATA %x/%x/%x", - ireg->iis, ireg->cmsb, ireg->clsb); - printk(KERN_WARNING"isar mode 0 spurious IIS_RDATA %x/%x/%x\n", - ireg->iis, ireg->cmsb, ireg->clsb); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - break; - case L1_MODE_TRANS: - case L1_MODE_V32: - if ((skb = dev_alloc_skb(ireg->clsb))) { - rcv_mbox(cs, ireg, (u_char *)skb_put(skb, ireg->clsb)); - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } else { - printk(KERN_WARNING "HiSax: skb out of memory\n"); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } - break; - case L1_MODE_HDLC: - if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: incoming packet too large"); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - bcs->hw.isar.rcvidx = 0; - } else if (ireg->cmsb & HDLC_ERROR) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar frame error %x len %d", - ireg->cmsb, ireg->clsb); -#ifdef ERROR_STATISTIC - if (ireg->cmsb & HDLC_ERR_RER) - bcs->err_inv++; - if (ireg->cmsb & HDLC_ERR_CER) - bcs->err_crc++; -#endif - bcs->hw.isar.rcvidx = 0; - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } else { - if (ireg->cmsb & HDLC_FSD) - bcs->hw.isar.rcvidx = 0; - ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx; - bcs->hw.isar.rcvidx += ireg->clsb; - rcv_mbox(cs, ireg, ptr); - if (ireg->cmsb & HDLC_FED) { - if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar frame to short %d", - bcs->hw.isar.rcvidx); - } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx - 2))) { - printk(KERN_WARNING "ISAR: receive out of memory\n"); - } else { - skb_put_data(skb, bcs->hw.isar.rcvbuf, - bcs->hw.isar.rcvidx - 2); - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - } - bcs->hw.isar.rcvidx = 0; - } - } - break; - case L1_MODE_FAX: - if (bcs->hw.isar.state != STFAX_ACTIV) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: not ACTIV"); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - bcs->hw.isar.rcvidx = 0; - break; - } - if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) { - rcv_mbox(cs, ireg, bcs->hw.isar.rcvbuf); - bcs->hw.isar.rcvidx = ireg->clsb + - dle_count(bcs->hw.isar.rcvbuf, ireg->clsb); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar_rcv_frame: raw(%d) dle(%d)", - ireg->clsb, bcs->hw.isar.rcvidx); - if ((skb = dev_alloc_skb(bcs->hw.isar.rcvidx))) { - insert_dle((u_char *)skb_put(skb, bcs->hw.isar.rcvidx), - bcs->hw.isar.rcvbuf, ireg->clsb); - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - if (ireg->cmsb & SART_NMD) { /* ABORT */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: no more data"); - bcs->hw.isar.rcvidx = 0; - send_DLE_ETX(bcs); - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | - ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, - 0, NULL); - bcs->hw.isar.state = STFAX_ESCAPE; - schedule_event(bcs, B_LL_NOCARRIER); - } - } else { - printk(KERN_WARNING "HiSax: skb out of memory\n"); - } - break; - } - if (bcs->hw.isar.cmd != PCTRL_CMD_FRH) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: unknown fax mode %x", - bcs->hw.isar.cmd); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - bcs->hw.isar.rcvidx = 0; - break; - } - /* PCTRL_CMD_FRH */ - if ((bcs->hw.isar.rcvidx + ireg->clsb) > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: incoming packet too large"); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - bcs->hw.isar.rcvidx = 0; - } else if (ireg->cmsb & HDLC_ERROR) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar frame error %x len %d", - ireg->cmsb, ireg->clsb); - bcs->hw.isar.rcvidx = 0; - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } else { - if (ireg->cmsb & HDLC_FSD) { - bcs->hw.isar.rcvidx = 0; - } - ptr = bcs->hw.isar.rcvbuf + bcs->hw.isar.rcvidx; - bcs->hw.isar.rcvidx += ireg->clsb; - rcv_mbox(cs, ireg, ptr); - if (ireg->cmsb & HDLC_FED) { - int len = bcs->hw.isar.rcvidx + - dle_count(bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx); - if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar frame to short %d", - bcs->hw.isar.rcvidx); - printk(KERN_WARNING "ISAR: frame to short %d\n", - bcs->hw.isar.rcvidx); - } else if (!(skb = dev_alloc_skb(len))) { - printk(KERN_WARNING "ISAR: receive out of memory\n"); - } else { - insert_dle((u_char *)skb_put(skb, len), - bcs->hw.isar.rcvbuf, - bcs->hw.isar.rcvidx); - skb_queue_tail(&bcs->rqueue, skb); - schedule_event(bcs, B_RCVBUFREADY); - send_DLE_ETX(bcs); - schedule_event(bcs, B_LL_OK); - test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); - } - bcs->hw.isar.rcvidx = 0; - } - } - if (ireg->cmsb & SART_NMD) { /* ABORT */ - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_rcv_frame: no more data"); - bcs->hw.isar.rcvidx = 0; - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | - ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); - bcs->hw.isar.state = STFAX_ESCAPE; - if (test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag)) { - send_DLE_ETX(bcs); - schedule_event(bcs, B_LL_NOCARRIER); - } - } - break; - default: - printk(KERN_ERR"isar_rcv_frame mode (%x)error\n", bcs->mode); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - break; - } -} - -void -isar_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int count; - u_char msb; - u_char *ptr; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "isar_fill_fifo"); - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - if (!(bcs->hw.isar.reg->bstat & - (bcs->hw.isar.dpath == 1 ? BSTAT_RDM1 : BSTAT_RDM2))) - return; - if (bcs->tx_skb->len > bcs->hw.isar.mml) { - msb = 0; - count = bcs->hw.isar.mml; - } else { - count = bcs->tx_skb->len; - msb = HDLC_FED; - } - ptr = bcs->tx_skb->data; - if (!bcs->hw.isar.txcnt) { - msb |= HDLC_FST; - if ((bcs->mode == L1_MODE_FAX) && - (bcs->hw.isar.cmd == PCTRL_CMD_FTH)) { - if (bcs->tx_skb->len > 1) { - if ((ptr[0] == 0xff) && (ptr[1] == 0x13)) - /* last frame */ - test_and_set_bit(BC_FLG_LASTDATA, - &bcs->Flag); - } - } - } - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.isar.txcnt += count; - switch (bcs->mode) { - case L1_MODE_NULL: - printk(KERN_ERR"isar_fill_fifo wrong mode 0\n"); - break; - case L1_MODE_TRANS: - case L1_MODE_V32: - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - 0, count, ptr); - break; - case L1_MODE_HDLC: - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - msb, count, ptr); - break; - case L1_MODE_FAX: - if (bcs->hw.isar.state != STFAX_ACTIV) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_fill_fifo: not ACTIV"); - } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - msb, count, ptr); - } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) { - sendmsg(cs, SET_DPS(bcs->hw.isar.dpath) | ISAR_HIS_SDATA, - 0, count, ptr); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar_fill_fifo: not FTH/FTM"); - } - break; - default: - if (cs->debug) - debugl1(cs, "isar_fill_fifo mode(%x) error", bcs->mode); - printk(KERN_ERR"isar_fill_fifo mode(%x) error\n", bcs->mode); - break; - } -} - -static inline -struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath) -{ - if ((!dpath) || (dpath == 3)) - return (NULL); - if (cs->bcs[0].hw.isar.dpath == dpath) - return (&cs->bcs[0]); - if (cs->bcs[1].hw.isar.dpath == dpath) - return (&cs->bcs[1]); - return (NULL); -} - -static void -send_frames(struct BCState *bcs) -{ - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - isar_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.isar.txcnt; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - if (bcs->mode == L1_MODE_FAX) { - if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { - if (test_bit(BC_FLG_LASTDATA, &bcs->Flag)) { - test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag); - } - } else if (bcs->hw.isar.cmd == PCTRL_CMD_FTM) { - if (test_bit(BC_FLG_DLEETX, &bcs->Flag)) { - test_and_set_bit(BC_FLG_LASTDATA, &bcs->Flag); - test_and_set_bit(BC_FLG_NMD_DATA, &bcs->Flag); - } - } - } - dev_kfree_skb_any(bcs->tx_skb); - bcs->hw.isar.txcnt = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.isar.txcnt = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - isar_fill_fifo(bcs); - } else { - if (test_and_clear_bit(BC_FLG_DLEETX, &bcs->Flag)) { - if (test_and_clear_bit(BC_FLG_LASTDATA, &bcs->Flag)) { - if (test_and_clear_bit(BC_FLG_NMD_DATA, &bcs->Flag)) { - u_char dummy = 0; - sendmsg(bcs->cs, SET_DPS(bcs->hw.isar.dpath) | - ISAR_HIS_SDATA, 0x01, 1, &dummy); - } - test_and_set_bit(BC_FLG_LL_OK, &bcs->Flag); - } else { - schedule_event(bcs, B_LL_CONNECT); - } - } - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } -} - -static inline void -check_send(struct IsdnCardState *cs, u_char rdm) -{ - struct BCState *bcs; - - if (rdm & BSTAT_RDM1) { - if ((bcs = sel_bcs_isar(cs, 1))) { - if (bcs->mode) { - send_frames(bcs); - } - } - } - if (rdm & BSTAT_RDM2) { - if ((bcs = sel_bcs_isar(cs, 2))) { - if (bcs->mode) { - send_frames(bcs); - } - } - } - -} - -static const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", - "NODEF4", "300", "600", "1200", "2400", - "4800", "7200", "9600nt", "9600t", "12000", - "14400", "WRONG"}; -static const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21", - "Bell103", "V23", "Bell202", "V17", "V29", - "V27ter"}; - -static void -isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) { - struct IsdnCardState *cs = bcs->cs; - u_char ril = ireg->par[0]; - u_char rim; - - if (!test_and_clear_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags)) - return; - if (ril > 14) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "wrong pstrsp ril=%d", ril); - ril = 15; - } - switch (ireg->par[1]) { - case 0: - rim = 0; - break; - case 0x20: - rim = 2; - break; - case 0x40: - rim = 3; - break; - case 0x41: - rim = 4; - break; - case 0x51: - rim = 5; - break; - case 0x61: - rim = 6; - break; - case 0x71: - rim = 7; - break; - case 0x82: - rim = 8; - break; - case 0x92: - rim = 9; - break; - case 0xa2: - rim = 10; - break; - default: - rim = 1; - break; - } - sprintf(bcs->hw.isar.conmsg, "%s %s", dmril[ril], dmrim[rim]); - bcs->conmsg = bcs->hw.isar.conmsg; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump strsp %s", bcs->conmsg); -} - -static void -isar_pump_statev_modem(struct BCState *bcs, u_char devt) { - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - - switch (devt) { - case PSEV_10MS_TIMER: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev TIMER"); - break; - case PSEV_CON_ON: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev CONNECT"); - l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL); - break; - case PSEV_CON_OFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev NO CONNECT"); - sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - l1_msg_b(bcs->st, PH_DEACTIVATE | REQUEST, NULL); - break; - case PSEV_V24_OFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev V24 OFF"); - break; - case PSEV_CTS_ON: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev CTS ON"); - break; - case PSEV_CTS_OFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev CTS OFF"); - break; - case PSEV_DCD_ON: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev CARRIER ON"); - test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags); - sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - break; - case PSEV_DCD_OFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev CARRIER OFF"); - break; - case PSEV_DSR_ON: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev DSR ON"); - break; - case PSEV_DSR_OFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev DSR_OFF"); - break; - case PSEV_REM_RET: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev REMOTE RETRAIN"); - break; - case PSEV_REM_REN: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev REMOTE RENEGOTIATE"); - break; - case PSEV_GSTN_CLR: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev GSTN CLEAR"); - break; - default: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "unknown pump stev %x", devt); - break; - } -} - -static void -ll_deliver_faxstat(struct BCState *bcs, u_char status) -{ - isdn_ctrl ic; - struct Channel *chanp = (struct Channel *) bcs->st->lli.userdata; - - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "HL->LL FAXIND %x", status); - ic.driver = bcs->cs->myid; - ic.command = ISDN_STAT_FAXIND; - ic.arg = chanp->chan; - ic.parm.aux.cmd = status; - bcs->cs->iif.statcallb(&ic); -} - -static void -isar_pump_statev_fax(struct BCState *bcs, u_char devt) { - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - u_char p1; - - switch (devt) { - case PSEV_10MS_TIMER: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev TIMER"); - break; - case PSEV_RSP_READY: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_READY"); - bcs->hw.isar.state = STFAX_READY; - l1_msg_b(bcs->st, PH_ACTIVATE | REQUEST, NULL); - if (test_bit(BC_FLG_ORIG, &bcs->Flag)) { - isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FRH, 3); - } else { - isar_pump_cmd(bcs, ISDN_FAX_CLASS1_FTH, 3); - } - break; - case PSEV_LINE_TX_H: - if (bcs->hw.isar.state == STFAX_LINE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev LINE_TX_H"); - bcs->hw.isar.state = STFAX_CONT; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "pump stev LINE_TX_H wrong st %x", - bcs->hw.isar.state); - } - break; - case PSEV_LINE_RX_H: - if (bcs->hw.isar.state == STFAX_LINE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev LINE_RX_H"); - bcs->hw.isar.state = STFAX_CONT; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "pump stev LINE_RX_H wrong st %x", - bcs->hw.isar.state); - } - break; - case PSEV_LINE_TX_B: - if (bcs->hw.isar.state == STFAX_LINE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev LINE_TX_B"); - bcs->hw.isar.state = STFAX_CONT; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "pump stev LINE_TX_B wrong st %x", - bcs->hw.isar.state); - } - break; - case PSEV_LINE_RX_B: - if (bcs->hw.isar.state == STFAX_LINE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev LINE_RX_B"); - bcs->hw.isar.state = STFAX_CONT; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_CONT, 0, NULL); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "pump stev LINE_RX_B wrong st %x", - bcs->hw.isar.state); - } - break; - case PSEV_RSP_CONN: - if (bcs->hw.isar.state == STFAX_CONT) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_CONN"); - bcs->hw.isar.state = STFAX_ACTIV; - test_and_set_bit(ISAR_RATE_REQ, &bcs->hw.isar.reg->Flags); - sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - if (bcs->hw.isar.cmd == PCTRL_CMD_FTH) { - /* 1s Flags before data */ - if (test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) - del_timer(&bcs->hw.isar.ftimer); - /* 1000 ms */ - bcs->hw.isar.ftimer.expires = - jiffies + ((1000 * HZ) / 1000); - test_and_set_bit(BC_FLG_LL_CONN, - &bcs->Flag); - add_timer(&bcs->hw.isar.ftimer); - } else { - schedule_event(bcs, B_LL_CONNECT); - } - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "pump stev RSP_CONN wrong st %x", - bcs->hw.isar.state); - } - break; - case PSEV_FLAGS_DET: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev FLAGS_DET"); - break; - case PSEV_RSP_DISC: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_DISC"); - if (bcs->hw.isar.state == STFAX_ESCAPE) { - p1 = 5; - switch (bcs->hw.isar.newcmd) { - case 0: - bcs->hw.isar.state = STFAX_READY; - break; - case PCTRL_CMD_FTM: - p1 = 2; - /* fall through */ - case PCTRL_CMD_FTH: - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, - PCTRL_CMD_SILON, 1, &p1); - bcs->hw.isar.state = STFAX_SILDET; - break; - case PCTRL_CMD_FRM: - if (frm_extra_delay) - mdelay(frm_extra_delay); - /* fall through */ - case PCTRL_CMD_FRH: - p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.cmd = bcs->hw.isar.newcmd; - bcs->hw.isar.newcmd = 0; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, - bcs->hw.isar.cmd, 1, &p1); - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.try_mod = 3; - break; - default: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "RSP_DISC unknown newcmd %x", bcs->hw.isar.newcmd); - break; - } - } else if (bcs->hw.isar.state == STFAX_ACTIV) { - if (test_and_clear_bit(BC_FLG_LL_OK, &bcs->Flag)) { - schedule_event(bcs, B_LL_OK); - } else if (bcs->hw.isar.cmd == PCTRL_CMD_FRM) { - send_DLE_ETX(bcs); - schedule_event(bcs, B_LL_NOCARRIER); - } else { - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); - } - bcs->hw.isar.state = STFAX_READY; - } else { - bcs->hw.isar.state = STFAX_READY; - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); - } - break; - case PSEV_RSP_SILDET: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_SILDET"); - if (bcs->hw.isar.state == STFAX_SILDET) { - p1 = bcs->hw.isar.mod = bcs->hw.isar.newmod; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.cmd = bcs->hw.isar.newcmd; - bcs->hw.isar.newcmd = 0; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, - bcs->hw.isar.cmd, 1, &p1); - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.try_mod = 3; - } - break; - case PSEV_RSP_SILOFF: - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_SILOFF"); - break; - case PSEV_RSP_FCERR: - if (bcs->hw.isar.state == STFAX_LINE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_FCERR try %d", - bcs->hw.isar.try_mod); - if (bcs->hw.isar.try_mod--) { - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, - bcs->hw.isar.cmd, 1, - &bcs->hw.isar.mod); - break; - } - } - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev RSP_FCERR"); - bcs->hw.isar.state = STFAX_ESCAPE; - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, PCTRL_CMD_ESC, 0, NULL); - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_FCERROR); - break; - default: - break; - } -} - -static char debbuf[128]; - -void -isar_int_main(struct IsdnCardState *cs) -{ - struct isar_reg *ireg = cs->bcs[0].hw.isar.reg; - struct BCState *bcs; - - get_irq_infos(cs, ireg); - switch (ireg->iis & ISAR_IIS_MSCMSD) { - case ISAR_IIS_RDATA: - if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { - isar_rcv_frame(cs, bcs); - } else { - debugl1(cs, "isar spurious IIS_RDATA %x/%x/%x", - ireg->iis, ireg->cmsb, ireg->clsb); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } - break; - case ISAR_IIS_GSTEV: - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - ireg->bstat |= ireg->cmsb; - check_send(cs, ireg->cmsb); - break; - case ISAR_IIS_BSTEV: -#ifdef ERROR_STATISTIC - if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { - if (ireg->cmsb == BSTEV_TBO) - bcs->err_tx++; - if (ireg->cmsb == BSTEV_RBO) - bcs->err_rdo++; - } -#endif - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "Buffer STEV dpath%d msb(%x)", - ireg->iis >> 6, ireg->cmsb); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - break; - case ISAR_IIS_PSTEV: - if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { - rcv_mbox(cs, ireg, (u_char *)ireg->par); - if (bcs->mode == L1_MODE_V32) { - isar_pump_statev_modem(bcs, ireg->cmsb); - } else if (bcs->mode == L1_MODE_FAX) { - isar_pump_statev_fax(bcs, ireg->cmsb); - } else if (ireg->cmsb == PSEV_10MS_TIMER) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "pump stev TIMER"); - } else { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "isar IIS_PSTEV pmode %d stat %x", - bcs->mode, ireg->cmsb); - } - } else { - debugl1(cs, "isar spurious IIS_PSTEV %x/%x/%x", - ireg->iis, ireg->cmsb, ireg->clsb); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } - break; - case ISAR_IIS_PSTRSP: - if ((bcs = sel_bcs_isar(cs, ireg->iis >> 6))) { - rcv_mbox(cs, ireg, (u_char *)ireg->par); - isar_pump_status_rsp(bcs, ireg); - } else { - debugl1(cs, "isar spurious IIS_PSTRSP %x/%x/%x", - ireg->iis, ireg->cmsb, ireg->clsb); - cs->BC_Write_Reg(cs, 1, ISAR_IIA, 0); - } - break; - case ISAR_IIS_DIAG: - case ISAR_IIS_BSTRSP: - case ISAR_IIS_IOM2RSP: - rcv_mbox(cs, ireg, (u_char *)ireg->par); - if ((cs->debug & (L1_DEB_HSCX | L1_DEB_HSCX_FIFO)) - == L1_DEB_HSCX) { - u_char *tp = debbuf; - - tp += sprintf(debbuf, "msg iis(%x) msb(%x)", - ireg->iis, ireg->cmsb); - QuickHex(tp, (u_char *)ireg->par, ireg->clsb); - debugl1(cs, "%s", debbuf); - } - break; - case ISAR_IIS_INVMSG: - rcv_mbox(cs, ireg, debbuf); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "invalid msg his:%x", - ireg->cmsb); - break; - default: - rcv_mbox(cs, ireg, debbuf); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "unhandled msg iis(%x) ctrl(%x/%x)", - ireg->iis, ireg->cmsb, ireg->clsb); - break; - } -} - -static void -ftimer_handler(struct timer_list *t) { - struct BCState *bcs = from_timer(bcs, t, hw.isar.ftimer); - if (bcs->cs->debug) - debugl1(bcs->cs, "ftimer flags %04lx", - bcs->Flag); - test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag); - if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) { - schedule_event(bcs, B_LL_CONNECT); - } - if (test_and_clear_bit(BC_FLG_FTI_FTS, &bcs->Flag)) { - schedule_event(bcs, B_LL_OK); - } -} - -static void -setup_pump(struct BCState *bcs) { - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - u_char ctrl, param[6]; - - switch (bcs->mode) { - case L1_MODE_NULL: - case L1_MODE_TRANS: - case L1_MODE_HDLC: - sendmsg(cs, dps | ISAR_HIS_PUMPCFG, PMOD_BYPASS, 0, NULL); - break; - case L1_MODE_V32: - ctrl = PMOD_DATAMODEM; - if (test_bit(BC_FLG_ORIG, &bcs->Flag)) { - ctrl |= PCTRL_ORIG; - param[5] = PV32P6_CTN; - } else { - param[5] = PV32P6_ATN; - } - param[0] = para_TOA; /* 6 db */ - param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | - PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; - param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; - param[3] = PV32P4_UT144; - param[4] = PV32P5_UT144; - sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param); - break; - case L1_MODE_FAX: - ctrl = PMOD_FAX; - if (test_bit(BC_FLG_ORIG, &bcs->Flag)) { - ctrl |= PCTRL_ORIG; - param[1] = PFAXP2_CTN; - } else { - param[1] = PFAXP2_ATN; - } - param[0] = para_TOA; /* 6 db */ - sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param); - bcs->hw.isar.state = STFAX_NULL; - bcs->hw.isar.newcmd = 0; - bcs->hw.isar.newmod = 0; - test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag); - break; - } - udelay(1000); - sendmsg(cs, dps | ISAR_HIS_PSTREQ, 0, 0, NULL); - udelay(1000); -} - -static void -setup_sart(struct BCState *bcs) { - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - u_char ctrl, param[2]; - - switch (bcs->mode) { - case L1_MODE_NULL: - sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_DISABLE, 0, - NULL); - break; - case L1_MODE_TRANS: - sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_BINARY, 2, - "\0\0"); - break; - case L1_MODE_HDLC: - param[0] = 0; - sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, - param); - break; - case L1_MODE_V32: - ctrl = SMODE_V14 | SCTRL_HDMC_BOTH; - param[0] = S_P1_CHS_8; - param[1] = S_P2_BFT_DEF; - sendmsg(cs, dps | ISAR_HIS_SARTCFG, ctrl, 2, - param); - break; - case L1_MODE_FAX: - /* SART must not configured with FAX */ - break; - } - udelay(1000); - sendmsg(cs, dps | ISAR_HIS_BSTREQ, 0, 0, NULL); - udelay(1000); -} - -static void -setup_iom2(struct BCState *bcs) { - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - u_char cmsb = IOM_CTRL_ENA, msg[5] = {IOM_P1_TXD, 0, 0, 0, 0}; - - if (bcs->channel) - msg[1] = msg[3] = 1; - switch (bcs->mode) { - case L1_MODE_NULL: - cmsb = 0; - /* dummy slot */ - msg[1] = msg[3] = bcs->hw.isar.dpath + 2; - break; - case L1_MODE_TRANS: - case L1_MODE_HDLC: - break; - case L1_MODE_V32: - case L1_MODE_FAX: - cmsb |= IOM_CTRL_ALAW | IOM_CTRL_RCV; - break; - } - sendmsg(cs, dps | ISAR_HIS_IOM2CFG, cmsb, 5, msg); - udelay(1000); - sendmsg(cs, dps | ISAR_HIS_IOM2REQ, 0, 0, NULL); - udelay(1000); -} - -static int -modeisar(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - - /* Here we are selecting the best datapath for requested mode */ - if (bcs->mode == L1_MODE_NULL) { /* New Setup */ - bcs->channel = bc; - switch (mode) { - case L1_MODE_NULL: /* init */ - if (!bcs->hw.isar.dpath) - /* no init for dpath 0 */ - return (0); - break; - case L1_MODE_TRANS: - case L1_MODE_HDLC: - /* best is datapath 2 */ - if (!test_and_set_bit(ISAR_DP2_USE, - &bcs->hw.isar.reg->Flags)) - bcs->hw.isar.dpath = 2; - else if (!test_and_set_bit(ISAR_DP1_USE, - &bcs->hw.isar.reg->Flags)) - bcs->hw.isar.dpath = 1; - else { - printk(KERN_WARNING"isar modeisar both paths in use\n"); - return (1); - } - break; - case L1_MODE_V32: - case L1_MODE_FAX: - /* only datapath 1 */ - if (!test_and_set_bit(ISAR_DP1_USE, - &bcs->hw.isar.reg->Flags)) - bcs->hw.isar.dpath = 1; - else { - printk(KERN_WARNING"isar modeisar analog functions only with DP1\n"); - debugl1(cs, "isar modeisar analog functions only with DP1"); - return (1); - } - break; - } - } - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar dp%d mode %d->%d ichan %d", - bcs->hw.isar.dpath, bcs->mode, mode, bc); - bcs->mode = mode; - setup_pump(bcs); - setup_iom2(bcs); - setup_sart(bcs); - if (bcs->mode == L1_MODE_NULL) { - /* Clear resources */ - if (bcs->hw.isar.dpath == 1) - test_and_clear_bit(ISAR_DP1_USE, &bcs->hw.isar.reg->Flags); - else if (bcs->hw.isar.dpath == 2) - test_and_clear_bit(ISAR_DP2_USE, &bcs->hw.isar.reg->Flags); - bcs->hw.isar.dpath = 0; - } - return (0); -} - -static void -isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para) -{ - struct IsdnCardState *cs = bcs->cs; - u_char dps = SET_DPS(bcs->hw.isar.dpath); - u_char ctrl = 0, nom = 0, p1 = 0; - - switch (cmd) { - case ISDN_FAX_CLASS1_FTM: - test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); - if (bcs->hw.isar.state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FTM; - nom = 1; - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.cmd = ctrl; - bcs->hw.isar.mod = para; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.newcmd = 0; - bcs->hw.isar.try_mod = 3; - } else if ((bcs->hw.isar.state == STFAX_ACTIV) && - (bcs->hw.isar.cmd == PCTRL_CMD_FTM) && - (bcs->hw.isar.mod == para)) { - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); - } else { - bcs->hw.isar.newmod = para; - bcs->hw.isar.newcmd = PCTRL_CMD_FTM; - nom = 0; - ctrl = PCTRL_CMD_ESC; - bcs->hw.isar.state = STFAX_ESCAPE; - } - break; - case ISDN_FAX_CLASS1_FTH: - test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); - if (bcs->hw.isar.state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FTH; - nom = 1; - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.cmd = ctrl; - bcs->hw.isar.mod = para; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.newcmd = 0; - bcs->hw.isar.try_mod = 3; - } else if ((bcs->hw.isar.state == STFAX_ACTIV) && - (bcs->hw.isar.cmd == PCTRL_CMD_FTH) && - (bcs->hw.isar.mod == para)) { - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); - } else { - bcs->hw.isar.newmod = para; - bcs->hw.isar.newcmd = PCTRL_CMD_FTH; - nom = 0; - ctrl = PCTRL_CMD_ESC; - bcs->hw.isar.state = STFAX_ESCAPE; - } - break; - case ISDN_FAX_CLASS1_FRM: - test_and_clear_bit(BC_FLG_FRH_WAIT, &bcs->Flag); - if (bcs->hw.isar.state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FRM; - nom = 1; - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.cmd = ctrl; - bcs->hw.isar.mod = para; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.newcmd = 0; - bcs->hw.isar.try_mod = 3; - } else if ((bcs->hw.isar.state == STFAX_ACTIV) && - (bcs->hw.isar.cmd == PCTRL_CMD_FRM) && - (bcs->hw.isar.mod == para)) { - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); - } else { - bcs->hw.isar.newmod = para; - bcs->hw.isar.newcmd = PCTRL_CMD_FRM; - nom = 0; - ctrl = PCTRL_CMD_ESC; - bcs->hw.isar.state = STFAX_ESCAPE; - } - break; - case ISDN_FAX_CLASS1_FRH: - test_and_set_bit(BC_FLG_FRH_WAIT, &bcs->Flag); - if (bcs->hw.isar.state == STFAX_READY) { - p1 = para; - ctrl = PCTRL_CMD_FRH; - nom = 1; - bcs->hw.isar.state = STFAX_LINE; - bcs->hw.isar.cmd = ctrl; - bcs->hw.isar.mod = para; - bcs->hw.isar.newmod = 0; - bcs->hw.isar.newcmd = 0; - bcs->hw.isar.try_mod = 3; - } else if ((bcs->hw.isar.state == STFAX_ACTIV) && - (bcs->hw.isar.cmd == PCTRL_CMD_FRH) && - (bcs->hw.isar.mod == para)) { - ll_deliver_faxstat(bcs, ISDN_FAX_CLASS1_CONNECT); - } else { - bcs->hw.isar.newmod = para; - bcs->hw.isar.newcmd = PCTRL_CMD_FRH; - nom = 0; - ctrl = PCTRL_CMD_ESC; - bcs->hw.isar.state = STFAX_ESCAPE; - } - break; - case ISDN_FAXPUMP_HALT: - bcs->hw.isar.state = STFAX_NULL; - nom = 0; - ctrl = PCTRL_CMD_HALT; - break; - } - if (ctrl) - sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1); -} - -static void -isar_setup(struct IsdnCardState *cs) -{ - u_char msg; - int i; - - /* Dpath 1, 2 */ - msg = 61; - for (i = 0; i < 2; i++) { - /* Buffer Config */ - sendmsg(cs, (i ? ISAR_HIS_DPS2 : ISAR_HIS_DPS1) | - ISAR_HIS_P12CFG, 4, 1, &msg); - cs->bcs[i].hw.isar.mml = msg; - cs->bcs[i].mode = 0; - cs->bcs[i].hw.isar.dpath = i + 1; - modeisar(&cs->bcs[i], 0, 0); - INIT_WORK(&cs->bcs[i].tqueue, isar_bh); - } -} - -static void -isar_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - int ret; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "DRQ set BC_FLG_BUSY"); - bcs->hw.isar.txcnt = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "isar_l2l1: this shouldn't happen\n"); - } else { - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "PUI set BC_FLG_BUSY"); - bcs->tx_skb = skb; - bcs->hw.isar.txcnt = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - bcs->hw.isar.conmsg[0] = 0; - if (test_bit(FLG_ORIG, &st->l2.flag)) - test_and_set_bit(BC_FLG_ORIG, &bcs->Flag); - else - test_and_clear_bit(BC_FLG_ORIG, &bcs->Flag); - switch (st->l1.mode) { - case L1_MODE_TRANS: - case L1_MODE_HDLC: - ret = modeisar(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - if (ret) - l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg); - else - l1_msg_b(st, PH_ACTIVATE | REQUEST, arg); - break; - case L1_MODE_V32: - case L1_MODE_FAX: - ret = modeisar(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - if (ret) - l1_msg_b(st, PH_DEACTIVATE | REQUEST, arg); - break; - default: - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - } - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - switch (st->l1.mode) { - case L1_MODE_TRANS: - case L1_MODE_HDLC: - case L1_MODE_V32: - break; - case L1_MODE_FAX: - isar_pump_cmd(bcs, ISDN_FAXPUMP_HALT, 0); - break; - } - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "PDAC clear BC_FLG_BUSY"); - modeisar(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_isarstate(struct BCState *bcs) -{ - modeisar(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.isar.rcvbuf); - bcs->hw.isar.rcvbuf = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "closeisar clear BC_FLG_BUSY"); - } - } - del_timer(&bcs->hw.isar.ftimer); -} - -static int -open_isarstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.isar.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for isar.rcvbuf\n"); - return (1); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "openisar clear BC_FLG_BUSY"); - bcs->event = 0; - bcs->hw.isar.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_isar(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_isarstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = isar_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -int -isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { - u_long adr; - int features, i; - struct BCState *bcs; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar_auxcmd cmd/ch %x/%ld", ic->command, ic->arg); - switch (ic->command) { - case (ISDN_CMD_FAXCMD): - bcs = cs->channel[ic->arg].bcs; - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar_auxcmd cmd/subcmd %d/%d", - ic->parm.aux.cmd, ic->parm.aux.subcmd); - switch (ic->parm.aux.cmd) { - case ISDN_FAX_CLASS1_CTRL: - if (ic->parm.aux.subcmd == ETX) - test_and_set_bit(BC_FLG_DLEETX, - &bcs->Flag); - break; - case ISDN_FAX_CLASS1_FTS: - if (ic->parm.aux.subcmd == AT_QUERY) { - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK; - cs->iif.statcallb(ic); - return (0); - } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) { - strcpy(ic->parm.aux.para, "0-255"); - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; - cs->iif.statcallb(ic); - return (0); - } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar_auxcmd %s=%d", - FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]); - if (bcs->hw.isar.state == STFAX_READY) { - if (!ic->parm.aux.para[0]) { - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_OK; - cs->iif.statcallb(ic); - return (0); - } - if (!test_and_set_bit(BC_FLG_FTI_RUN, &bcs->Flag)) { - /* n*10 ms */ - bcs->hw.isar.ftimer.expires = - jiffies + ((ic->parm.aux.para[0] * 10 * HZ) / 1000); - test_and_set_bit(BC_FLG_FTI_FTS, &bcs->Flag); - add_timer(&bcs->hw.isar.ftimer); - return (0); - } else { - if (cs->debug) - debugl1(cs, "isar FTS=%d and FTI busy", - ic->parm.aux.para[0]); - } - } else { - if (cs->debug) - debugl1(cs, "isar FTS=%d and isar.state not ready(%x)", - ic->parm.aux.para[0], bcs->hw.isar.state); - } - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR; - cs->iif.statcallb(ic); - } - break; - case ISDN_FAX_CLASS1_FRM: - case ISDN_FAX_CLASS1_FRH: - case ISDN_FAX_CLASS1_FTM: - case ISDN_FAX_CLASS1_FTH: - if (ic->parm.aux.subcmd == AT_QUERY) { - sprintf(ic->parm.aux.para, - "%d", bcs->hw.isar.mod); - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; - cs->iif.statcallb(ic); - return (0); - } else if (ic->parm.aux.subcmd == AT_EQ_QUERY) { - char *p = ic->parm.aux.para; - for (i = 0; i < FAXMODCNT; i++) - if ((1 << i) & modmask) - p += sprintf(p, "%d,", faxmodulation[i]); - p--; - *p = 0; - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_QUERY; - cs->iif.statcallb(ic); - return (0); - } else if (ic->parm.aux.subcmd == AT_EQ_VALUE) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "isar_auxcmd %s=%d", - FC1_CMD[ic->parm.aux.cmd], ic->parm.aux.para[0]); - for (i = 0; i < FAXMODCNT; i++) - if (faxmodulation[i] == ic->parm.aux.para[0]) - break; - if ((i < FAXMODCNT) && ((1 << i) & modmask) && - test_bit(BC_FLG_INIT, &bcs->Flag)) { - isar_pump_cmd(bcs, - ic->parm.aux.cmd, - ic->parm.aux.para[0]); - return (0); - } - } - /* wrong modulation or not activ */ - /* fall through */ - default: - ic->command = ISDN_STAT_FAXIND; - ic->parm.aux.cmd = ISDN_FAX_CLASS1_ERROR; - cs->iif.statcallb(ic); - } - break; - case (ISDN_CMD_IOCTL): - switch (ic->arg) { - case 9: /* load firmware */ - features = ISDN_FEATURE_L2_MODEM | - ISDN_FEATURE_L2_FAX | - ISDN_FEATURE_L3_FCLASS1; - memcpy(&adr, ic->parm.num, sizeof(ulong)); - if (isar_load_firmware(cs, (u_char __user *)adr)) - return (1); - else - ll_run(cs, features); - break; - case 20: - features = *(unsigned int *) ic->parm.num; - printk(KERN_DEBUG "HiSax: max modulation old(%04x) new(%04x)\n", - modmask, features); - modmask = features; - break; - case 21: - features = *(unsigned int *) ic->parm.num; - printk(KERN_DEBUG "HiSax: FRM extra delay old(%d) new(%d) ms\n", - frm_extra_delay, features); - if (features >= 0) - frm_extra_delay = features; - break; - case 22: - features = *(unsigned int *) ic->parm.num; - printk(KERN_DEBUG "HiSax: TOA old(%d) new(%d) db\n", - para_TOA, features); - if (features >= 0 && features < 32) - para_TOA = features; - break; - default: - printk(KERN_DEBUG "HiSax: invalid ioctl %d\n", - (int) ic->arg); - return (-EINVAL); - } - break; - default: - return (-EINVAL); - } - return (0); -} - -void initisar(struct IsdnCardState *cs) -{ - cs->bcs[0].BC_SetStack = setstack_isar; - cs->bcs[1].BC_SetStack = setstack_isar; - cs->bcs[0].BC_Close = close_isarstate; - cs->bcs[1].BC_Close = close_isarstate; - timer_setup(&cs->bcs[0].hw.isar.ftimer, ftimer_handler, 0); - timer_setup(&cs->bcs[1].hw.isar.ftimer, ftimer_handler, 0); -} diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h deleted file mode 100644 index 0f4d101faf37..000000000000 --- a/drivers/isdn/hisax/isar.h +++ /dev/null @@ -1,222 +0,0 @@ -/* $Id: isar.h,v 1.11.2.2 2004/01/12 22:52:27 keil Exp $ - * - * ISAR (Siemens PSB 7110) specific defines - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define ISAR_IRQMSK 0x04 -#define ISAR_IRQSTA 0x04 -#define ISAR_IRQBIT 0x75 -#define ISAR_CTRL_H 0x61 -#define ISAR_CTRL_L 0x60 -#define ISAR_IIS 0x58 -#define ISAR_IIA 0x58 -#define ISAR_HIS 0x50 -#define ISAR_HIA 0x50 -#define ISAR_MBOX 0x4c -#define ISAR_WADR 0x4a -#define ISAR_RADR 0x48 - -#define ISAR_HIS_VNR 0x14 -#define ISAR_HIS_DKEY 0x02 -#define ISAR_HIS_FIRM 0x1e -#define ISAR_HIS_STDSP 0x08 -#define ISAR_HIS_DIAG 0x05 -#define ISAR_HIS_WAITSTATE 0x27 -#define ISAR_HIS_TIMERIRQ 0x25 -#define ISAR_HIS_P0CFG 0x3c -#define ISAR_HIS_P12CFG 0x24 -#define ISAR_HIS_SARTCFG 0x25 -#define ISAR_HIS_PUMPCFG 0x26 -#define ISAR_HIS_PUMPCTRL 0x2a -#define ISAR_HIS_IOM2CFG 0x27 -#define ISAR_HIS_IOM2REQ 0x07 -#define ISAR_HIS_IOM2CTRL 0x2b -#define ISAR_HIS_BSTREQ 0x0c -#define ISAR_HIS_PSTREQ 0x0e -#define ISAR_HIS_SDATA 0x20 -#define ISAR_HIS_DPS1 0x40 -#define ISAR_HIS_DPS2 0x80 -#define SET_DPS(x) ((x << 6) & 0xc0) - -#define ISAR_CMD_TIMERIRQ_OFF 0x20 -#define ISAR_CMD_TIMERIRQ_ON 0x21 - - -#define ISAR_IIS_MSCMSD 0x3f -#define ISAR_IIS_VNR 0x15 -#define ISAR_IIS_DKEY 0x03 -#define ISAR_IIS_FIRM 0x1f -#define ISAR_IIS_STDSP 0x09 -#define ISAR_IIS_DIAG 0x25 -#define ISAR_IIS_GSTEV 0x00 -#define ISAR_IIS_BSTEV 0x28 -#define ISAR_IIS_BSTRSP 0x2c -#define ISAR_IIS_PSTRSP 0x2e -#define ISAR_IIS_PSTEV 0x2a -#define ISAR_IIS_IOM2RSP 0x27 -#define ISAR_IIS_RDATA 0x20 -#define ISAR_IIS_INVMSG 0x3f - -#define ISAR_CTRL_SWVER 0x10 -#define ISAR_CTRL_STST 0x40 - -#define ISAR_MSG_HWVER {0x20, 0, 1} - -#define ISAR_DP1_USE 1 -#define ISAR_DP2_USE 2 -#define ISAR_RATE_REQ 3 - -#define PMOD_DISABLE 0 -#define PMOD_FAX 1 -#define PMOD_DATAMODEM 2 -#define PMOD_HALFDUPLEX 3 -#define PMOD_V110 4 -#define PMOD_DTMF 5 -#define PMOD_DTMF_TRANS 6 -#define PMOD_BYPASS 7 - -#define PCTRL_ORIG 0x80 -#define PV32P2_V23R 0x40 -#define PV32P2_V22A 0x20 -#define PV32P2_V22B 0x10 -#define PV32P2_V22C 0x08 -#define PV32P2_V21 0x02 -#define PV32P2_BEL 0x01 - -// LSB MSB in ISAR doc wrong !!! Arghhh -#define PV32P3_AMOD 0x80 -#define PV32P3_V32B 0x02 -#define PV32P3_V23B 0x01 -#define PV32P4_48 0x11 -#define PV32P5_48 0x05 -#define PV32P4_UT48 0x11 -#define PV32P5_UT48 0x0d -#define PV32P4_96 0x11 -#define PV32P5_96 0x03 -#define PV32P4_UT96 0x11 -#define PV32P5_UT96 0x0f -#define PV32P4_B96 0x91 -#define PV32P5_B96 0x0b -#define PV32P4_UTB96 0xd1 -#define PV32P5_UTB96 0x0f -#define PV32P4_120 0xb1 -#define PV32P5_120 0x09 -#define PV32P4_UT120 0xf1 -#define PV32P5_UT120 0x0f -#define PV32P4_144 0x99 -#define PV32P5_144 0x09 -#define PV32P4_UT144 0xf9 -#define PV32P5_UT144 0x0f -#define PV32P6_CTN 0x01 -#define PV32P6_ATN 0x02 - -#define PFAXP2_CTN 0x01 -#define PFAXP2_ATN 0x04 - -#define PSEV_10MS_TIMER 0x02 -#define PSEV_CON_ON 0x18 -#define PSEV_CON_OFF 0x19 -#define PSEV_V24_OFF 0x20 -#define PSEV_CTS_ON 0x21 -#define PSEV_CTS_OFF 0x22 -#define PSEV_DCD_ON 0x23 -#define PSEV_DCD_OFF 0x24 -#define PSEV_DSR_ON 0x25 -#define PSEV_DSR_OFF 0x26 -#define PSEV_REM_RET 0xcc -#define PSEV_REM_REN 0xcd -#define PSEV_GSTN_CLR 0xd4 - -#define PSEV_RSP_READY 0xbc -#define PSEV_LINE_TX_H 0xb3 -#define PSEV_LINE_TX_B 0xb2 -#define PSEV_LINE_RX_H 0xb1 -#define PSEV_LINE_RX_B 0xb0 -#define PSEV_RSP_CONN 0xb5 -#define PSEV_RSP_DISC 0xb7 -#define PSEV_RSP_FCERR 0xb9 -#define PSEV_RSP_SILDET 0xbe -#define PSEV_RSP_SILOFF 0xab -#define PSEV_FLAGS_DET 0xba - -#define PCTRL_CMD_FTH 0xa7 -#define PCTRL_CMD_FRH 0xa5 -#define PCTRL_CMD_FTM 0xa8 -#define PCTRL_CMD_FRM 0xa6 -#define PCTRL_CMD_SILON 0xac -#define PCTRL_CMD_CONT 0xa2 -#define PCTRL_CMD_ESC 0xa4 -#define PCTRL_CMD_SILOFF 0xab -#define PCTRL_CMD_HALT 0xa9 - -#define PCTRL_LOC_RET 0xcf -#define PCTRL_LOC_REN 0xce - -#define SMODE_DISABLE 0 -#define SMODE_V14 2 -#define SMODE_HDLC 3 -#define SMODE_BINARY 4 -#define SMODE_FSK_V14 5 - -#define SCTRL_HDMC_BOTH 0x00 -#define SCTRL_HDMC_DTX 0x80 -#define SCTRL_HDMC_DRX 0x40 -#define S_P1_OVSP 0x40 -#define S_P1_SNP 0x20 -#define S_P1_EOP 0x10 -#define S_P1_EDP 0x08 -#define S_P1_NSB 0x04 -#define S_P1_CHS_8 0x03 -#define S_P1_CHS_7 0x02 -#define S_P1_CHS_6 0x01 -#define S_P1_CHS_5 0x00 - -#define S_P2_BFT_DEF 0x10 - -#define IOM_CTRL_ENA 0x80 -#define IOM_CTRL_NOPCM 0x00 -#define IOM_CTRL_ALAW 0x02 -#define IOM_CTRL_ULAW 0x04 -#define IOM_CTRL_RCV 0x01 - -#define IOM_P1_TXD 0x10 - -#define HDLC_FED 0x40 -#define HDLC_FSD 0x20 -#define HDLC_FST 0x20 -#define HDLC_ERROR 0x1c -#define HDLC_ERR_FAD 0x10 -#define HDLC_ERR_RER 0x08 -#define HDLC_ERR_CER 0x04 -#define SART_NMD 0x01 - -#define BSTAT_RDM0 0x1 -#define BSTAT_RDM1 0x2 -#define BSTAT_RDM2 0x4 -#define BSTAT_RDM3 0x8 -#define BSTEV_TBO 0x1f -#define BSTEV_RBO 0x2f - -/* FAX State Machine */ -#define STFAX_NULL 0 -#define STFAX_READY 1 -#define STFAX_LINE 2 -#define STFAX_CONT 3 -#define STFAX_ACTIV 4 -#define STFAX_ESCAPE 5 -#define STFAX_SILDET 6 - -#define ISDN_FAXPUMP_HALT 100 - -extern int ISARVersion(struct IsdnCardState *cs, char *s); -extern void isar_int_main(struct IsdnCardState *cs); -extern void initisar(struct IsdnCardState *cs); -extern void isar_fill_fifo(struct BCState *bcs); -extern int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic); diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c deleted file mode 100644 index a560842c0e48..000000000000 --- a/drivers/isdn/hisax/isdnl1.c +++ /dev/null @@ -1,930 +0,0 @@ -/* $Id: isdnl1.c,v 2.46.2.5 2004/02/11 13:21:34 keil Exp $ - * - * common low level stuff for Siemens Chipsetbased isdn cards - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil <keil@isdn4linux.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 - * - * Thanks to Jan den Ouden - * Fritz Elfert - * Beat Doebeli - * - */ - -#include <linux/init.h> -#include <linux/gfp.h> -#include "hisax.h" -#include "isdnl1.h" - -const char *l1_revision = "$Revision: 2.46.2.5 $"; - -#define TIMER3_VALUE 7000 - -static struct Fsm l1fsm_b; -static struct Fsm l1fsm_s; - -enum { - ST_L1_F2, - ST_L1_F3, - ST_L1_F4, - ST_L1_F5, - ST_L1_F6, - ST_L1_F7, - ST_L1_F8, -}; - -#define L1S_STATE_COUNT (ST_L1_F8 + 1) - -static char *strL1SState[] = -{ - "ST_L1_F2", - "ST_L1_F3", - "ST_L1_F4", - "ST_L1_F5", - "ST_L1_F6", - "ST_L1_F7", - "ST_L1_F8", -}; - -#ifdef HISAX_UINTERFACE -static -struct Fsm l1fsm_u = -{NULL, 0, 0, NULL, NULL}; - -enum { - ST_L1_RESET, - ST_L1_DEACT, - ST_L1_SYNC2, - ST_L1_TRANS, -}; - -#define L1U_STATE_COUNT (ST_L1_TRANS + 1) - -static char *strL1UState[] = -{ - "ST_L1_RESET", - "ST_L1_DEACT", - "ST_L1_SYNC2", - "ST_L1_TRANS", -}; -#endif - -enum { - ST_L1_NULL, - ST_L1_WAIT_ACT, - ST_L1_WAIT_DEACT, - ST_L1_ACTIV, -}; - -#define L1B_STATE_COUNT (ST_L1_ACTIV + 1) - -static char *strL1BState[] = -{ - "ST_L1_NULL", - "ST_L1_WAIT_ACT", - "ST_L1_WAIT_DEACT", - "ST_L1_ACTIV", -}; - -enum { - EV_PH_ACTIVATE, - EV_PH_DEACTIVATE, - EV_RESET_IND, - EV_DEACT_CNF, - EV_DEACT_IND, - EV_POWER_UP, - EV_RSYNC_IND, - EV_INFO2_IND, - EV_INFO4_IND, - EV_TIMER_DEACT, - EV_TIMER_ACT, - EV_TIMER3, -}; - -#define L1_EVENT_COUNT (EV_TIMER3 + 1) - -static char *strL1Event[] = -{ - "EV_PH_ACTIVATE", - "EV_PH_DEACTIVATE", - "EV_RESET_IND", - "EV_DEACT_CNF", - "EV_DEACT_IND", - "EV_POWER_UP", - "EV_RSYNC_IND", - "EV_INFO2_IND", - "EV_INFO4_IND", - "EV_TIMER_DEACT", - "EV_TIMER_ACT", - "EV_TIMER3", -}; - -void -debugl1(struct IsdnCardState *cs, char *fmt, ...) -{ - va_list args; - char tmp[8]; - - va_start(args, fmt); - sprintf(tmp, "Card%d ", cs->cardnr + 1); - VHiSax_putstatus(cs, tmp, fmt, args); - va_end(args); -} - -static void -l1m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - struct PStack *st = fi->userdata; - struct IsdnCardState *cs = st->l1.hardware; - char tmp[8]; - - va_start(args, fmt); - sprintf(tmp, "Card%d ", cs->cardnr + 1); - VHiSax_putstatus(cs, tmp, fmt, args); - va_end(args); -} - -static void -L1activated(struct IsdnCardState *cs) -{ - struct PStack *st; - - st = cs->stlist; - while (st) { - if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - else - st->l1.l1l2(st, PH_ACTIVATE | INDICATION, NULL); - st = st->next; - } -} - -static void -L1deactivated(struct IsdnCardState *cs) -{ - struct PStack *st; - - st = cs->stlist; - while (st) { - if (test_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL); - st->l1.l1l2(st, PH_DEACTIVATE | INDICATION, NULL); - st = st->next; - } - test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags); -} - -void -DChannel_proc_xmt(struct IsdnCardState *cs) -{ - struct PStack *stptr; - - if (cs->tx_skb) - return; - - stptr = cs->stlist; - while (stptr != NULL) { - if (test_and_clear_bit(FLG_L1_PULL_REQ, &stptr->l1.Flags)) { - stptr->l1.l1l2(stptr, PH_PULL | CONFIRM, NULL); - break; - } else - stptr = stptr->next; - } -} - -void -DChannel_proc_rcv(struct IsdnCardState *cs) -{ - struct sk_buff *skb, *nskb; - struct PStack *stptr = cs->stlist; - int found, tei, sapi; - - if (stptr) - if (test_bit(FLG_L1_ACTTIMER, &stptr->l1.Flags)) - FsmEvent(&stptr->l1.l1m, EV_TIMER_ACT, NULL); - while ((skb = skb_dequeue(&cs->rq))) { -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 1); -#endif - stptr = cs->stlist; - if (skb->len < 3) { - debugl1(cs, "D-channel frame too short(%d)", skb->len); - dev_kfree_skb(skb); - return; - } - if ((skb->data[0] & 1) || !(skb->data[1] & 1)) { - debugl1(cs, "D-channel frame wrong EA0/EA1"); - dev_kfree_skb(skb); - return; - } - sapi = skb->data[0] >> 2; - tei = skb->data[1] >> 1; - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 1); - if (tei == GROUP_TEI) { - if (sapi == CTRL_SAPI) { /* sapi 0 */ - while (stptr != NULL) { - if ((nskb = skb_clone(skb, GFP_ATOMIC))) - stptr->l1.l1l2(stptr, PH_DATA | INDICATION, nskb); - else - printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n"); - stptr = stptr->next; - } - } else if (sapi == TEI_SAPI) { - while (stptr != NULL) { - if ((nskb = skb_clone(skb, GFP_ATOMIC))) - stptr->l1.l1tei(stptr, PH_DATA | INDICATION, nskb); - else - printk(KERN_WARNING "HiSax: tei broadcast buffer shortage\n"); - stptr = stptr->next; - } - } - dev_kfree_skb(skb); - } else if (sapi == CTRL_SAPI) { /* sapi 0 */ - found = 0; - while (stptr != NULL) - if (tei == stptr->l2.tei) { - stptr->l1.l1l2(stptr, PH_DATA | INDICATION, skb); - found = !0; - break; - } else - stptr = stptr->next; - if (!found) - dev_kfree_skb(skb); - } else - dev_kfree_skb(skb); - } -} - -static void -BChannel_proc_xmt(struct BCState *bcs) -{ - struct PStack *st = bcs->st; - - if (test_bit(BC_FLG_BUSY, &bcs->Flag)) { - debugl1(bcs->cs, "BC_BUSY Error"); - return; - } - - if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags)) - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) { - if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && - skb_queue_empty(&bcs->squeue)) { - st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); - } - } -} - -static void -BChannel_proc_rcv(struct BCState *bcs) -{ - struct sk_buff *skb; - - if (bcs->st->l1.l1m.state == ST_L1_WAIT_ACT) { - FsmDelTimer(&bcs->st->l1.timer, 4); - FsmEvent(&bcs->st->l1.l1m, EV_TIMER_ACT, NULL); - } - while ((skb = skb_dequeue(&bcs->rqueue))) { - bcs->st->l1.l1l2(bcs->st, PH_DATA | INDICATION, skb); - } -} - -static void -BChannel_proc_ack(struct BCState *bcs) -{ - u_long flags; - int ack; - - spin_lock_irqsave(&bcs->aclock, flags); - ack = bcs->ackcnt; - bcs->ackcnt = 0; - spin_unlock_irqrestore(&bcs->aclock, flags); - if (ack) - lli_writewakeup(bcs->st, ack); -} - -void -BChannel_bh(struct work_struct *work) -{ - struct BCState *bcs = container_of(work, struct BCState, tqueue); - - if (!bcs) - return; - if (test_and_clear_bit(B_RCVBUFREADY, &bcs->event)) - BChannel_proc_rcv(bcs); - if (test_and_clear_bit(B_XMTBUFREADY, &bcs->event)) - BChannel_proc_xmt(bcs); - if (test_and_clear_bit(B_ACKPENDING, &bcs->event)) - BChannel_proc_ack(bcs); -} - -void -HiSax_addlist(struct IsdnCardState *cs, - struct PStack *st) -{ - st->next = cs->stlist; - cs->stlist = st; -} - -void -HiSax_rmlist(struct IsdnCardState *cs, - struct PStack *st) -{ - struct PStack *p; - - FsmDelTimer(&st->l1.timer, 0); - if (cs->stlist == st) - cs->stlist = st->next; - else { - p = cs->stlist; - while (p) - if (p->next == st) { - p->next = st->next; - return; - } else - p = p->next; - } -} - -void -init_bcstate(struct IsdnCardState *cs, int bc) -{ - struct BCState *bcs = cs->bcs + bc; - - bcs->cs = cs; - bcs->channel = bc; - INIT_WORK(&bcs->tqueue, BChannel_bh); - spin_lock_init(&bcs->aclock); - bcs->BC_SetStack = NULL; - bcs->BC_Close = NULL; - bcs->Flag = 0; -} - -#ifdef L2FRAME_DEBUG /* psa */ - -static char * -l2cmd(u_char cmd) -{ - switch (cmd & ~0x10) { - case 1: - return "RR"; - case 5: - return "RNR"; - case 9: - return "REJ"; - case 0x6f: - return "SABME"; - case 0x0f: - return "DM"; - case 3: - return "UI"; - case 0x43: - return "DISC"; - case 0x63: - return "UA"; - case 0x87: - return "FRMR"; - case 0xaf: - return "XID"; - default: - if (!(cmd & 1)) - return "I"; - else - return "invalid command"; - } -} - -static char tmpdeb[32]; - -static char * -l2frames(u_char *ptr) -{ - switch (ptr[2] & ~0x10) { - case 1: - case 5: - case 9: - sprintf(tmpdeb, "%s[%d](nr %d)", l2cmd(ptr[2]), ptr[3] & 1, ptr[3] >> 1); - break; - case 0x6f: - case 0x0f: - case 3: - case 0x43: - case 0x63: - case 0x87: - case 0xaf: - sprintf(tmpdeb, "%s[%d]", l2cmd(ptr[2]), (ptr[2] & 0x10) >> 4); - break; - default: - if (!(ptr[2] & 1)) { - sprintf(tmpdeb, "I[%d](ns %d, nr %d)", ptr[3] & 1, ptr[2] >> 1, ptr[3] >> 1); - break; - } else - return "invalid command"; - } - - - return tmpdeb; -} - -void -Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, int dir) -{ - u_char *ptr; - - ptr = skb->data; - - if (ptr[0] & 1 || !(ptr[1] & 1)) - debugl1(cs, "Address not LAPD"); - else - debugl1(cs, "%s %s: %s%c (sapi %d, tei %d)", - (dir ? "<-" : "->"), buf, l2frames(ptr), - ((ptr[0] & 2) >> 1) == dir ? 'C' : 'R', ptr[0] >> 2, ptr[1] >> 1); -} -#endif - -static void -l1_reset(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F3); -} - -static void -l1_deact_cnf(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_F3); - if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); -} - -static void -l1_deact_req_s(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_F3); - FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); - test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); -} - -static void -l1_power_up_s(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) { - FsmChangeState(fi, ST_L1_F4); - st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); - FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); - test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); - } else - FsmChangeState(fi, ST_L1_F3); -} - -static void -l1_go_F5(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F5); -} - -static void -l1_go_F8(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_F8); -} - -static void -l1_info2_ind(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - -#ifdef HISAX_UINTERFACE - if (test_bit(FLG_L1_UINT, &st->l1.Flags)) - FsmChangeState(fi, ST_L1_SYNC2); - else -#endif - FsmChangeState(fi, ST_L1_F6); - st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); -} - -static void -l1_info4_ind(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - -#ifdef HISAX_UINTERFACE - if (test_bit(FLG_L1_UINT, &st->l1.Flags)) - FsmChangeState(fi, ST_L1_TRANS); - else -#endif - FsmChangeState(fi, ST_L1_F7); - st->l1.l1hw(st, HW_INFO3 | REQUEST, NULL); - if (test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) - FsmDelTimer(&st->l1.timer, 4); - if (!test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) { - if (test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags)) - FsmDelTimer(&st->l1.timer, 3); - FsmRestartTimer(&st->l1.timer, 110, EV_TIMER_ACT, NULL, 2); - test_and_set_bit(FLG_L1_ACTTIMER, &st->l1.Flags); - } -} - -static void -l1_timer3(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - test_and_clear_bit(FLG_L1_T3RUN, &st->l1.Flags); - if (test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags)) - L1deactivated(st->l1.hardware); - -#ifdef HISAX_UINTERFACE - if (!test_bit(FLG_L1_UINT, &st->l1.Flags)) -#endif - if (st->l1.l1m.state != ST_L1_F6) { - FsmChangeState(fi, ST_L1_F3); - st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); - } -} - -static void -l1_timer_act(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - test_and_clear_bit(FLG_L1_ACTTIMER, &st->l1.Flags); - test_and_set_bit(FLG_L1_ACTIVATED, &st->l1.Flags); - L1activated(st->l1.hardware); -} - -static void -l1_timer_deact(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - test_and_clear_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); - test_and_clear_bit(FLG_L1_ACTIVATED, &st->l1.Flags); - L1deactivated(st->l1.hardware); - st->l1.l1hw(st, HW_DEACTIVATE | RESPONSE, NULL); -} - -static void -l1_activate_s(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l1.l1hw(st, HW_RESET | REQUEST, NULL); -} - -static void -l1_activate_no(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if ((!test_bit(FLG_L1_DEACTTIMER, &st->l1.Flags)) && (!test_bit(FLG_L1_T3RUN, &st->l1.Flags))) { - test_and_clear_bit(FLG_L1_ACTIVATING, &st->l1.Flags); - L1deactivated(st->l1.hardware); - } -} - -static struct FsmNode L1SFnList[] __initdata = -{ - {ST_L1_F3, EV_PH_ACTIVATE, l1_activate_s}, - {ST_L1_F6, EV_PH_ACTIVATE, l1_activate_no}, - {ST_L1_F8, EV_PH_ACTIVATE, l1_activate_no}, - {ST_L1_F3, EV_RESET_IND, l1_reset}, - {ST_L1_F4, EV_RESET_IND, l1_reset}, - {ST_L1_F5, EV_RESET_IND, l1_reset}, - {ST_L1_F6, EV_RESET_IND, l1_reset}, - {ST_L1_F7, EV_RESET_IND, l1_reset}, - {ST_L1_F8, EV_RESET_IND, l1_reset}, - {ST_L1_F3, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F4, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F5, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F6, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F7, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F8, EV_DEACT_CNF, l1_deact_cnf}, - {ST_L1_F6, EV_DEACT_IND, l1_deact_req_s}, - {ST_L1_F7, EV_DEACT_IND, l1_deact_req_s}, - {ST_L1_F8, EV_DEACT_IND, l1_deact_req_s}, - {ST_L1_F3, EV_POWER_UP, l1_power_up_s}, - {ST_L1_F4, EV_RSYNC_IND, l1_go_F5}, - {ST_L1_F6, EV_RSYNC_IND, l1_go_F8}, - {ST_L1_F7, EV_RSYNC_IND, l1_go_F8}, - {ST_L1_F3, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F4, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F5, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F7, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F8, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_F3, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F4, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F5, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F6, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F8, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_F3, EV_TIMER3, l1_timer3}, - {ST_L1_F4, EV_TIMER3, l1_timer3}, - {ST_L1_F5, EV_TIMER3, l1_timer3}, - {ST_L1_F6, EV_TIMER3, l1_timer3}, - {ST_L1_F8, EV_TIMER3, l1_timer3}, - {ST_L1_F7, EV_TIMER_ACT, l1_timer_act}, - {ST_L1_F3, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F4, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F5, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F6, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F7, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_F8, EV_TIMER_DEACT, l1_timer_deact}, -}; - -#ifdef HISAX_UINTERFACE -static void -l1_deact_req_u(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_RESET); - FsmRestartTimer(&st->l1.timer, 550, EV_TIMER_DEACT, NULL, 2); - test_and_set_bit(FLG_L1_DEACTTIMER, &st->l1.Flags); - st->l1.l1hw(st, HW_ENABLE | REQUEST, NULL); -} - -static void -l1_power_up_u(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmRestartTimer(&st->l1.timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); - test_and_set_bit(FLG_L1_T3RUN, &st->l1.Flags); -} - -static void -l1_info0_ind(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L1_DEACT); -} - -static void -l1_activate_u(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l1.l1hw(st, HW_INFO1 | REQUEST, NULL); -} - -static struct FsmNode L1UFnList[] __initdata = -{ - {ST_L1_RESET, EV_DEACT_IND, l1_deact_req_u}, - {ST_L1_DEACT, EV_DEACT_IND, l1_deact_req_u}, - {ST_L1_SYNC2, EV_DEACT_IND, l1_deact_req_u}, - {ST_L1_TRANS, EV_DEACT_IND, l1_deact_req_u}, - {ST_L1_DEACT, EV_PH_ACTIVATE, l1_activate_u}, - {ST_L1_DEACT, EV_POWER_UP, l1_power_up_u}, - {ST_L1_DEACT, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_TRANS, EV_INFO2_IND, l1_info2_ind}, - {ST_L1_RESET, EV_DEACT_CNF, l1_info0_ind}, - {ST_L1_DEACT, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_SYNC2, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_RESET, EV_INFO4_IND, l1_info4_ind}, - {ST_L1_DEACT, EV_TIMER3, l1_timer3}, - {ST_L1_SYNC2, EV_TIMER3, l1_timer3}, - {ST_L1_TRANS, EV_TIMER_ACT, l1_timer_act}, - {ST_L1_DEACT, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_SYNC2, EV_TIMER_DEACT, l1_timer_deact}, - {ST_L1_RESET, EV_TIMER_DEACT, l1_timer_deact}, -}; - -#endif - -static void -l1b_activate(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_WAIT_ACT); - FsmRestartTimer(&st->l1.timer, st->l1.delay, EV_TIMER_ACT, NULL, 2); -} - -static void -l1b_deactivate(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_WAIT_DEACT); - FsmRestartTimer(&st->l1.timer, 10, EV_TIMER_DEACT, NULL, 2); -} - -static void -l1b_timer_act(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_ACTIV); - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); -} - -static void -l1b_timer_deact(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L1_NULL); - st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL); -} - -static struct FsmNode L1BFnList[] __initdata = -{ - {ST_L1_NULL, EV_PH_ACTIVATE, l1b_activate}, - {ST_L1_WAIT_ACT, EV_TIMER_ACT, l1b_timer_act}, - {ST_L1_ACTIV, EV_PH_DEACTIVATE, l1b_deactivate}, - {ST_L1_WAIT_DEACT, EV_TIMER_DEACT, l1b_timer_deact}, -}; - -int __init -Isdnl1New(void) -{ - int retval; - - l1fsm_s.state_count = L1S_STATE_COUNT; - l1fsm_s.event_count = L1_EVENT_COUNT; - l1fsm_s.strEvent = strL1Event; - l1fsm_s.strState = strL1SState; - retval = FsmNew(&l1fsm_s, L1SFnList, ARRAY_SIZE(L1SFnList)); - if (retval) - return retval; - - l1fsm_b.state_count = L1B_STATE_COUNT; - l1fsm_b.event_count = L1_EVENT_COUNT; - l1fsm_b.strEvent = strL1Event; - l1fsm_b.strState = strL1BState; - retval = FsmNew(&l1fsm_b, L1BFnList, ARRAY_SIZE(L1BFnList)); - if (retval) { - FsmFree(&l1fsm_s); - return retval; - } -#ifdef HISAX_UINTERFACE - l1fsm_u.state_count = L1U_STATE_COUNT; - l1fsm_u.event_count = L1_EVENT_COUNT; - l1fsm_u.strEvent = strL1Event; - l1fsm_u.strState = strL1UState; - retval = FsmNew(&l1fsm_u, L1UFnList, ARRAY_SIZE(L1UFnList)); - if (retval) { - FsmFree(&l1fsm_s); - FsmFree(&l1fsm_b); - return retval; - } -#endif - return 0; -} - -void Isdnl1Free(void) -{ -#ifdef HISAX_UINTERFACE - FsmFree(&l1fsm_u); -#endif - FsmFree(&l1fsm_s); - FsmFree(&l1fsm_b); -} - -static void -dch_l2l1(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - - switch (pr) { - case (PH_DATA | REQUEST): - case (PH_PULL | REQUEST): - case (PH_PULL | INDICATION): - st->l1.l1hw(st, pr, arg); - break; - case (PH_ACTIVATE | REQUEST): - if (cs->debug) - debugl1(cs, "PH_ACTIVATE_REQ %s", - st->l1.l1m.fsm->strState[st->l1.l1m.state]); - if (test_bit(FLG_L1_ACTIVATED, &st->l1.Flags)) - st->l1.l1l2(st, PH_ACTIVATE | CONFIRM, NULL); - else { - test_and_set_bit(FLG_L1_ACTIVATING, &st->l1.Flags); - FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, arg); - } - break; - case (PH_TESTLOOP | REQUEST): - if (1 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B1"); - if (2 & (long) arg) - debugl1(cs, "PH_TEST_LOOP B2"); - if (!(3 & (long) arg)) - debugl1(cs, "PH_TEST_LOOP DISABLED"); - st->l1.l1hw(st, HW_TESTLOOP | REQUEST, arg); - break; - default: - if (cs->debug) - debugl1(cs, "dch_l2l1 msg %04X unhandled", pr); - break; - } -} - -void -l1_msg(struct IsdnCardState *cs, int pr, void *arg) { - struct PStack *st; - - st = cs->stlist; - - while (st) { - switch (pr) { - case (HW_RESET | INDICATION): - FsmEvent(&st->l1.l1m, EV_RESET_IND, arg); - break; - case (HW_DEACTIVATE | CONFIRM): - FsmEvent(&st->l1.l1m, EV_DEACT_CNF, arg); - break; - case (HW_DEACTIVATE | INDICATION): - FsmEvent(&st->l1.l1m, EV_DEACT_IND, arg); - break; - case (HW_POWERUP | CONFIRM): - FsmEvent(&st->l1.l1m, EV_POWER_UP, arg); - break; - case (HW_RSYNC | INDICATION): - FsmEvent(&st->l1.l1m, EV_RSYNC_IND, arg); - break; - case (HW_INFO2 | INDICATION): - FsmEvent(&st->l1.l1m, EV_INFO2_IND, arg); - break; - case (HW_INFO4_P8 | INDICATION): - case (HW_INFO4_P10 | INDICATION): - FsmEvent(&st->l1.l1m, EV_INFO4_IND, arg); - break; - default: - if (cs->debug) - debugl1(cs, "%s %04X unhandled", __func__, pr); - break; - } - st = st->next; - } -} - -void -l1_msg_b(struct PStack *st, int pr, void *arg) { - switch (pr) { - case (PH_ACTIVATE | REQUEST): - FsmEvent(&st->l1.l1m, EV_PH_ACTIVATE, NULL); - break; - case (PH_DEACTIVATE | REQUEST): - FsmEvent(&st->l1.l1m, EV_PH_DEACTIVATE, NULL); - break; - } -} - -void -setstack_HiSax(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.hardware = cs; - st->protocol = cs->protocol; - st->l1.l1m.fsm = &l1fsm_s; - st->l1.l1m.state = ST_L1_F3; - st->l1.Flags = 0; -#ifdef HISAX_UINTERFACE - if (test_bit(FLG_HW_L1_UINT, &cs->HW_Flags)) { - st->l1.l1m.fsm = &l1fsm_u; - st->l1.l1m.state = ST_L1_RESET; - st->l1.Flags = FLG_L1_UINT; - } -#endif - st->l1.l1m.debug = cs->debug; - st->l1.l1m.userdata = st; - st->l1.l1m.userint = 0; - st->l1.l1m.printdebug = l1m_debug; - FsmInitTimer(&st->l1.l1m, &st->l1.timer); - setstack_tei(st); - setstack_manager(st); - st->l1.stlistp = &(cs->stlist); - st->l2.l2l1 = dch_l2l1; - if (cs->setstack_d) - cs->setstack_d(st, cs); -} - -void -setstack_l1_B(struct PStack *st) -{ - struct IsdnCardState *cs = st->l1.hardware; - - st->l1.l1m.fsm = &l1fsm_b; - st->l1.l1m.state = ST_L1_NULL; - st->l1.l1m.debug = cs->debug; - st->l1.l1m.userdata = st; - st->l1.l1m.userint = 0; - st->l1.l1m.printdebug = l1m_debug; - st->l1.Flags = 0; - FsmInitTimer(&st->l1.l1m, &st->l1.timer); -} diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h deleted file mode 100644 index 66ddcab19bba..000000000000 --- a/drivers/isdn/hisax/isdnl1.h +++ /dev/null @@ -1,32 +0,0 @@ -/* $Id: isdnl1.h,v 2.12.2.3 2004/02/11 13:21:34 keil Exp $ - * - * Layer 1 defines - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define D_RCVBUFREADY 0 -#define D_XMTBUFREADY 1 -#define D_L1STATECHANGE 2 -#define D_CLEARBUSY 3 -#define D_RX_MON0 4 -#define D_RX_MON1 5 -#define D_TX_MON0 6 -#define D_TX_MON1 7 -#define E_RCVBUFREADY 8 - -#define B_RCVBUFREADY 0 -#define B_XMTBUFREADY 1 -#define B_ACKPENDING 2 - -__printf(2, 3) -void debugl1(struct IsdnCardState *cs, char *fmt, ...); -void DChannel_proc_xmt(struct IsdnCardState *cs); -void DChannel_proc_rcv(struct IsdnCardState *cs); -void l1_msg(struct IsdnCardState *cs, int pr, void *arg); -void l1_msg_b(struct PStack *st, int pr, void *arg); -void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf, - int dir); -void BChannel_bh(struct work_struct *work); diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c deleted file mode 100644 index 1a40ed04cb52..000000000000 --- a/drivers/isdn/hisax/isdnl2.c +++ /dev/null @@ -1,1839 +0,0 @@ -/* $Id: isdnl2.c,v 2.30.2.4 2004/02/11 13:21:34 keil Exp $ - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil <keil@isdn4linux.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 - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include <linux/init.h> -#include <linux/gfp.h> -#include "hisax.h" -#include "isdnl2.h" - -const char *l2_revision = "$Revision: 2.30.2.4 $"; - -static void l2m_debug(struct FsmInst *fi, char *fmt, ...); - -static struct Fsm l2fsm; - -enum { - ST_L2_1, - ST_L2_2, - ST_L2_3, - ST_L2_4, - ST_L2_5, - ST_L2_6, - ST_L2_7, - ST_L2_8, -}; - -#define L2_STATE_COUNT (ST_L2_8 + 1) - -static char *strL2State[] = -{ - "ST_L2_1", - "ST_L2_2", - "ST_L2_3", - "ST_L2_4", - "ST_L2_5", - "ST_L2_6", - "ST_L2_7", - "ST_L2_8", -}; - -enum { - EV_L2_UI, - EV_L2_SABME, - EV_L2_DISC, - EV_L2_DM, - EV_L2_UA, - EV_L2_FRMR, - EV_L2_SUPER, - EV_L2_I, - EV_L2_DL_DATA, - EV_L2_ACK_PULL, - EV_L2_DL_UNIT_DATA, - EV_L2_DL_ESTABLISH_REQ, - EV_L2_DL_RELEASE_REQ, - EV_L2_MDL_ASSIGN, - EV_L2_MDL_REMOVE, - EV_L2_MDL_ERROR, - EV_L1_DEACTIVATE, - EV_L2_T200, - EV_L2_T203, - EV_L2_SET_OWN_BUSY, - EV_L2_CLEAR_OWN_BUSY, - EV_L2_FRAME_ERROR, -}; - -#define L2_EVENT_COUNT (EV_L2_FRAME_ERROR + 1) - -static char *strL2Event[] = -{ - "EV_L2_UI", - "EV_L2_SABME", - "EV_L2_DISC", - "EV_L2_DM", - "EV_L2_UA", - "EV_L2_FRMR", - "EV_L2_SUPER", - "EV_L2_I", - "EV_L2_DL_DATA", - "EV_L2_ACK_PULL", - "EV_L2_DL_UNIT_DATA", - "EV_L2_DL_ESTABLISH_REQ", - "EV_L2_DL_RELEASE_REQ", - "EV_L2_MDL_ASSIGN", - "EV_L2_MDL_REMOVE", - "EV_L2_MDL_ERROR", - "EV_L1_DEACTIVATE", - "EV_L2_T200", - "EV_L2_T203", - "EV_L2_SET_OWN_BUSY", - "EV_L2_CLEAR_OWN_BUSY", - "EV_L2_FRAME_ERROR", -}; - -static int l2addrsize(struct Layer2 *l2); - -static void -set_peer_busy(struct Layer2 *l2) { - test_and_set_bit(FLG_PEER_BUSY, &l2->flag); - if (!skb_queue_empty(&l2->i_queue) || - !skb_queue_empty(&l2->ui_queue)) - test_and_set_bit(FLG_L2BLOCK, &l2->flag); -} - -static void -clear_peer_busy(struct Layer2 *l2) { - if (test_and_clear_bit(FLG_PEER_BUSY, &l2->flag)) - test_and_clear_bit(FLG_L2BLOCK, &l2->flag); -} - -static void -InitWin(struct Layer2 *l2) -{ - int i; - - for (i = 0; i < MAX_WINDOW; i++) - l2->windowar[i] = NULL; -} - -static int -freewin1(struct Layer2 *l2) -{ - int i, cnt = 0; - - for (i = 0; i < MAX_WINDOW; i++) { - if (l2->windowar[i]) { - cnt++; - dev_kfree_skb(l2->windowar[i]); - l2->windowar[i] = NULL; - } - } - return cnt; -} - -static inline void -freewin(struct PStack *st) -{ - freewin1(&st->l2); -} - -static void -ReleaseWin(struct Layer2 *l2) -{ - int cnt; - - if ((cnt = freewin1(l2))) - printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt); -} - -static inline unsigned int -cansend(struct PStack *st) -{ - unsigned int p1; - - if (test_bit(FLG_MOD128, &st->l2.flag)) - p1 = (st->l2.vs - st->l2.va) % 128; - else - p1 = (st->l2.vs - st->l2.va) % 8; - return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag)); -} - -static inline void -clear_exception(struct Layer2 *l2) -{ - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); - test_and_clear_bit(FLG_REJEXC, &l2->flag); - test_and_clear_bit(FLG_OWN_BUSY, &l2->flag); - clear_peer_busy(l2); -} - -static inline int -l2headersize(struct Layer2 *l2, int ui) -{ - return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) + - (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1)); -} - -inline int -l2addrsize(struct Layer2 *l2) -{ - return (test_bit(FLG_LAPD, &l2->flag) ? 2 : 1); -} - -static int -sethdraddr(struct Layer2 *l2, u_char *header, int rsp) -{ - u_char *ptr = header; - int crbit = rsp; - - if (test_bit(FLG_LAPD, &l2->flag)) { - *ptr++ = (l2->sap << 2) | (rsp ? 2 : 0); - *ptr++ = (l2->tei << 1) | 1; - return (2); - } else { - if (test_bit(FLG_ORIG, &l2->flag)) - crbit = !crbit; - if (crbit) - *ptr++ = 1; - else - *ptr++ = 3; - return (1); - } -} - -static inline void -enqueue_super(struct PStack *st, - struct sk_buff *skb) -{ - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l1.bcs->tx_cnt += skb->len; - st->l2.l2l1(st, PH_DATA | REQUEST, skb); -} - -#define enqueue_ui(a, b) enqueue_super(a, b) - -static inline int -IsUI(u_char *data) -{ - return ((data[0] & 0xef) == UI); -} - -static inline int -IsUA(u_char *data) -{ - return ((data[0] & 0xef) == UA); -} - -static inline int -IsDM(u_char *data) -{ - return ((data[0] & 0xef) == DM); -} - -static inline int -IsDISC(u_char *data) -{ - return ((data[0] & 0xef) == DISC); -} - -static inline int -IsSFrame(u_char *data, struct PStack *st) -{ - register u_char d = *data; - - if (!test_bit(FLG_MOD128, &st->l2.flag)) - d &= 0xf; - return (((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c)); -} - -static inline int -IsSABME(u_char *data, struct PStack *st) -{ - u_char d = data[0] & ~0x10; - - return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM); -} - -static inline int -IsREJ(u_char *data, struct PStack *st) -{ - return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ); -} - -static inline int -IsFRMR(u_char *data) -{ - return ((data[0] & 0xef) == FRMR); -} - -static inline int -IsRNR(u_char *data, struct PStack *st) -{ - return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR); -} - -static int -iframe_error(struct PStack *st, struct sk_buff *skb) -{ - int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1); - int rsp = *skb->data & 0x2; - - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - - if (rsp) - return 'L'; - - - if (skb->len < i) - return 'N'; - - if ((skb->len - i) > st->l2.maxlen) - return 'O'; - - - return 0; -} - -static int -super_error(struct PStack *st, struct sk_buff *skb) -{ - if (skb->len != l2addrsize(&st->l2) + - (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1)) - return 'N'; - - return 0; -} - -static int -unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp) -{ - int rsp = (*skb->data & 0x2) >> 1; - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - - if (rsp != wantrsp) - return 'L'; - - if (skb->len != l2addrsize(&st->l2) + 1) - return 'N'; - - return 0; -} - -static int -UI_error(struct PStack *st, struct sk_buff *skb) -{ - int rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - - if (rsp) - return 'L'; - - if (skb->len > st->l2.maxlen + l2addrsize(&st->l2) + 1) - return 'O'; - - return 0; -} - -static int -FRMR_error(struct PStack *st, struct sk_buff *skb) -{ - int headers = l2addrsize(&st->l2) + 1; - u_char *datap = skb->data + headers; - int rsp = *skb->data & 0x2; - - if (test_bit(FLG_ORIG, &st->l2.flag)) - rsp = !rsp; - - if (!rsp) - return 'L'; - - if (test_bit(FLG_MOD128, &st->l2.flag)) { - if (skb->len < headers + 5) - return 'N'; - else - l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x %2x %2x", - datap[0], datap[1], datap[2], - datap[3], datap[4]); - } else { - if (skb->len < headers + 3) - return 'N'; - else - l2m_debug(&st->l2.l2m, "FRMR information %2x %2x %2x", - datap[0], datap[1], datap[2]); - } - - return 0; -} - -static unsigned int -legalnr(struct PStack *st, unsigned int nr) -{ - struct Layer2 *l2 = &st->l2; - - if (test_bit(FLG_MOD128, &l2->flag)) - return ((nr - l2->va) % 128) <= ((l2->vs - l2->va) % 128); - else - return ((nr - l2->va) % 8) <= ((l2->vs - l2->va) % 8); -} - -static void -setva(struct PStack *st, unsigned int nr) -{ - struct Layer2 *l2 = &st->l2; - int len; - u_long flags; - - spin_lock_irqsave(&l2->lock, flags); - while (l2->va != nr) { - (l2->va)++; - if (test_bit(FLG_MOD128, &l2->flag)) - l2->va %= 128; - else - l2->va %= 8; - len = l2->windowar[l2->sow]->len; - if (PACKET_NOACK == l2->windowar[l2->sow]->pkt_type) - len = -1; - dev_kfree_skb(l2->windowar[l2->sow]); - l2->windowar[l2->sow] = NULL; - l2->sow = (l2->sow + 1) % l2->window; - spin_unlock_irqrestore(&l2->lock, flags); - if (test_bit(FLG_LLI_L2WAKEUP, &st->lli.flag) && (len >= 0)) - lli_writewakeup(st, len); - spin_lock_irqsave(&l2->lock, flags); - } - spin_unlock_irqrestore(&l2->lock, flags); -} - -static void -send_uframe(struct PStack *st, u_char cmd, u_char cr) -{ - struct sk_buff *skb; - u_char tmp[MAX_HEADER_LEN]; - int i; - - i = sethdraddr(&st->l2, tmp, cr); - tmp[i++] = cmd; - if (!(skb = alloc_skb(i, GFP_ATOMIC))) { - printk(KERN_WARNING "isdl2 can't alloc sbbuff for send_uframe\n"); - return; - } - skb_put_data(skb, tmp, i); - enqueue_super(st, skb); -} - -static inline u_char -get_PollFlag(struct PStack *st, struct sk_buff *skb) -{ - return (skb->data[l2addrsize(&(st->l2))] & 0x10); -} - -static inline u_char -get_PollFlagFree(struct PStack *st, struct sk_buff *skb) -{ - u_char PF; - - PF = get_PollFlag(st, skb); - dev_kfree_skb(skb); - return (PF); -} - -static inline void -start_t200(struct PStack *st, int i) -{ - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); -} - -static inline void -restart_t200(struct PStack *st, int i) -{ - FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i); - test_and_set_bit(FLG_T200_RUN, &st->l2.flag); -} - -static inline void -stop_t200(struct PStack *st, int i) -{ - if (test_and_clear_bit(FLG_T200_RUN, &st->l2.flag)) - FsmDelTimer(&st->l2.t200, i); -} - -static inline void -st5_dl_release_l2l3(struct PStack *st) -{ - int pr; - - if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) - pr = DL_RELEASE | CONFIRM; - else - pr = DL_RELEASE | INDICATION; - - st->l2.l2l3(st, pr, NULL); -} - -static inline void -lapb_dl_release_l2l3(struct PStack *st, int f) -{ - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); - st->l2.l2l3(st, DL_RELEASE | f, NULL); -} - -static void -establishlink(struct FsmInst *fi) -{ - struct PStack *st = fi->userdata; - u_char cmd; - - clear_exception(&st->l2); - st->l2.rc = 0; - cmd = (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM) | 0x10; - send_uframe(st, cmd, CMD); - FsmDelTimer(&st->l2.t203, 1); - restart_t200(st, 1); - test_and_clear_bit(FLG_PEND_REL, &st->l2.flag); - freewin(st); - FsmChangeState(fi, ST_L2_5); -} - -static void -l2_mdl_error_ua(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct PStack *st = fi->userdata; - - if (get_PollFlagFree(st, skb)) - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'C'); - else - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'D'); -} - -static void -l2_mdl_error_dm(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct PStack *st = fi->userdata; - - if (get_PollFlagFree(st, skb)) - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B'); - else { - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); - } -} - -static void -l2_st8_mdl_error_dm(struct FsmInst *fi, int event, void *arg) -{ - struct sk_buff *skb = arg; - struct PStack *st = fi->userdata; - - if (get_PollFlagFree(st, skb)) - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'B'); - else { - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'E'); - } - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); -} - -static void -l2_go_st3(struct FsmInst *fi, int event, void *arg) -{ - FsmChangeState(fi, ST_L2_3); -} - -static void -l2_mdl_assign(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L2_3); - st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL); -} - -static void -l2_queue_ui_assign(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&st->l2.ui_queue, skb); - FsmChangeState(fi, ST_L2_2); - st->l2.l2tei(st, MDL_ASSIGN | INDICATION, NULL); -} - -static void -l2_queue_ui(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&st->l2.ui_queue, skb); -} - -static void -tx_ui(struct PStack *st) -{ - struct sk_buff *skb; - u_char header[MAX_HEADER_LEN]; - int i; - - i = sethdraddr(&(st->l2), header, CMD); - header[i++] = UI; - while ((skb = skb_dequeue(&st->l2.ui_queue))) { - memcpy(skb_push(skb, i), header, i); - enqueue_ui(st, skb); - } -} - -static void -l2_send_ui(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - skb_queue_tail(&st->l2.ui_queue, skb); - tx_ui(st); -} - -static void -l2_got_ui(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - skb_pull(skb, l2headersize(&st->l2, 1)); - st->l2.l2l3(st, DL_UNIT_DATA | INDICATION, skb); -/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * in states 1-3 for broadcast - */ - - -} - -static void -l2_establish(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &st->l2.flag); -} - -static void -l2_discard_i_setl3(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - test_and_set_bit(FLG_L3_INIT, &st->l2.flag); - test_and_clear_bit(FLG_PEND_REL, &st->l2.flag); -} - -static void -l2_l3_reestablish(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &st->l2.flag); -} - -static void -l2_release(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); -} - -static void -l2_pend_rel(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - test_and_set_bit(FLG_PEND_REL, &st->l2.flag); -} - -static void -l2_disconnect(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - freewin(st); - FsmChangeState(fi, ST_L2_6); - st->l2.rc = 0; - send_uframe(st, DISC | 0x10, CMD); - FsmDelTimer(&st->l2.t203, 1); - restart_t200(st, 2); -} - -static void -l2_start_multi(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); - - clear_exception(&st->l2); - st->l2.vs = 0; - st->l2.va = 0; - st->l2.vr = 0; - st->l2.sow = 0; - FsmChangeState(fi, ST_L2_7); - FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); - - st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); -} - -static void -l2_send_UA(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); -} - -static void -l2_send_DM(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - send_uframe(st, DM | get_PollFlagFree(st, skb), RSP); -} - -static void -l2_restart_multi(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int est = 0, state; - - state = fi->state; - - send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); - - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'F'); - - if (st->l2.vs != st->l2.va) { - skb_queue_purge(&st->l2.i_queue); - est = 1; - } - - clear_exception(&st->l2); - st->l2.vs = 0; - st->l2.va = 0; - st->l2.vr = 0; - st->l2.sow = 0; - FsmChangeState(fi, ST_L2_7); - stop_t200(st, 3); - FsmRestartTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 3); - - if (est) - st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL); - - if ((ST_L2_7 == state) || (ST_L2_8 == state)) - if (!skb_queue_empty(&st->l2.i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); -} - -static void -l2_stop_multi(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - FsmChangeState(fi, ST_L2_4); - FsmDelTimer(&st->l2.t203, 3); - stop_t200(st, 4); - - send_uframe(st, UA | get_PollFlagFree(st, skb), RSP); - - skb_queue_purge(&st->l2.i_queue); - freewin(st); - lapb_dl_release_l2l3(st, INDICATION); -} - -static void -l2_connected(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int pr = -1; - - if (!get_PollFlag(st, skb)) { - l2_mdl_error_ua(fi, event, arg); - return; - } - dev_kfree_skb(skb); - - if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag)) - l2_disconnect(fi, event, arg); - - if (test_and_clear_bit(FLG_L3_INIT, &st->l2.flag)) { - pr = DL_ESTABLISH | CONFIRM; - } else if (st->l2.vs != st->l2.va) { - skb_queue_purge(&st->l2.i_queue); - pr = DL_ESTABLISH | INDICATION; - } - - stop_t200(st, 5); - - st->l2.vr = 0; - st->l2.vs = 0; - st->l2.va = 0; - st->l2.sow = 0; - FsmChangeState(fi, ST_L2_7); - FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 4); - - if (pr != -1) - st->l2.l2l3(st, pr, NULL); - - if (!skb_queue_empty(&st->l2.i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); -} - -static void -l2_released(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (!get_PollFlag(st, skb)) { - l2_mdl_error_ua(fi, event, arg); - return; - } - dev_kfree_skb(skb); - - stop_t200(st, 6); - lapb_dl_release_l2l3(st, CONFIRM); - FsmChangeState(fi, ST_L2_4); -} - -static void -l2_reestablish(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (!get_PollFlagFree(st, skb)) { - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &st->l2.flag); - } -} - -static void -l2_st5_dm_release(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (get_PollFlagFree(st, skb)) { - stop_t200(st, 7); - if (!test_bit(FLG_L3_INIT, &st->l2.flag)) - skb_queue_purge(&st->l2.i_queue); - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); - st5_dl_release_l2l3(st); - FsmChangeState(fi, ST_L2_4); - } -} - -static void -l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (get_PollFlagFree(st, skb)) { - stop_t200(st, 8); - lapb_dl_release_l2l3(st, CONFIRM); - FsmChangeState(fi, ST_L2_4); - } -} - -static inline void -enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf) -{ - struct sk_buff *skb; - struct Layer2 *l2; - u_char tmp[MAX_HEADER_LEN]; - int i; - - l2 = &st->l2; - i = sethdraddr(l2, tmp, cr); - if (test_bit(FLG_MOD128, &l2->flag)) { - tmp[i++] = typ; - tmp[i++] = (l2->vr << 1) | (pf ? 1 : 0); - } else - tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); - if (!(skb = alloc_skb(i, GFP_ATOMIC))) { - printk(KERN_WARNING "isdl2 can't alloc sbbuff for enquiry_cr\n"); - return; - } - skb_put_data(skb, tmp, i); - enqueue_super(st, skb); -} - -static inline void -enquiry_response(struct PStack *st) -{ - if (test_bit(FLG_OWN_BUSY, &st->l2.flag)) - enquiry_cr(st, RNR, RSP, 1); - else - enquiry_cr(st, RR, RSP, 1); - test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); -} - -static inline void -transmit_enquiry(struct PStack *st) -{ - if (test_bit(FLG_OWN_BUSY, &st->l2.flag)) - enquiry_cr(st, RNR, CMD, 1); - else - enquiry_cr(st, RR, CMD, 1); - test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); - start_t200(st, 9); -} - - -static void -nrerrorrecovery(struct FsmInst *fi) -{ - struct PStack *st = fi->userdata; - - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'J'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); -} - -static void -invoke_retransmission(struct PStack *st, unsigned int nr) -{ - struct Layer2 *l2 = &st->l2; - u_int p1; - u_long flags; - - spin_lock_irqsave(&l2->lock, flags); - if (l2->vs != nr) { - while (l2->vs != nr) { - (l2->vs)--; - if (test_bit(FLG_MOD128, &l2->flag)) { - l2->vs %= 128; - p1 = (l2->vs - l2->va) % 128; - } else { - l2->vs %= 8; - p1 = (l2->vs - l2->va) % 8; - } - p1 = (p1 + l2->sow) % l2->window; - if (test_bit(FLG_LAPB, &l2->flag)) - st->l1.bcs->tx_cnt += l2->windowar[p1]->len + l2headersize(l2, 0); - skb_queue_head(&l2->i_queue, l2->windowar[p1]); - l2->windowar[p1] = NULL; - } - spin_unlock_irqrestore(&l2->lock, flags); - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); - return; - } - spin_unlock_irqrestore(&l2->lock, flags); -} - -static void -l2_st7_got_super(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int PollFlag, rsp, typ = RR; - unsigned int nr; - struct Layer2 *l2 = &st->l2; - - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; - - skb_pull(skb, l2addrsize(l2)); - if (IsRNR(skb->data, st)) { - set_peer_busy(l2); - typ = RNR; - } else - clear_peer_busy(l2); - if (IsREJ(skb->data, st)) - typ = REJ; - - if (test_bit(FLG_MOD128, &l2->flag)) { - PollFlag = (skb->data[1] & 0x1) == 0x1; - nr = skb->data[1] >> 1; - } else { - PollFlag = (skb->data[0] & 0x10); - nr = (skb->data[0] >> 5) & 0x7; - } - dev_kfree_skb(skb); - - if (PollFlag) { - if (rsp) - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'A'); - else - enquiry_response(st); - } - if (legalnr(st, nr)) { - if (typ == REJ) { - setva(st, nr); - invoke_retransmission(st, nr); - stop_t200(st, 10); - if (FsmAddTimer(&st->l2.t203, st->l2.T203, - EV_L2_T203, NULL, 6)) - l2m_debug(&st->l2.l2m, "Restart T203 ST7 REJ"); - } else if ((nr == l2->vs) && (typ == RR)) { - setva(st, nr); - stop_t200(st, 11); - FsmRestartTimer(&st->l2.t203, st->l2.T203, - EV_L2_T203, NULL, 7); - } else if ((l2->va != nr) || (typ == RNR)) { - setva(st, nr); - if (typ != RR) FsmDelTimer(&st->l2.t203, 9); - restart_t200(st, 12); - } - if (!skb_queue_empty(&st->l2.i_queue) && (typ == RR)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); - } else - nrerrorrecovery(fi); -} - -static void -l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0); - if (!test_bit(FLG_L3_INIT, &st->l2.flag)) - skb_queue_tail(&st->l2.i_queue, skb); - else - dev_kfree_skb(skb); -} - -static void -l2_feed_i_pull(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0); - skb_queue_tail(&st->l2.i_queue, skb); - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); -} - -static void -l2_feed_iqueue(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l1.bcs->tx_cnt += skb->len + l2headersize(&st->l2, 0); - skb_queue_tail(&st->l2.i_queue, skb); -} - -static void -l2_got_iframe(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - struct Layer2 *l2 = &(st->l2); - int PollFlag, ns, i; - unsigned int nr; - - i = l2addrsize(l2); - if (test_bit(FLG_MOD128, &l2->flag)) { - PollFlag = ((skb->data[i + 1] & 0x1) == 0x1); - ns = skb->data[i] >> 1; - nr = (skb->data[i + 1] >> 1) & 0x7f; - } else { - PollFlag = (skb->data[i] & 0x10); - ns = (skb->data[i] >> 1) & 0x7; - nr = (skb->data[i] >> 5) & 0x7; - } - if (test_bit(FLG_OWN_BUSY, &l2->flag)) { - dev_kfree_skb(skb); - if (PollFlag) enquiry_response(st); - } else if (l2->vr == ns) { - (l2->vr)++; - if (test_bit(FLG_MOD128, &l2->flag)) - l2->vr %= 128; - else - l2->vr %= 8; - test_and_clear_bit(FLG_REJEXC, &l2->flag); - - if (PollFlag) - enquiry_response(st); - else - test_and_set_bit(FLG_ACK_PEND, &l2->flag); - skb_pull(skb, l2headersize(l2, 0)); - st->l2.l2l3(st, DL_DATA | INDICATION, skb); - } else { - /* n(s)!=v(r) */ - dev_kfree_skb(skb); - if (test_and_set_bit(FLG_REJEXC, &l2->flag)) { - if (PollFlag) - enquiry_response(st); - } else { - enquiry_cr(st, REJ, RSP, PollFlag); - test_and_clear_bit(FLG_ACK_PEND, &l2->flag); - } - } - - if (legalnr(st, nr)) { - if (!test_bit(FLG_PEER_BUSY, &st->l2.flag) && (fi->state == ST_L2_7)) { - if (nr == st->l2.vs) { - stop_t200(st, 13); - FsmRestartTimer(&st->l2.t203, st->l2.T203, - EV_L2_T203, NULL, 7); - } else if (nr != st->l2.va) - restart_t200(st, 14); - } - setva(st, nr); - } else { - nrerrorrecovery(fi); - return; - } - - if (!skb_queue_empty(&st->l2.i_queue) && (fi->state == ST_L2_7)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); - if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag)) - enquiry_cr(st, RR, RSP, 0); -} - -static void -l2_got_tei(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->l2.tei = (long) arg; - - if (fi->state == ST_L2_3) { - establishlink(fi); - test_and_set_bit(FLG_L3_INIT, &st->l2.flag); - } else - FsmChangeState(fi, ST_L2_4); - if (!skb_queue_empty(&st->l2.ui_queue)) - tx_ui(st); -} - -static void -l2_st5_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_LAPD, &st->l2.flag) && - test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); - } else if (st->l2.rc == st->l2.N200) { - FsmChangeState(fi, ST_L2_4); - test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - skb_queue_purge(&st->l2.i_queue); - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'G'); - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); - st5_dl_release_l2l3(st); - } else { - st->l2.rc++; - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); - send_uframe(st, (test_bit(FLG_MOD128, &st->l2.flag) ? SABME : SABM) - | 0x10, CMD); - } -} - -static void -l2_st6_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_LAPD, &st->l2.flag) && - test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); - } else if (st->l2.rc == st->l2.N200) { - FsmChangeState(fi, ST_L2_4); - test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'H'); - lapb_dl_release_l2l3(st, CONFIRM); - } else { - st->l2.rc++; - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, - NULL, 9); - send_uframe(st, DISC | 0x10, CMD); - } -} - -static void -l2_st7_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_LAPD, &st->l2.flag) && - test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); - return; - } - test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - st->l2.rc = 0; - FsmChangeState(fi, ST_L2_8); - - transmit_enquiry(st); - st->l2.rc++; -} - -static void -l2_st8_tout_200(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_LAPD, &st->l2.flag) && - test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 9); - return; - } - test_and_clear_bit(FLG_T200_RUN, &st->l2.flag); - if (st->l2.rc == st->l2.N200) { - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'I'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); - } else { - transmit_enquiry(st); - st->l2.rc++; - } -} - -static void -l2_st7_tout_203(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_LAPD, &st->l2.flag) && - test_bit(FLG_DCHAN_BUSY, &st->l2.flag)) { - FsmAddTimer(&st->l2.t203, st->l2.T203, EV_L2_T203, NULL, 9); - return; - } - FsmChangeState(fi, ST_L2_8); - transmit_enquiry(st); - st->l2.rc = 0; -} - -static void -l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb, *nskb; - struct Layer2 *l2 = &st->l2; - u_char header[MAX_HEADER_LEN]; - int i, hdr_space_needed; - int unsigned p1; - u_long flags; - - if (!cansend(st)) - return; - - skb = skb_dequeue(&l2->i_queue); - if (!skb) - return; - - hdr_space_needed = l2headersize(l2, 0); - nskb = skb_realloc_headroom(skb, hdr_space_needed); - if (!nskb) { - skb_queue_head(&l2->i_queue, skb); - return; - } - spin_lock_irqsave(&l2->lock, flags); - if (test_bit(FLG_MOD128, &l2->flag)) - p1 = (l2->vs - l2->va) % 128; - else - p1 = (l2->vs - l2->va) % 8; - p1 = (p1 + l2->sow) % l2->window; - if (l2->windowar[p1]) { - printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", - p1); - dev_kfree_skb(l2->windowar[p1]); - } - l2->windowar[p1] = skb; - - i = sethdraddr(&st->l2, header, CMD); - - if (test_bit(FLG_MOD128, &l2->flag)) { - header[i++] = l2->vs << 1; - header[i++] = l2->vr << 1; - l2->vs = (l2->vs + 1) % 128; - } else { - header[i++] = (l2->vr << 5) | (l2->vs << 1); - l2->vs = (l2->vs + 1) % 8; - } - spin_unlock_irqrestore(&l2->lock, flags); - memcpy(skb_push(nskb, i), header, i); - st->l2.l2l1(st, PH_PULL | INDICATION, nskb); - test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); - if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) { - FsmDelTimer(&st->l2.t203, 13); - FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11); - } - if (!skb_queue_empty(&l2->i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); -} - -static void -l2_st8_got_super(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int PollFlag, rsp, rnr = 0; - unsigned int nr; - struct Layer2 *l2 = &st->l2; - - rsp = *skb->data & 0x2; - if (test_bit(FLG_ORIG, &l2->flag)) - rsp = !rsp; - - skb_pull(skb, l2addrsize(l2)); - - if (IsRNR(skb->data, st)) { - set_peer_busy(l2); - rnr = 1; - } else - clear_peer_busy(l2); - - if (test_bit(FLG_MOD128, &l2->flag)) { - PollFlag = (skb->data[1] & 0x1) == 0x1; - nr = skb->data[1] >> 1; - } else { - PollFlag = (skb->data[0] & 0x10); - nr = (skb->data[0] >> 5) & 0x7; - } - dev_kfree_skb(skb); - - if (rsp && PollFlag) { - if (legalnr(st, nr)) { - if (rnr) { - restart_t200(st, 15); - } else { - stop_t200(st, 16); - FsmAddTimer(&l2->t203, l2->T203, - EV_L2_T203, NULL, 5); - setva(st, nr); - } - invoke_retransmission(st, nr); - FsmChangeState(fi, ST_L2_7); - if (!skb_queue_empty(&l2->i_queue) && cansend(st)) - st->l2.l2l1(st, PH_PULL | REQUEST, NULL); - } else - nrerrorrecovery(fi); - } else { - if (!rsp && PollFlag) - enquiry_response(st); - if (legalnr(st, nr)) { - setva(st, nr); - } else - nrerrorrecovery(fi); - } -} - -static void -l2_got_FRMR(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - - skb_pull(skb, l2addrsize(&st->l2) + 1); - - if (!(skb->data[0] & 1) || ((skb->data[0] & 3) == 1) || /* I or S */ - (IsUA(skb->data) && (fi->state == ST_L2_7))) { - st->ma.layer(st, MDL_ERROR | INDICATION, (void *) 'K'); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); - } - dev_kfree_skb(skb); -} - -static void -l2_st24_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.ui_queue); - st->l2.tei = -1; - FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st3_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.ui_queue); - st->l2.tei = -1; - st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); - FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st5_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - freewin(st); - st->l2.tei = -1; - stop_t200(st, 17); - st5_dl_release_l2l3(st); - FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st6_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.ui_queue); - st->l2.tei = -1; - stop_t200(st, 18); - st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); - FsmChangeState(fi, ST_L2_1); -} - -static void -l2_tei_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - freewin(st); - st->l2.tei = -1; - stop_t200(st, 17); - FsmDelTimer(&st->l2.t203, 19); - st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); - FsmChangeState(fi, ST_L2_1); -} - -static void -l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag)) - st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); -} - -static void -l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - freewin(st); - stop_t200(st, 19); - st5_dl_release_l2l3(st); - FsmChangeState(fi, ST_L2_4); -} - -static void -l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.ui_queue); - stop_t200(st, 20); - st->l2.l2l3(st, DL_RELEASE | CONFIRM, NULL); - FsmChangeState(fi, ST_L2_4); -} - -static void -l2_persistent_da(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - freewin(st); - stop_t200(st, 19); - FsmDelTimer(&st->l2.t203, 19); - st->l2.l2l3(st, DL_RELEASE | INDICATION, NULL); - FsmChangeState(fi, ST_L2_4); -} - -static void -l2_set_own_busy(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (!test_and_set_bit(FLG_OWN_BUSY, &st->l2.flag)) { - enquiry_cr(st, RNR, RSP, 0); - test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); - } -} - -static void -l2_clear_own_busy(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (!test_and_clear_bit(FLG_OWN_BUSY, &st->l2.flag)) { - enquiry_cr(st, RR, RSP, 0); - test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); - } -} - -static void -l2_frame_error(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->ma.layer(st, MDL_ERROR | INDICATION, arg); -} - -static void -l2_frame_error_reest(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - st->ma.layer(st, MDL_ERROR | INDICATION, arg); - establishlink(fi); - test_and_clear_bit(FLG_L3_INIT, &st->l2.flag); -} - -static struct FsmNode L2FnList[] __initdata = -{ - {ST_L2_1, EV_L2_DL_ESTABLISH_REQ, l2_mdl_assign}, - {ST_L2_2, EV_L2_DL_ESTABLISH_REQ, l2_go_st3}, - {ST_L2_4, EV_L2_DL_ESTABLISH_REQ, l2_establish}, - {ST_L2_5, EV_L2_DL_ESTABLISH_REQ, l2_discard_i_setl3}, - {ST_L2_7, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, - {ST_L2_8, EV_L2_DL_ESTABLISH_REQ, l2_l3_reestablish}, - {ST_L2_4, EV_L2_DL_RELEASE_REQ, l2_release}, - {ST_L2_5, EV_L2_DL_RELEASE_REQ, l2_pend_rel}, - {ST_L2_7, EV_L2_DL_RELEASE_REQ, l2_disconnect}, - {ST_L2_8, EV_L2_DL_RELEASE_REQ, l2_disconnect}, - {ST_L2_5, EV_L2_DL_DATA, l2_feed_i_if_reest}, - {ST_L2_7, EV_L2_DL_DATA, l2_feed_i_pull}, - {ST_L2_8, EV_L2_DL_DATA, l2_feed_iqueue}, - {ST_L2_1, EV_L2_DL_UNIT_DATA, l2_queue_ui_assign}, - {ST_L2_2, EV_L2_DL_UNIT_DATA, l2_queue_ui}, - {ST_L2_3, EV_L2_DL_UNIT_DATA, l2_queue_ui}, - {ST_L2_4, EV_L2_DL_UNIT_DATA, l2_send_ui}, - {ST_L2_5, EV_L2_DL_UNIT_DATA, l2_send_ui}, - {ST_L2_6, EV_L2_DL_UNIT_DATA, l2_send_ui}, - {ST_L2_7, EV_L2_DL_UNIT_DATA, l2_send_ui}, - {ST_L2_8, EV_L2_DL_UNIT_DATA, l2_send_ui}, - {ST_L2_1, EV_L2_MDL_ASSIGN, l2_got_tei}, - {ST_L2_2, EV_L2_MDL_ASSIGN, l2_got_tei}, - {ST_L2_3, EV_L2_MDL_ASSIGN, l2_got_tei}, - {ST_L2_2, EV_L2_MDL_ERROR, l2_st24_tei_remove}, - {ST_L2_3, EV_L2_MDL_ERROR, l2_st3_tei_remove}, - {ST_L2_4, EV_L2_MDL_REMOVE, l2_st24_tei_remove}, - {ST_L2_5, EV_L2_MDL_REMOVE, l2_st5_tei_remove}, - {ST_L2_6, EV_L2_MDL_REMOVE, l2_st6_tei_remove}, - {ST_L2_7, EV_L2_MDL_REMOVE, l2_tei_remove}, - {ST_L2_8, EV_L2_MDL_REMOVE, l2_tei_remove}, - {ST_L2_4, EV_L2_SABME, l2_start_multi}, - {ST_L2_5, EV_L2_SABME, l2_send_UA}, - {ST_L2_6, EV_L2_SABME, l2_send_DM}, - {ST_L2_7, EV_L2_SABME, l2_restart_multi}, - {ST_L2_8, EV_L2_SABME, l2_restart_multi}, - {ST_L2_4, EV_L2_DISC, l2_send_DM}, - {ST_L2_5, EV_L2_DISC, l2_send_DM}, - {ST_L2_6, EV_L2_DISC, l2_send_UA}, - {ST_L2_7, EV_L2_DISC, l2_stop_multi}, - {ST_L2_8, EV_L2_DISC, l2_stop_multi}, - {ST_L2_4, EV_L2_UA, l2_mdl_error_ua}, - {ST_L2_5, EV_L2_UA, l2_connected}, - {ST_L2_6, EV_L2_UA, l2_released}, - {ST_L2_7, EV_L2_UA, l2_mdl_error_ua}, - {ST_L2_8, EV_L2_UA, l2_mdl_error_ua}, - {ST_L2_4, EV_L2_DM, l2_reestablish}, - {ST_L2_5, EV_L2_DM, l2_st5_dm_release}, - {ST_L2_6, EV_L2_DM, l2_st6_dm_release}, - {ST_L2_7, EV_L2_DM, l2_mdl_error_dm}, - {ST_L2_8, EV_L2_DM, l2_st8_mdl_error_dm}, - {ST_L2_1, EV_L2_UI, l2_got_ui}, - {ST_L2_2, EV_L2_UI, l2_got_ui}, - {ST_L2_3, EV_L2_UI, l2_got_ui}, - {ST_L2_4, EV_L2_UI, l2_got_ui}, - {ST_L2_5, EV_L2_UI, l2_got_ui}, - {ST_L2_6, EV_L2_UI, l2_got_ui}, - {ST_L2_7, EV_L2_UI, l2_got_ui}, - {ST_L2_8, EV_L2_UI, l2_got_ui}, - {ST_L2_7, EV_L2_FRMR, l2_got_FRMR}, - {ST_L2_8, EV_L2_FRMR, l2_got_FRMR}, - {ST_L2_7, EV_L2_SUPER, l2_st7_got_super}, - {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, - {ST_L2_7, EV_L2_I, l2_got_iframe}, - {ST_L2_8, EV_L2_I, l2_got_iframe}, - {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, - {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, - {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, - {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, - {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, - {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, - {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, - {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, - {ST_L2_7, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, - {ST_L2_8, EV_L2_CLEAR_OWN_BUSY, l2_clear_own_busy}, - {ST_L2_4, EV_L2_FRAME_ERROR, l2_frame_error}, - {ST_L2_5, EV_L2_FRAME_ERROR, l2_frame_error}, - {ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error}, - {ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest}, - {ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest}, - {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da}, - {ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove}, - {ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove}, - {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da}, - {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da}, - {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da}, - {ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da}, - {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da}, -}; - -static void -isdnl2_l1l2(struct PStack *st, int pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *datap; - int ret = 1, len; - int c = 0; - - switch (pr) { - case (PH_DATA | INDICATION): - datap = skb->data; - len = l2addrsize(&st->l2); - if (skb->len > len) - datap += len; - else { - FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'N'); - dev_kfree_skb(skb); - return; - } - if (!(*datap & 1)) { /* I-Frame */ - if (!(c = iframe_error(st, skb))) - ret = FsmEvent(&st->l2.l2m, EV_L2_I, skb); - } else if (IsSFrame(datap, st)) { /* S-Frame */ - if (!(c = super_error(st, skb))) - ret = FsmEvent(&st->l2.l2m, EV_L2_SUPER, skb); - } else if (IsUI(datap)) { - if (!(c = UI_error(st, skb))) - ret = FsmEvent(&st->l2.l2m, EV_L2_UI, skb); - } else if (IsSABME(datap, st)) { - if (!(c = unnum_error(st, skb, CMD))) - ret = FsmEvent(&st->l2.l2m, EV_L2_SABME, skb); - } else if (IsUA(datap)) { - if (!(c = unnum_error(st, skb, RSP))) - ret = FsmEvent(&st->l2.l2m, EV_L2_UA, skb); - } else if (IsDISC(datap)) { - if (!(c = unnum_error(st, skb, CMD))) - ret = FsmEvent(&st->l2.l2m, EV_L2_DISC, skb); - } else if (IsDM(datap)) { - if (!(c = unnum_error(st, skb, RSP))) - ret = FsmEvent(&st->l2.l2m, EV_L2_DM, skb); - } else if (IsFRMR(datap)) { - if (!(c = FRMR_error(st, skb))) - ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb); - } else { - FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'L'); - dev_kfree_skb(skb); - ret = 0; - } - if (c) { - dev_kfree_skb(skb); - FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *)(long)c); - ret = 0; - } - if (ret) - dev_kfree_skb(skb); - break; - case (PH_PULL | CONFIRM): - FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg); - break; - case (PH_PAUSE | INDICATION): - test_and_set_bit(FLG_DCHAN_BUSY, &st->l2.flag); - break; - case (PH_PAUSE | CONFIRM): - test_and_clear_bit(FLG_DCHAN_BUSY, &st->l2.flag); - break; - case (PH_ACTIVATE | CONFIRM): - case (PH_ACTIVATE | INDICATION): - test_and_set_bit(FLG_L1_ACTIV, &st->l2.flag); - if (test_and_clear_bit(FLG_ESTAB_PEND, &st->l2.flag)) - FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg); - break; - case (PH_DEACTIVATE | INDICATION): - case (PH_DEACTIVATE | CONFIRM): - test_and_clear_bit(FLG_L1_ACTIV, &st->l2.flag); - FsmEvent(&st->l2.l2m, EV_L1_DEACTIVATE, arg); - break; - default: - l2m_debug(&st->l2.l2m, "l2 unknown pr %04x", pr); - break; - } -} - -static void -isdnl2_l3l2(struct PStack *st, int pr, void *arg) -{ - switch (pr) { - case (DL_DATA | REQUEST): - if (FsmEvent(&st->l2.l2m, EV_L2_DL_DATA, arg)) { - dev_kfree_skb((struct sk_buff *) arg); - } - break; - case (DL_UNIT_DATA | REQUEST): - if (FsmEvent(&st->l2.l2m, EV_L2_DL_UNIT_DATA, arg)) { - dev_kfree_skb((struct sk_buff *) arg); - } - break; - case (DL_ESTABLISH | REQUEST): - if (test_bit(FLG_L1_ACTIV, &st->l2.flag)) { - if (test_bit(FLG_LAPD, &st->l2.flag) || - test_bit(FLG_ORIG, &st->l2.flag)) { - FsmEvent(&st->l2.l2m, EV_L2_DL_ESTABLISH_REQ, arg); - } - } else { - if (test_bit(FLG_LAPD, &st->l2.flag) || - test_bit(FLG_ORIG, &st->l2.flag)) { - test_and_set_bit(FLG_ESTAB_PEND, &st->l2.flag); - } - st->l2.l2l1(st, PH_ACTIVATE, NULL); - } - break; - case (DL_RELEASE | REQUEST): - if (test_bit(FLG_LAPB, &st->l2.flag)) { - st->l2.l2l1(st, PH_DEACTIVATE, NULL); - } - FsmEvent(&st->l2.l2m, EV_L2_DL_RELEASE_REQ, arg); - break; - case (MDL_ASSIGN | REQUEST): - FsmEvent(&st->l2.l2m, EV_L2_MDL_ASSIGN, arg); - break; - case (MDL_REMOVE | REQUEST): - FsmEvent(&st->l2.l2m, EV_L2_MDL_REMOVE, arg); - break; - case (MDL_ERROR | RESPONSE): - FsmEvent(&st->l2.l2m, EV_L2_MDL_ERROR, arg); - break; - } -} - -void -releasestack_isdnl2(struct PStack *st) -{ - FsmDelTimer(&st->l2.t200, 21); - FsmDelTimer(&st->l2.t203, 16); - skb_queue_purge(&st->l2.i_queue); - skb_queue_purge(&st->l2.ui_queue); - ReleaseWin(&st->l2); -} - -static void -l2m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - struct PStack *st = fi->userdata; - - va_start(args, fmt); - VHiSax_putstatus(st->l1.hardware, st->l2.debug_id, fmt, args); - va_end(args); -} - -void -setstack_isdnl2(struct PStack *st, char *debug_id) -{ - spin_lock_init(&st->l2.lock); - st->l1.l1l2 = isdnl2_l1l2; - st->l3.l3l2 = isdnl2_l3l2; - - skb_queue_head_init(&st->l2.i_queue); - skb_queue_head_init(&st->l2.ui_queue); - InitWin(&st->l2); - st->l2.debug = 0; - - st->l2.l2m.fsm = &l2fsm; - if (test_bit(FLG_LAPB, &st->l2.flag)) - st->l2.l2m.state = ST_L2_4; - else - st->l2.l2m.state = ST_L2_1; - st->l2.l2m.debug = 0; - st->l2.l2m.userdata = st; - st->l2.l2m.userint = 0; - st->l2.l2m.printdebug = l2m_debug; - strcpy(st->l2.debug_id, debug_id); - - FsmInitTimer(&st->l2.l2m, &st->l2.t200); - FsmInitTimer(&st->l2.l2m, &st->l2.t203); -} - -static void -transl2_l3l2(struct PStack *st, int pr, void *arg) -{ - switch (pr) { - case (DL_DATA | REQUEST): - case (DL_UNIT_DATA | REQUEST): - st->l2.l2l1(st, PH_DATA | REQUEST, arg); - break; - case (DL_ESTABLISH | REQUEST): - st->l2.l2l1(st, PH_ACTIVATE | REQUEST, NULL); - break; - case (DL_RELEASE | REQUEST): - st->l2.l2l1(st, PH_DEACTIVATE | REQUEST, NULL); - break; - } -} - -void -setstack_transl2(struct PStack *st) -{ - st->l3.l3l2 = transl2_l3l2; -} - -void -releasestack_transl2(struct PStack *st) -{ -} - -int __init -Isdnl2New(void) -{ - l2fsm.state_count = L2_STATE_COUNT; - l2fsm.event_count = L2_EVENT_COUNT; - l2fsm.strEvent = strL2Event; - l2fsm.strState = strL2State; - return FsmNew(&l2fsm, L2FnList, ARRAY_SIZE(L2FnList)); -} - -void -Isdnl2Free(void) -{ - FsmFree(&l2fsm); -} diff --git a/drivers/isdn/hisax/isdnl2.h b/drivers/isdn/hisax/isdnl2.h deleted file mode 100644 index 7e447fb8ed1d..000000000000 --- a/drivers/isdn/hisax/isdnl2.h +++ /dev/null @@ -1,25 +0,0 @@ -/* $Id: isdnl2.h,v 1.3.6.2 2001/09/23 22:24:49 kai Exp $ - * - * Layer 2 defines - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define RR 0x01 -#define RNR 0x05 -#define REJ 0x09 -#define SABME 0x6f -#define SABM 0x2f -#define DM 0x0f -#define UI 0x03 -#define DISC 0x43 -#define UA 0x63 -#define FRMR 0x87 -#define XID 0xaf - -#define CMD 0 -#define RSP 1 - -#define LC_FLUSH_WAIT 1 diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c deleted file mode 100644 index bb3f9ec62749..000000000000 --- a/drivers/isdn/hisax/isdnl3.c +++ /dev/null @@ -1,594 +0,0 @@ -/* $Id: isdnl3.c,v 2.22.2.3 2004/01/13 14:31:25 keil Exp $ - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil <keil@isdn4linux.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 - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include <linux/init.h> -#include <linux/slab.h> -#include "hisax.h" -#include "isdnl3.h" - -const char *l3_revision = "$Revision: 2.22.2.3 $"; - -static struct Fsm l3fsm; - -enum { - ST_L3_LC_REL, - ST_L3_LC_ESTAB_WAIT, - ST_L3_LC_REL_DELAY, - ST_L3_LC_REL_WAIT, - ST_L3_LC_ESTAB, -}; - -#define L3_STATE_COUNT (ST_L3_LC_ESTAB + 1) - -static char *strL3State[] = -{ - "ST_L3_LC_REL", - "ST_L3_LC_ESTAB_WAIT", - "ST_L3_LC_REL_DELAY", - "ST_L3_LC_REL_WAIT", - "ST_L3_LC_ESTAB", -}; - -enum { - EV_ESTABLISH_REQ, - EV_ESTABLISH_IND, - EV_ESTABLISH_CNF, - EV_RELEASE_REQ, - EV_RELEASE_CNF, - EV_RELEASE_IND, - EV_TIMEOUT, -}; - -#define L3_EVENT_COUNT (EV_TIMEOUT + 1) - -static char *strL3Event[] = -{ - "EV_ESTABLISH_REQ", - "EV_ESTABLISH_IND", - "EV_ESTABLISH_CNF", - "EV_RELEASE_REQ", - "EV_RELEASE_CNF", - "EV_RELEASE_IND", - "EV_TIMEOUT", -}; - -static __printf(2, 3) void - l3m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - struct PStack *st = fi->userdata; - - va_start(args, fmt); - VHiSax_putstatus(st->l1.hardware, st->l3.debug_id, fmt, args); - va_end(args); -} - -u_char * -findie(u_char *p, int size, u_char ie, int wanted_set) -{ - int l, codeset, maincodeset; - u_char *pend = p + size; - - /* skip protocol discriminator, callref and message type */ - p++; - l = (*p++) & 0xf; - p += l; - p++; - codeset = 0; - maincodeset = 0; - /* while there are bytes left... */ - while (p < pend) { - if ((*p & 0xf0) == 0x90) { - codeset = *p & 0x07; - if (!(*p & 0x08)) - maincodeset = codeset; - } - if (*p & 0x80) - p++; - else { - if (codeset == wanted_set) { - if (*p == ie) - { /* improved length check (Werner Cornelius) */ - if ((pend - p) < 2) - return (NULL); - if (*(p + 1) > (pend - (p + 2))) - return (NULL); - return (p); - } - - if (*p > ie) - return (NULL); - } - p++; - l = *p++; - p += l; - codeset = maincodeset; - } - } - return (NULL); -} - -int -getcallref(u_char *p) -{ - int l, cr = 0; - - p++; /* prot discr */ - if (*p & 0xfe) /* wrong callref BRI only 1 octet*/ - return (-2); - l = 0xf & *p++; /* callref length */ - if (!l) /* dummy CallRef */ - return (-1); - cr = *p++; - return (cr); -} - -static int OrigCallRef = 0; - -int -newcallref(void) -{ - if (OrigCallRef == 127) - OrigCallRef = 1; - else - OrigCallRef++; - return (OrigCallRef); -} - -void -newl3state(struct l3_process *pc, int state) -{ - if (pc->debug & L3_DEB_STATE) - l3_debug(pc->st, "%s cr %d %d --> %d", __func__, - pc->callref & 0x7F, - pc->state, state); - pc->state = state; -} - -static void -L3ExpireTimer(struct timer_list *timer) -{ - struct L3Timer *t = from_timer(t, timer, tl); - t->pc->st->lli.l4l3(t->pc->st, t->event, t->pc); -} - -void -L3InitTimer(struct l3_process *pc, struct L3Timer *t) -{ - t->pc = pc; - timer_setup(&t->tl, L3ExpireTimer, 0); -} - -void -L3DelTimer(struct L3Timer *t) -{ - del_timer(&t->tl); -} - -int -L3AddTimer(struct L3Timer *t, - int millisec, int event) -{ - if (timer_pending(&t->tl)) { - printk(KERN_WARNING "L3AddTimer: timer already active!\n"); - return -1; - } - t->event = event; - t->tl.expires = jiffies + (millisec * HZ) / 1000; - add_timer(&t->tl); - return 0; -} - -void -StopAllL3Timer(struct l3_process *pc) -{ - L3DelTimer(&pc->timer); -} - -struct sk_buff * -l3_alloc_skb(int len) -{ - struct sk_buff *skb; - - if (!(skb = alloc_skb(len + MAX_HEADER_LEN, GFP_ATOMIC))) { - printk(KERN_WARNING "HiSax: No skb for D-channel\n"); - return (NULL); - } - skb_reserve(skb, MAX_HEADER_LEN); - return (skb); -} - -static void -no_l3_proto(struct PStack *st, int pr, void *arg) -{ - struct sk_buff *skb = arg; - - HiSax_putstatus(st->l1.hardware, "L3", "no D protocol"); - if (skb) { - dev_kfree_skb(skb); - } -} - -static int -no_l3_proto_spec(struct PStack *st, isdn_ctrl *ic) -{ - printk(KERN_WARNING "HiSax: no specific protocol handler for proto %lu\n", ic->arg & 0xFF); - return (-1); -} - -struct l3_process -*getl3proc(struct PStack *st, int cr) -{ - struct l3_process *p = st->l3.proc; - - while (p) - if (p->callref == cr) - return (p); - else - p = p->next; - return (NULL); -} - -struct l3_process -*new_l3_process(struct PStack *st, int cr) -{ - struct l3_process *p, *np; - - if (!(p = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { - printk(KERN_ERR "HiSax can't get memory for cr %d\n", cr); - return (NULL); - } - if (!st->l3.proc) - st->l3.proc = p; - else { - np = st->l3.proc; - while (np->next) - np = np->next; - np->next = p; - } - p->next = NULL; - p->debug = st->l3.debug; - p->callref = cr; - p->state = 0; - p->chan = NULL; - p->st = st; - p->N303 = st->l3.N303; - L3InitTimer(p, &p->timer); - return (p); -}; - -void -release_l3_process(struct l3_process *p) -{ - struct l3_process *np, *pp = NULL; - - if (!p) - return; - np = p->st->l3.proc; - while (np) { - if (np == p) { - StopAllL3Timer(p); - if (pp) - pp->next = np->next; - else if (!(p->st->l3.proc = np->next) && - !test_bit(FLG_PTP, &p->st->l2.flag)) { - if (p->debug) - l3_debug(p->st, "release_l3_process: last process"); - if (skb_queue_empty(&p->st->l3.squeue)) { - if (p->debug) - l3_debug(p->st, "release_l3_process: release link"); - if (p->st->protocol != ISDN_PTYPE_NI1) - FsmEvent(&p->st->l3.l3m, EV_RELEASE_REQ, NULL); - else - FsmEvent(&p->st->l3.l3m, EV_RELEASE_IND, NULL); - } else { - if (p->debug) - l3_debug(p->st, "release_l3_process: not release link"); - } - } - kfree(p); - return; - } - pp = np; - np = np->next; - } - printk(KERN_ERR "HiSax internal L3 error CR(%d) not in list\n", p->callref); - l3_debug(p->st, "HiSax internal L3 error CR(%d) not in list", p->callref); -}; - -static void -l3ml3p(struct PStack *st, int pr) -{ - struct l3_process *p = st->l3.proc; - struct l3_process *np; - - while (p) { - /* p might be kfreed under us, so we need to save where we want to go on */ - np = p->next; - st->l3.l3ml3(st, pr, p); - p = np; - } -} - -void -setstack_l3dc(struct PStack *st, struct Channel *chanp) -{ - char tmp[64]; - - st->l3.proc = NULL; - st->l3.global = NULL; - skb_queue_head_init(&st->l3.squeue); - st->l3.l3m.fsm = &l3fsm; - st->l3.l3m.state = ST_L3_LC_REL; - st->l3.l3m.debug = 1; - st->l3.l3m.userdata = st; - st->l3.l3m.userint = 0; - st->l3.l3m.printdebug = l3m_debug; - FsmInitTimer(&st->l3.l3m, &st->l3.l3m_timer); - strcpy(st->l3.debug_id, "L3DC "); - st->lli.l4l3_proto = no_l3_proto_spec; - -#ifdef CONFIG_HISAX_EURO - if (st->protocol == ISDN_PTYPE_EURO) { - setstack_dss1(st); - } else -#endif -#ifdef CONFIG_HISAX_NI1 - if (st->protocol == ISDN_PTYPE_NI1) { - setstack_ni1(st); - } else -#endif -#ifdef CONFIG_HISAX_1TR6 - if (st->protocol == ISDN_PTYPE_1TR6) { - setstack_1tr6(st); - } else -#endif - if (st->protocol == ISDN_PTYPE_LEASED) { - st->lli.l4l3 = no_l3_proto; - st->l2.l2l3 = no_l3_proto; - st->l3.l3ml3 = no_l3_proto; - printk(KERN_INFO "HiSax: Leased line mode\n"); - } else { - st->lli.l4l3 = no_l3_proto; - st->l2.l2l3 = no_l3_proto; - st->l3.l3ml3 = no_l3_proto; - sprintf(tmp, "protocol %s not supported", - (st->protocol == ISDN_PTYPE_1TR6) ? "1tr6" : - (st->protocol == ISDN_PTYPE_EURO) ? "euro" : - (st->protocol == ISDN_PTYPE_NI1) ? "ni1" : - "unknown"); - printk(KERN_WARNING "HiSax: %s\n", tmp); - st->protocol = -1; - } -} - -static void -isdnl3_trans(struct PStack *st, int pr, void *arg) { - st->l3.l3l2(st, pr, arg); -} - -void -releasestack_isdnl3(struct PStack *st) -{ - while (st->l3.proc) - release_l3_process(st->l3.proc); - if (st->l3.global) { - StopAllL3Timer(st->l3.global); - kfree(st->l3.global); - st->l3.global = NULL; - } - FsmDelTimer(&st->l3.l3m_timer, 54); - skb_queue_purge(&st->l3.squeue); -} - -void -setstack_l3bc(struct PStack *st, struct Channel *chanp) -{ - - st->l3.proc = NULL; - st->l3.global = NULL; - skb_queue_head_init(&st->l3.squeue); - st->l3.l3m.fsm = &l3fsm; - st->l3.l3m.state = ST_L3_LC_REL; - st->l3.l3m.debug = 1; - st->l3.l3m.userdata = st; - st->l3.l3m.userint = 0; - st->l3.l3m.printdebug = l3m_debug; - strcpy(st->l3.debug_id, "L3BC "); - st->lli.l4l3 = isdnl3_trans; -} - -#define DREL_TIMER_VALUE 40000 - -static void -lc_activate(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L3_LC_ESTAB_WAIT); - st->l3.l3l2(st, DL_ESTABLISH | REQUEST, NULL); -} - -static void -lc_connect(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int dequeued = 0; - - FsmChangeState(fi, ST_L3_LC_ESTAB); - while ((skb = skb_dequeue(&st->l3.squeue))) { - st->l3.l3l2(st, DL_DATA | REQUEST, skb); - dequeued++; - } - if ((!st->l3.proc) && dequeued) { - if (st->l3.debug) - l3_debug(st, "lc_connect: release link"); - FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); - } else - l3ml3p(st, DL_ESTABLISH | INDICATION); -} - -static void -lc_connected(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int dequeued = 0; - - FsmDelTimer(&st->l3.l3m_timer, 51); - FsmChangeState(fi, ST_L3_LC_ESTAB); - while ((skb = skb_dequeue(&st->l3.squeue))) { - st->l3.l3l2(st, DL_DATA | REQUEST, skb); - dequeued++; - } - if ((!st->l3.proc) && dequeued) { - if (st->l3.debug) - l3_debug(st, "lc_connected: release link"); - FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); - } else - l3ml3p(st, DL_ESTABLISH | CONFIRM); -} - -static void -lc_start_delay(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L3_LC_REL_DELAY); - FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50); -} - -static void -lc_start_delay_check(struct FsmInst *fi, int event, void *arg) -/* 20/09/00 - GE timer not user for NI-1 as layer 2 should stay up */ -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L3_LC_REL_DELAY); - /* 19/09/00 - GE timer not user for NI-1 */ - if (st->protocol != ISDN_PTYPE_NI1) - FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 50); -} - -static void -lc_release_req(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (test_bit(FLG_L2BLOCK, &st->l2.flag)) { - if (st->l3.debug) - l3_debug(st, "lc_release_req: l2 blocked"); - /* restart release timer */ - FsmAddTimer(&st->l3.l3m_timer, DREL_TIMER_VALUE, EV_TIMEOUT, NULL, 51); - } else { - FsmChangeState(fi, ST_L3_LC_REL_WAIT); - st->l3.l3l2(st, DL_RELEASE | REQUEST, NULL); - } -} - -static void -lc_release_ind(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmDelTimer(&st->l3.l3m_timer, 52); - FsmChangeState(fi, ST_L3_LC_REL); - skb_queue_purge(&st->l3.squeue); - l3ml3p(st, DL_RELEASE | INDICATION); -} - -static void -lc_release_cnf(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - FsmChangeState(fi, ST_L3_LC_REL); - skb_queue_purge(&st->l3.squeue); - l3ml3p(st, DL_RELEASE | CONFIRM); -} - - -/* *INDENT-OFF* */ -static struct FsmNode L3FnList[] __initdata = -{ - {ST_L3_LC_REL, EV_ESTABLISH_REQ, lc_activate}, - {ST_L3_LC_REL, EV_ESTABLISH_IND, lc_connect}, - {ST_L3_LC_REL, EV_ESTABLISH_CNF, lc_connect}, - {ST_L3_LC_ESTAB_WAIT, EV_ESTABLISH_CNF, lc_connected}, - {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_REQ, lc_start_delay}, - {ST_L3_LC_ESTAB_WAIT, EV_RELEASE_IND, lc_release_ind}, - {ST_L3_LC_ESTAB, EV_RELEASE_IND, lc_release_ind}, - {ST_L3_LC_ESTAB, EV_RELEASE_REQ, lc_start_delay_check}, - {ST_L3_LC_REL_DELAY, EV_RELEASE_IND, lc_release_ind}, - {ST_L3_LC_REL_DELAY, EV_ESTABLISH_REQ, lc_connected}, - {ST_L3_LC_REL_DELAY, EV_TIMEOUT, lc_release_req}, - {ST_L3_LC_REL_WAIT, EV_RELEASE_CNF, lc_release_cnf}, - {ST_L3_LC_REL_WAIT, EV_ESTABLISH_REQ, lc_activate}, -}; -/* *INDENT-ON* */ - -void -l3_msg(struct PStack *st, int pr, void *arg) -{ - switch (pr) { - case (DL_DATA | REQUEST): - if (st->l3.l3m.state == ST_L3_LC_ESTAB) { - st->l3.l3l2(st, pr, arg); - } else { - struct sk_buff *skb = arg; - - skb_queue_tail(&st->l3.squeue, skb); - FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); - } - break; - case (DL_ESTABLISH | REQUEST): - FsmEvent(&st->l3.l3m, EV_ESTABLISH_REQ, NULL); - break; - case (DL_ESTABLISH | CONFIRM): - FsmEvent(&st->l3.l3m, EV_ESTABLISH_CNF, NULL); - break; - case (DL_ESTABLISH | INDICATION): - FsmEvent(&st->l3.l3m, EV_ESTABLISH_IND, NULL); - break; - case (DL_RELEASE | INDICATION): - FsmEvent(&st->l3.l3m, EV_RELEASE_IND, NULL); - break; - case (DL_RELEASE | CONFIRM): - FsmEvent(&st->l3.l3m, EV_RELEASE_CNF, NULL); - break; - case (DL_RELEASE | REQUEST): - FsmEvent(&st->l3.l3m, EV_RELEASE_REQ, NULL); - break; - } -} - -int __init -Isdnl3New(void) -{ - l3fsm.state_count = L3_STATE_COUNT; - l3fsm.event_count = L3_EVENT_COUNT; - l3fsm.strEvent = strL3Event; - l3fsm.strState = strL3State; - return FsmNew(&l3fsm, L3FnList, ARRAY_SIZE(L3FnList)); -} - -void -Isdnl3Free(void) -{ - FsmFree(&l3fsm); -} diff --git a/drivers/isdn/hisax/isdnl3.h b/drivers/isdn/hisax/isdnl3.h deleted file mode 100644 index 0edc99d40dc2..000000000000 --- a/drivers/isdn/hisax/isdnl3.h +++ /dev/null @@ -1,42 +0,0 @@ -/* $Id: isdnl3.h,v 2.6.6.2 2001/09/23 22:24:49 kai Exp $ - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define SBIT(state) (1 << state) -#define ALL_STATES 0x03ffffff - -#define PROTO_DIS_EURO 0x08 - -#define L3_DEB_WARN 0x01 -#define L3_DEB_PROTERR 0x02 -#define L3_DEB_STATE 0x04 -#define L3_DEB_CHARGE 0x08 -#define L3_DEB_CHECK 0x10 -#define L3_DEB_SI 0x20 - -struct stateentry { - int state; - int primitive; - void (*rout) (struct l3_process *, u8, void *); -}; - -#define l3_debug(st, fmt, args...) HiSax_putstatus(st->l1.hardware, "l3 ", fmt, ## args) - -struct PStack; - -void newl3state(struct l3_process *pc, int state); -void L3InitTimer(struct l3_process *pc, struct L3Timer *t); -void L3DelTimer(struct L3Timer *t); -int L3AddTimer(struct L3Timer *t, int millisec, int event); -void StopAllL3Timer(struct l3_process *pc); -struct sk_buff *l3_alloc_skb(int len); -struct l3_process *new_l3_process(struct PStack *st, int cr); -void release_l3_process(struct l3_process *p); -struct l3_process *getl3proc(struct PStack *st, int cr); -void l3_msg(struct PStack *st, int pr, void *arg); -void setstack_dss1(struct PStack *st); -void setstack_ni1(struct PStack *st); -void setstack_1tr6(struct PStack *st); diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c deleted file mode 100644 index 53e299be4304..000000000000 --- a/drivers/isdn/hisax/isurf.c +++ /dev/null @@ -1,305 +0,0 @@ -/* $Id: isurf.c,v 1.12.2.4 2004/01/13 21:46:03 keil Exp $ - * - * low level stuff for Siemens I-Surf/I-Talk cards - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "isar.h" -#include "isdnl1.h" -#include <linux/isapnp.h> - -static const char *ISurf_revision = "$Revision: 1.12.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define ISURF_ISAR_RESET 1 -#define ISURF_ISAC_RESET 2 -#define ISURF_ISAR_EA 4 -#define ISURF_ARCOFI_RESET 8 -#define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET) - -#define ISURF_ISAR_OFFSET 0 -#define ISURF_ISAC_OFFSET 0x100 -#define ISURF_IOMEM_SIZE 0x400 -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readb(cs->hw.isurf.isac + offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writeb(value, cs->hw.isurf.isac + offset); mb(); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - register int i; - for (i = 0; i < size; i++) - data[i] = readb(cs->hw.isurf.isac); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - register int i; - for (i = 0; i < size; i++) { - writeb(data[i], cs->hw.isurf.isac); mb(); - } -} - -/* ISAR access routines - * mode = 0 access with IRQ on - * mode = 1 access with IRQ off - * mode = 2 access with IRQ off and using last offset - */ - -static u_char -ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) -{ - return (readb(cs->hw.isurf.isar + offset)); -} - -static void -WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) -{ - writeb(value, cs->hw.isurf.isar + offset); mb(); -} - -static irqreturn_t -isurf_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - int cnt = 5; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readb(cs->hw.isurf.isar + ISAR_IRQBIT); -Start_ISAR: - if (val & ISAR_IRQSTA) - isar_int_main(cs); - val = readb(cs->hw.isurf.isac + ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readb(cs->hw.isurf.isar + ISAR_IRQBIT); - if ((val & ISAR_IRQSTA) && --cnt) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "ISAR IntStat after IntRoutine"); - goto Start_ISAR; - } - val = readb(cs->hw.isurf.isac + ISAC_ISTA); - if (val && --cnt) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - if (!cnt) - printk(KERN_WARNING "ISurf IRQ LOOP\n"); - - writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); - writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK); mb(); - writeb(0, cs->hw.isurf.isac + ISAC_MASK); mb(); - writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_isurf(struct IsdnCardState *cs) -{ - release_region(cs->hw.isurf.reset, 1); - iounmap(cs->hw.isurf.isar); - release_mem_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); -} - -static void -reset_isurf(struct IsdnCardState *cs, u_char chips) -{ - printk(KERN_INFO "ISurf: resetting card\n"); - - byteout(cs->hw.isurf.reset, chips); /* Reset On */ - mdelay(10); - byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */ - mdelay(10); -} - -static int -ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_isurf(cs, ISURF_RESET); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_isurf(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - reset_isurf(cs, ISURF_RESET); - clear_pending_isac_ints(cs); - writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb(); - initisac(cs); - initisar(cs); - /* Reenable ISAC IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - /* RESET Receiver and Transmitter */ - cs->writeisac(cs, ISAC_CMDR, 0x41); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int -isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { - int ret; - u_long flags; - - if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) { - ret = isar_auxcmd(cs, ic); - spin_lock_irqsave(&cs->lock, flags); - if (!ret) { - reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET | - ISURF_ARCOFI_RESET); - initisac(cs); - cs->writeisac(cs, ISAC_MASK, 0); - cs->writeisac(cs, ISAC_CMDR, 0x41); - } - spin_unlock_irqrestore(&cs->lock, flags); - return (ret); - } - return (isar_auxcmd(cs, ic)); -} - -#ifdef __ISAPNP__ -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_isurf(struct IsdnCard *card) -{ - int ver; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, ISurf_revision); - printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp)); - - if (cs->typ != ISDN_CTYPE_ISURF) - return (0); - if (card->para[1] && card->para[2]) { - cs->hw.isurf.reset = card->para[1]; - cs->hw.isurf.phymem = card->para[2]; - cs->irq = card->para[0]; - } else { -#ifdef __ISAPNP__ - if (isapnp_present()) { - struct pnp_dev *pnp_d = NULL; - int err; - - cs->subtyp = 0; - if ((pnp_c = pnp_find_card( - ISAPNP_VENDOR('S', 'I', 'E'), - ISAPNP_FUNCTION(0x0010), pnp_c))) { - if (!(pnp_d = pnp_find_dev(pnp_c, - ISAPNP_VENDOR('S', 'I', 'E'), - ISAPNP_FUNCTION(0x0010), pnp_d))) { - printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n"); - return (0); - } - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - pr_warn("%s: pnp_activate_dev ret=%d\n", - __func__, err); - return 0; - } - cs->hw.isurf.reset = pnp_port_start(pnp_d, 0); - cs->hw.isurf.phymem = pnp_mem_start(pnp_d, 1); - cs->irq = pnp_irq(pnp_d, 0); - if (cs->irq == -1 || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) { - printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n", - cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem); - pnp_disable_dev(pnp_d); - return (0); - } - } else { - printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n"); - return (0); - } - } else { - printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n"); - return (0); - } -#else - printk(KERN_WARNING "HiSax: Siemens I-Surf port/mem not set\n"); - return (0); -#endif - } - if (!request_region(cs->hw.isurf.reset, 1, "isurf isdn")) { - printk(KERN_WARNING - "HiSax: Siemens I-Surf config port %x already in use\n", - cs->hw.isurf.reset); - return (0); - } - if (!request_region(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE, "isurf iomem")) { - printk(KERN_WARNING "HiSax: Siemens I-Surf memory region " - "%lx-%lx already in use\n", - cs->hw.isurf.phymem, - cs->hw.isurf.phymem + ISURF_IOMEM_SIZE); - release_region(cs->hw.isurf.reset, 1); - return (0); - } - cs->hw.isurf.isar = ioremap(cs->hw.isurf.phymem, ISURF_IOMEM_SIZE); - cs->hw.isurf.isac = cs->hw.isurf.isar + ISURF_ISAC_OFFSET; - printk(KERN_INFO - "ISurf: defined at 0x%x 0x%lx IRQ %d\n", - cs->hw.isurf.reset, - cs->hw.isurf.phymem, - cs->irq); - - setup_isac(cs); - cs->cardmsg = &ISurf_card_msg; - cs->irq_func = &isurf_interrupt; - cs->auxcmd = &isurf_auxcmd; - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r; - cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r; - test_and_set_bit(HW_ISAR, &cs->HW_Flags); - ISACVersion(cs, "ISurf:"); - cs->BC_Read_Reg = &ReadISAR; - cs->BC_Write_Reg = &WriteISAR; - cs->BC_Send_Data = &isar_fill_fifo; - ver = ISARVersion(cs, "ISurf:"); - if (ver < 0) { - printk(KERN_WARNING - "ISurf: wrong ISAR version (ret = %d)\n", ver); - release_io_isurf(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c deleted file mode 100644 index bfb79f3f0a49..000000000000 --- a/drivers/isdn/hisax/ix1_micro.c +++ /dev/null @@ -1,316 +0,0 @@ -/* $Id: ix1_micro.c,v 2.12.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for ITK ix1-micro Rev.2 isdn cards - * derived from the original file teles3.c from Karsten Keil - * - * Author Klaus-Peter Nischke - * Copyright by Klaus-Peter Nischke, ITK AG - * <klaus@nischke.do.eunet.de> - * by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Klaus-Peter Nischke - * Deusener Str. 287 - * 44369 Dortmund - * Germany - */ - -#include <linux/init.h> -#include <linux/isapnp.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *ix1_revision = "$Revision: 2.12.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define SPECIAL_PORT_OFFSET 3 - -#define ISAC_COMMAND_OFFSET 2 -#define ISAC_DATA_OFFSET 0 -#define HSCX_COMMAND_OFFSET 2 -#define HSCX_DATA_OFFSET 1 - -#define TIMEOUT 50 - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, 0, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.ix1.hscx_ale, - cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.ix1.hscx_ale, - cs->hw.ix1.hscx, offset + (hscx ? 0x40 : 0), value); -} - -#define READHSCX(cs, nr, reg) readreg(cs->hw.ix1.hscx_ale, \ - cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ix1.hscx_ale, \ - cs->hw.ix1.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ix1.hscx_ale, \ - cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ix1.hscx_ale, \ - cs->hw.ix1.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -ix1micro_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.ix1.isac_ale, cs->hw.ix1.isac, ISAC_MASK, 0); - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK, 0); - writereg(cs->hw.ix1.hscx_ale, cs->hw.ix1.hscx, HSCX_MASK + 0x40, 0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_ix1micro(struct IsdnCardState *cs) -{ - if (cs->hw.ix1.cfg_reg) - release_region(cs->hw.ix1.cfg_reg, 4); -} - -static void -ix1_reset(struct IsdnCardState *cs) -{ - int cnt; - - /* reset isac */ - cnt = 3 * (HZ / 10) + 1; - while (cnt--) { - byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 1); - HZDELAY(1); /* wait >=10 ms */ - } - byteout(cs->hw.ix1.cfg_reg + SPECIAL_PORT_OFFSET, 0); -} - -static int -ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - ix1_reset(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_ix1micro(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - ix1_reset(cs); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id itk_ids[] = { - { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), - ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), - (unsigned long) "ITK micro 2" }, - { ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), - ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), - (unsigned long) "ITK micro 2." }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &itk_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif - - -int setup_ix1micro(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, ix1_revision); - printk(KERN_INFO "HiSax: ITK IX1 driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_IX1MICROR2) - return (0); - -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - break; - } else { - printk(KERN_ERR "ITK PnP: PnP error card found, no device\n"); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "ITK PnP: no ISAPnP card found\n"); - return (0); - } - } -#endif - /* IO-Ports */ - cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET; - cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET; - cs->hw.ix1.isac = card->para[1] + ISAC_DATA_OFFSET; - cs->hw.ix1.hscx = card->para[1] + HSCX_DATA_OFFSET; - cs->hw.ix1.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (cs->hw.ix1.cfg_reg) { - if (!request_region(cs->hw.ix1.cfg_reg, 4, "ix1micro cfg")) { - printk(KERN_WARNING - "HiSax: ITK ix1-micro Rev.2 config port " - "%x-%x already in use\n", - cs->hw.ix1.cfg_reg, - cs->hw.ix1.cfg_reg + 4); - return (0); - } - } - printk(KERN_INFO "HiSax: ITK ix1-micro Rev.2 config irq:%d io:0x%X\n", - cs->irq, cs->hw.ix1.cfg_reg); - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &ix1_card_msg; - cs->irq_func = &ix1micro_interrupt; - ISACVersion(cs, "ix1-Micro:"); - if (HscxVersion(cs, "ix1-Micro:")) { - printk(KERN_WARNING - "ix1-Micro: wrong HSCX versions check IO address\n"); - release_io_ix1micro(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c deleted file mode 100644 index e2ae7871a209..000000000000 --- a/drivers/isdn/hisax/jade.c +++ /dev/null @@ -1,305 +0,0 @@ -/* $Id: jade.c,v 1.9.2.4 2004/01/14 16:04:48 keil Exp $ - * - * JADE stuff (derived from original hscx.c) - * - * Author Roland Klabunde - * Copyright by Roland Klabunde <R.Klabunde@Berkom.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#include <linux/init.h> -#include "hisax.h" -#include "hscx.h" -#include "jade.h" -#include "isdnl1.h" -#include <linux/interrupt.h> -#include <linux/slab.h> - - -int -JadeVersion(struct IsdnCardState *cs, char *s) -{ - int ver; - int to = 50; - cs->BC_Write_Reg(cs, -1, 0x50, 0x19); - while (to) { - udelay(1); - ver = cs->BC_Read_Reg(cs, -1, 0x60); - to--; - if (ver) - break; - if (!to) { - printk(KERN_INFO "%s JADE version not obtainable\n", s); - return (0); - } - } - /* Wait for the JADE */ - udelay(10); - /* Read version */ - ver = cs->BC_Read_Reg(cs, -1, 0x60); - printk(KERN_INFO "%s JADE version: %d\n", s, ver); - return (1); -} - -/* Write to indirect accessible jade register set */ -static void -jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value) -{ - int to = 50; - u_char ret; - - /* Write the data */ - cs->BC_Write_Reg(cs, -1, COMM_JADE + 1, value); - /* Say JADE we wanna write indirect reg 'reg' */ - cs->BC_Write_Reg(cs, -1, COMM_JADE, reg); - to = 50; - /* Wait for RDY goes high */ - while (to) { - udelay(1); - ret = cs->BC_Read_Reg(cs, -1, COMM_JADE); - to--; - if (ret & 1) - /* Got acknowledge */ - break; - if (!to) { - printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value); - return; - } - } -} - - - -static void -modejade(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - int jade = bcs->hw.hscx.hscx; - - if (cs->debug & L1_DEB_HSCX) { - debugl1(cs, "jade %c mode %d ichan %d", 'A' + jade, mode, bc); - } - bcs->mode = mode; - bcs->channel = bc; - - cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO : 0x00)); - cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU | jadeCCR0_ITF)); - cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR1, 0x00); - - jade_write_indirect(cs, jade_HDLC1SERRXPATH, 0x08); - jade_write_indirect(cs, jade_HDLC2SERRXPATH, 0x08); - jade_write_indirect(cs, jade_HDLC1SERTXPATH, 0x00); - jade_write_indirect(cs, jade_HDLC2SERTXPATH, 0x00); - - cs->BC_Write_Reg(cs, jade, jade_HDLC_XCCR, 0x07); - cs->BC_Write_Reg(cs, jade, jade_HDLC_RCCR, 0x07); - - if (bc == 0) { - cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x00); - cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x00); - } else { - cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x04); - cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x04); - } - switch (mode) { - case (L1_MODE_NULL): - cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO); - break; - case (L1_MODE_TRANS): - cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO | jadeMODE_RAC | jadeMODE_XAC)); - break; - case (L1_MODE_HDLC): - cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC | jadeMODE_XAC)); - break; - } - if (mode) { - cs->BC_Write_Reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES | jadeRCMD_RMC)); - cs->BC_Write_Reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES); - /* Unmask ints */ - cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0xF8); - } - else - /* Mask ints */ - cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0x00); -} - -static void -jade_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.hscx.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "jade_l2l1: this shouldn't happen\n"); - } else { - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->hw.hscx.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - modejade(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - modejade(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_jadestate(struct BCState *bcs) -{ - modejade(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - kfree(bcs->blog); - bcs->blog = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static int -open_jadestate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for hscx.rcvbuf\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - return (1); - } - if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for bcs->blog\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - kfree(bcs->hw.hscx.rcvbuf); - bcs->hw.hscx.rcvbuf = NULL; - return (2); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.hscx.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - - -static int -setstack_jade(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_jadestate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = jade_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -void -clear_pending_jade_ints(struct IsdnCardState *cs) -{ - int val; - - cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00); - cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00); - - val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR); - debugl1(cs, "jade B ISTA %x", val); - val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR); - debugl1(cs, "jade A ISTA %x", val); - val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR); - debugl1(cs, "jade B STAR %x", val); - val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR); - debugl1(cs, "jade A STAR %x", val); - /* Unmask ints */ - cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8); - cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8); -} - -void -initjade(struct IsdnCardState *cs) -{ - cs->bcs[0].BC_SetStack = setstack_jade; - cs->bcs[1].BC_SetStack = setstack_jade; - cs->bcs[0].BC_Close = close_jadestate; - cs->bcs[1].BC_Close = close_jadestate; - cs->bcs[0].hw.hscx.hscx = 0; - cs->bcs[1].hw.hscx.hscx = 1; - - /* Stop DSP audio tx/rx */ - jade_write_indirect(cs, 0x11, 0x0f); - jade_write_indirect(cs, 0x17, 0x2f); - - /* Transparent Mode, RxTx inactive, No Test, No RFS/TFS */ - cs->BC_Write_Reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO); - cs->BC_Write_Reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO); - /* Power down, 1-Idle, RxTx least significant bit first */ - cs->BC_Write_Reg(cs, 0, jade_HDLC_CCR0, 0x00); - cs->BC_Write_Reg(cs, 1, jade_HDLC_CCR0, 0x00); - /* Mask all interrupts */ - cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00); - cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00); - /* Setup host access to hdlc controller */ - jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1 | jadeINDIRECT_HAH2)); - /* Unmask HDLC int (don't forget DSP int later on)*/ - cs->BC_Write_Reg(cs, -1, jade_INT, (jadeINT_HDLC1 | jadeINT_HDLC2)); - - /* once again TRANSPARENT */ - modejade(cs->bcs, 0, 0); - modejade(cs->bcs + 1, 0, 0); -} diff --git a/drivers/isdn/hisax/jade.h b/drivers/isdn/hisax/jade.h deleted file mode 100644 index 4b98096a5858..000000000000 --- a/drivers/isdn/hisax/jade.h +++ /dev/null @@ -1,134 +0,0 @@ -/* $Id: jade.h,v 1.5.2.3 2004/01/14 16:04:48 keil Exp $ - * - * JADE specific defines - * - * Author Roland Klabunde - * Copyright by Roland Klabunde <R.Klabunde@Berkom.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* All Registers original Siemens Spec */ -#ifndef __JADE_H__ -#define __JADE_H__ - -/* Special registers for access to indirect accessible JADE regs */ -#define DIRECT_IO_JADE 0x0000 /* Jade direct io access area */ -#define COMM_JADE 0x0040 /* Jade communication area */ - -/********************************************************************/ -/* JADE-HDLC registers */ -/********************************************************************/ -#define jade_HDLC_RFIFO 0x00 /* R */ -#define jade_HDLC_XFIFO 0x00 /* W */ - -#define jade_HDLC_STAR 0x20 /* R */ -#define jadeSTAR_XDOV 0x80 -#define jadeSTAR_XFW 0x40 /* Does not work*/ -#define jadeSTAR_XCEC 0x20 -#define jadeSTAR_RCEC 0x10 -#define jadeSTAR_BSY 0x08 -#define jadeSTAR_RNA 0x04 -#define jadeSTAR_STR 0x02 -#define jadeSTAR_STX 0x01 - -#define jade_HDLC_XCMD 0x20 /* W */ -#define jadeXCMD_XF 0x80 -#define jadeXCMD_XME 0x40 -#define jadeXCMD_XRES 0x20 -#define jadeXCMD_STX 0x01 - -#define jade_HDLC_RSTA 0x21 /* R */ -#define jadeRSTA_VFR 0x80 -#define jadeRSTA_RDO 0x40 -#define jadeRSTA_CRC 0x20 -#define jadeRSTA_RAB 0x10 -#define jadeRSTA_MASK 0xF0 - -#define jade_HDLC_MODE 0x22 /* RW*/ -#define jadeMODE_TMO 0x80 -#define jadeMODE_RAC 0x40 -#define jadeMODE_XAC 0x20 -#define jadeMODE_TLP 0x10 -#define jadeMODE_ERFS 0x02 -#define jadeMODE_ETFS 0x01 - -#define jade_HDLC_RBCH 0x24 /* R */ - -#define jade_HDLC_RBCL 0x25 /* R */ -#define jade_HDLC_RCMD 0x25 /* W */ -#define jadeRCMD_RMC 0x80 -#define jadeRCMD_RRES 0x40 -#define jadeRCMD_RMD 0x20 -#define jadeRCMD_STR 0x02 - -#define jade_HDLC_CCR0 0x26 /* RW*/ -#define jadeCCR0_PU 0x80 -#define jadeCCR0_ITF 0x40 -#define jadeCCR0_C32 0x20 -#define jadeCCR0_CRL 0x10 -#define jadeCCR0_RCRC 0x08 -#define jadeCCR0_XCRC 0x04 -#define jadeCCR0_RMSB 0x02 -#define jadeCCR0_XMSB 0x01 - -#define jade_HDLC_CCR1 0x27 /* RW*/ -#define jadeCCR1_RCS0 0x80 -#define jadeCCR1_RCONT 0x40 -#define jadeCCR1_RFDIS 0x20 -#define jadeCCR1_XCS0 0x10 -#define jadeCCR1_XCONT 0x08 -#define jadeCCR1_XFDIS 0x04 - -#define jade_HDLC_TSAR 0x28 /* RW*/ -#define jade_HDLC_TSAX 0x29 /* RW*/ -#define jade_HDLC_RCCR 0x2A /* RW*/ -#define jade_HDLC_XCCR 0x2B /* RW*/ - -#define jade_HDLC_ISR 0x2C /* R */ -#define jade_HDLC_IMR 0x2C /* W */ -#define jadeISR_RME 0x80 -#define jadeISR_RPF 0x40 -#define jadeISR_RFO 0x20 -#define jadeISR_XPR 0x10 -#define jadeISR_XDU 0x08 -#define jadeISR_ALLS 0x04 - -#define jade_INT 0x75 -#define jadeINT_HDLC1 0x02 -#define jadeINT_HDLC2 0x01 -#define jadeINT_DSP 0x04 -#define jade_INTR 0x70 - -/********************************************************************/ -/* Indirect accessible JADE registers of common interest */ -/********************************************************************/ -#define jade_CHIPVERSIONNR 0x00 /* Does not work*/ - -#define jade_HDLCCNTRACCESS 0x10 -#define jadeINDIRECT_HAH1 0x02 -#define jadeINDIRECT_HAH2 0x01 - -#define jade_HDLC1SERRXPATH 0x1D -#define jade_HDLC1SERTXPATH 0x1E -#define jade_HDLC2SERRXPATH 0x1F -#define jade_HDLC2SERTXPATH 0x20 -#define jadeINDIRECT_SLIN1 0x10 -#define jadeINDIRECT_SLIN0 0x08 -#define jadeINDIRECT_LMOD1 0x04 -#define jadeINDIRECT_LMOD0 0x02 -#define jadeINDIRECT_HHR 0x01 -#define jadeINDIRECT_HHX 0x01 - -#define jade_RXAUDIOCH1CFG 0x11 -#define jade_RXAUDIOCH2CFG 0x14 -#define jade_TXAUDIOCH1CFG 0x17 -#define jade_TXAUDIOCH2CFG 0x1A - -extern int JadeVersion(struct IsdnCardState *cs, char *s); -extern void clear_pending_jade_ints(struct IsdnCardState *cs); -extern void initjade(struct IsdnCardState *cs); - -#endif /* __JADE_H__ */ diff --git a/drivers/isdn/hisax/jade_irq.c b/drivers/isdn/hisax/jade_irq.c deleted file mode 100644 index a89e2df911c5..000000000000 --- a/drivers/isdn/hisax/jade_irq.c +++ /dev/null @@ -1,238 +0,0 @@ -/* $Id: jade_irq.c,v 1.7.2.4 2004/02/11 13:21:34 keil Exp $ - * - * Low level JADE IRQ stuff (derived from original hscx_irq.c) - * - * Author Roland Klabunde - * Copyright by Roland Klabunde <R.Klabunde@Berkom.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -static inline void -waitforCEC(struct IsdnCardState *cs, int jade, int reg) -{ - int to = 50; - int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC); - while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) { - udelay(1); - to--; - } - if (!to) - printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n"); -} - - -static inline void -waitforXFW(struct IsdnCardState *cs, int jade) -{ - /* Does not work on older jade versions, don't care */ -} - -static inline void -WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data) -{ - waitforCEC(cs, jade, reg); - WRITEJADE(cs, jade, reg, data); -} - - - -static void -jade_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct IsdnCardState *cs = bcs->cs; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "jade_empty_fifo"); - - if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "jade_empty_fifo: incoming packet too large"); - WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC); - bcs->hw.hscx.rcvidx = 0; - return; - } - ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx; - bcs->hw.hscx.rcvidx += count; - READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count); - WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "jade_empty_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -jade_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int more, count; - int fifo_size = 32; - u_char *ptr; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "jade_fill_fifo"); - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->tx_skb->len > fifo_size) { - more = !0; - count = fifo_size; - } else - count = bcs->tx_skb->len; - - waitforXFW(cs, bcs->hw.hscx.hscx); - ptr = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.hscx.count += count; - WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count); - WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF | jadeXCMD_XME)); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "jade_fill_fifo %c cnt %d", - bcs->hw.hscx.hscx ? 'B' : 'A', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - - -static void -jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade) -{ - u_char r; - struct BCState *bcs = cs->bcs + jade; - struct sk_buff *skb; - int fifo_size = 32; - int count; - int i_jade = (int) jade; /* To satisfy the compiler */ - - if (!test_bit(BC_FLG_INIT, &bcs->Flag)) - return; - - if (val & 0x80) { /* RME */ - r = READJADE(cs, i_jade, jade_HDLC_RSTA); - if ((r & 0xf0) != 0xa0) { - if (!(r & 0x80)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "JADE %s invalid frame", (jade ? "B" : "A")); - if ((r & 0x40) && bcs->mode) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "JADE %c RDO mode=%d", 'A' + jade, bcs->mode); - if (!(r & 0x20)) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "JADE %c CRC error", 'A' + jade); - WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC); - } else { - count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F; - if (count == 0) - count = fifo_size; - jade_empty_fifo(bcs, count); - if ((count = bcs->hw.hscx.rcvidx - 1) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "HX Frame %d", count); - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B" : "A")); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - count); - skb_queue_tail(&bcs->rqueue, skb); - } - } - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - if (val & 0x40) { /* RPF */ - jade_empty_fifo(bcs, fifo_size); - if (bcs->mode == L1_MODE_TRANS) { - /* receive audio data */ - if (!(skb = dev_alloc_skb(fifo_size))) - printk(KERN_WARNING "HiSax: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.hscx.rcvbuf, - fifo_size); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.hscx.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - } - if (val & 0x10) { /* XPR */ - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - jade_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.hscx.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.hscx.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.hscx.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - jade_fill_fifo(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -} - -static inline void -jade_int_main(struct IsdnCardState *cs, u_char val, int jade) -{ - struct BCState *bcs; - bcs = cs->bcs + jade; - - if (val & jadeISR_RFO) { - /* handled with RDO */ - val &= ~jadeISR_RFO; - } - if (val & jadeISR_XDU) { - /* relevant in HDLC mode only */ - /* don't reset XPR here */ - if (bcs->mode == 1) - jade_fill_fifo(bcs); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.hscx.count); - bcs->tx_cnt += bcs->hw.hscx.count; - bcs->hw.hscx.count = 0; - } - WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "JADE %c EXIR %x Lost TX", 'A' + jade, val); - } - } - if (val & (jadeISR_RME | jadeISR_RPF | jadeISR_XPR)) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "JADE %c interrupt %x", 'A' + jade, val); - jade_interrupt(cs, val, jade); - } -} diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c deleted file mode 100644 index 98f60d1523f4..000000000000 --- a/drivers/isdn/hisax/l3_1tr6.c +++ /dev/null @@ -1,932 +0,0 @@ -/* $Id: l3_1tr6.c,v 2.15.2.3 2004/01/13 14:31:25 keil Exp $ - * - * German 1TR6 D-channel protocol - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.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 - * - */ - -#include "hisax.h" -#include "l3_1tr6.h" -#include "isdnl3.h" -#include <linux/ctype.h> - -extern char *HiSax_getrev(const char *revision); -static const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $"; - -#define MsgHead(ptr, cref, mty, dis) \ - *ptr++ = dis; \ - *ptr++ = 0x1; \ - *ptr++ = cref ^ 0x80; \ - *ptr++ = mty - -static void -l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd) -{ - struct sk_buff *skb; - u_char *p; - - if (!(skb = l3_alloc_skb(4))) - return; - p = skb_put(skb, 4); - MsgHead(p, pc->callref, mt, pd); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg) -{ - StopAllL3Timer(pc); - newl3state(pc, 19); - l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - dev_kfree_skb(skb); - l3_1tr6_release_req(pc, 0, NULL); -} - -static void -l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb) -{ - dev_kfree_skb(skb); - if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "%s", msg); - l3_1tr6_release_req(pc, 0, NULL); -} - -static void -l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[128]; - u_char *p = tmp; - u_char *teln; - u_char *eaz; - u_char channel = 0; - int l; - - MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1); - teln = pc->para.setup.phone; - pc->para.spv = 0; - if (!isdigit(*teln)) { - switch (0x5f & *teln) { - case 'S': - pc->para.spv = 1; - break; - case 'C': - channel = 0x08; - /* fall through */ - case 'P': - channel |= 0x80; - teln++; - if (*teln == '1') - channel |= 0x01; - else - channel |= 0x02; - break; - default: - if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "Wrong MSN Code"); - break; - } - teln++; - } - if (channel) { - *p++ = 0x18; /* channel indicator */ - *p++ = 1; - *p++ = channel; - } - if (pc->para.spv) { /* SPV ? */ - /* NSF SPV */ - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_SPV; /* SPV */ - *p++ = pc->para.setup.si1; /* 0 for all Services */ - *p++ = pc->para.setup.si2; /* 0 for all Services */ - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_Activate; /* aktiviere SPV (default) */ - *p++ = pc->para.setup.si1; /* 0 for all Services */ - *p++ = pc->para.setup.si2; /* 0 for all Services */ - } - eaz = pc->para.setup.eazmsn; - if (*eaz) { - *p++ = WE0_origAddr; - *p++ = strlen(eaz) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*eaz) - *p++ = *eaz++ & 0x7f; - } - *p++ = WE0_destAddr; - *p++ = strlen(teln) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*teln) - *p++ = *teln++ & 0x7f; - - *p++ = WE_Shift_F6; - /* Codesatz 6 fuer Service */ - *p++ = WE6_serviceInd; - *p++ = 2; /* len=2 info,info2 */ - *p++ = pc->para.setup.si1; - *p++ = pc->para.setup.si2; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T303, CC_T303); - newl3state(pc, 1); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - int bcfound = 0; - struct sk_buff *skb = arg; - - /* Channel Identification */ - p = findie(skb->data, skb->len, WE0_chanID, 0); - if (p) { - if (p[1] != 1) { - l3_1tr6_error(pc, "setup wrong chanID len", skb); - return; - } - if ((p[2] & 0xf4) != 0x80) { - l3_1tr6_error(pc, "setup wrong WE0_chanID", skb); - return; - } - if ((pc->para.bchannel = p[2] & 0x3)) - bcfound++; - } else { - l3_1tr6_error(pc, "missing setup chanID", skb); - return; - } - - p = skb->data; - if ((p = findie(p, skb->len, WE6_serviceInd, 6))) { - pc->para.setup.si1 = p[2]; - pc->para.setup.si2 = p[3]; - } else { - l3_1tr6_error(pc, "missing setup SI", skb); - return; - } - - p = skb->data; - if ((p = findie(p, skb->len, WE0_destAddr, 0))) - iecpy(pc->para.setup.eazmsn, p, 1); - else - pc->para.setup.eazmsn[0] = 0; - - p = skb->data; - if ((p = findie(p, skb->len, WE0_origAddr, 0))) { - iecpy(pc->para.setup.phone, p, 1); - } else - pc->para.setup.phone[0] = 0; - - p = skb->data; - pc->para.spv = 0; - if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) { - if ((FAC_SPV == p[3]) || (FAC_Activate == p[3])) - pc->para.spv = 1; - } - dev_kfree_skb(skb); - - /* Signal all services, linklevel takes care of Service-Indicator */ - if (bcfound) { - if ((pc->para.setup.si1 != 7) && (pc->st->l3.debug & L3_DEB_WARN)) { - l3_debug(pc->st, "non-digital call: %s -> %s", - pc->para.setup.phone, - pc->para.setup.eazmsn); - } - newl3state(pc, 6); - pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); - } else - release_l3_process(pc); -} - -static void -l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - - L3DelTimer(&pc->timer); - p = skb->data; - newl3state(pc, 2); - if ((p = findie(p, skb->len, WE0_chanID, 0))) { - if (p[1] != 1) { - l3_1tr6_error(pc, "setup_ack wrong chanID len", skb); - return; - } - if ((p[2] & 0xf4) != 0x80) { - l3_1tr6_error(pc, "setup_ack wrong WE0_chanID", skb); - return; - } - pc->para.bchannel = p[2] & 0x3; - } else { - l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb); - return; - } - dev_kfree_skb(skb); - L3AddTimer(&pc->timer, T304, CC_T304); - pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); -} - -static void -l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - - L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, WE0_chanID, 0))) { - if (p[1] != 1) { - l3_1tr6_error(pc, "call sent wrong chanID len", skb); - return; - } - if ((p[2] & 0xf4) != 0x80) { - l3_1tr6_error(pc, "call sent wrong WE0_chanID", skb); - return; - } - if ((pc->state == 2) && (pc->para.bchannel != (p[2] & 0x3))) { - l3_1tr6_error(pc, "call sent wrong chanID value", skb); - return; - } - pc->para.bchannel = p[2] & 0x3; - } else { - l3_1tr6_error(pc, "missing call sent WE0_chanID", skb); - return; - } - dev_kfree_skb(skb); - L3AddTimer(&pc->timer, T310, CC_T310); - newl3state(pc, 3); - pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); -} - -static void -l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - dev_kfree_skb(skb); - L3DelTimer(&pc->timer); /* T304 */ - newl3state(pc, 4); - pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); -} - -static void -l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - int i, tmpcharge = 0; - char a_charge[8]; - struct sk_buff *skb = arg; - - p = skb->data; - if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) { - iecpy(a_charge, p, 1); - for (i = 0; i < strlen(a_charge); i++) { - tmpcharge *= 10; - tmpcharge += a_charge[i] & 0xf; - } - if (tmpcharge > pc->para.chargeinfo) { - pc->para.chargeinfo = tmpcharge; - pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); - } - if (pc->st->l3.debug & L3_DEB_CHARGE) { - l3_debug(pc->st, "charging info %d", - pc->para.chargeinfo); - } - } else if (pc->st->l3.debug & L3_DEB_CHARGE) - l3_debug(pc->st, "charging info not found"); - dev_kfree_skb(skb); - -} - -static void -l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - dev_kfree_skb(skb); -} - -static void -l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - L3DelTimer(&pc->timer); /* T310 */ - if (!findie(skb->data, skb->len, WE6_date, 6)) { - l3_1tr6_error(pc, "missing connect date", skb); - return; - } - newl3state(pc, 10); - dev_kfree_skb(skb); - pc->para.chargeinfo = 0; - pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); -} - -static void -l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - - p = skb->data; - if ((p = findie(p, skb->len, WE0_cause, 0))) { - if (p[1] > 0) { - pc->para.cause = p[2]; - if (p[1] > 1) - pc->para.loc = p[3]; - else - pc->para.loc = 0; - } else { - pc->para.cause = 0; - pc->para.loc = 0; - } - } else { - pc->para.cause = NO_CAUSE; - l3_1tr6_error(pc, "missing REL cause", skb); - return; - } - dev_kfree_skb(skb); - StopAllL3Timer(pc); - newl3state(pc, 0); - l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - release_l3_process(pc); -} - -static void -l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - dev_kfree_skb(skb); - StopAllL3Timer(pc); - newl3state(pc, 0); - pc->para.cause = NO_CAUSE; - pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); - release_l3_process(pc); -} - -static void -l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - int i, tmpcharge = 0; - char a_charge[8]; - - StopAllL3Timer(pc); - p = skb->data; - if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) { - iecpy(a_charge, p, 1); - for (i = 0; i < strlen(a_charge); i++) { - tmpcharge *= 10; - tmpcharge += a_charge[i] & 0xf; - } - if (tmpcharge > pc->para.chargeinfo) { - pc->para.chargeinfo = tmpcharge; - pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); - } - if (pc->st->l3.debug & L3_DEB_CHARGE) { - l3_debug(pc->st, "charging info %d", - pc->para.chargeinfo); - } - } else if (pc->st->l3.debug & L3_DEB_CHARGE) - l3_debug(pc->st, "charging info not found"); - - - p = skb->data; - if ((p = findie(p, skb->len, WE0_cause, 0))) { - if (p[1] > 0) { - pc->para.cause = p[2]; - if (p[1] > 1) - pc->para.loc = p[3]; - else - pc->para.loc = 0; - } else { - pc->para.cause = 0; - pc->para.loc = 0; - } - } else { - if (pc->st->l3.debug & L3_DEB_WARN) - l3_debug(pc->st, "cause not found"); - pc->para.cause = NO_CAUSE; - } - if (!findie(skb->data, skb->len, WE6_date, 6)) { - l3_1tr6_error(pc, "missing connack date", skb); - return; - } - dev_kfree_skb(skb); - newl3state(pc, 12); - pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); -} - - -static void -l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - if (!findie(skb->data, skb->len, WE6_date, 6)) { - l3_1tr6_error(pc, "missing connack date", skb); - return; - } - dev_kfree_skb(skb); - newl3state(pc, 10); - pc->para.chargeinfo = 0; - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); -} - -static void -l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 7); - l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1); -} - -static void -l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[24]; - u_char *p = tmp; - int l; - - MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1); - if (pc->para.spv) { /* SPV ? */ - /* NSF SPV */ - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_SPV; /* SPV */ - *p++ = pc->para.setup.si1; - *p++ = pc->para.setup.si2; - *p++ = WE0_netSpecFac; - *p++ = 4; /* Laenge */ - *p++ = 0; - *p++ = FAC_Activate; /* aktiviere SPV */ - *p++ = pc->para.setup.si1; - *p++ = pc->para.setup.si2; - } - newl3state(pc, 8); - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T313, CC_T313); -} - -static void -l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg) -{ - release_l3_process(pc); -} - -static void -l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - u_char cause = 0x10; - u_char clen = 1; - - if (pc->para.cause > 0) - cause = pc->para.cause; - /* Map DSS1 causes */ - switch (cause & 0x7f) { - case 0x10: - clen = 0; - break; - case 0x11: - cause = CAUSE_UserBusy; - break; - case 0x15: - cause = CAUSE_CallRejected; - break; - } - StopAllL3Timer(pc); - MsgHead(p, pc->callref, MT_N1_DISC, PROTO_DIS_N1); - *p++ = WE0_cause; - *p++ = clen; /* Laenge */ - if (clen) - *p++ = cause | 0x80; - newl3state(pc, 11); - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T305, CC_T305); -} - -static void -l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg) -{ - if (pc->N303 > 0) { - pc->N303--; - L3DelTimer(&pc->timer); - l3_1tr6_setup_req(pc, pr, arg); - } else { - L3DelTimer(&pc->timer); - pc->para.cause = 0; - l3_1tr6_disconnect_req(pc, 0, NULL); - } -} - -static void -l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 0xE6; - l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - u_char cause = 0x90; - u_char clen = 1; - - L3DelTimer(&pc->timer); - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - /* Map DSS1 causes */ - switch (cause & 0x7f) { - case 0x10: - clen = 0; - break; - case 0x15: - cause = CAUSE_CallRejected; - break; - } - MsgHead(p, pc->callref, MT_N1_REL, PROTO_DIS_N1); - *p++ = WE0_cause; - *p++ = clen; /* Laenge */ - if (clen) - *p++ = cause; - newl3state(pc, 19); - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 0xE6; - l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 0xE6; - l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); -} - -static void -l3_1tr6_t308_1(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); - L3AddTimer(&pc->timer, T308, CC_T308_2); - newl3state(pc, 19); -} - -static void -l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); - release_l3_process(pc); -} - -static void -l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg) -{ - pc->para.cause = CAUSE_LocalProcErr; - l3_1tr6_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 0); - pc->para.cause = 0x1b; /* Destination out of order */ - pc->para.loc = 0; - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - release_l3_process(pc); -} - -/* *INDENT-OFF* */ -static struct stateentry downstl[] = -{ - {SBIT(0), - CC_SETUP | REQUEST, l3_1tr6_setup_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | - SBIT(10), - CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req}, - {SBIT(12), - CC_RELEASE | REQUEST, l3_1tr6_release_req}, - {SBIT(6), - CC_IGNORE | REQUEST, l3_1tr6_reset}, - {SBIT(6), - CC_REJECT | REQUEST, l3_1tr6_disconnect_req}, - {SBIT(6), - CC_ALERTING | REQUEST, l3_1tr6_alert_req}, - {SBIT(6) | SBIT(7), - CC_SETUP | RESPONSE, l3_1tr6_setup_rsp}, - {SBIT(1), - CC_T303, l3_1tr6_t303}, - {SBIT(2), - CC_T304, l3_1tr6_t304}, - {SBIT(3), - CC_T310, l3_1tr6_t310}, - {SBIT(8), - CC_T313, l3_1tr6_t313}, - {SBIT(11), - CC_T305, l3_1tr6_t305}, - {SBIT(19), - CC_T308_1, l3_1tr6_t308_1}, - {SBIT(19), - CC_T308_2, l3_1tr6_t308_2}, -}; - -static struct stateentry datastln1[] = -{ - {SBIT(0), - MT_N1_INVALID, l3_1tr6_invalid}, - {SBIT(0), - MT_N1_SETUP, l3_1tr6_setup}, - {SBIT(1), - MT_N1_SETUP_ACK, l3_1tr6_setup_ack}, - {SBIT(1) | SBIT(2), - MT_N1_CALL_SENT, l3_1tr6_call_sent}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10), - MT_N1_DISC, l3_1tr6_disc}, - {SBIT(2) | SBIT(3) | SBIT(4), - MT_N1_ALERT, l3_1tr6_alert}, - {SBIT(2) | SBIT(3) | SBIT(4), - MT_N1_CONN, l3_1tr6_connect}, - {SBIT(2), - MT_N1_INFO, l3_1tr6_info_s2}, - {SBIT(8), - MT_N1_CONN_ACK, l3_1tr6_connect_ack}, - {SBIT(10), - MT_N1_INFO, l3_1tr6_info}, - {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | - SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17), - MT_N1_REL, l3_1tr6_rel}, - {SBIT(19), - MT_N1_REL, l3_1tr6_rel_ack}, - {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | - SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17), - MT_N1_REL_ACK, l3_1tr6_invalid}, - {SBIT(19), - MT_N1_REL_ACK, l3_1tr6_rel_ack} -}; - -static struct stateentry manstatelist[] = -{ - {SBIT(2), - DL_ESTABLISH | INDICATION, l3_1tr6_dl_reset}, - {ALL_STATES, - DL_RELEASE | INDICATION, l3_1tr6_dl_release}, -}; - -/* *INDENT-ON* */ - -static void -up1tr6(struct PStack *st, int pr, void *arg) -{ - int i, mt, cr; - struct l3_process *proc; - struct sk_buff *skb = arg; - - switch (pr) { - case (DL_DATA | INDICATION): - case (DL_UNIT_DATA | INDICATION): - break; - case (DL_ESTABLISH | CONFIRM): - case (DL_ESTABLISH | INDICATION): - case (DL_RELEASE | INDICATION): - case (DL_RELEASE | CONFIRM): - l3_msg(st, pr, arg); - return; - break; - } - if (skb->len < 4) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "up1tr6 len only %d", skb->len); - } - dev_kfree_skb(skb); - return; - } - if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "up1tr6%sunexpected discriminator %x message len %d", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - skb->data[0], skb->len); - } - dev_kfree_skb(skb); - return; - } - if (skb->data[1] != 1) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "up1tr6 CR len not 1"); - } - dev_kfree_skb(skb); - return; - } - cr = skb->data[2]; - mt = skb->data[3]; - if (skb->data[0] == PROTO_DIS_N0) { - dev_kfree_skb(skb); - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "up1tr6%s N0 mt %x unhandled", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt); - } - } else if (skb->data[0] == PROTO_DIS_N1) { - if (!(proc = getl3proc(st, cr))) { - if (mt == MT_N1_SETUP) { - if (cr < 128) { - if (!(proc = new_l3_process(st, cr))) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "up1tr6 no roc mem"); - } - dev_kfree_skb(skb); - return; - } - } else { - dev_kfree_skb(skb); - return; - } - } else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) || - (mt == MT_N1_CANC_ACK) || (mt == MT_N1_CANC_REJ) || - (mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) || - (mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) || - (mt == MT_N1_INFO)) { - dev_kfree_skb(skb); - return; - } else { - if (!(proc = new_l3_process(st, cr))) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "up1tr6 no roc mem"); - } - dev_kfree_skb(skb); - return; - } - mt = MT_N1_INVALID; - } - } - for (i = 0; i < ARRAY_SIZE(datastln1); i++) - if ((mt == datastln1[i].primitive) && - ((1 << proc->state) & datastln1[i].state)) - break; - if (i == ARRAY_SIZE(datastln1)) { - dev_kfree_skb(skb); - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "up1tr6%sstate %d mt %x unhandled", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - return; - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "up1tr6%sstate %d mt %x", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - datastln1[i].rout(proc, pr, skb); - } - } -} - -static void -down1tr6(struct PStack *st, int pr, void *arg) -{ - int i, cr; - struct l3_process *proc; - struct Channel *chan; - - if ((DL_ESTABLISH | REQUEST) == pr) { - l3_msg(st, pr, NULL); - return; - } else if ((CC_SETUP | REQUEST) == pr) { - chan = arg; - cr = newcallref(); - cr |= 0x80; - if (!(proc = new_l3_process(st, cr))) { - return; - } else { - proc->chan = chan; - chan->proc = proc; - memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); - proc->callref = cr; - } - } else { - proc = arg; - } - - for (i = 0; i < ARRAY_SIZE(downstl); i++) - if ((pr == downstl[i].primitive) && - ((1 << proc->state) & downstl[i].state)) - break; - if (i == ARRAY_SIZE(downstl)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "down1tr6 state %d prim %d unhandled", - proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "down1tr6 state %d prim %d", - proc->state, pr); - } - downstl[i].rout(proc, pr, arg); - } -} - -static void -man1tr6(struct PStack *st, int pr, void *arg) -{ - int i; - struct l3_process *proc = arg; - - if (!proc) { - printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr); - return; - } - for (i = 0; i < ARRAY_SIZE(manstatelist); i++) - if ((pr == manstatelist[i].primitive) && - ((1 << proc->state) & manstatelist[i].state)) - break; - if (i == ARRAY_SIZE(manstatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled", - proc->callref & 0x7f, proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d man1tr6 state %d prim %d", - proc->callref & 0x7f, proc->state, pr); - } - manstatelist[i].rout(proc, pr, arg); - } -} - -void -setstack_1tr6(struct PStack *st) -{ - char tmp[64]; - - st->lli.l4l3 = down1tr6; - st->l2.l2l3 = up1tr6; - st->l3.l3ml3 = man1tr6; - st->l3.N303 = 0; - - strcpy(tmp, l3_1tr6_revision); - printk(KERN_INFO "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp)); -} diff --git a/drivers/isdn/hisax/l3_1tr6.h b/drivers/isdn/hisax/l3_1tr6.h deleted file mode 100644 index 43215c00cada..000000000000 --- a/drivers/isdn/hisax/l3_1tr6.h +++ /dev/null @@ -1,164 +0,0 @@ -/* $Id: l3_1tr6.h,v 2.2.6.2 2001/09/23 22:24:49 kai Exp $ - * - * German 1TR6 D-channel protocol defines - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef l3_1tr6 -#define l3_1tr6 - -#define PROTO_DIS_N0 0x40 -#define PROTO_DIS_N1 0x41 - -/* - * MsgType N0 - */ -#define MT_N0_REG_IND 0x61 -#define MT_N0_CANC_IND 0x62 -#define MT_N0_FAC_STA 0x63 -#define MT_N0_STA_ACK 0x64 -#define MT_N0_STA_REJ 0x65 -#define MT_N0_FAC_INF 0x66 -#define MT_N0_INF_ACK 0x67 -#define MT_N0_INF_REJ 0x68 -#define MT_N0_CLOSE 0x75 -#define MT_N0_CLO_ACK 0x77 - -/* - * MsgType N1 - */ - -#define MT_N1_ESC 0x00 -#define MT_N1_ALERT 0x01 -#define MT_N1_CALL_SENT 0x02 -#define MT_N1_CONN 0x07 -#define MT_N1_CONN_ACK 0x0F -#define MT_N1_SETUP 0x05 -#define MT_N1_SETUP_ACK 0x0D -#define MT_N1_RES 0x26 -#define MT_N1_RES_ACK 0x2E -#define MT_N1_RES_REJ 0x22 -#define MT_N1_SUSP 0x25 -#define MT_N1_SUSP_ACK 0x2D -#define MT_N1_SUSP_REJ 0x21 -#define MT_N1_USER_INFO 0x20 -#define MT_N1_DET 0x40 -#define MT_N1_DISC 0x45 -#define MT_N1_REL 0x4D -#define MT_N1_REL_ACK 0x5A -#define MT_N1_CANC_ACK 0x6E -#define MT_N1_CANC_REJ 0x67 -#define MT_N1_CON_CON 0x69 -#define MT_N1_FAC 0x60 -#define MT_N1_FAC_ACK 0x68 -#define MT_N1_FAC_CAN 0x66 -#define MT_N1_FAC_REG 0x64 -#define MT_N1_FAC_REJ 0x65 -#define MT_N1_INFO 0x6D -#define MT_N1_REG_ACK 0x6C -#define MT_N1_REG_REJ 0x6F -#define MT_N1_STAT 0x63 -#define MT_N1_INVALID 0 - -/* - * W Elemente - */ - -#define WE_Shift_F0 0x90 -#define WE_Shift_F6 0x96 -#define WE_Shift_OF0 0x98 -#define WE_Shift_OF6 0x9E - -#define WE0_cause 0x08 -#define WE0_connAddr 0x0C -#define WE0_callID 0x10 -#define WE0_chanID 0x18 -#define WE0_netSpecFac 0x20 -#define WE0_display 0x28 -#define WE0_keypad 0x2C -#define WE0_origAddr 0x6C -#define WE0_destAddr 0x70 -#define WE0_userInfo 0x7E - -#define WE0_moreData 0xA0 -#define WE0_congestLevel 0xB0 - -#define WE6_serviceInd 0x01 -#define WE6_chargingInfo 0x02 -#define WE6_date 0x03 -#define WE6_facSelect 0x05 -#define WE6_facStatus 0x06 -#define WE6_statusCalled 0x07 -#define WE6_addTransAttr 0x08 - -/* - * FacCodes - */ -#define FAC_Sperre 0x01 -#define FAC_Sperre_All 0x02 -#define FAC_Sperre_Fern 0x03 -#define FAC_Sperre_Intl 0x04 -#define FAC_Sperre_Interk 0x05 - -#define FAC_Forward1 0x02 -#define FAC_Forward2 0x03 -#define FAC_Konferenz 0x06 -#define FAC_GrabBchan 0x0F -#define FAC_Reactivate 0x10 -#define FAC_Konferenz3 0x11 -#define FAC_Dienstwechsel1 0x12 -#define FAC_Dienstwechsel2 0x13 -#define FAC_NummernIdent 0x14 -#define FAC_GBG 0x15 -#define FAC_DisplayUebergeben 0x17 -#define FAC_DisplayUmgeleitet 0x1A -#define FAC_Unterdruecke 0x1B -#define FAC_Deactivate 0x1E -#define FAC_Activate 0x1D -#define FAC_SPV 0x1F -#define FAC_Rueckwechsel 0x23 -#define FAC_Umleitung 0x24 - -/* - * Cause codes - */ -#define CAUSE_InvCRef 0x01 -#define CAUSE_BearerNotImpl 0x03 -#define CAUSE_CIDunknown 0x07 -#define CAUSE_CIDinUse 0x08 -#define CAUSE_NoChans 0x0A -#define CAUSE_FacNotImpl 0x10 -#define CAUSE_FacNotSubscr 0x11 -#define CAUSE_OutgoingBarred 0x20 -#define CAUSE_UserAccessBusy 0x21 -#define CAUSE_NegativeGBG 0x22 -#define CAUSE_UnknownGBG 0x23 -#define CAUSE_NoSPVknown 0x25 -#define CAUSE_DestNotObtain 0x35 -#define CAUSE_NumberChanged 0x38 -#define CAUSE_OutOfOrder 0x39 -#define CAUSE_NoUserResponse 0x3A -#define CAUSE_UserBusy 0x3B -#define CAUSE_IncomingBarred 0x3D -#define CAUSE_CallRejected 0x3E -#define CAUSE_NetworkCongestion 0x59 -#define CAUSE_RemoteUser 0x5A -#define CAUSE_LocalProcErr 0x70 -#define CAUSE_RemoteProcErr 0x71 -#define CAUSE_RemoteUserSuspend 0x72 -#define CAUSE_RemoteUserResumed 0x73 -#define CAUSE_UserInfoDiscarded 0x7F - -#define T303 4000 -#define T304 20000 -#define T305 4000 -#define T308 4000 -#define T310 120000 -#define T313 4000 -#define T318 4000 -#define T319 4000 - -#endif diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c deleted file mode 100644 index 368d152a8f1d..000000000000 --- a/drivers/isdn/hisax/l3dss1.c +++ /dev/null @@ -1,3227 +0,0 @@ -/* $Id: l3dss1.c,v 2.32.2.3 2004/01/13 14:31:25 keil Exp $ - * - * EURO/DSS1 D-channel protocol - * - * German 1TR6 D-channel protocol - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil <keil@isdn4linux.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 - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include "hisax.h" -#include "isdnl3.h" -#include "l3dss1.h" -#include <linux/ctype.h> -#include <linux/slab.h> - -extern char *HiSax_getrev(const char *revision); -static const char *dss1_revision = "$Revision: 2.32.2.3 $"; - -#define EXT_BEARER_CAPS 1 - -#define MsgHead(ptr, cref, mty) \ - *ptr++ = 0x8; \ - if (cref == -1) { \ - *ptr++ = 0x0; \ - } else { \ - *ptr++ = 0x1; \ - *ptr++ = cref^0x80; \ - } \ - *ptr++ = mty - - -/**********************************************/ -/* get a new invoke id for remote operations. */ -/* Only a return value != 0 is valid */ -/**********************************************/ -static unsigned char new_invoke_id(struct PStack *p) -{ - unsigned char retval; - int i; - - i = 32; /* maximum search depth */ - - retval = p->prot.dss1.last_invoke_id + 1; /* try new id */ - while ((i) && (p->prot.dss1.invoke_used[retval >> 3] == 0xFF)) { - p->prot.dss1.last_invoke_id = (retval & 0xF8) + 8; - i--; - } - if (i) { - while (p->prot.dss1.invoke_used[retval >> 3] & (1 << (retval & 7))) - retval++; - } else - retval = 0; - p->prot.dss1.last_invoke_id = retval; - p->prot.dss1.invoke_used[retval >> 3] |= (1 << (retval & 7)); - return (retval); -} /* new_invoke_id */ - -/*************************/ -/* free a used invoke id */ -/*************************/ -static void free_invoke_id(struct PStack *p, unsigned char id) -{ - - if (!id) return; /* 0 = invalid value */ - - p->prot.dss1.invoke_used[id >> 3] &= ~(1 << (id & 7)); -} /* free_invoke_id */ - - -/**********************************************************/ -/* create a new l3 process and fill in dss1 specific data */ -/**********************************************************/ -static struct l3_process -*dss1_new_l3_process(struct PStack *st, int cr) -{ struct l3_process *proc; - - if (!(proc = new_l3_process(st, cr))) - return (NULL); - - proc->prot.dss1.invoke_id = 0; - proc->prot.dss1.remote_operation = 0; - proc->prot.dss1.uus1_data[0] = '\0'; - - return (proc); -} /* dss1_new_l3_process */ - -/************************************************/ -/* free a l3 process and all dss1 specific data */ -/************************************************/ -static void -dss1_release_l3_process(struct l3_process *p) -{ - free_invoke_id(p->st, p->prot.dss1.invoke_id); - release_l3_process(p); -} /* dss1_release_l3_process */ - -/********************************************************/ -/* search a process with invoke id id and dummy callref */ -/********************************************************/ -static struct l3_process * -l3dss1_search_dummy_proc(struct PStack *st, int id) -{ struct l3_process *pc = st->l3.proc; /* start of processes */ - - if (!id) return (NULL); - - while (pc) - { if ((pc->callref == -1) && (pc->prot.dss1.invoke_id == id)) - return (pc); - pc = pc->next; - } - return (NULL); -} /* l3dss1_search_dummy_proc */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a return result is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3dss1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - struct l3_process *pc = NULL; - - if ((pc = l3dss1_search_dummy_proc(st, id))) - { L3DelTimer(&pc->timer); /* remove timer */ - - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = DSS1_STAT_INVOKE_RES; - ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; - ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; - ic.parm.dss1_io.proc = pc->prot.dss1.proc; - ic.parm.dss1_io.timeout = 0; - ic.parm.dss1_io.datalen = nlen; - ic.parm.dss1_io.data = p; - free_invoke_id(pc->st, pc->prot.dss1.invoke_id); - pc->prot.dss1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - dss1_release_l3_process(pc); - } - else - l3_debug(st, "dummy return result id=0x%x result len=%d", id, nlen); -} /* l3dss1_dummy_return_result */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a return error is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3dss1_dummy_error_return(struct PStack *st, int id, ulong error) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - struct l3_process *pc = NULL; - - if ((pc = l3dss1_search_dummy_proc(st, id))) - { L3DelTimer(&pc->timer); /* remove timer */ - - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = DSS1_STAT_INVOKE_ERR; - ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; - ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; - ic.parm.dss1_io.proc = pc->prot.dss1.proc; - ic.parm.dss1_io.timeout = error; - ic.parm.dss1_io.datalen = 0; - ic.parm.dss1_io.data = NULL; - free_invoke_id(pc->st, pc->prot.dss1.invoke_id); - pc->prot.dss1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - dss1_release_l3_process(pc); - } - else - l3_debug(st, "dummy return error id=0x%x error=0x%lx", id, error); -} /* l3dss1_error_return */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a invoke is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3dss1_dummy_invoke(struct PStack *st, int cr, int id, - int ident, u_char *p, u_char nlen) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - - l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", - (cr == -1) ? "local" : "broadcast", id, ident, nlen); - if (cr >= -1) return; /* ignore local data */ - - cs = st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = DSS1_STAT_INVOKE_BRD; - ic.parm.dss1_io.hl_id = id; - ic.parm.dss1_io.ll_id = 0; - ic.parm.dss1_io.proc = ident; - ic.parm.dss1_io.timeout = 0; - ic.parm.dss1_io.datalen = nlen; - ic.parm.dss1_io.data = p; - - cs->iif.statcallb(&ic); -} /* l3dss1_dummy_invoke */ - -static void -l3dss1_parse_facility(struct PStack *st, struct l3_process *pc, - int cr, u_char *p) -{ - int qd_len = 0; - unsigned char nlen = 0, ilen, cp_tag; - int ident, id; - ulong err_ret; - - if (pc) - st = pc->st; /* valid Stack */ - else - if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ - - p++; - qd_len = *p++; - if (qd_len == 0) { - l3_debug(st, "qd_len == 0"); - return; - } - if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ - l3_debug(st, "supplementary service != 0x11"); - return; - } - while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ - p++; - qd_len--; - } - if (qd_len < 2) { - l3_debug(st, "qd_len < 2"); - return; - } - p++; - qd_len--; - if ((*p & 0xE0) != 0xA0) { /* class and form */ - l3_debug(st, "class and form != 0xA0"); - return; - } - - cp_tag = *p & 0x1F; /* remember tag value */ - - p++; - qd_len--; - if (qd_len < 1) - { l3_debug(st, "qd_len < 1"); - return; - } - if (*p & 0x80) - { /* length format indefinite or limited */ - nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ - if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || - (nlen > 1)) - { l3_debug(st, "length format error or not implemented"); - return; - } - if (nlen == 1) - { nlen = *p++; /* complete length */ - qd_len--; - } - else - { qd_len -= 2; /* trailing null bytes */ - if ((*(p + qd_len)) || (*(p + qd_len + 1))) - { l3_debug(st, "length format indefinite error"); - return; - } - nlen = qd_len; - } - } - else - { nlen = *p++; - qd_len--; - } - if (qd_len < nlen) - { l3_debug(st, "qd_len < nlen"); - return; - } - qd_len -= nlen; - - if (nlen < 2) - { l3_debug(st, "nlen < 2"); - return; - } - if (*p != 0x02) - { /* invoke identifier tag */ - l3_debug(st, "invoke identifier tag !=0x02"); - return; - } - p++; - nlen--; - if (*p & 0x80) - { /* length format */ - l3_debug(st, "invoke id length format 2"); - return; - } - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) - { l3_debug(st, "ilen > nlen || ilen == 0"); - return; - } - nlen -= ilen; - id = 0; - while (ilen > 0) - { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */ - ilen--; - } - - switch (cp_tag) { /* component tag */ - case 1: /* invoke */ - if (nlen < 2) { - l3_debug(st, "nlen < 2 22"); - return; - } - if (*p != 0x02) { /* operation value */ - l3_debug(st, "operation value !=0x02"); - return; - } - p++; - nlen--; - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) { - l3_debug(st, "ilen > nlen || ilen == 0 22"); - return; - } - nlen -= ilen; - ident = 0; - while (ilen > 0) { - ident = (ident << 8) | (*p++ & 0xFF); - ilen--; - } - - if (!pc) - { l3dss1_dummy_invoke(st, cr, id, ident, p, nlen); - return; - } -#ifdef CONFIG_DE_AOC - { - -#define FOO1(s, a, b) \ - while (nlen > 1) { \ - int ilen = p[1]; \ - if (nlen < ilen + 2) { \ - l3_debug(st, "FOO1 nlen < ilen+2"); \ - return; \ - } \ - nlen -= ilen + 2; \ - if ((*p & 0xFF) == (a)) { \ - int nlen = ilen; \ - p += 2; \ - b; \ - } else { \ - p += ilen + 2; \ - } \ - } - - switch (ident) { - case 0x22: /* during */ - FOO1("1A", 0x30, FOO1("1C", 0xA1, FOO1("1D", 0x30, FOO1("1E", 0x02, ( { - ident = 0; - nlen = (nlen) ? nlen : 0; /* Make gcc happy */ - while (ilen > 0) { - ident = (ident << 8) | *p++; - ilen--; - } - if (ident > pc->para.chargeinfo) { - pc->para.chargeinfo = ident; - st->l3.l3l4(st, CC_CHARGE | INDICATION, pc); - } - if (st->l3.debug & L3_DEB_CHARGE) { - if (*(p + 2) == 0) { - l3_debug(st, "charging info during %d", pc->para.chargeinfo); - } - else { - l3_debug(st, "charging info final %d", pc->para.chargeinfo); - } - } - } - ))))) - break; - case 0x24: /* final */ - FOO1("2A", 0x30, FOO1("2B", 0x30, FOO1("2C", 0xA1, FOO1("2D", 0x30, FOO1("2E", 0x02, ( { - ident = 0; - nlen = (nlen) ? nlen : 0; /* Make gcc happy */ - while (ilen > 0) { - ident = (ident << 8) | *p++; - ilen--; - } - if (ident > pc->para.chargeinfo) { - pc->para.chargeinfo = ident; - st->l3.l3l4(st, CC_CHARGE | INDICATION, pc); - } - if (st->l3.debug & L3_DEB_CHARGE) { - l3_debug(st, "charging info final %d", pc->para.chargeinfo); - } - } - )))))) - break; - default: - l3_debug(st, "invoke break invalid ident %02x", ident); - break; - } -#undef FOO1 - - } -#else /* not CONFIG_DE_AOC */ - l3_debug(st, "invoke break"); -#endif /* not CONFIG_DE_AOC */ - break; - case 2: /* return result */ - /* if no process available handle separately */ - if (!pc) - { if (cr == -1) - l3dss1_dummy_return_result(st, id, p, nlen); - return; - } - if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id)) - { /* Diversion successful */ - free_invoke_id(st, pc->prot.dss1.invoke_id); - pc->prot.dss1.remote_result = 0; /* success */ - pc->prot.dss1.invoke_id = 0; - pc->redir_result = pc->prot.dss1.remote_result; - st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ - else - l3_debug(st, "return error unknown identifier"); - break; - case 3: /* return error */ - err_ret = 0; - if (nlen < 2) - { l3_debug(st, "return error nlen < 2"); - return; - } - if (*p != 0x02) - { /* result tag */ - l3_debug(st, "invoke error tag !=0x02"); - return; - } - p++; - nlen--; - if (*p > 4) - { /* length format */ - l3_debug(st, "invoke return errlen > 4 "); - return; - } - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) - { l3_debug(st, "error return ilen > nlen || ilen == 0"); - return; - } - nlen -= ilen; - while (ilen > 0) - { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */ - ilen--; - } - /* if no process available handle separately */ - if (!pc) - { if (cr == -1) - l3dss1_dummy_error_return(st, id, err_ret); - return; - } - if ((pc->prot.dss1.invoke_id) && (pc->prot.dss1.invoke_id == id)) - { /* Deflection error */ - free_invoke_id(st, pc->prot.dss1.invoke_id); - pc->prot.dss1.remote_result = err_ret; /* result */ - pc->prot.dss1.invoke_id = 0; - pc->redir_result = pc->prot.dss1.remote_result; - st->l3.l3l4(st, CC_REDIR | INDICATION, pc); - } /* Deflection error */ - else - l3_debug(st, "return result unknown identifier"); - break; - default: - l3_debug(st, "facility default break tag=0x%02x", cp_tag); - break; - } -} - -static void -l3dss1_message(struct l3_process *pc, u_char mt) -{ - struct sk_buff *skb; - u_char *p; - - if (!(skb = l3_alloc_skb(4))) - return; - p = skb_put(skb, 4); - MsgHead(p, pc->callref, mt); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3dss1_message_cause(struct l3_process *pc, u_char mt, u_char cause) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - - MsgHead(p, pc->callref, mt); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3dss1_status_send(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - - MsgHead(p, pc->callref, MT_STATUS); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = pc->para.cause | 0x80; - - *p++ = IE_CALL_STATE; - *p++ = 0x1; - *p++ = pc->state & 0x3f; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3dss1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) -{ - /* This routine is called if here was no SETUP made (checks in dss1up and in - * l3dss1_setup) and a RELEASE_COMPLETE have to be sent with an error code - * MT_STATUS_ENQUIRE in the NULL state is handled too - */ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - - switch (pc->para.cause) { - case 81: /* invalid callreference */ - case 88: /* incomp destination */ - case 96: /* mandory IE missing */ - case 100: /* invalid IE contents */ - case 101: /* incompatible Callstate */ - MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = pc->para.cause | 0x80; - break; - default: - printk(KERN_ERR "HiSax l3dss1_msg_without_setup wrong cause %d\n", - pc->para.cause); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - dss1_release_l3_process(pc); -} - -static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC, - IE_USER_USER, -1}; -static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; -static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, - IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; -static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; -static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, - IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; -static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, - IE_CALLED_PN, -1}; -static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | - IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; -static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, - IE_SIGNAL, IE_USER_USER, -1}; -/* a RELEASE_COMPLETE with errors don't require special actions - static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; -*/ -static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, - IE_DISPLAY, -1}; -static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY, - IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, IE_PROGRESS, - IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, - IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR, - IE_LLC, IE_HLC, IE_USER_USER, -1}; -static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, - IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; -static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | - IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; -static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1}; -static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; -/* not used - * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, - * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; - * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; - * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND | - * IE_MANDATORY, -1}; - */ -static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1}; -static int comp_required[] = {1, 2, 3, 5, 6, 7, 9, 10, 11, 14, 15, -1}; -static int l3_valid_states[] = {0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 17, 19, 25, -1}; - -struct ie_len { - int ie; - int len; -}; - -static -struct ie_len max_ie_len[] = { - {IE_SEGMENT, 4}, - {IE_BEARER, 12}, - {IE_CAUSE, 32}, - {IE_CALL_ID, 10}, - {IE_CALL_STATE, 3}, - {IE_CHANNEL_ID, 34}, - {IE_FACILITY, 255}, - {IE_PROGRESS, 4}, - {IE_NET_FAC, 255}, - {IE_NOTIFY, 3}, - {IE_DISPLAY, 82}, - {IE_DATE, 8}, - {IE_KEYPAD, 34}, - {IE_SIGNAL, 3}, - {IE_INFORATE, 6}, - {IE_E2E_TDELAY, 11}, - {IE_TDELAY_SEL, 5}, - {IE_PACK_BINPARA, 3}, - {IE_PACK_WINSIZE, 4}, - {IE_PACK_SIZE, 4}, - {IE_CUG, 7}, - {IE_REV_CHARGE, 3}, - {IE_CALLING_PN, 24}, - {IE_CALLING_SUB, 23}, - {IE_CALLED_PN, 24}, - {IE_CALLED_SUB, 23}, - {IE_REDIR_NR, 255}, - {IE_TRANS_SEL, 255}, - {IE_RESTART_IND, 3}, - {IE_LLC, 18}, - {IE_HLC, 5}, - {IE_USER_USER, 131}, - {-1, 0}, -}; - -static int -getmax_ie_len(u_char ie) { - int i = 0; - while (max_ie_len[i].ie != -1) { - if (max_ie_len[i].ie == ie) - return (max_ie_len[i].len); - i++; - } - return (255); -} - -static int -ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { - int ret = 1; - - while (*checklist != -1) { - if ((*checklist & 0xff) == ie) { - if (ie & 0x80) - return (-ret); - else - return (ret); - } - ret++; - checklist++; - } - return (0); -} - -static int -check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) -{ - int *cl = checklist; - u_char mt; - u_char *p, ie; - int l, newpos, oldpos; - int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; - u_char codeset = 0; - u_char old_codeset = 0; - u_char codelock = 1; - - p = skb->data; - /* skip cr */ - p++; - l = (*p++) & 0xf; - p += l; - mt = *p++; - oldpos = 0; - while ((p - skb->data) < skb->len) { - if ((*p & 0xf0) == 0x90) { /* shift codeset */ - old_codeset = codeset; - codeset = *p & 7; - if (*p & 0x08) - codelock = 0; - else - codelock = 1; - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE shift%scodeset %d->%d", - codelock ? " locking " : " ", old_codeset, codeset); - p++; - continue; - } - if (!codeset) { /* only codeset 0 */ - if ((newpos = ie_in_set(pc, *p, cl))) { - if (newpos > 0) { - if (newpos < oldpos) - err_seq++; - else - oldpos = newpos; - } - } else { - if (ie_in_set(pc, *p, comp_required)) - err_compr++; - else - err_ureg++; - } - } - ie = *p++; - if (ie & 0x80) { - l = 1; - } else { - l = *p++; - p += l; - l += 2; - } - if (!codeset && (l > getmax_ie_len(ie))) - err_len++; - if (!codelock) { - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE shift back codeset %d->%d", - codeset, old_codeset); - codeset = old_codeset; - codelock = 1; - } - } - if (err_compr | err_ureg | err_len | err_seq) { - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", - mt, err_compr, err_ureg, err_len, err_seq); - if (err_compr) - return (ERR_IE_COMPREHENSION); - if (err_ureg) - return (ERR_IE_UNRECOGNIZED); - if (err_len) - return (ERR_IE_LENGTH); - if (err_seq) - return (ERR_IE_SEQUENCE); - } - return (0); -} - -/* verify if a message type exists and contain no IE error */ -static int -l3dss1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg) -{ - switch (mt) { - case MT_ALERTING: - case MT_CALL_PROCEEDING: - case MT_CONNECT: - case MT_CONNECT_ACKNOWLEDGE: - case MT_DISCONNECT: - case MT_INFORMATION: - case MT_FACILITY: - case MT_NOTIFY: - case MT_PROGRESS: - case MT_RELEASE: - case MT_RELEASE_COMPLETE: - case MT_SETUP: - case MT_SETUP_ACKNOWLEDGE: - case MT_RESUME_ACKNOWLEDGE: - case MT_RESUME_REJECT: - case MT_SUSPEND_ACKNOWLEDGE: - case MT_SUSPEND_REJECT: - case MT_USER_INFORMATION: - case MT_RESTART: - case MT_RESTART_ACKNOWLEDGE: - case MT_CONGESTION_CONTROL: - case MT_STATUS: - case MT_STATUS_ENQUIRY: - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) OK", mt); - break; - case MT_RESUME: /* RESUME only in user->net */ - case MT_SUSPEND: /* SUSPEND only in user->net */ - default: - if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN)) - l3_debug(pc->st, "l3dss1_check_messagetype_validity mt(%x) fail", mt); - pc->para.cause = 97; - l3dss1_status_send(pc, 0, NULL); - return (1); - } - return (0); -} - -static void -l3dss1_std_ie_err(struct l3_process *pc, int ret) { - - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check_infoelements ret %d", ret); - switch (ret) { - case 0: - break; - case ERR_IE_COMPREHENSION: - pc->para.cause = 96; - l3dss1_status_send(pc, 0, NULL); - break; - case ERR_IE_UNRECOGNIZED: - pc->para.cause = 99; - l3dss1_status_send(pc, 0, NULL); - break; - case ERR_IE_LENGTH: - pc->para.cause = 100; - l3dss1_status_send(pc, 0, NULL); - break; - case ERR_IE_SEQUENCE: - default: - break; - } -} - -static int -l3dss1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { - u_char *p; - - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - p++; - if (*p != 1) { /* len for BRI = 1 */ - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong chid len %d", *p); - return (-2); - } - p++; - if (*p & 0x60) { /* only base rate interface */ - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong chid %x", *p); - return (-3); - } - return (*p & 0x3); - } else - return (-1); -} - -static int -l3dss1_get_cause(struct l3_process *pc, struct sk_buff *skb) { - u_char l, i = 0; - u_char *p; - - p = skb->data; - pc->para.cause = 31; - pc->para.loc = 0; - if ((p = findie(p, skb->len, IE_CAUSE, 0))) { - p++; - l = *p++; - if (l > 30) - return (1); - if (l) { - pc->para.loc = *p++; - l--; - } else { - return (2); - } - if (l && !(pc->para.loc & 0x80)) { - l--; - p++; /* skip recommendation */ - } - if (l) { - pc->para.cause = *p++; - l--; - if (!(pc->para.cause & 0x80)) - return (3); - } else - return (4); - while (l && (i < 6)) { - pc->para.diag[i++] = *p++; - l--; - } - } else - return (-1); - return (0); -} - -static void -l3dss1_msg_with_uus(struct l3_process *pc, u_char cmd) -{ - struct sk_buff *skb; - u_char tmp[16 + 40]; - u_char *p = tmp; - int l; - - MsgHead(p, pc->callref, cmd); - - if (pc->prot.dss1.uus1_data[0]) - { *p++ = IE_USER_USER; /* UUS info element */ - *p++ = strlen(pc->prot.dss1.uus1_data) + 1; - *p++ = 0x04; /* IA5 chars */ - strcpy(p, pc->prot.dss1.uus1_data); - p += strlen(pc->prot.dss1.uus1_data); - pc->prot.dss1.uus1_data[0] = '\0'; - } - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} /* l3dss1_msg_with_uus */ - -static void -l3dss1_release_req(struct l3_process *pc, u_char pr, void *arg) -{ - StopAllL3Timer(pc); - newl3state(pc, 19); - if (!pc->prot.dss1.uus1_data[0]) - l3dss1_message(pc, MT_RELEASE); - else - l3dss1_msg_with_uus(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3dss1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3dss1_get_cause(pc, skb)) > 0) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "RELCMPL get_cause ret(%d)", ret); - } else if (ret < 0) - pc->para.cause = NO_CAUSE; - StopAllL3Timer(pc); - newl3state(pc, 0); - pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); - dss1_release_l3_process(pc); -} - -#ifdef EXT_BEARER_CAPS - -static u_char * -EncodeASyncParams(u_char *p, u_char si2) -{ // 7c 06 88 90 21 42 00 bb - - p[0] = 0; - p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 - p[2] = 0x80; - if (si2 & 32) // 7 data bits - - p[2] += 16; - else // 8 data bits - - p[2] += 24; - - if (si2 & 16) // 2 stop bits - - p[2] += 96; - else // 1 stop bit - - p[2] += 32; - - if (si2 & 8) // even parity - - p[2] += 2; - else // no parity - - p[2] += 3; - - switch (si2 & 0x07) { - case 0: - p[0] = 66; // 1200 bit/s - - break; - case 1: - p[0] = 88; // 1200/75 bit/s - - break; - case 2: - p[0] = 87; // 75/1200 bit/s - - break; - case 3: - p[0] = 67; // 2400 bit/s - - break; - case 4: - p[0] = 69; // 4800 bit/s - - break; - case 5: - p[0] = 72; // 9600 bit/s - - break; - case 6: - p[0] = 73; // 14400 bit/s - - break; - case 7: - p[0] = 75; // 19200 bit/s - - break; - } - return p + 3; -} - -static u_char -EncodeSyncParams(u_char si2, u_char ai) -{ - - switch (si2) { - case 0: - return ai + 2; // 1200 bit/s - - case 1: - return ai + 24; // 1200/75 bit/s - - case 2: - return ai + 23; // 75/1200 bit/s - - case 3: - return ai + 3; // 2400 bit/s - - case 4: - return ai + 5; // 4800 bit/s - - case 5: - return ai + 8; // 9600 bit/s - - case 6: - return ai + 9; // 14400 bit/s - - case 7: - return ai + 11; // 19200 bit/s - - case 8: - return ai + 14; // 48000 bit/s - - case 9: - return ai + 15; // 56000 bit/s - - case 15: - return ai + 40; // negotiate bit/s - - default: - break; - } - return ai; -} - - -static u_char -DecodeASyncParams(u_char si2, u_char *p) -{ - u_char info; - - switch (p[5]) { - case 66: // 1200 bit/s - - break; // si2 don't change - - case 88: // 1200/75 bit/s - - si2 += 1; - break; - case 87: // 75/1200 bit/s - - si2 += 2; - break; - case 67: // 2400 bit/s - - si2 += 3; - break; - case 69: // 4800 bit/s - - si2 += 4; - break; - case 72: // 9600 bit/s - - si2 += 5; - break; - case 73: // 14400 bit/s - - si2 += 6; - break; - case 75: // 19200 bit/s - - si2 += 7; - break; - } - - info = p[7] & 0x7f; - if ((info & 16) && (!(info & 8))) // 7 data bits - - si2 += 32; // else 8 data bits - - if ((info & 96) == 96) // 2 stop bits - - si2 += 16; // else 1 stop bit - - if ((info & 2) && (!(info & 1))) // even parity - - si2 += 8; // else no parity - - return si2; -} - - -static u_char -DecodeSyncParams(u_char si2, u_char info) -{ - info &= 0x7f; - switch (info) { - case 40: // bit/s negotiation failed ai := 165 not 175! - - return si2 + 15; - case 15: // 56000 bit/s failed, ai := 0 not 169 ! - - return si2 + 9; - case 14: // 48000 bit/s - - return si2 + 8; - case 11: // 19200 bit/s - - return si2 + 7; - case 9: // 14400 bit/s - - return si2 + 6; - case 8: // 9600 bit/s - - return si2 + 5; - case 5: // 4800 bit/s - - return si2 + 4; - case 3: // 2400 bit/s - - return si2 + 3; - case 23: // 75/1200 bit/s - - return si2 + 2; - case 24: // 1200/75 bit/s - - return si2 + 1; - default: // 1200 bit/s - - return si2; - } -} - -static u_char -DecodeSI2(struct sk_buff *skb) -{ - u_char *p; //, *pend=skb->data + skb->len; - - if ((p = findie(skb->data, skb->len, 0x7c, 0))) { - switch (p[4] & 0x0f) { - case 0x01: - if (p[1] == 0x04) // sync. Bitratenadaption - - return DecodeSyncParams(160, p[5]); // V.110/X.30 - - else if (p[1] == 0x06) // async. Bitratenadaption - - return DecodeASyncParams(192, p); // V.110/X.30 - - break; - case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption - if (p[1] > 3) - return DecodeSyncParams(176, p[5]); // V.120 - break; - } - } - return 0; -} - -#endif - - -static void -l3dss1_setup_req(struct l3_process *pc, u_char pr, - void *arg) -{ - struct sk_buff *skb; - u_char tmp[128]; - u_char *p = tmp; - u_char channel = 0; - - u_char send_keypad; - u_char screen = 0x80; - u_char *teln; - u_char *msn; - u_char *sub; - u_char *sp; - int l; - - MsgHead(p, pc->callref, MT_SETUP); - - teln = pc->para.setup.phone; -#ifndef CONFIG_HISAX_NO_KEYPAD - send_keypad = (strchr(teln, '*') || strchr(teln, '#')) ? 1 : 0; -#else - send_keypad = 0; -#endif -#ifndef CONFIG_HISAX_NO_SENDCOMPLETE - if (!send_keypad) - *p++ = 0xa1; /* complete indicator */ -#endif - /* - * Set Bearer Capability, Map info from 1TR6-convention to EDSS1 - */ - switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = IE_BEARER; - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa3; /* A-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = IE_BEARER; - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - break; - } - - if (send_keypad) { - *p++ = IE_KEYPAD; - *p++ = strlen(teln); - while (*teln) - *p++ = (*teln++) & 0x7F; - } - - /* - * What about info2? Mapping to High-Layer-Compatibility? - */ - if ((*teln) && (!send_keypad)) { - /* parse number for special things */ - if (!isdigit(*teln)) { - switch (0x5f & *teln) { - case 'C': - channel = 0x08; - /* fall through */ - case 'P': - channel |= 0x80; - teln++; - if (*teln == '1') - channel |= 0x01; - else - channel |= 0x02; - break; - case 'R': - screen = 0xA0; - break; - case 'D': - screen = 0x80; - break; - - default: - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "Wrong MSN Code"); - break; - } - teln++; - } - } - if (channel) { - *p++ = IE_CHANNEL_ID; - *p++ = 1; - *p++ = channel; - } - msn = pc->para.setup.eazmsn; - sub = NULL; - sp = msn; - while (*sp) { - if ('.' == *sp) { - sub = sp; - *sp = 0; - } else - sp++; - } - if (*msn) { - *p++ = IE_CALLING_PN; - *p++ = strlen(msn) + (screen ? 2 : 1); - /* Classify as AnyPref. */ - if (screen) { - *p++ = 0x01; /* Ext = '0'B, Type = '000'B, Plan = '0001'B. */ - *p++ = screen; - } else - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*msn) - *p++ = *msn++ & 0x7f; - } - if (sub) { - *sub++ = '.'; - *p++ = IE_CALLING_SUB; - *p++ = strlen(sub) + 2; - *p++ = 0x80; /* NSAP coded */ - *p++ = 0x50; /* local IDI format */ - while (*sub) - *p++ = *sub++ & 0x7f; - } - sub = NULL; - sp = teln; - while (*sp) { - if ('.' == *sp) { - sub = sp; - *sp = 0; - } else - sp++; - } - - if (!send_keypad) { - *p++ = IE_CALLED_PN; - *p++ = strlen(teln) + 1; - /* Classify as AnyPref. */ - *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ - while (*teln) - *p++ = *teln++ & 0x7f; - - if (sub) { - *sub++ = '.'; - *p++ = IE_CALLED_SUB; - *p++ = strlen(sub) + 2; - *p++ = 0x80; /* NSAP coded */ - *p++ = 0x50; /* local IDI format */ - while (*sub) - *p++ = *sub++ & 0x7f; - } - } -#ifdef EXT_BEARER_CAPS - if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 - - *p++ = IE_LLC; - *p++ = 0x04; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x21; - *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); - } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 - - *p++ = IE_LLC; - *p++ = 0x05; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x28; - *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); - *p++ = 0x82; - } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 - - *p++ = IE_LLC; - *p++ = 0x06; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x21; - p = EncodeASyncParams(p, pc->para.setup.si2 - 192); -#ifndef CONFIG_HISAX_NO_LLC - } else { - switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = IE_LLC; - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa3; /* A-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = IE_LLC; - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - break; - } -#endif - } -#endif - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T303, CC_T303); - newl3state(pc, 1); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3dss1_call_proc(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer with wrong chid %x", id); - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else if (1 == pc->state) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - newl3state(pc, 3); - L3AddTimer(&pc->timer, T310, CC_T310); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); -} - -static void -l3dss1_setup_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer with wrong chid %x", id); - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - newl3state(pc, 2); - L3AddTimer(&pc->timer, T304, CC_T304); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); -} - -static void -l3dss1_disconnect(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - int ret; - u_char cause = 0; - - StopAllL3Timer(pc); - if ((ret = l3dss1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "DISC get_cause ret(%d)", ret); - if (ret < 0) - cause = 96; - else if (ret > 0) - cause = 100; - } - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) - l3dss1_parse_facility(pc->st, pc, pc->callref, p); - ret = check_infoelements(pc, skb, ie_DISCONNECT); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret)) - cause = 99; - ret = pc->state; - newl3state(pc, 12); - if (cause) - newl3state(pc, 19); - if (11 != ret) - pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); - else if (!cause) - l3dss1_release_req(pc, pr, NULL); - if (cause) { - l3dss1_message_cause(pc, MT_RELEASE, cause); - L3AddTimer(&pc->timer, T308, CC_T308_1); - } -} - -static void -l3dss1_connect(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_CONNECT); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); /* T310 */ - newl3state(pc, 10); - pc->para.chargeinfo = 0; - /* here should inserted COLP handling KKe */ - if (ret) - l3dss1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); -} - -static void -l3dss1_alerting(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_ALERTING); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); /* T304 */ - newl3state(pc, 4); - if (ret) - l3dss1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); -} - -static void -l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - int bcfound = 0; - char tmp[80]; - struct sk_buff *skb = arg; - int id; - int err = 0; - - /* - * Bearer Capabilities - */ - p = skb->data; - /* only the first occurrence 'll be detected ! */ - if ((p = findie(p, skb->len, 0x04, 0))) { - if ((p[1] < 2) || (p[1] > 11)) - err = 1; - else { - pc->para.setup.si2 = 0; - switch (p[2] & 0x7f) { - case 0x00: /* Speech */ - case 0x10: /* 3.1 Khz audio */ - pc->para.setup.si1 = 1; - break; - case 0x08: /* Unrestricted digital information */ - pc->para.setup.si1 = 7; -/* JIM, 05.11.97 I wanna set service indicator 2 */ -#ifdef EXT_BEARER_CAPS - pc->para.setup.si2 = DecodeSI2(skb); -#endif - break; - case 0x09: /* Restricted digital information */ - pc->para.setup.si1 = 2; - break; - case 0x11: - /* Unrestr. digital information with - * tones/announcements ( or 7 kHz audio - */ - pc->para.setup.si1 = 3; - break; - case 0x18: /* Video */ - pc->para.setup.si1 = 4; - break; - default: - err = 2; - break; - } - switch (p[3] & 0x7f) { - case 0x40: /* packed mode */ - pc->para.setup.si1 = 8; - break; - case 0x10: /* 64 kbit */ - case 0x11: /* 2*64 kbit */ - case 0x13: /* 384 kbit */ - case 0x15: /* 1536 kbit */ - case 0x17: /* 1920 kbit */ - pc->para.moderate = p[3] & 0x7f; - break; - default: - err = 3; - break; - } - } - if (pc->debug & L3_DEB_SI) - l3_debug(pc->st, "SI=%d, AI=%d", - pc->para.setup.si1, pc->para.setup.si2); - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)", - p[1], p[2], p[3]); - pc->para.cause = 100; - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bearer capabilities"); - /* ETS 300-104 1.3.3 */ - pc->para.cause = 96; - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - /* - * Channel Identification - */ - if ((id = l3dss1_get_channel_id(pc, skb)) >= 0) { - if ((pc->para.bchannel = id)) { - if ((3 == id) && (0x10 == pc->para.moderate)) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong chid %x", - id); - pc->para.cause = 100; - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - bcfound++; - } else - { if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bchannel, call waiting"); - bcfound++; - } - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong chid ret %d", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_SETUP); - if (ERR_IE_COMPREHENSION == err) { - pc->para.cause = 96; - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - p = skb->data; - if ((p = findie(p, skb->len, 0x70, 0))) - iecpy(pc->para.setup.eazmsn, p, 1); - else - pc->para.setup.eazmsn[0] = 0; - - p = skb->data; - if ((p = findie(p, skb->len, 0x71, 0))) { - /* Called party subaddress */ - if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { - tmp[0] = '.'; - iecpy(&tmp[1], p, 2); - strcat(pc->para.setup.eazmsn, tmp); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong called subaddress"); - } - p = skb->data; - if ((p = findie(p, skb->len, 0x6c, 0))) { - pc->para.setup.plan = p[2]; - if (p[2] & 0x80) { - iecpy(pc->para.setup.phone, p, 1); - pc->para.setup.screen = 0; - } else { - iecpy(pc->para.setup.phone, p, 2); - pc->para.setup.screen = p[3]; - } - } else { - pc->para.setup.phone[0] = 0; - pc->para.setup.plan = 0; - pc->para.setup.screen = 0; - } - p = skb->data; - if ((p = findie(p, skb->len, 0x6d, 0))) { - /* Calling party subaddress */ - if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { - tmp[0] = '.'; - iecpy(&tmp[1], p, 2); - strcat(pc->para.setup.phone, tmp); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong calling subaddress"); - } - newl3state(pc, 6); - if (err) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, err); - pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); -} - -static void -l3dss1_reset(struct l3_process *pc, u_char pr, void *arg) -{ - dss1_release_l3_process(pc); -} - -static void -l3dss1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16 + 40]; - u_char *p = tmp; - int l; - u_char cause = 16; - - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - StopAllL3Timer(pc); - - MsgHead(p, pc->callref, MT_DISCONNECT); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - if (pc->prot.dss1.uus1_data[0]) - { *p++ = IE_USER_USER; /* UUS info element */ - *p++ = strlen(pc->prot.dss1.uus1_data) + 1; - *p++ = 0x04; /* IA5 chars */ - strcpy(p, pc->prot.dss1.uus1_data); - p += strlen(pc->prot.dss1.uus1_data); - pc->prot.dss1.uus1_data[0] = '\0'; - } - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 11); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T305, CC_T305); -} - -static void -l3dss1_setup_rsp(struct l3_process *pc, u_char pr, - void *arg) -{ - if (!pc->para.bchannel) - { if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "D-chan connect for waiting call"); - l3dss1_disconnect_req(pc, pr, arg); - return; - } - newl3state(pc, 8); - l3dss1_message(pc, MT_CONNECT); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T313, CC_T313); -} - -static void -l3dss1_connect_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - newl3state(pc, 10); - L3DelTimer(&pc->timer); - if (ret) - l3dss1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); -} - -static void -l3dss1_reject_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - u_char cause = 21; - - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - dss1_release_l3_process(pc); -} - -static void -l3dss1_release(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - int ret, cause = 0; - - StopAllL3Timer(pc); - if ((ret = l3dss1_get_cause(pc, skb)) > 0) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "REL get_cause ret(%d)", ret); - } else if (ret < 0) - pc->para.cause = NO_CAUSE; - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { - l3dss1_parse_facility(pc->st, pc, pc->callref, p); - } - if ((ret < 0) && (pc->state != 11)) - cause = 96; - else if (ret > 0) - cause = 100; - ret = check_infoelements(pc, skb, ie_RELEASE); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause)) - cause = 99; - if (cause) - l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, cause); - else - l3dss1_message(pc, MT_RELEASE_COMPLETE); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - dss1_release_l3_process(pc); -} - -static void -l3dss1_alert_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 7); - if (!pc->prot.dss1.uus1_data[0]) - l3dss1_message(pc, MT_ALERTING); - else - l3dss1_msg_with_uus(pc, MT_ALERTING); -} - -static void -l3dss1_proceed_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 9); - l3dss1_message(pc, MT_CALL_PROCEEDING); - pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); -} - -static void -l3dss1_setup_ack_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 25); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T302, CC_T302); - l3dss1_message(pc, MT_SETUP_ACKNOWLEDGE); -} - -/********************************************/ -/* deliver a incoming display message to HL */ -/********************************************/ -static void -l3dss1_deliver_display(struct l3_process *pc, int pr, u_char *infp) -{ u_char len; - isdn_ctrl ic; - struct IsdnCardState *cs; - char *p; - - if (*infp++ != IE_DISPLAY) return; - if ((len = *infp++) > 80) return; /* total length <= 82 */ - if (!pc->chan) return; - - p = ic.parm.display; - while (len--) - *p++ = *infp++; - *p = '\0'; - ic.command = ISDN_STAT_DISPLAY; - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.arg = pc->chan->chan; - cs->iif.statcallb(&ic); -} /* l3dss1_deliver_display */ - - -static void -l3dss1_progress(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int err = 0; - u_char *p; - - if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { - if (p[1] != 2) { - err = 1; - pc->para.cause = 100; - } else if (!(p[2] & 0x70)) { - switch (p[2]) { - case 0x80: - case 0x81: - case 0x82: - case 0x84: - case 0x85: - case 0x87: - case 0x8a: - switch (p[3]) { - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x88: - break; - default: - err = 2; - pc->para.cause = 100; - break; - } - break; - default: - err = 3; - pc->para.cause = 100; - break; - } - } - } else { - pc->para.cause = 96; - err = 4; - } - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "progress error %d", err); - l3dss1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_PROGRESS); - if (err) - l3dss1_std_ie_err(pc, err); - if (ERR_IE_COMPREHENSION != err) - pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); -} - -static void -l3dss1_notify(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int err = 0; - u_char *p; - - if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { - if (p[1] != 1) { - err = 1; - pc->para.cause = 100; - } else { - switch (p[2]) { - case 0x80: - case 0x81: - case 0x82: - break; - default: - pc->para.cause = 100; - err = 2; - break; - } - } - } else { - pc->para.cause = 96; - err = 3; - } - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "notify error %d", err); - l3dss1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_NOTIFY); - if (err) - l3dss1_std_ie_err(pc, err); - if (ERR_IE_COMPREHENSION != err) - pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); -} - -static void -l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg) -{ - int ret; - struct sk_buff *skb = arg; - - ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); - l3dss1_std_ie_err(pc, ret); - pc->para.cause = 30; /* response to STATUS_ENQUIRY */ - l3dss1_status_send(pc, pr, NULL); -} - -static void -l3dss1_information(struct l3_process *pc, u_char pr, void *arg) -{ - int ret; - struct sk_buff *skb = arg; - u_char *p; - char tmp[32]; - - ret = check_infoelements(pc, skb, ie_INFORMATION); - if (ret) - l3dss1_std_ie_err(pc, ret); - if (pc->state == 25) { /* overlap receiving */ - L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, 0x70, 0))) { - iecpy(tmp, p, 1); - strcat(pc->para.setup.eazmsn, tmp); - pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); - } - L3AddTimer(&pc->timer, T302, CC_T302); - } -} - -/******************************/ -/* handle deflection requests */ -/******************************/ -static void l3dss1_redir_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[128]; - u_char *p = tmp; - u_char *subp; - u_char len_phone = 0; - u_char len_sub = 0; - int l; - - - strcpy(pc->prot.dss1.uus1_data, pc->chan->setup.eazmsn); /* copy uus element if available */ - if (!pc->chan->setup.phone[0]) - { pc->para.cause = -1; - l3dss1_disconnect_req(pc, pr, arg); /* disconnect immediately */ - return; - } /* only uus */ - - if (pc->prot.dss1.invoke_id) - free_invoke_id(pc->st, pc->prot.dss1.invoke_id); - - if (!(pc->prot.dss1.invoke_id = new_invoke_id(pc->st))) - return; - - MsgHead(p, pc->callref, MT_FACILITY); - - for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ - if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */ - - *p++ = 0x1c; /* Facility info element */ - *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ - *p++ = 0x91; /* remote operations protocol */ - *p++ = 0xa1; /* invoke component */ - - *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */ - *p++ = 0x02; /* invoke id tag, integer */ - *p++ = 0x01; /* length */ - *p++ = pc->prot.dss1.invoke_id; /* invoke id */ - *p++ = 0x02; /* operation value tag, integer */ - *p++ = 0x01; /* length */ - *p++ = 0x0D; /* Call Deflect */ - - *p++ = 0x30; /* sequence phone number */ - *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */ - - *p++ = 0x30; /* Deflected to UserNumber */ - *p++ = len_phone + 2 + len_sub; /* length */ - *p++ = 0x80; /* NumberDigits */ - *p++ = len_phone; /* length */ - for (l = 0; l < len_phone; l++) - *p++ = pc->chan->setup.phone[l]; - - if (len_sub) - { *p++ = 0x04; /* called party subaddress */ - *p++ = len_sub - 2; - while (*subp) *p++ = *subp++; - } - - *p++ = 0x01; /* screening identifier */ - *p++ = 0x01; - *p++ = pc->chan->setup.screen; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) return; - skb_put_data(skb, tmp, l); - - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} /* l3dss1_redir_req */ - -/********************************************/ -/* handle deflection request in early state */ -/********************************************/ -static void l3dss1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) -{ - l3dss1_proceed_req(pc, pr, arg); - l3dss1_redir_req(pc, pr, arg); -} /* l3dss1_redir_req_early */ - -/***********************************************/ -/* handle special commands for this protocol. */ -/* Examples are call independent services like */ -/* remote operations with dummy callref. */ -/***********************************************/ -static int l3dss1_cmd_global(struct PStack *st, isdn_ctrl *ic) -{ u_char id; - u_char temp[265]; - u_char *p = temp; - int i, l, proc_len; - struct sk_buff *skb; - struct l3_process *pc = NULL; - - switch (ic->arg) - { case DSS1_CMD_INVOKE: - if (ic->parm.dss1_io.datalen < 0) return (-2); /* invalid parameter */ - - for (proc_len = 1, i = ic->parm.dss1_io.proc >> 8; i; i++) - i = i >> 8; /* add one byte */ - l = ic->parm.dss1_io.datalen + proc_len + 8; /* length excluding ie header */ - if (l > 255) - return (-2); /* too long */ - - if (!(id = new_invoke_id(st))) - return (0); /* first get a invoke id -> return if no available */ - - i = -1; - MsgHead(p, i, MT_FACILITY); /* build message head */ - *p++ = 0x1C; /* Facility IE */ - *p++ = l; /* length of ie */ - *p++ = 0x91; /* remote operations */ - *p++ = 0xA1; /* invoke */ - *p++ = l - 3; /* length of invoke */ - *p++ = 0x02; /* invoke id tag */ - *p++ = 0x01; /* length is 1 */ - *p++ = id; /* invoke id */ - *p++ = 0x02; /* operation */ - *p++ = proc_len; /* length of operation */ - - for (i = proc_len; i; i--) - *p++ = (ic->parm.dss1_io.proc >> (i - 1)) & 0xFF; - memcpy(p, ic->parm.dss1_io.data, ic->parm.dss1_io.datalen); /* copy data */ - l = (p - temp) + ic->parm.dss1_io.datalen; /* total length */ - - if (ic->parm.dss1_io.timeout > 0) - if (!(pc = dss1_new_l3_process(st, -1))) - { free_invoke_id(st, id); - return (-2); - } - pc->prot.dss1.ll_id = ic->parm.dss1_io.ll_id; /* remember id */ - pc->prot.dss1.proc = ic->parm.dss1_io.proc; /* and procedure */ - - if (!(skb = l3_alloc_skb(l))) - { free_invoke_id(st, id); - if (pc) dss1_release_l3_process(pc); - return (-2); - } - skb_put_data(skb, temp, l); - - if (pc) - { pc->prot.dss1.invoke_id = id; /* remember id */ - L3AddTimer(&pc->timer, ic->parm.dss1_io.timeout, CC_TDSS1_IO | REQUEST); - } - - l3_msg(st, DL_DATA | REQUEST, skb); - ic->parm.dss1_io.hl_id = id; /* return id */ - return (0); - - case DSS1_CMD_INVOKE_ABORT: - if ((pc = l3dss1_search_dummy_proc(st, ic->parm.dss1_io.hl_id))) - { L3DelTimer(&pc->timer); /* remove timer */ - dss1_release_l3_process(pc); - return (0); - } - else - { l3_debug(st, "l3dss1_cmd_global abort unknown id"); - return (-2); - } - break; - - default: - l3_debug(st, "l3dss1_cmd_global unknown cmd 0x%lx", ic->arg); - return (-1); - } /* switch ic-> arg */ - return (-1); -} /* l3dss1_cmd_global */ - -static void -l3dss1_io_timer(struct l3_process *pc) -{ isdn_ctrl ic; - struct IsdnCardState *cs = pc->st->l1.hardware; - - L3DelTimer(&pc->timer); /* remove timer */ - - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = DSS1_STAT_INVOKE_ERR; - ic.parm.dss1_io.hl_id = pc->prot.dss1.invoke_id; - ic.parm.dss1_io.ll_id = pc->prot.dss1.ll_id; - ic.parm.dss1_io.proc = pc->prot.dss1.proc; - ic.parm.dss1_io.timeout = -1; - ic.parm.dss1_io.datalen = 0; - ic.parm.dss1_io.data = NULL; - free_invoke_id(pc->st, pc->prot.dss1.invoke_id); - pc->prot.dss1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - - dss1_release_l3_process(pc); -} /* l3dss1_io_timer */ - -static void -l3dss1_release_ind(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - int callState = 0; - p = skb->data; - - if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { - p++; - if (1 == *p++) - callState = *p; - } - if (callState == 0) { - /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 - * set down layer 3 without sending any message - */ - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - dss1_release_l3_process(pc); - } else { - pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); - } -} - -static void -l3dss1_dummy(struct l3_process *pc, u_char pr, void *arg) -{ -} - -static void -l3dss1_t302(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 28; /* invalid number */ - l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3dss1_t303(struct l3_process *pc, u_char pr, void *arg) -{ - if (pc->N303 > 0) { - pc->N303--; - L3DelTimer(&pc->timer); - l3dss1_setup_req(pc, pr, arg); - } else { - L3DelTimer(&pc->timer); - l3dss1_message_cause(pc, MT_RELEASE_COMPLETE, 102); - pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); - dss1_release_l3_process(pc); - } -} - -static void -l3dss1_t304(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); - -} - -static void -l3dss1_t305(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - u_char cause = 16; - - L3DelTimer(&pc->timer); - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - MsgHead(p, pc->callref, MT_RELEASE); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 19); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3dss1_t310(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3dss1_t313(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); -} - -static void -l3dss1_t308_1(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 19); - L3DelTimer(&pc->timer); - l3dss1_message(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_2); -} - -static void -l3dss1_t308_2(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); - dss1_release_l3_process(pc); -} - -static void -l3dss1_t318(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 102; /* Timer expiry */ - pc->para.loc = 0; /* local */ - pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); - newl3state(pc, 19); - l3dss1_message(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3dss1_t319(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 102; /* Timer expiry */ - pc->para.loc = 0; /* local */ - pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); - newl3state(pc, 10); -} - -static void -l3dss1_restart(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - dss1_release_l3_process(pc); -} - -static void -l3dss1_status(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - int ret; - u_char cause = 0, callState = 0; - - if ((ret = l3dss1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "STATUS get_cause ret(%d)", ret); - if (ret < 0) - cause = 96; - else if (ret > 0) - cause = 100; - } - if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) { - p++; - if (1 == *p++) { - callState = *p; - if (!ie_in_set(pc, *p, l3_valid_states)) - cause = 100; - } else - cause = 100; - } else - cause = 96; - if (!cause) { /* no error before */ - ret = check_infoelements(pc, skb, ie_STATUS); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if (ERR_IE_UNRECOGNIZED == ret) - cause = 99; - } - if (cause) { - u_char tmp; - - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "STATUS error(%d/%d)", ret, cause); - tmp = pc->para.cause; - pc->para.cause = cause; - l3dss1_status_send(pc, 0, NULL); - if (cause == 99) - pc->para.cause = tmp; - else - return; - } - cause = pc->para.cause; - if (((cause & 0x7f) == 111) && (callState == 0)) { - /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... - * if received MT_STATUS with cause == 111 and call - * state == 0, then we must set down layer 3 - */ - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - dss1_release_l3_process(pc); - } -} - -static void -l3dss1_facility(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_FACILITY); - l3dss1_std_ie_err(pc, ret); - { - u_char *p; - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) - l3dss1_parse_facility(pc->st, pc, pc->callref, p); - } -} - -static void -l3dss1_suspend_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[32]; - u_char *p = tmp; - u_char i, l; - u_char *msg = pc->chan->setup.phone; - - MsgHead(p, pc->callref, MT_SUSPEND); - l = *msg++; - if (l && (l <= 10)) { /* Max length 10 octets */ - *p++ = IE_CALL_ID; - *p++ = l; - for (i = 0; i < l; i++) - *p++ = *msg++; - } else if (l) { - l3_debug(pc->st, "SUS wrong CALL_ID len %d", l); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - newl3state(pc, 15); - L3AddTimer(&pc->timer, T319, CC_T319); -} - -static void -l3dss1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - L3DelTimer(&pc->timer); - newl3state(pc, 0); - pc->para.cause = NO_CAUSE; - pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); - /* We don't handle suspend_ack for IE errors now */ - if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "SUSPACK check ie(%d)", ret); - dss1_release_l3_process(pc); -} - -static void -l3dss1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3dss1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)", ret); - if (ret < 0) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); - newl3state(pc, 10); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, ret); -} - -static void -l3dss1_resume_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[32]; - u_char *p = tmp; - u_char i, l; - u_char *msg = pc->para.setup.phone; - - MsgHead(p, pc->callref, MT_RESUME); - - l = *msg++; - if (l && (l <= 10)) { /* Max length 10 octets */ - *p++ = IE_CALL_ID; - *p++ = l; - for (i = 0; i < l; i++) - *p++ = *msg++; - } else if (l) { - l3_debug(pc->st, "RES wrong CALL_ID len %d", l); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - newl3state(pc, 17); - L3AddTimer(&pc->timer, T318, CC_T318); -} - -static void -l3dss1_resume_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3dss1_get_channel_id(pc, skb)) > 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "resume ack with wrong chid %x", id); - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else if (1 == pc->state) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "resume ack without chid (ret %d)", id); - pc->para.cause = 96; - l3dss1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); - newl3state(pc, 10); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, ret); -} - -static void -l3dss1_resume_rej(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3dss1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "RES_REJ get_cause ret(%d)", ret); - if (ret < 0) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3dss1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_RESUME_REJECT); - if (ERR_IE_COMPREHENSION == ret) { - l3dss1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); - newl3state(pc, 0); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3dss1_std_ie_err(pc, ret); - dss1_release_l3_process(pc); -} - -static void -l3dss1_global_restart(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[32]; - u_char *p; - u_char ri, ch = 0, chan = 0; - int l; - struct sk_buff *skb = arg; - struct l3_process *up; - - newl3state(pc, 2); - L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { - ri = p[2]; - l3_debug(pc->st, "Restart %x", ri); - } else { - l3_debug(pc->st, "Restart without restart IE"); - ri = 0x86; - } - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - chan = p[2] & 3; - ch = p[2]; - if (pc->st->l3.debug) - l3_debug(pc->st, "Restart for channel %d", chan); - } - newl3state(pc, 2); - up = pc->st->l3.proc; - while (up) { - if ((ri & 7) == 7) - up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); - else if (up->para.bchannel == chan) - up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); - up = up->next; - } - p = tmp; - MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE); - if (chan) { - *p++ = IE_CHANNEL_ID; - *p++ = 1; - *p++ = ch | 0x80; - } - *p++ = 0x79; /* RESTART Ind */ - *p++ = 1; - *p++ = ri; - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 0); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3dss1_dl_reset(struct l3_process *pc, u_char pr, void *arg) -{ - pc->para.cause = 0x29; /* Temporary failure */ - pc->para.loc = 0; - l3dss1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3dss1_dl_release(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 0); - pc->para.cause = 0x1b; /* Destination out of order */ - pc->para.loc = 0; - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - release_l3_process(pc); -} - -static void -l3dss1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T309, CC_T309); - l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL); -} - -static void -l3dss1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - - pc->para.cause = 0x1F; /* normal, unspecified */ - l3dss1_status_send(pc, 0, NULL); -} - -/* *INDENT-OFF* */ -static struct stateentry downstatelist[] = -{ - {SBIT(0), - CC_SETUP | REQUEST, l3dss1_setup_req}, - {SBIT(0), - CC_RESUME | REQUEST, l3dss1_resume_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), - CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, - {SBIT(12), - CC_RELEASE | REQUEST, l3dss1_release_req}, - {ALL_STATES, - CC_RESTART | REQUEST, l3dss1_restart}, - {SBIT(6) | SBIT(25), - CC_IGNORE | REQUEST, l3dss1_reset}, - {SBIT(6) | SBIT(25), - CC_REJECT | REQUEST, l3dss1_reject_req}, - {SBIT(6) | SBIT(25), - CC_PROCEED_SEND | REQUEST, l3dss1_proceed_req}, - {SBIT(6), - CC_MORE_INFO | REQUEST, l3dss1_setup_ack_req}, - {SBIT(25), - CC_MORE_INFO | REQUEST, l3dss1_dummy}, - {SBIT(6) | SBIT(9) | SBIT(25), - CC_ALERTING | REQUEST, l3dss1_alert_req}, - {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), - CC_SETUP | RESPONSE, l3dss1_setup_rsp}, - {SBIT(10), - CC_SUSPEND | REQUEST, l3dss1_suspend_req}, - {SBIT(7) | SBIT(9) | SBIT(25), - CC_REDIR | REQUEST, l3dss1_redir_req}, - {SBIT(6), - CC_REDIR | REQUEST, l3dss1_redir_req_early}, - {SBIT(9) | SBIT(25), - CC_DISCONNECT | REQUEST, l3dss1_disconnect_req}, - {SBIT(25), - CC_T302, l3dss1_t302}, - {SBIT(1), - CC_T303, l3dss1_t303}, - {SBIT(2), - CC_T304, l3dss1_t304}, - {SBIT(3), - CC_T310, l3dss1_t310}, - {SBIT(8), - CC_T313, l3dss1_t313}, - {SBIT(11), - CC_T305, l3dss1_t305}, - {SBIT(15), - CC_T319, l3dss1_t319}, - {SBIT(17), - CC_T318, l3dss1_t318}, - {SBIT(19), - CC_T308_1, l3dss1_t308_1}, - {SBIT(19), - CC_T308_2, l3dss1_t308_2}, - {SBIT(10), - CC_T309, l3dss1_dl_release}, -}; - -static struct stateentry datastatelist[] = -{ - {ALL_STATES, - MT_STATUS_ENQUIRY, l3dss1_status_enq}, - {ALL_STATES, - MT_FACILITY, l3dss1_facility}, - {SBIT(19), - MT_STATUS, l3dss1_release_ind}, - {ALL_STATES, - MT_STATUS, l3dss1_status}, - {SBIT(0), - MT_SETUP, l3dss1_setup}, - {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | - SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_SETUP, l3dss1_dummy}, - {SBIT(1) | SBIT(2), - MT_CALL_PROCEEDING, l3dss1_call_proc}, - {SBIT(1), - MT_SETUP_ACKNOWLEDGE, l3dss1_setup_ack}, - {SBIT(2) | SBIT(3), - MT_ALERTING, l3dss1_alerting}, - {SBIT(2) | SBIT(3), - MT_PROGRESS, l3dss1_progress}, - {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | - SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_INFORMATION, l3dss1_information}, - {SBIT(10) | SBIT(11) | SBIT(15), - MT_NOTIFY, l3dss1_notify}, - {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | - SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_RELEASE_COMPLETE, l3dss1_release_cmpl}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25), - MT_RELEASE, l3dss1_release}, - {SBIT(19), MT_RELEASE, l3dss1_release_ind}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), - MT_DISCONNECT, l3dss1_disconnect}, - {SBIT(19), - MT_DISCONNECT, l3dss1_dummy}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), - MT_CONNECT, l3dss1_connect}, - {SBIT(8), - MT_CONNECT_ACKNOWLEDGE, l3dss1_connect_ack}, - {SBIT(15), - MT_SUSPEND_ACKNOWLEDGE, l3dss1_suspend_ack}, - {SBIT(15), - MT_SUSPEND_REJECT, l3dss1_suspend_rej}, - {SBIT(17), - MT_RESUME_ACKNOWLEDGE, l3dss1_resume_ack}, - {SBIT(17), - MT_RESUME_REJECT, l3dss1_resume_rej}, -}; - -static struct stateentry globalmes_list[] = -{ - {ALL_STATES, - MT_STATUS, l3dss1_status}, - {SBIT(0), - MT_RESTART, l3dss1_global_restart}, -/* {SBIT(1), - MT_RESTART_ACKNOWLEDGE, l3dss1_restart_ack}, -*/ -}; - -static struct stateentry manstatelist[] = -{ - {SBIT(2), - DL_ESTABLISH | INDICATION, l3dss1_dl_reset}, - {SBIT(10), - DL_ESTABLISH | CONFIRM, l3dss1_dl_reest_status}, - {SBIT(10), - DL_RELEASE | INDICATION, l3dss1_dl_reestablish}, - {ALL_STATES, - DL_RELEASE | INDICATION, l3dss1_dl_release}, -}; - -/* *INDENT-ON* */ - - -static void -global_handler(struct PStack *st, int mt, struct sk_buff *skb) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - int i; - struct l3_process *proc = st->l3.global; - - proc->callref = skb->data[2]; /* cr flag */ - for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) - if ((mt == globalmes_list[i].primitive) && - ((1 << proc->state) & globalmes_list[i].state)) - break; - if (i == ARRAY_SIZE(globalmes_list)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1 global state %d mt %x unhandled", - proc->state, mt); - } - MsgHead(p, proc->callref, MT_STATUS); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = 81 | 0x80; /* invalid cr */ - *p++ = 0x14; /* CallState */ - *p++ = 0x1; - *p++ = proc->state & 0x3f; - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(proc->st, DL_DATA | REQUEST, skb); - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1 global %d mt %x", - proc->state, mt); - } - globalmes_list[i].rout(proc, mt, skb); - } -} - -static void -dss1up(struct PStack *st, int pr, void *arg) -{ - int i, mt, cr, callState; - char *ptr; - u_char *p; - struct sk_buff *skb = arg; - struct l3_process *proc; - - switch (pr) { - case (DL_DATA | INDICATION): - case (DL_UNIT_DATA | INDICATION): - break; - case (DL_ESTABLISH | CONFIRM): - case (DL_ESTABLISH | INDICATION): - case (DL_RELEASE | INDICATION): - case (DL_RELEASE | CONFIRM): - l3_msg(st, pr, arg); - return; - break; - default: - printk(KERN_ERR "HiSax dss1up unknown pr=%04x\n", pr); - return; - } - if (skb->len < 3) { - l3_debug(st, "dss1up frame too short(%d)", skb->len); - dev_kfree_skb(skb); - return; - } - - if (skb->data[0] != PROTO_DIS_EURO) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "dss1up%sunexpected discriminator %x message len %d", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - skb->data[0], skb->len); - } - dev_kfree_skb(skb); - return; - } - cr = getcallref(skb->data); - if (skb->len < ((skb->data[1] & 0x0f) + 3)) { - l3_debug(st, "dss1up frame too short(%d)", skb->len); - dev_kfree_skb(skb); - return; - } - mt = skb->data[skb->data[1] + 2]; - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "dss1up cr %d", cr); - if (cr == -2) { /* wrong Callref */ - if (st->l3.debug & L3_DEB_WARN) - l3_debug(st, "dss1up wrong Callref"); - dev_kfree_skb(skb); - return; - } else if (cr == -1) { /* Dummy Callref */ - if (mt == MT_FACILITY) - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { - l3dss1_parse_facility(st, NULL, - (pr == (DL_DATA | INDICATION)) ? -1 : -2, p); - dev_kfree_skb(skb); - return; - } - if (st->l3.debug & L3_DEB_WARN) - l3_debug(st, "dss1up dummy Callref (no facility msg or ie)"); - dev_kfree_skb(skb); - return; - } else if ((((skb->data[1] & 0x0f) == 1) && (0 == (cr & 0x7f))) || - (((skb->data[1] & 0x0f) == 2) && (0 == (cr & 0x7fff)))) { /* Global CallRef */ - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "dss1up Global CallRef"); - global_handler(st, mt, skb); - dev_kfree_skb(skb); - return; - } else if (!(proc = getl3proc(st, cr))) { - /* No transaction process exist, that means no call with - * this callreference is active - */ - if (mt == MT_SETUP) { - /* Setup creates a new transaction process */ - if (skb->data[2] & 0x80) { - /* Setup with wrong CREF flag */ - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "dss1up wrong CRef flag"); - dev_kfree_skb(skb); - return; - } - if (!(proc = dss1_new_l3_process(st, cr))) { - /* May be to answer with RELEASE_COMPLETE and - * CAUSE 0x2f "Resource unavailable", but this - * need a new_l3_process too ... arghh - */ - dev_kfree_skb(skb); - return; - } - } else if (mt == MT_STATUS) { - if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { - ptr++; - if (*ptr++ == 2) - ptr++; - } - callState = 0; - if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { - ptr++; - if (*ptr++ == 2) - ptr++; - callState = *ptr; - } - /* ETS 300-104 part 2.4.1 - * if setup has not been made and a message type - * MT_STATUS is received with call state == 0, - * we must send nothing - */ - if (callState != 0) { - /* ETS 300-104 part 2.4.2 - * if setup has not been made and a message type - * MT_STATUS is received with call state != 0, - * we must send MT_RELEASE_COMPLETE cause 101 - */ - if ((proc = dss1_new_l3_process(st, cr))) { - proc->para.cause = 101; - l3dss1_msg_without_setup(proc, 0, NULL); - } - } - dev_kfree_skb(skb); - return; - } else if (mt == MT_RELEASE_COMPLETE) { - dev_kfree_skb(skb); - return; - } else { - /* ETS 300-104 part 2 - * if setup has not been made and a message type - * (except MT_SETUP and RELEASE_COMPLETE) is received, - * we must send MT_RELEASE_COMPLETE cause 81 */ - dev_kfree_skb(skb); - if ((proc = dss1_new_l3_process(st, cr))) { - proc->para.cause = 81; - l3dss1_msg_without_setup(proc, 0, NULL); - } - return; - } - } - if (l3dss1_check_messagetype_validity(proc, mt, skb)) { - dev_kfree_skb(skb); - return; - } - if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) - l3dss1_deliver_display(proc, pr, p); /* Display IE included */ - for (i = 0; i < ARRAY_SIZE(datastatelist); i++) - if ((mt == datastatelist[i].primitive) && - ((1 << proc->state) & datastatelist[i].state)) - break; - if (i == ARRAY_SIZE(datastatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1up%sstate %d mt %#x unhandled", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) { - proc->para.cause = 101; - l3dss1_status_send(proc, pr, skb); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1up%sstate %d mt %x", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - datastatelist[i].rout(proc, pr, skb); - } - dev_kfree_skb(skb); - return; -} - -static void -dss1down(struct PStack *st, int pr, void *arg) -{ - int i, cr; - struct l3_process *proc; - struct Channel *chan; - - if ((DL_ESTABLISH | REQUEST) == pr) { - l3_msg(st, pr, NULL); - return; - } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { - chan = arg; - cr = newcallref(); - cr |= 0x80; - if ((proc = dss1_new_l3_process(st, cr))) { - proc->chan = chan; - chan->proc = proc; - memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); - proc->callref = cr; - } - } else { - proc = arg; - } - if (!proc) { - printk(KERN_ERR "HiSax dss1down without proc pr=%04x\n", pr); - return; - } - - if (pr == (CC_TDSS1_IO | REQUEST)) { - l3dss1_io_timer(proc); /* timer expires */ - return; - } - - for (i = 0; i < ARRAY_SIZE(downstatelist); i++) - if ((pr == downstatelist[i].primitive) && - ((1 << proc->state) & downstatelist[i].state)) - break; - if (i == ARRAY_SIZE(downstatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1down state %d prim %#x unhandled", - proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "dss1down state %d prim %#x", - proc->state, pr); - } - downstatelist[i].rout(proc, pr, arg); - } -} - -static void -dss1man(struct PStack *st, int pr, void *arg) -{ - int i; - struct l3_process *proc = arg; - - if (!proc) { - printk(KERN_ERR "HiSax dss1man without proc pr=%04x\n", pr); - return; - } - for (i = 0; i < ARRAY_SIZE(manstatelist); i++) - if ((pr == manstatelist[i].primitive) && - ((1 << proc->state) & manstatelist[i].state)) - break; - if (i == ARRAY_SIZE(manstatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d dss1man state %d prim %#x unhandled", - proc->callref & 0x7f, proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d dss1man state %d prim %#x", - proc->callref & 0x7f, proc->state, pr); - } - manstatelist[i].rout(proc, pr, arg); - } -} - -void -setstack_dss1(struct PStack *st) -{ - char tmp[64]; - int i; - - st->lli.l4l3 = dss1down; - st->lli.l4l3_proto = l3dss1_cmd_global; - st->l2.l2l3 = dss1up; - st->l3.l3ml3 = dss1man; - st->l3.N303 = 1; - st->prot.dss1.last_invoke_id = 0; - st->prot.dss1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */ - i = 1; - while (i < 32) - st->prot.dss1.invoke_used[i++] = 0; - - if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { - printk(KERN_ERR "HiSax can't get memory for dss1 global CR\n"); - } else { - st->l3.global->state = 0; - st->l3.global->callref = 0; - st->l3.global->next = NULL; - st->l3.global->debug = L3_DEB_WARN; - st->l3.global->st = st; - st->l3.global->N303 = 1; - st->l3.global->prot.dss1.invoke_id = 0; - - L3InitTimer(st->l3.global, &st->l3.global->timer); - } - strcpy(tmp, dss1_revision); - printk(KERN_INFO "HiSax: DSS1 Rev. %s\n", HiSax_getrev(tmp)); -} diff --git a/drivers/isdn/hisax/l3dss1.h b/drivers/isdn/hisax/l3dss1.h deleted file mode 100644 index a7807e8a94f1..000000000000 --- a/drivers/isdn/hisax/l3dss1.h +++ /dev/null @@ -1,124 +0,0 @@ -/* $Id: l3dss1.h,v 1.10.6.2 2001/09/23 22:24:50 kai Exp $ - * - * DSS1 (Euro) D-channel protocol defines - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef l3dss1_process - -#define T302 15000 -#define T303 4000 -#define T304 30000 -#define T305 30000 -#define T308 4000 -/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */ -/* This makes some tests easier and quicker */ -#define T309 40000 -#define T310 30000 -#define T313 4000 -#define T318 4000 -#define T319 4000 - -/* - * Message-Types - */ - -#define MT_ALERTING 0x01 -#define MT_CALL_PROCEEDING 0x02 -#define MT_CONNECT 0x07 -#define MT_CONNECT_ACKNOWLEDGE 0x0f -#define MT_PROGRESS 0x03 -#define MT_SETUP 0x05 -#define MT_SETUP_ACKNOWLEDGE 0x0d -#define MT_RESUME 0x26 -#define MT_RESUME_ACKNOWLEDGE 0x2e -#define MT_RESUME_REJECT 0x22 -#define MT_SUSPEND 0x25 -#define MT_SUSPEND_ACKNOWLEDGE 0x2d -#define MT_SUSPEND_REJECT 0x21 -#define MT_USER_INFORMATION 0x20 -#define MT_DISCONNECT 0x45 -#define MT_RELEASE 0x4d -#define MT_RELEASE_COMPLETE 0x5a -#define MT_RESTART 0x46 -#define MT_RESTART_ACKNOWLEDGE 0x4e -#define MT_SEGMENT 0x60 -#define MT_CONGESTION_CONTROL 0x79 -#define MT_INFORMATION 0x7b -#define MT_FACILITY 0x62 -#define MT_NOTIFY 0x6e -#define MT_STATUS 0x7d -#define MT_STATUS_ENQUIRY 0x75 - -#define IE_SEGMENT 0x00 -#define IE_BEARER 0x04 -#define IE_CAUSE 0x08 -#define IE_CALL_ID 0x10 -#define IE_CALL_STATE 0x14 -#define IE_CHANNEL_ID 0x18 -#define IE_FACILITY 0x1c -#define IE_PROGRESS 0x1e -#define IE_NET_FAC 0x20 -#define IE_NOTIFY 0x27 -#define IE_DISPLAY 0x28 -#define IE_DATE 0x29 -#define IE_KEYPAD 0x2c -#define IE_SIGNAL 0x34 -#define IE_INFORATE 0x40 -#define IE_E2E_TDELAY 0x42 -#define IE_TDELAY_SEL 0x43 -#define IE_PACK_BINPARA 0x44 -#define IE_PACK_WINSIZE 0x45 -#define IE_PACK_SIZE 0x46 -#define IE_CUG 0x47 -#define IE_REV_CHARGE 0x4a -#define IE_CONNECT_PN 0x4c -#define IE_CONNECT_SUB 0x4d -#define IE_CALLING_PN 0x6c -#define IE_CALLING_SUB 0x6d -#define IE_CALLED_PN 0x70 -#define IE_CALLED_SUB 0x71 -#define IE_REDIR_NR 0x74 -#define IE_TRANS_SEL 0x78 -#define IE_RESTART_IND 0x79 -#define IE_LLC 0x7c -#define IE_HLC 0x7d -#define IE_USER_USER 0x7e -#define IE_ESCAPE 0x7f -#define IE_SHIFT 0x90 -#define IE_MORE_DATA 0xa0 -#define IE_COMPLETE 0xa1 -#define IE_CONGESTION 0xb0 -#define IE_REPEAT 0xd0 - -#define IE_MANDATORY 0x0100 -/* mandatory not in every case */ -#define IE_MANDATORY_1 0x0200 - -#define ERR_IE_COMPREHENSION 1 -#define ERR_IE_UNRECOGNIZED -1 -#define ERR_IE_LENGTH -2 -#define ERR_IE_SEQUENCE -3 - -#else /* only l3dss1_process */ - -/* l3dss1 specific data in l3 process */ -typedef struct -{ unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */ - ulong ll_id; /* remebered ll id */ - u8 remote_operation; /* handled remote operation, 0 = not active */ - int proc; /* rememered procedure */ - ulong remote_result; /* result of remote operation for statcallb */ - char uus1_data[35]; /* data send during alerting or disconnect */ -} dss1_proc_priv; - -/* l3dss1 specific data in protocol stack */ -typedef struct -{ unsigned char last_invoke_id; /* last used value for invoking */ - unsigned char invoke_used[32]; /* 256 bits for 256 values */ -} dss1_stk_priv; - -#endif /* only l3dss1_process */ diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c deleted file mode 100644 index ea311e7df48e..000000000000 --- a/drivers/isdn/hisax/l3ni1.c +++ /dev/null @@ -1,3182 +0,0 @@ -/* $Id: l3ni1.c,v 2.8.2.3 2004/01/13 14:31:25 keil Exp $ - * - * NI1 D-channel protocol - * - * Author Matt Henderson & Guy Ellis - * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * 2000.6.6 Initial implementation of routines for US NI1 - * Layer 3 protocol based on the EURO/DSS1 D-channel protocol - * driver written by Karsten Keil et al. - * NI-1 Hall of Fame - Thanks to.... - * Ragnar Paulson - for some handy code fragments - * Will Scales - beta tester extraordinaire - * Brett Whittacre - beta tester and remote devel system in Vegas - * - */ - -#include "hisax.h" -#include "isdnl3.h" -#include "l3ni1.h" -#include <linux/ctype.h> -#include <linux/slab.h> - -extern char *HiSax_getrev(const char *revision); -static const char *ni1_revision = "$Revision: 2.8.2.3 $"; - -#define EXT_BEARER_CAPS 1 - -#define MsgHead(ptr, cref, mty) \ - *ptr++ = 0x8; \ - if (cref == -1) { \ - *ptr++ = 0x0; \ - } else { \ - *ptr++ = 0x1; \ - *ptr++ = cref^0x80; \ - } \ - *ptr++ = mty - - -/**********************************************/ -/* get a new invoke id for remote operations. */ -/* Only a return value != 0 is valid */ -/**********************************************/ -static unsigned char new_invoke_id(struct PStack *p) -{ - unsigned char retval; - int i; - - i = 32; /* maximum search depth */ - - retval = p->prot.ni1.last_invoke_id + 1; /* try new id */ - while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) { - p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8; - i--; - } - if (i) { - while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7))) - retval++; - } else - retval = 0; - p->prot.ni1.last_invoke_id = retval; - p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7)); - return (retval); -} /* new_invoke_id */ - -/*************************/ -/* free a used invoke id */ -/*************************/ -static void free_invoke_id(struct PStack *p, unsigned char id) -{ - - if (!id) return; /* 0 = invalid value */ - - p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7)); -} /* free_invoke_id */ - - -/**********************************************************/ -/* create a new l3 process and fill in ni1 specific data */ -/**********************************************************/ -static struct l3_process -*ni1_new_l3_process(struct PStack *st, int cr) -{ struct l3_process *proc; - - if (!(proc = new_l3_process(st, cr))) - return (NULL); - - proc->prot.ni1.invoke_id = 0; - proc->prot.ni1.remote_operation = 0; - proc->prot.ni1.uus1_data[0] = '\0'; - - return (proc); -} /* ni1_new_l3_process */ - -/************************************************/ -/* free a l3 process and all ni1 specific data */ -/************************************************/ -static void -ni1_release_l3_process(struct l3_process *p) -{ - free_invoke_id(p->st, p->prot.ni1.invoke_id); - release_l3_process(p); -} /* ni1_release_l3_process */ - -/********************************************************/ -/* search a process with invoke id id and dummy callref */ -/********************************************************/ -static struct l3_process * -l3ni1_search_dummy_proc(struct PStack *st, int id) -{ struct l3_process *pc = st->l3.proc; /* start of processes */ - - if (!id) return (NULL); - - while (pc) - { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id)) - return (pc); - pc = pc->next; - } - return (NULL); -} /* l3ni1_search_dummy_proc */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a return result is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - struct l3_process *pc = NULL; - - if ((pc = l3ni1_search_dummy_proc(st, id))) - { L3DelTimer(&pc->timer); /* remove timer */ - - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = NI1_STAT_INVOKE_RES; - ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; - ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; - ic.parm.ni1_io.proc = pc->prot.ni1.proc; - ic.parm.ni1_io.timeout = 0; - ic.parm.ni1_io.datalen = nlen; - ic.parm.ni1_io.data = p; - free_invoke_id(pc->st, pc->prot.ni1.invoke_id); - pc->prot.ni1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - ni1_release_l3_process(pc); - } - else - l3_debug(st, "dummy return result id=0x%x result len=%d", id, nlen); -} /* l3ni1_dummy_return_result */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a return error is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3ni1_dummy_error_return(struct PStack *st, int id, ulong error) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - struct l3_process *pc = NULL; - - if ((pc = l3ni1_search_dummy_proc(st, id))) - { L3DelTimer(&pc->timer); /* remove timer */ - - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = NI1_STAT_INVOKE_ERR; - ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; - ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; - ic.parm.ni1_io.proc = pc->prot.ni1.proc; - ic.parm.ni1_io.timeout = error; - ic.parm.ni1_io.datalen = 0; - ic.parm.ni1_io.data = NULL; - free_invoke_id(pc->st, pc->prot.ni1.invoke_id); - pc->prot.ni1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - ni1_release_l3_process(pc); - } - else - l3_debug(st, "dummy return error id=0x%x error=0x%lx", id, error); -} /* l3ni1_error_return */ - -/*******************************************************************/ -/* called when a facility message with a dummy callref is received */ -/* and a invoke is delivered. id specifies the invoke id. */ -/*******************************************************************/ -static void -l3ni1_dummy_invoke(struct PStack *st, int cr, int id, - int ident, u_char *p, u_char nlen) -{ isdn_ctrl ic; - struct IsdnCardState *cs; - - l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", - (cr == -1) ? "local" : "broadcast", id, ident, nlen); - if (cr >= -1) return; /* ignore local data */ - - cs = st->l1.hardware; - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = NI1_STAT_INVOKE_BRD; - ic.parm.ni1_io.hl_id = id; - ic.parm.ni1_io.ll_id = 0; - ic.parm.ni1_io.proc = ident; - ic.parm.ni1_io.timeout = 0; - ic.parm.ni1_io.datalen = nlen; - ic.parm.ni1_io.data = p; - - cs->iif.statcallb(&ic); -} /* l3ni1_dummy_invoke */ - -static void -l3ni1_parse_facility(struct PStack *st, struct l3_process *pc, - int cr, u_char *p) -{ - int qd_len = 0; - unsigned char nlen = 0, ilen, cp_tag; - int ident, id; - ulong err_ret; - - if (pc) - st = pc->st; /* valid Stack */ - else - if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ - - p++; - qd_len = *p++; - if (qd_len == 0) { - l3_debug(st, "qd_len == 0"); - return; - } - if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */ - l3_debug(st, "supplementary service != 0x11"); - return; - } - while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */ - p++; - qd_len--; - } - if (qd_len < 2) { - l3_debug(st, "qd_len < 2"); - return; - } - p++; - qd_len--; - if ((*p & 0xE0) != 0xA0) { /* class and form */ - l3_debug(st, "class and form != 0xA0"); - return; - } - - cp_tag = *p & 0x1F; /* remember tag value */ - - p++; - qd_len--; - if (qd_len < 1) - { l3_debug(st, "qd_len < 1"); - return; - } - if (*p & 0x80) - { /* length format indefinite or limited */ - nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ - if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || - (nlen > 1)) - { l3_debug(st, "length format error or not implemented"); - return; - } - if (nlen == 1) - { nlen = *p++; /* complete length */ - qd_len--; - } - else - { qd_len -= 2; /* trailing null bytes */ - if ((*(p + qd_len)) || (*(p + qd_len + 1))) - { l3_debug(st, "length format indefinite error"); - return; - } - nlen = qd_len; - } - } - else - { nlen = *p++; - qd_len--; - } - if (qd_len < nlen) - { l3_debug(st, "qd_len < nlen"); - return; - } - qd_len -= nlen; - - if (nlen < 2) - { l3_debug(st, "nlen < 2"); - return; - } - if (*p != 0x02) - { /* invoke identifier tag */ - l3_debug(st, "invoke identifier tag !=0x02"); - return; - } - p++; - nlen--; - if (*p & 0x80) - { /* length format */ - l3_debug(st, "invoke id length format 2"); - return; - } - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) - { l3_debug(st, "ilen > nlen || ilen == 0"); - return; - } - nlen -= ilen; - id = 0; - while (ilen > 0) - { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */ - ilen--; - } - - switch (cp_tag) { /* component tag */ - case 1: /* invoke */ - if (nlen < 2) { - l3_debug(st, "nlen < 2 22"); - return; - } - if (*p != 0x02) { /* operation value */ - l3_debug(st, "operation value !=0x02"); - return; - } - p++; - nlen--; - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) { - l3_debug(st, "ilen > nlen || ilen == 0 22"); - return; - } - nlen -= ilen; - ident = 0; - while (ilen > 0) { - ident = (ident << 8) | (*p++ & 0xFF); - ilen--; - } - - if (!pc) - { - l3ni1_dummy_invoke(st, cr, id, ident, p, nlen); - return; - } - l3_debug(st, "invoke break"); - break; - case 2: /* return result */ - /* if no process available handle separately */ - if (!pc) - { if (cr == -1) - l3ni1_dummy_return_result(st, id, p, nlen); - return; - } - if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) - { /* Diversion successful */ - free_invoke_id(st, pc->prot.ni1.invoke_id); - pc->prot.ni1.remote_result = 0; /* success */ - pc->prot.ni1.invoke_id = 0; - pc->redir_result = pc->prot.ni1.remote_result; - st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */ - else - l3_debug(st, "return error unknown identifier"); - break; - case 3: /* return error */ - err_ret = 0; - if (nlen < 2) - { l3_debug(st, "return error nlen < 2"); - return; - } - if (*p != 0x02) - { /* result tag */ - l3_debug(st, "invoke error tag !=0x02"); - return; - } - p++; - nlen--; - if (*p > 4) - { /* length format */ - l3_debug(st, "invoke return errlen > 4 "); - return; - } - ilen = *p++; - nlen--; - if (ilen > nlen || ilen == 0) - { l3_debug(st, "error return ilen > nlen || ilen == 0"); - return; - } - nlen -= ilen; - while (ilen > 0) - { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */ - ilen--; - } - /* if no process available handle separately */ - if (!pc) - { if (cr == -1) - l3ni1_dummy_error_return(st, id, err_ret); - return; - } - if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) - { /* Deflection error */ - free_invoke_id(st, pc->prot.ni1.invoke_id); - pc->prot.ni1.remote_result = err_ret; /* result */ - pc->prot.ni1.invoke_id = 0; - pc->redir_result = pc->prot.ni1.remote_result; - st->l3.l3l4(st, CC_REDIR | INDICATION, pc); - } /* Deflection error */ - else - l3_debug(st, "return result unknown identifier"); - break; - default: - l3_debug(st, "facility default break tag=0x%02x", cp_tag); - break; - } -} - -static void -l3ni1_message(struct l3_process *pc, u_char mt) -{ - struct sk_buff *skb; - u_char *p; - - if (!(skb = l3_alloc_skb(4))) - return; - p = skb_put(skb, 4); - MsgHead(p, pc->callref, mt); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_message_plus_chid(struct l3_process *pc, u_char mt) -/* sends an l3 messages plus channel id - added GE 05/09/00 */ -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - u_char chid; - - chid = (u_char)(pc->para.bchannel & 0x03) | 0x88; - MsgHead(p, pc->callref, mt); - *p++ = IE_CHANNEL_ID; - *p++ = 0x01; - *p++ = chid; - - if (!(skb = l3_alloc_skb(7))) - return; - skb_put_data(skb, tmp, 7); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - - MsgHead(p, pc->callref, mt); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - - MsgHead(p, pc->callref, MT_STATUS); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = pc->para.cause | 0x80; - - *p++ = IE_CALL_STATE; - *p++ = 0x1; - *p++ = pc->state & 0x3f; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) -{ - /* This routine is called if here was no SETUP made (checks in ni1up and in - * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code - * MT_STATUS_ENQUIRE in the NULL state is handled too - */ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - - switch (pc->para.cause) { - case 81: /* invalid callreference */ - case 88: /* incomp destination */ - case 96: /* mandory IE missing */ - case 100: /* invalid IE contents */ - case 101: /* incompatible Callstate */ - MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = pc->para.cause | 0x80; - break; - default: - printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n", - pc->para.cause); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - ni1_release_l3_process(pc); -} - -static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC, - IE_USER_USER, -1}; -static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; -static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, - IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, - IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; -static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; -static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, - IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; -static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, - IE_CALLED_PN, -1}; -static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | - IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; -static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, - IE_SIGNAL, IE_USER_USER, -1}; -/* a RELEASE_COMPLETE with errors don't require special actions - static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; -*/ -static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, - IE_DISPLAY, -1}; -static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY, - IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, IE_PROGRESS, - IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, - IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR, - IE_LLC, IE_HLC, IE_USER_USER, -1}; -static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, - IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; -static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | - IE_MANDATORY, IE_DISPLAY, -1}; -static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; -static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1}; -static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; -/* not used - * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, - * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; - * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; - * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND | - * IE_MANDATORY, -1}; - */ -static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1}; -static int comp_required[] = {1, 2, 3, 5, 6, 7, 9, 10, 11, 14, 15, -1}; -static int l3_valid_states[] = {0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 17, 19, 25, -1}; - -struct ie_len { - int ie; - int len; -}; - -static -struct ie_len max_ie_len[] = { - {IE_SEGMENT, 4}, - {IE_BEARER, 12}, - {IE_CAUSE, 32}, - {IE_CALL_ID, 10}, - {IE_CALL_STATE, 3}, - {IE_CHANNEL_ID, 34}, - {IE_FACILITY, 255}, - {IE_PROGRESS, 4}, - {IE_NET_FAC, 255}, - {IE_NOTIFY, 3}, - {IE_DISPLAY, 82}, - {IE_DATE, 8}, - {IE_KEYPAD, 34}, - {IE_SIGNAL, 3}, - {IE_INFORATE, 6}, - {IE_E2E_TDELAY, 11}, - {IE_TDELAY_SEL, 5}, - {IE_PACK_BINPARA, 3}, - {IE_PACK_WINSIZE, 4}, - {IE_PACK_SIZE, 4}, - {IE_CUG, 7}, - {IE_REV_CHARGE, 3}, - {IE_CALLING_PN, 24}, - {IE_CALLING_SUB, 23}, - {IE_CALLED_PN, 24}, - {IE_CALLED_SUB, 23}, - {IE_REDIR_NR, 255}, - {IE_TRANS_SEL, 255}, - {IE_RESTART_IND, 3}, - {IE_LLC, 18}, - {IE_HLC, 5}, - {IE_USER_USER, 131}, - {-1, 0}, -}; - -static int -getmax_ie_len(u_char ie) { - int i = 0; - while (max_ie_len[i].ie != -1) { - if (max_ie_len[i].ie == ie) - return (max_ie_len[i].len); - i++; - } - return (255); -} - -static int -ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { - int ret = 1; - - while (*checklist != -1) { - if ((*checklist & 0xff) == ie) { - if (ie & 0x80) - return (-ret); - else - return (ret); - } - ret++; - checklist++; - } - return (0); -} - -static int -check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) -{ - int *cl = checklist; - u_char mt; - u_char *p, ie; - int l, newpos, oldpos; - int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; - u_char codeset = 0; - u_char old_codeset = 0; - u_char codelock = 1; - - p = skb->data; - /* skip cr */ - p++; - l = (*p++) & 0xf; - p += l; - mt = *p++; - oldpos = 0; - while ((p - skb->data) < skb->len) { - if ((*p & 0xf0) == 0x90) { /* shift codeset */ - old_codeset = codeset; - codeset = *p & 7; - if (*p & 0x08) - codelock = 0; - else - codelock = 1; - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE shift%scodeset %d->%d", - codelock ? " locking " : " ", old_codeset, codeset); - p++; - continue; - } - if (!codeset) { /* only codeset 0 */ - if ((newpos = ie_in_set(pc, *p, cl))) { - if (newpos > 0) { - if (newpos < oldpos) - err_seq++; - else - oldpos = newpos; - } - } else { - if (ie_in_set(pc, *p, comp_required)) - err_compr++; - else - err_ureg++; - } - } - ie = *p++; - if (ie & 0x80) { - l = 1; - } else { - l = *p++; - p += l; - l += 2; - } - if (!codeset && (l > getmax_ie_len(ie))) - err_len++; - if (!codelock) { - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE shift back codeset %d->%d", - codeset, old_codeset); - codeset = old_codeset; - codelock = 1; - } - } - if (err_compr | err_ureg | err_len | err_seq) { - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", - mt, err_compr, err_ureg, err_len, err_seq); - if (err_compr) - return (ERR_IE_COMPREHENSION); - if (err_ureg) - return (ERR_IE_UNRECOGNIZED); - if (err_len) - return (ERR_IE_LENGTH); - if (err_seq) - return (ERR_IE_SEQUENCE); - } - return (0); -} - -/* verify if a message type exists and contain no IE error */ -static int -l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg) -{ - switch (mt) { - case MT_ALERTING: - case MT_CALL_PROCEEDING: - case MT_CONNECT: - case MT_CONNECT_ACKNOWLEDGE: - case MT_DISCONNECT: - case MT_INFORMATION: - case MT_FACILITY: - case MT_NOTIFY: - case MT_PROGRESS: - case MT_RELEASE: - case MT_RELEASE_COMPLETE: - case MT_SETUP: - case MT_SETUP_ACKNOWLEDGE: - case MT_RESUME_ACKNOWLEDGE: - case MT_RESUME_REJECT: - case MT_SUSPEND_ACKNOWLEDGE: - case MT_SUSPEND_REJECT: - case MT_USER_INFORMATION: - case MT_RESTART: - case MT_RESTART_ACKNOWLEDGE: - case MT_CONGESTION_CONTROL: - case MT_STATUS: - case MT_STATUS_ENQUIRY: - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt); - break; - case MT_RESUME: /* RESUME only in user->net */ - case MT_SUSPEND: /* SUSPEND only in user->net */ - default: - if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN)) - l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt); - pc->para.cause = 97; - l3ni1_status_send(pc, 0, NULL); - return (1); - } - return (0); -} - -static void -l3ni1_std_ie_err(struct l3_process *pc, int ret) { - - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "check_infoelements ret %d", ret); - switch (ret) { - case 0: - break; - case ERR_IE_COMPREHENSION: - pc->para.cause = 96; - l3ni1_status_send(pc, 0, NULL); - break; - case ERR_IE_UNRECOGNIZED: - pc->para.cause = 99; - l3ni1_status_send(pc, 0, NULL); - break; - case ERR_IE_LENGTH: - pc->para.cause = 100; - l3ni1_status_send(pc, 0, NULL); - break; - case ERR_IE_SEQUENCE: - default: - break; - } -} - -static int -l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { - u_char *p; - - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - p++; - if (*p != 1) { /* len for BRI = 1 */ - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong chid len %d", *p); - return (-2); - } - p++; - if (*p & 0x60) { /* only base rate interface */ - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong chid %x", *p); - return (-3); - } - return (*p & 0x3); - } else - return (-1); -} - -static int -l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) { - u_char l, i = 0; - u_char *p; - - p = skb->data; - pc->para.cause = 31; - pc->para.loc = 0; - if ((p = findie(p, skb->len, IE_CAUSE, 0))) { - p++; - l = *p++; - if (l > 30) - return (1); - if (l) { - pc->para.loc = *p++; - l--; - } else { - return (2); - } - if (l && !(pc->para.loc & 0x80)) { - l--; - p++; /* skip recommendation */ - } - if (l) { - pc->para.cause = *p++; - l--; - if (!(pc->para.cause & 0x80)) - return (3); - } else - return (4); - while (l && (i < 6)) { - pc->para.diag[i++] = *p++; - l--; - } - } else - return (-1); - return (0); -} - -static void -l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd) -{ - struct sk_buff *skb; - u_char tmp[16 + 40]; - u_char *p = tmp; - int l; - - MsgHead(p, pc->callref, cmd); - - if (pc->prot.ni1.uus1_data[0]) - { *p++ = IE_USER_USER; /* UUS info element */ - *p++ = strlen(pc->prot.ni1.uus1_data) + 1; - *p++ = 0x04; /* IA5 chars */ - strcpy(p, pc->prot.ni1.uus1_data); - p += strlen(pc->prot.ni1.uus1_data); - pc->prot.ni1.uus1_data[0] = '\0'; - } - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} /* l3ni1_msg_with_uus */ - -static void -l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg) -{ - StopAllL3Timer(pc); - newl3state(pc, 19); - if (!pc->prot.ni1.uus1_data[0]) - l3ni1_message(pc, MT_RELEASE); - else - l3ni1_msg_with_uus(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3ni1_get_cause(pc, skb)) > 0) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "RELCMPL get_cause ret(%d)", ret); - } else if (ret < 0) - pc->para.cause = NO_CAUSE; - StopAllL3Timer(pc); - newl3state(pc, 0); - pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); - ni1_release_l3_process(pc); -} - -#if EXT_BEARER_CAPS - -static u_char * -EncodeASyncParams(u_char *p, u_char si2) -{ // 7c 06 88 90 21 42 00 bb - - p[0] = 0; - p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19 - p[2] = 0x80; - if (si2 & 32) // 7 data bits - - p[2] += 16; - else // 8 data bits - - p[2] += 24; - - if (si2 & 16) // 2 stop bits - - p[2] += 96; - else // 1 stop bit - - p[2] += 32; - - if (si2 & 8) // even parity - - p[2] += 2; - else // no parity - - p[2] += 3; - - switch (si2 & 0x07) { - case 0: - p[0] = 66; // 1200 bit/s - - break; - case 1: - p[0] = 88; // 1200/75 bit/s - - break; - case 2: - p[0] = 87; // 75/1200 bit/s - - break; - case 3: - p[0] = 67; // 2400 bit/s - - break; - case 4: - p[0] = 69; // 4800 bit/s - - break; - case 5: - p[0] = 72; // 9600 bit/s - - break; - case 6: - p[0] = 73; // 14400 bit/s - - break; - case 7: - p[0] = 75; // 19200 bit/s - - break; - } - return p + 3; -} - -static u_char -EncodeSyncParams(u_char si2, u_char ai) -{ - - switch (si2) { - case 0: - return ai + 2; // 1200 bit/s - - case 1: - return ai + 24; // 1200/75 bit/s - - case 2: - return ai + 23; // 75/1200 bit/s - - case 3: - return ai + 3; // 2400 bit/s - - case 4: - return ai + 5; // 4800 bit/s - - case 5: - return ai + 8; // 9600 bit/s - - case 6: - return ai + 9; // 14400 bit/s - - case 7: - return ai + 11; // 19200 bit/s - - case 8: - return ai + 14; // 48000 bit/s - - case 9: - return ai + 15; // 56000 bit/s - - case 15: - return ai + 40; // negotiate bit/s - - default: - break; - } - return ai; -} - - -static u_char -DecodeASyncParams(u_char si2, u_char *p) -{ - u_char info; - - switch (p[5]) { - case 66: // 1200 bit/s - - break; // si2 don't change - - case 88: // 1200/75 bit/s - - si2 += 1; - break; - case 87: // 75/1200 bit/s - - si2 += 2; - break; - case 67: // 2400 bit/s - - si2 += 3; - break; - case 69: // 4800 bit/s - - si2 += 4; - break; - case 72: // 9600 bit/s - - si2 += 5; - break; - case 73: // 14400 bit/s - - si2 += 6; - break; - case 75: // 19200 bit/s - - si2 += 7; - break; - } - - info = p[7] & 0x7f; - if ((info & 16) && (!(info & 8))) // 7 data bits - - si2 += 32; // else 8 data bits - - if ((info & 96) == 96) // 2 stop bits - - si2 += 16; // else 1 stop bit - - if ((info & 2) && (!(info & 1))) // even parity - - si2 += 8; // else no parity - - return si2; -} - - -static u_char -DecodeSyncParams(u_char si2, u_char info) -{ - info &= 0x7f; - switch (info) { - case 40: // bit/s negotiation failed ai := 165 not 175! - - return si2 + 15; - case 15: // 56000 bit/s failed, ai := 0 not 169 ! - - return si2 + 9; - case 14: // 48000 bit/s - - return si2 + 8; - case 11: // 19200 bit/s - - return si2 + 7; - case 9: // 14400 bit/s - - return si2 + 6; - case 8: // 9600 bit/s - - return si2 + 5; - case 5: // 4800 bit/s - - return si2 + 4; - case 3: // 2400 bit/s - - return si2 + 3; - case 23: // 75/1200 bit/s - - return si2 + 2; - case 24: // 1200/75 bit/s - - return si2 + 1; - default: // 1200 bit/s - - return si2; - } -} - -static u_char -DecodeSI2(struct sk_buff *skb) -{ - u_char *p; //, *pend=skb->data + skb->len; - - if ((p = findie(skb->data, skb->len, 0x7c, 0))) { - switch (p[4] & 0x0f) { - case 0x01: - if (p[1] == 0x04) // sync. Bitratenadaption - - return DecodeSyncParams(160, p[5]); // V.110/X.30 - - else if (p[1] == 0x06) // async. Bitratenadaption - - return DecodeASyncParams(192, p); // V.110/X.30 - - break; - case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption - if (p[1] > 3) - return DecodeSyncParams(176, p[5]); // V.120 - break; - } - } - return 0; -} - -#endif - - -static void -l3ni1_setup_req(struct l3_process *pc, u_char pr, - void *arg) -{ - struct sk_buff *skb; - u_char tmp[128]; - u_char *p = tmp; - - u_char *teln; - u_char *sub; - u_char *sp; - int l; - - MsgHead(p, pc->callref, MT_SETUP); - - teln = pc->para.setup.phone; - - *p++ = 0xa1; /* complete indicator */ - /* - * Set Bearer Capability, Map info from 1TR6-convention to NI1 - */ - switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = IE_BEARER; - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* 3.1khz Audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa2; /* u-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = IE_BEARER; - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - break; - } - - sub = NULL; - sp = teln; - while (*sp) { - if ('.' == *sp) { - sub = sp; - *sp = 0; - } else - sp++; - } - - *p++ = IE_KEYPAD; - *p++ = strlen(teln); - while (*teln) - *p++ = (*teln++) & 0x7F; - - if (sub) - *sub++ = '.'; - -#if EXT_BEARER_CAPS - if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30 - - *p++ = IE_LLC; - *p++ = 0x04; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x21; - *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); - } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120 - - *p++ = IE_LLC; - *p++ = 0x05; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x28; - *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); - *p++ = 0x82; - } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30 - - *p++ = IE_LLC; - *p++ = 0x06; - *p++ = 0x88; - *p++ = 0x90; - *p++ = 0x21; - p = EncodeASyncParams(p, pc->para.setup.si2 - 192); - } else { - switch (pc->para.setup.si1) { - case 1: /* Telephony */ - *p++ = IE_LLC; - *p++ = 0x3; /* Length */ - *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - *p++ = 0xa2; /* u-Law Audio */ - break; - case 5: /* Datatransmission 64k, BTX */ - case 7: /* Datatransmission 64k */ - default: - *p++ = IE_LLC; - *p++ = 0x2; /* Length */ - *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */ - *p++ = 0x90; /* Circuit-Mode 64kbps */ - break; - } - } -#endif - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - { - return; - } - skb_put_data(skb, tmp, l); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T303, CC_T303); - newl3state(pc, 1); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer with wrong chid %x", id); - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else if (1 == pc->state) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - newl3state(pc, 3); - L3AddTimer(&pc->timer, T310, CC_T310); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); -} - -static void -l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer with wrong chid %x", id); - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - newl3state(pc, 2); - L3AddTimer(&pc->timer, T304, CC_T304); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); -} - -static void -l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - int ret; - u_char cause = 0; - - StopAllL3Timer(pc); - if ((ret = l3ni1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "DISC get_cause ret(%d)", ret); - if (ret < 0) - cause = 96; - else if (ret > 0) - cause = 100; - } - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) - l3ni1_parse_facility(pc->st, pc, pc->callref, p); - ret = check_infoelements(pc, skb, ie_DISCONNECT); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret)) - cause = 99; - ret = pc->state; - newl3state(pc, 12); - if (cause) - newl3state(pc, 19); - if (11 != ret) - pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); - else if (!cause) - l3ni1_release_req(pc, pr, NULL); - if (cause) { - l3ni1_message_cause(pc, MT_RELEASE, cause); - L3AddTimer(&pc->timer, T308, CC_T308_1); - } -} - -static void -l3ni1_connect(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_CONNECT); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); /* T310 */ - newl3state(pc, 10); - pc->para.chargeinfo = 0; - /* here should inserted COLP handling KKe */ - if (ret) - l3ni1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); -} - -static void -l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_ALERTING); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); /* T304 */ - newl3state(pc, 4); - if (ret) - l3ni1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); -} - -static void -l3ni1_setup(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - int bcfound = 0; - char tmp[80]; - struct sk_buff *skb = arg; - int id; - int err = 0; - - /* - * Bearer Capabilities - */ - p = skb->data; - /* only the first occurrence 'll be detected ! */ - if ((p = findie(p, skb->len, 0x04, 0))) { - if ((p[1] < 2) || (p[1] > 11)) - err = 1; - else { - pc->para.setup.si2 = 0; - switch (p[2] & 0x7f) { - case 0x00: /* Speech */ - case 0x10: /* 3.1 Khz audio */ - pc->para.setup.si1 = 1; - break; - case 0x08: /* Unrestricted digital information */ - pc->para.setup.si1 = 7; -/* JIM, 05.11.97 I wanna set service indicator 2 */ -#if EXT_BEARER_CAPS - pc->para.setup.si2 = DecodeSI2(skb); -#endif - break; - case 0x09: /* Restricted digital information */ - pc->para.setup.si1 = 2; - break; - case 0x11: - /* Unrestr. digital information with - * tones/announcements ( or 7 kHz audio - */ - pc->para.setup.si1 = 3; - break; - case 0x18: /* Video */ - pc->para.setup.si1 = 4; - break; - default: - err = 2; - break; - } - switch (p[3] & 0x7f) { - case 0x40: /* packed mode */ - pc->para.setup.si1 = 8; - break; - case 0x10: /* 64 kbit */ - case 0x11: /* 2*64 kbit */ - case 0x13: /* 384 kbit */ - case 0x15: /* 1536 kbit */ - case 0x17: /* 1920 kbit */ - pc->para.moderate = p[3] & 0x7f; - break; - default: - err = 3; - break; - } - } - if (pc->debug & L3_DEB_SI) - l3_debug(pc->st, "SI=%d, AI=%d", - pc->para.setup.si1, pc->para.setup.si2); - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)", - p[1], p[2], p[3]); - pc->para.cause = 100; - l3ni1_msg_without_setup(pc, pr, NULL); - return; - } - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bearer capabilities"); - /* ETS 300-104 1.3.3 */ - pc->para.cause = 96; - l3ni1_msg_without_setup(pc, pr, NULL); - return; - } - /* - * Channel Identification - */ - if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { - if ((pc->para.bchannel = id)) { - if ((3 == id) && (0x10 == pc->para.moderate)) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong chid %x", - id); - pc->para.cause = 100; - l3ni1_msg_without_setup(pc, pr, NULL); - return; - } - bcfound++; - } else - { if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup without bchannel, call waiting"); - bcfound++; - } - } else { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "setup with wrong chid ret %d", id); - if (id == -1) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3ni1_msg_without_setup(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_SETUP); - if (ERR_IE_COMPREHENSION == err) { - pc->para.cause = 96; - l3ni1_msg_without_setup(pc, pr, NULL); - return; - } - p = skb->data; - if ((p = findie(p, skb->len, 0x70, 0))) - iecpy(pc->para.setup.eazmsn, p, 1); - else - pc->para.setup.eazmsn[0] = 0; - - p = skb->data; - if ((p = findie(p, skb->len, 0x71, 0))) { - /* Called party subaddress */ - if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { - tmp[0] = '.'; - iecpy(&tmp[1], p, 2); - strcat(pc->para.setup.eazmsn, tmp); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong called subaddress"); - } - p = skb->data; - if ((p = findie(p, skb->len, 0x6c, 0))) { - pc->para.setup.plan = p[2]; - if (p[2] & 0x80) { - iecpy(pc->para.setup.phone, p, 1); - pc->para.setup.screen = 0; - } else { - iecpy(pc->para.setup.phone, p, 2); - pc->para.setup.screen = p[3]; - } - } else { - pc->para.setup.phone[0] = 0; - pc->para.setup.plan = 0; - pc->para.setup.screen = 0; - } - p = skb->data; - if ((p = findie(p, skb->len, 0x6d, 0))) { - /* Calling party subaddress */ - if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { - tmp[0] = '.'; - iecpy(&tmp[1], p, 2); - strcat(pc->para.setup.phone, tmp); - } else if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "wrong calling subaddress"); - } - newl3state(pc, 6); - if (err) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, err); - pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); -} - -static void -l3ni1_reset(struct l3_process *pc, u_char pr, void *arg) -{ - ni1_release_l3_process(pc); -} - -static void -l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16 + 40]; - u_char *p = tmp; - int l; - u_char cause = 16; - - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - StopAllL3Timer(pc); - - MsgHead(p, pc->callref, MT_DISCONNECT); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - if (pc->prot.ni1.uus1_data[0]) - { *p++ = IE_USER_USER; /* UUS info element */ - *p++ = strlen(pc->prot.ni1.uus1_data) + 1; - *p++ = 0x04; /* IA5 chars */ - strcpy(p, pc->prot.ni1.uus1_data); - p += strlen(pc->prot.ni1.uus1_data); - pc->prot.ni1.uus1_data[0] = '\0'; - } - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 11); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T305, CC_T305); -} - -static void -l3ni1_setup_rsp(struct l3_process *pc, u_char pr, - void *arg) -{ - if (!pc->para.bchannel) - { if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "D-chan connect for waiting call"); - l3ni1_disconnect_req(pc, pr, arg); - return; - } - newl3state(pc, 8); - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "D-chan connect for waiting call"); - l3ni1_message_plus_chid(pc, MT_CONNECT); /* GE 05/09/00 */ - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T313, CC_T313); -} - -static void -l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - newl3state(pc, 10); - L3DelTimer(&pc->timer); - if (ret) - l3ni1_std_ie_err(pc, ret); - pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); -} - -static void -l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[16]; - u_char *p = tmp; - int l; - u_char cause = 21; - - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - ni1_release_l3_process(pc); -} - -static void -l3ni1_release(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - u_char *p; - int ret, cause = 0; - - StopAllL3Timer(pc); - if ((ret = l3ni1_get_cause(pc, skb)) > 0) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "REL get_cause ret(%d)", ret); - } else if (ret < 0) - pc->para.cause = NO_CAUSE; - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { - l3ni1_parse_facility(pc->st, pc, pc->callref, p); - } - if ((ret < 0) && (pc->state != 11)) - cause = 96; - else if (ret > 0) - cause = 100; - ret = check_infoelements(pc, skb, ie_RELEASE); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause)) - cause = 99; - if (cause) - l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause); - else - l3ni1_message(pc, MT_RELEASE_COMPLETE); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - ni1_release_l3_process(pc); -} - -static void -l3ni1_alert_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 7); - if (!pc->prot.ni1.uus1_data[0]) - l3ni1_message(pc, MT_ALERTING); - else - l3ni1_msg_with_uus(pc, MT_ALERTING); -} - -static void -l3ni1_proceed_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 9); - l3ni1_message(pc, MT_CALL_PROCEEDING); - pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc); -} - -static void -l3ni1_setup_ack_req(struct l3_process *pc, u_char pr, - void *arg) -{ - newl3state(pc, 25); - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T302, CC_T302); - l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE); -} - -/********************************************/ -/* deliver a incoming display message to HL */ -/********************************************/ -static void -l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp) -{ u_char len; - isdn_ctrl ic; - struct IsdnCardState *cs; - char *p; - - if (*infp++ != IE_DISPLAY) return; - if ((len = *infp++) > 80) return; /* total length <= 82 */ - if (!pc->chan) return; - - p = ic.parm.display; - while (len--) - *p++ = *infp++; - *p = '\0'; - ic.command = ISDN_STAT_DISPLAY; - cs = pc->st->l1.hardware; - ic.driver = cs->myid; - ic.arg = pc->chan->chan; - cs->iif.statcallb(&ic); -} /* l3ni1_deliver_display */ - - -static void -l3ni1_progress(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int err = 0; - u_char *p; - - if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { - if (p[1] != 2) { - err = 1; - pc->para.cause = 100; - } else if (!(p[2] & 0x70)) { - switch (p[2]) { - case 0x80: - case 0x81: - case 0x82: - case 0x84: - case 0x85: - case 0x87: - case 0x8a: - switch (p[3]) { - case 0x81: - case 0x82: - case 0x83: - case 0x84: - case 0x88: - break; - default: - err = 2; - pc->para.cause = 100; - break; - } - break; - default: - err = 3; - pc->para.cause = 100; - break; - } - } - } else { - pc->para.cause = 96; - err = 4; - } - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "progress error %d", err); - l3ni1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_PROGRESS); - if (err) - l3ni1_std_ie_err(pc, err); - if (ERR_IE_COMPREHENSION != err) - pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); -} - -static void -l3ni1_notify(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int err = 0; - u_char *p; - - if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { - if (p[1] != 1) { - err = 1; - pc->para.cause = 100; - } else { - switch (p[2]) { - case 0x80: - case 0x81: - case 0x82: - break; - default: - pc->para.cause = 100; - err = 2; - break; - } - } - } else { - pc->para.cause = 96; - err = 3; - } - if (err) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "notify error %d", err); - l3ni1_status_send(pc, pr, NULL); - return; - } - /* Now we are on none mandatory IEs */ - err = check_infoelements(pc, skb, ie_NOTIFY); - if (err) - l3ni1_std_ie_err(pc, err); - if (ERR_IE_COMPREHENSION != err) - pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); -} - -static void -l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg) -{ - int ret; - struct sk_buff *skb = arg; - - ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); - l3ni1_std_ie_err(pc, ret); - pc->para.cause = 30; /* response to STATUS_ENQUIRY */ - l3ni1_status_send(pc, pr, NULL); -} - -static void -l3ni1_information(struct l3_process *pc, u_char pr, void *arg) -{ - int ret; - struct sk_buff *skb = arg; - u_char *p; - char tmp[32]; - - ret = check_infoelements(pc, skb, ie_INFORMATION); - if (ret) - l3ni1_std_ie_err(pc, ret); - if (pc->state == 25) { /* overlap receiving */ - L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, 0x70, 0))) { - iecpy(tmp, p, 1); - strcat(pc->para.setup.eazmsn, tmp); - pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); - } - L3AddTimer(&pc->timer, T302, CC_T302); - } -} - -/******************************/ -/* handle deflection requests */ -/******************************/ -static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[128]; - u_char *p = tmp; - u_char *subp; - u_char len_phone = 0; - u_char len_sub = 0; - int l; - - - strcpy(pc->prot.ni1.uus1_data, pc->chan->setup.eazmsn); /* copy uus element if available */ - if (!pc->chan->setup.phone[0]) - { pc->para.cause = -1; - l3ni1_disconnect_req(pc, pr, arg); /* disconnect immediately */ - return; - } /* only uus */ - - if (pc->prot.ni1.invoke_id) - free_invoke_id(pc->st, pc->prot.ni1.invoke_id); - - if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st))) - return; - - MsgHead(p, pc->callref, MT_FACILITY); - - for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ - if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */ - - *p++ = 0x1c; /* Facility info element */ - *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ - *p++ = 0x91; /* remote operations protocol */ - *p++ = 0xa1; /* invoke component */ - - *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */ - *p++ = 0x02; /* invoke id tag, integer */ - *p++ = 0x01; /* length */ - *p++ = pc->prot.ni1.invoke_id; /* invoke id */ - *p++ = 0x02; /* operation value tag, integer */ - *p++ = 0x01; /* length */ - *p++ = 0x0D; /* Call Deflect */ - - *p++ = 0x30; /* sequence phone number */ - *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */ - - *p++ = 0x30; /* Deflected to UserNumber */ - *p++ = len_phone + 2 + len_sub; /* length */ - *p++ = 0x80; /* NumberDigits */ - *p++ = len_phone; /* length */ - for (l = 0; l < len_phone; l++) - *p++ = pc->chan->setup.phone[l]; - - if (len_sub) - { *p++ = 0x04; /* called party subaddress */ - *p++ = len_sub - 2; - while (*subp) *p++ = *subp++; - } - - *p++ = 0x01; /* screening identifier */ - *p++ = 0x01; - *p++ = pc->chan->setup.screen; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) return; - skb_put_data(skb, tmp, l); - - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} /* l3ni1_redir_req */ - -/********************************************/ -/* handle deflection request in early state */ -/********************************************/ -static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) -{ - l3ni1_proceed_req(pc, pr, arg); - l3ni1_redir_req(pc, pr, arg); -} /* l3ni1_redir_req_early */ - -/***********************************************/ -/* handle special commands for this protocol. */ -/* Examples are call independent services like */ -/* remote operations with dummy callref. */ -/***********************************************/ -static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic) -{ u_char id; - u_char temp[265]; - u_char *p = temp; - int i, l, proc_len; - struct sk_buff *skb; - struct l3_process *pc = NULL; - - switch (ic->arg) - { case NI1_CMD_INVOKE: - if (ic->parm.ni1_io.datalen < 0) return (-2); /* invalid parameter */ - - for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++) - i = i >> 8; /* add one byte */ - l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */ - if (l > 255) - return (-2); /* too long */ - - if (!(id = new_invoke_id(st))) - return (0); /* first get a invoke id -> return if no available */ - - i = -1; - MsgHead(p, i, MT_FACILITY); /* build message head */ - *p++ = 0x1C; /* Facility IE */ - *p++ = l; /* length of ie */ - *p++ = 0x91; /* remote operations */ - *p++ = 0xA1; /* invoke */ - *p++ = l - 3; /* length of invoke */ - *p++ = 0x02; /* invoke id tag */ - *p++ = 0x01; /* length is 1 */ - *p++ = id; /* invoke id */ - *p++ = 0x02; /* operation */ - *p++ = proc_len; /* length of operation */ - - for (i = proc_len; i; i--) - *p++ = (ic->parm.ni1_io.proc >> (i - 1)) & 0xFF; - memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */ - l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */ - - if (ic->parm.ni1_io.timeout > 0) { - pc = ni1_new_l3_process(st, -1); - if (!pc) { - free_invoke_id(st, id); - return (-2); - } - /* remember id */ - pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id; - /* and procedure */ - pc->prot.ni1.proc = ic->parm.ni1_io.proc; - } - - if (!(skb = l3_alloc_skb(l))) - { free_invoke_id(st, id); - if (pc) ni1_release_l3_process(pc); - return (-2); - } - skb_put_data(skb, temp, l); - - if (pc) - { pc->prot.ni1.invoke_id = id; /* remember id */ - L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST); - } - - l3_msg(st, DL_DATA | REQUEST, skb); - ic->parm.ni1_io.hl_id = id; /* return id */ - return (0); - - case NI1_CMD_INVOKE_ABORT: - if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id))) - { L3DelTimer(&pc->timer); /* remove timer */ - ni1_release_l3_process(pc); - return (0); - } - else - { l3_debug(st, "l3ni1_cmd_global abort unknown id"); - return (-2); - } - break; - - default: - l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg); - return (-1); - } /* switch ic-> arg */ - return (-1); -} /* l3ni1_cmd_global */ - -static void -l3ni1_io_timer(struct l3_process *pc) -{ isdn_ctrl ic; - struct IsdnCardState *cs = pc->st->l1.hardware; - - L3DelTimer(&pc->timer); /* remove timer */ - - ic.driver = cs->myid; - ic.command = ISDN_STAT_PROT; - ic.arg = NI1_STAT_INVOKE_ERR; - ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; - ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; - ic.parm.ni1_io.proc = pc->prot.ni1.proc; - ic.parm.ni1_io.timeout = -1; - ic.parm.ni1_io.datalen = 0; - ic.parm.ni1_io.data = NULL; - free_invoke_id(pc->st, pc->prot.ni1.invoke_id); - pc->prot.ni1.invoke_id = 0; /* reset id */ - - cs->iif.statcallb(&ic); - - ni1_release_l3_process(pc); -} /* l3ni1_io_timer */ - -static void -l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - int callState = 0; - p = skb->data; - - if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { - p++; - if (1 == *p++) - callState = *p; - } - if (callState == 0) { - /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 - * set down layer 3 without sending any message - */ - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - ni1_release_l3_process(pc); - } else { - pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); - } -} - -static void -l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg) -{ -} - -static void -l3ni1_t302(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 28; /* invalid number */ - l3ni1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3ni1_t303(struct l3_process *pc, u_char pr, void *arg) -{ - if (pc->N303 > 0) { - pc->N303--; - L3DelTimer(&pc->timer); - l3ni1_setup_req(pc, pr, arg); - } else { - L3DelTimer(&pc->timer); - l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102); - pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); - ni1_release_l3_process(pc); - } -} - -static void -l3ni1_t304(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3ni1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); - -} - -static void -l3ni1_t305(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - struct sk_buff *skb; - u_char cause = 16; - - L3DelTimer(&pc->timer); - if (pc->para.cause != NO_CAUSE) - cause = pc->para.cause; - - MsgHead(p, pc->callref, MT_RELEASE); - - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = cause | 0x80; - - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 19); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3ni1_t310(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3ni1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3ni1_t313(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.loc = 0; - pc->para.cause = 102; - l3ni1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); -} - -static void -l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 19); - L3DelTimer(&pc->timer); - l3ni1_message(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_2); -} - -static void -l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); - ni1_release_l3_process(pc); -} - -static void -l3ni1_t318(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 102; /* Timer expiry */ - pc->para.loc = 0; /* local */ - pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); - newl3state(pc, 19); - l3ni1_message(pc, MT_RELEASE); - L3AddTimer(&pc->timer, T308, CC_T308_1); -} - -static void -l3ni1_t319(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->para.cause = 102; /* Timer expiry */ - pc->para.loc = 0; /* local */ - pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); - newl3state(pc, 10); -} - -static void -l3ni1_restart(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - ni1_release_l3_process(pc); -} - -static void -l3ni1_status(struct l3_process *pc, u_char pr, void *arg) -{ - u_char *p; - struct sk_buff *skb = arg; - int ret; - u_char cause = 0, callState = 0; - - if ((ret = l3ni1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "STATUS get_cause ret(%d)", ret); - if (ret < 0) - cause = 96; - else if (ret > 0) - cause = 100; - } - if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) { - p++; - if (1 == *p++) { - callState = *p; - if (!ie_in_set(pc, *p, l3_valid_states)) - cause = 100; - } else - cause = 100; - } else - cause = 96; - if (!cause) { /* no error before */ - ret = check_infoelements(pc, skb, ie_STATUS); - if (ERR_IE_COMPREHENSION == ret) - cause = 96; - else if (ERR_IE_UNRECOGNIZED == ret) - cause = 99; - } - if (cause) { - u_char tmp; - - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "STATUS error(%d/%d)", ret, cause); - tmp = pc->para.cause; - pc->para.cause = cause; - l3ni1_status_send(pc, 0, NULL); - if (cause == 99) - pc->para.cause = tmp; - else - return; - } - cause = pc->para.cause; - if (((cause & 0x7f) == 111) && (callState == 0)) { - /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... - * if received MT_STATUS with cause == 111 and call - * state == 0, then we must set down layer 3 - */ - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - newl3state(pc, 0); - ni1_release_l3_process(pc); - } -} - -static void -l3ni1_facility(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - ret = check_infoelements(pc, skb, ie_FACILITY); - l3ni1_std_ie_err(pc, ret); - { - u_char *p; - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) - l3ni1_parse_facility(pc->st, pc, pc->callref, p); - } -} - -static void -l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[32]; - u_char *p = tmp; - u_char i, l; - u_char *msg = pc->chan->setup.phone; - - MsgHead(p, pc->callref, MT_SUSPEND); - l = *msg++; - if (l && (l <= 10)) { /* Max length 10 octets */ - *p++ = IE_CALL_ID; - *p++ = l; - for (i = 0; i < l; i++) - *p++ = *msg++; - } else if (l) { - l3_debug(pc->st, "SUS wrong CALL_ID len %d", l); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - newl3state(pc, 15); - L3AddTimer(&pc->timer, T319, CC_T319); -} - -static void -l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - L3DelTimer(&pc->timer); - newl3state(pc, 0); - pc->para.cause = NO_CAUSE; - pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); - /* We don't handle suspend_ack for IE errors now */ - if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "SUSPACK check ie(%d)", ret); - ni1_release_l3_process(pc); -} - -static void -l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3ni1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)", ret); - if (ret < 0) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); - newl3state(pc, 10); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, ret); -} - -static void -l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb; - u_char tmp[32]; - u_char *p = tmp; - u_char i, l; - u_char *msg = pc->para.setup.phone; - - MsgHead(p, pc->callref, MT_RESUME); - - l = *msg++; - if (l && (l <= 10)) { /* Max length 10 octets */ - *p++ = IE_CALL_ID; - *p++ = l; - for (i = 0; i < l; i++) - *p++ = *msg++; - } else if (l) { - l3_debug(pc->st, "RES wrong CALL_ID len %d", l); - return; - } - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(pc->st, DL_DATA | REQUEST, skb); - newl3state(pc, 17); - L3AddTimer(&pc->timer, T318, CC_T318); -} - -static void -l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int id, ret; - - if ((id = l3ni1_get_channel_id(pc, skb)) > 0) { - if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "resume ack with wrong chid %x", id); - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - pc->para.bchannel = id; - } else if (1 == pc->state) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "resume ack without chid (ret %d)", id); - pc->para.cause = 96; - l3ni1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); - newl3state(pc, 10); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, ret); -} - -static void -l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - int ret; - - if ((ret = l3ni1_get_cause(pc, skb))) { - if (pc->debug & L3_DEB_WARN) - l3_debug(pc->st, "RES_REJ get_cause ret(%d)", ret); - if (ret < 0) - pc->para.cause = 96; - else - pc->para.cause = 100; - l3ni1_status_send(pc, pr, NULL); - return; - } - ret = check_infoelements(pc, skb, ie_RESUME_REJECT); - if (ERR_IE_COMPREHENSION == ret) { - l3ni1_std_ie_err(pc, ret); - return; - } - L3DelTimer(&pc->timer); - pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); - newl3state(pc, 0); - if (ret) /* STATUS for none mandatory IE errors after actions are taken */ - l3ni1_std_ie_err(pc, ret); - ni1_release_l3_process(pc); -} - -static void -l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg) -{ - u_char tmp[32]; - u_char *p; - u_char ri, ch = 0, chan = 0; - int l; - struct sk_buff *skb = arg; - struct l3_process *up; - - newl3state(pc, 2); - L3DelTimer(&pc->timer); - p = skb->data; - if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { - ri = p[2]; - l3_debug(pc->st, "Restart %x", ri); - } else { - l3_debug(pc->st, "Restart without restart IE"); - ri = 0x86; - } - p = skb->data; - if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { - chan = p[2] & 3; - ch = p[2]; - if (pc->st->l3.debug) - l3_debug(pc->st, "Restart for channel %d", chan); - } - newl3state(pc, 2); - up = pc->st->l3.proc; - while (up) { - if ((ri & 7) == 7) - up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); - else if (up->para.bchannel == chan) - up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); - - up = up->next; - } - p = tmp; - MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE); - if (chan) { - *p++ = IE_CHANNEL_ID; - *p++ = 1; - *p++ = ch | 0x80; - } - *p++ = 0x79; /* RESTART Ind */ - *p++ = 1; - *p++ = ri; - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - newl3state(pc, 0); - l3_msg(pc->st, DL_DATA | REQUEST, skb); -} - -static void -l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg) -{ - pc->para.cause = 0x29; /* Temporary failure */ - pc->para.loc = 0; - l3ni1_disconnect_req(pc, pr, NULL); - pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); -} - -static void -l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg) -{ - newl3state(pc, 0); - pc->para.cause = 0x1b; /* Destination out of order */ - pc->para.loc = 0; - pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); - release_l3_process(pc); -} - -static void -l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, T309, CC_T309); - l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL); -} - -static void -l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) -{ - L3DelTimer(&pc->timer); - - pc->para.cause = 0x1F; /* normal, unspecified */ - l3ni1_status_send(pc, 0, NULL); -} - -static void l3ni1_SendSpid(struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState) -{ - u_char *p; - char *pSPID; - struct Channel *pChan = pc->st->lli.userdata; - int l; - - if (skb) - dev_kfree_skb(skb); - - if (!(pSPID = strchr(pChan->setup.eazmsn, ':'))) - { - printk(KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn); - newl3state(pc, 0); - pc->st->l3.l3l2(pc->st, DL_RELEASE | REQUEST, NULL); - return; - } - - l = strlen(++pSPID); - if (!(skb = l3_alloc_skb(5 + l))) - { - printk(KERN_ERR "HiSax can't get memory to send SPID\n"); - return; - } - - p = skb_put(skb, 5); - *p++ = PROTO_DIS_EURO; - *p++ = 0; - *p++ = MT_INFORMATION; - *p++ = IE_SPID; - *p++ = l; - - skb_put_data(skb, pSPID, l); - - newl3state(pc, iNewState); - - L3DelTimer(&pc->timer); - L3AddTimer(&pc->timer, TSPID, CC_TSPID); - - pc->st->l3.l3l2(pc->st, DL_DATA | REQUEST, skb); -} - -static void l3ni1_spid_send(struct l3_process *pc, u_char pr, void *arg) -{ - l3ni1_SendSpid(pc, pr, arg, 20); -} - -static void l3ni1_spid_epid(struct l3_process *pc, u_char pr, void *arg) -{ - struct sk_buff *skb = arg; - - if (skb->data[1] == 0) - if (skb->data[3] == IE_ENDPOINT_ID) - { - L3DelTimer(&pc->timer); - newl3state(pc, 0); - l3_msg(pc->st, DL_ESTABLISH | CONFIRM, NULL); - } - dev_kfree_skb(skb); -} - -static void l3ni1_spid_tout(struct l3_process *pc, u_char pr, void *arg) -{ - if (pc->state < 22) - l3ni1_SendSpid(pc, pr, arg, pc->state + 1); - else - { - L3DelTimer(&pc->timer); - dev_kfree_skb(arg); - - printk(KERN_ERR "SPID not accepted\n"); - newl3state(pc, 0); - pc->st->l3.l3l2(pc->st, DL_RELEASE | REQUEST, NULL); - } -} - -/* *INDENT-OFF* */ -static struct stateentry downstatelist[] = -{ - {SBIT(0), - CC_SETUP | REQUEST, l3ni1_setup_req}, - {SBIT(0), - CC_RESUME | REQUEST, l3ni1_resume_req}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), - CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, - {SBIT(12), - CC_RELEASE | REQUEST, l3ni1_release_req}, - {ALL_STATES, - CC_RESTART | REQUEST, l3ni1_restart}, - {SBIT(6) | SBIT(25), - CC_IGNORE | REQUEST, l3ni1_reset}, - {SBIT(6) | SBIT(25), - CC_REJECT | REQUEST, l3ni1_reject_req}, - {SBIT(6) | SBIT(25), - CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req}, - {SBIT(6), - CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req}, - {SBIT(25), - CC_MORE_INFO | REQUEST, l3ni1_dummy}, - {SBIT(6) | SBIT(9) | SBIT(25), - CC_ALERTING | REQUEST, l3ni1_alert_req}, - {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), - CC_SETUP | RESPONSE, l3ni1_setup_rsp}, - {SBIT(10), - CC_SUSPEND | REQUEST, l3ni1_suspend_req}, - {SBIT(7) | SBIT(9) | SBIT(25), - CC_REDIR | REQUEST, l3ni1_redir_req}, - {SBIT(6), - CC_REDIR | REQUEST, l3ni1_redir_req_early}, - {SBIT(9) | SBIT(25), - CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, - {SBIT(25), - CC_T302, l3ni1_t302}, - {SBIT(1), - CC_T303, l3ni1_t303}, - {SBIT(2), - CC_T304, l3ni1_t304}, - {SBIT(3), - CC_T310, l3ni1_t310}, - {SBIT(8), - CC_T313, l3ni1_t313}, - {SBIT(11), - CC_T305, l3ni1_t305}, - {SBIT(15), - CC_T319, l3ni1_t319}, - {SBIT(17), - CC_T318, l3ni1_t318}, - {SBIT(19), - CC_T308_1, l3ni1_t308_1}, - {SBIT(19), - CC_T308_2, l3ni1_t308_2}, - {SBIT(10), - CC_T309, l3ni1_dl_release}, - { SBIT(20) | SBIT(21) | SBIT(22), - CC_TSPID, l3ni1_spid_tout }, -}; - -static struct stateentry datastatelist[] = -{ - {ALL_STATES, - MT_STATUS_ENQUIRY, l3ni1_status_enq}, - {ALL_STATES, - MT_FACILITY, l3ni1_facility}, - {SBIT(19), - MT_STATUS, l3ni1_release_ind}, - {ALL_STATES, - MT_STATUS, l3ni1_status}, - {SBIT(0), - MT_SETUP, l3ni1_setup}, - {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | - SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_SETUP, l3ni1_dummy}, - {SBIT(1) | SBIT(2), - MT_CALL_PROCEEDING, l3ni1_call_proc}, - {SBIT(1), - MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack}, - {SBIT(2) | SBIT(3), - MT_ALERTING, l3ni1_alerting}, - {SBIT(2) | SBIT(3), - MT_PROGRESS, l3ni1_progress}, - {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | - SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_INFORMATION, l3ni1_information}, - {SBIT(10) | SBIT(11) | SBIT(15), - MT_NOTIFY, l3ni1_notify}, - {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | - SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), - MT_RELEASE_COMPLETE, l3ni1_release_cmpl}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25), - MT_RELEASE, l3ni1_release}, - {SBIT(19), MT_RELEASE, l3ni1_release_ind}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), - MT_DISCONNECT, l3ni1_disconnect}, - {SBIT(19), - MT_DISCONNECT, l3ni1_dummy}, - {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), - MT_CONNECT, l3ni1_connect}, - {SBIT(8), - MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack}, - {SBIT(15), - MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack}, - {SBIT(15), - MT_SUSPEND_REJECT, l3ni1_suspend_rej}, - {SBIT(17), - MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack}, - {SBIT(17), - MT_RESUME_REJECT, l3ni1_resume_rej}, -}; - -static struct stateentry globalmes_list[] = -{ - {ALL_STATES, - MT_STATUS, l3ni1_status}, - {SBIT(0), - MT_RESTART, l3ni1_global_restart}, -/* {SBIT(1), - MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack}, -*/ - { SBIT(0), MT_DL_ESTABLISHED, l3ni1_spid_send }, - { SBIT(20) | SBIT(21) | SBIT(22), MT_INFORMATION, l3ni1_spid_epid }, -}; - -static struct stateentry manstatelist[] = -{ - {SBIT(2), - DL_ESTABLISH | INDICATION, l3ni1_dl_reset}, - {SBIT(10), - DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status}, - {SBIT(10), - DL_RELEASE | INDICATION, l3ni1_dl_reestablish}, - {ALL_STATES, - DL_RELEASE | INDICATION, l3ni1_dl_release}, -}; - -/* *INDENT-ON* */ - - -static void -global_handler(struct PStack *st, int mt, struct sk_buff *skb) -{ - u_char tmp[16]; - u_char *p = tmp; - int l; - int i; - struct l3_process *proc = st->l3.global; - - if (skb) - proc->callref = skb->data[2]; /* cr flag */ - else - proc->callref = 0; - for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) - if ((mt == globalmes_list[i].primitive) && - ((1 << proc->state) & globalmes_list[i].state)) - break; - if (i == ARRAY_SIZE(globalmes_list)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1 global state %d mt %x unhandled", - proc->state, mt); - } - MsgHead(p, proc->callref, MT_STATUS); - *p++ = IE_CAUSE; - *p++ = 0x2; - *p++ = 0x80; - *p++ = 81 | 0x80; /* invalid cr */ - *p++ = 0x14; /* CallState */ - *p++ = 0x1; - *p++ = proc->state & 0x3f; - l = p - tmp; - if (!(skb = l3_alloc_skb(l))) - return; - skb_put_data(skb, tmp, l); - l3_msg(proc->st, DL_DATA | REQUEST, skb); - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1 global %d mt %x", - proc->state, mt); - } - globalmes_list[i].rout(proc, mt, skb); - } -} - -static void -ni1up(struct PStack *st, int pr, void *arg) -{ - int i, mt, cr, callState; - char *ptr; - u_char *p; - struct sk_buff *skb = arg; - struct l3_process *proc; - - switch (pr) { - case (DL_DATA | INDICATION): - case (DL_UNIT_DATA | INDICATION): - break; - case (DL_ESTABLISH | INDICATION): - case (DL_RELEASE | INDICATION): - case (DL_RELEASE | CONFIRM): - l3_msg(st, pr, arg); - return; - break; - - case (DL_ESTABLISH | CONFIRM): - global_handler(st, MT_DL_ESTABLISHED, NULL); - return; - - default: - printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr); - return; - } - if (skb->len < 3) { - l3_debug(st, "ni1up frame too short(%d)", skb->len); - dev_kfree_skb(skb); - return; - } - - if (skb->data[0] != PROTO_DIS_EURO) { - if (st->l3.debug & L3_DEB_PROTERR) { - l3_debug(st, "ni1up%sunexpected discriminator %x message len %d", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - skb->data[0], skb->len); - } - dev_kfree_skb(skb); - return; - } - cr = getcallref(skb->data); - if (skb->len < ((skb->data[1] & 0x0f) + 3)) { - l3_debug(st, "ni1up frame too short(%d)", skb->len); - dev_kfree_skb(skb); - return; - } - mt = skb->data[skb->data[1] + 2]; - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "ni1up cr %d", cr); - if (cr == -2) { /* wrong Callref */ - if (st->l3.debug & L3_DEB_WARN) - l3_debug(st, "ni1up wrong Callref"); - dev_kfree_skb(skb); - return; - } else if (cr == -1) { /* Dummy Callref */ - if (mt == MT_FACILITY) - { - if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { - l3ni1_parse_facility(st, NULL, - (pr == (DL_DATA | INDICATION)) ? -1 : -2, p); - dev_kfree_skb(skb); - return; - } - } - else - { - global_handler(st, mt, skb); - return; - } - - if (st->l3.debug & L3_DEB_WARN) - l3_debug(st, "ni1up dummy Callref (no facility msg or ie)"); - dev_kfree_skb(skb); - return; - } else if ((((skb->data[1] & 0x0f) == 1) && (0 == (cr & 0x7f))) || - (((skb->data[1] & 0x0f) == 2) && (0 == (cr & 0x7fff)))) { /* Global CallRef */ - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "ni1up Global CallRef"); - global_handler(st, mt, skb); - dev_kfree_skb(skb); - return; - } else if (!(proc = getl3proc(st, cr))) { - /* No transaction process exist, that means no call with - * this callreference is active - */ - if (mt == MT_SETUP) { - /* Setup creates a new transaction process */ - if (skb->data[2] & 0x80) { - /* Setup with wrong CREF flag */ - if (st->l3.debug & L3_DEB_STATE) - l3_debug(st, "ni1up wrong CRef flag"); - dev_kfree_skb(skb); - return; - } - if (!(proc = ni1_new_l3_process(st, cr))) { - /* May be to answer with RELEASE_COMPLETE and - * CAUSE 0x2f "Resource unavailable", but this - * need a new_l3_process too ... arghh - */ - dev_kfree_skb(skb); - return; - } - } else if (mt == MT_STATUS) { - if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { - ptr++; - if (*ptr++ == 2) - ptr++; - } - callState = 0; - if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { - ptr++; - if (*ptr++ == 2) - ptr++; - callState = *ptr; - } - /* ETS 300-104 part 2.4.1 - * if setup has not been made and a message type - * MT_STATUS is received with call state == 0, - * we must send nothing - */ - if (callState != 0) { - /* ETS 300-104 part 2.4.2 - * if setup has not been made and a message type - * MT_STATUS is received with call state != 0, - * we must send MT_RELEASE_COMPLETE cause 101 - */ - if ((proc = ni1_new_l3_process(st, cr))) { - proc->para.cause = 101; - l3ni1_msg_without_setup(proc, 0, NULL); - } - } - dev_kfree_skb(skb); - return; - } else if (mt == MT_RELEASE_COMPLETE) { - dev_kfree_skb(skb); - return; - } else { - /* ETS 300-104 part 2 - * if setup has not been made and a message type - * (except MT_SETUP and RELEASE_COMPLETE) is received, - * we must send MT_RELEASE_COMPLETE cause 81 */ - dev_kfree_skb(skb); - if ((proc = ni1_new_l3_process(st, cr))) { - proc->para.cause = 81; - l3ni1_msg_without_setup(proc, 0, NULL); - } - return; - } - } - if (l3ni1_check_messagetype_validity(proc, mt, skb)) { - dev_kfree_skb(skb); - return; - } - if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL) - l3ni1_deliver_display(proc, pr, p); /* Display IE included */ - for (i = 0; i < ARRAY_SIZE(datastatelist); i++) - if ((mt == datastatelist[i].primitive) && - ((1 << proc->state) & datastatelist[i].state)) - break; - if (i == ARRAY_SIZE(datastatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1up%sstate %d mt %#x unhandled", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) { - proc->para.cause = 101; - l3ni1_status_send(proc, pr, skb); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1up%sstate %d mt %x", - (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", - proc->state, mt); - } - datastatelist[i].rout(proc, pr, skb); - } - dev_kfree_skb(skb); - return; -} - -static void -ni1down(struct PStack *st, int pr, void *arg) -{ - int i, cr; - struct l3_process *proc; - struct Channel *chan; - - if ((DL_ESTABLISH | REQUEST) == pr) { - l3_msg(st, pr, NULL); - return; - } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { - chan = arg; - cr = newcallref(); - cr |= 0x80; - if ((proc = ni1_new_l3_process(st, cr))) { - proc->chan = chan; - chan->proc = proc; - memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); - proc->callref = cr; - } - } else { - proc = arg; - } - if (!proc) { - printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr); - return; - } - - if (pr == (CC_TNI1_IO | REQUEST)) { - l3ni1_io_timer(proc); /* timer expires */ - return; - } - - for (i = 0; i < ARRAY_SIZE(downstatelist); i++) - if ((pr == downstatelist[i].primitive) && - ((1 << proc->state) & downstatelist[i].state)) - break; - if (i == ARRAY_SIZE(downstatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1down state %d prim %#x unhandled", - proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "ni1down state %d prim %#x", - proc->state, pr); - } - downstatelist[i].rout(proc, pr, arg); - } -} - -static void -ni1man(struct PStack *st, int pr, void *arg) -{ - int i; - struct l3_process *proc = arg; - - if (!proc) { - printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); - return; - } - for (i = 0; i < ARRAY_SIZE(manstatelist); i++) - if ((pr == manstatelist[i].primitive) && - ((1 << proc->state) & manstatelist[i].state)) - break; - if (i == ARRAY_SIZE(manstatelist)) { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", - proc->callref & 0x7f, proc->state, pr); - } - } else { - if (st->l3.debug & L3_DEB_STATE) { - l3_debug(st, "cr %d ni1man state %d prim %#x", - proc->callref & 0x7f, proc->state, pr); - } - manstatelist[i].rout(proc, pr, arg); - } -} - -void -setstack_ni1(struct PStack *st) -{ - char tmp[64]; - int i; - - st->lli.l4l3 = ni1down; - st->lli.l4l3_proto = l3ni1_cmd_global; - st->l2.l2l3 = ni1up; - st->l3.l3ml3 = ni1man; - st->l3.N303 = 1; - st->prot.ni1.last_invoke_id = 0; - st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */ - i = 1; - while (i < 32) - st->prot.ni1.invoke_used[i++] = 0; - - if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { - printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n"); - } else { - st->l3.global->state = 0; - st->l3.global->callref = 0; - st->l3.global->next = NULL; - st->l3.global->debug = L3_DEB_WARN; - st->l3.global->st = st; - st->l3.global->N303 = 1; - st->l3.global->prot.ni1.invoke_id = 0; - - L3InitTimer(st->l3.global, &st->l3.global->timer); - } - strcpy(tmp, ni1_revision); - printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp)); -} diff --git a/drivers/isdn/hisax/l3ni1.h b/drivers/isdn/hisax/l3ni1.h deleted file mode 100644 index 99d37d2cea4f..000000000000 --- a/drivers/isdn/hisax/l3ni1.h +++ /dev/null @@ -1,136 +0,0 @@ -/* $Id: l3ni1.h,v 2.3.6.2 2001/09/23 22:24:50 kai Exp $ - * - * NI1 D-channel protocol - * - * Author Matt Henderson & Guy Ellis - * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * 2000.6.6 Initial implementation of routines for US NI1 - * Layer 3 protocol based on the EURO/DSS1 D-channel protocol - * driver written by Karsten Keil et al. Thanks also for the - * code provided by Ragnar Paulson. - * - */ - -#ifndef l3ni1_process - -#define T302 15000 -#define T303 4000 -#define T304 30000 -#define T305 30000 -#define T308 4000 -/* for layer 1 certification T309 < layer1 T3 (e.g. 4000) */ -/* This makes some tests easier and quicker */ -#define T309 40000 -#define T310 30000 -#define T313 4000 -#define T318 4000 -#define T319 4000 -#define TSPID 5000 /* was 2000 - Guy Ellis */ - -/* - * Message-Types - */ - -#define MT_ALERTING 0x01 -#define MT_CALL_PROCEEDING 0x02 -#define MT_CONNECT 0x07 -#define MT_CONNECT_ACKNOWLEDGE 0x0f -#define MT_PROGRESS 0x03 -#define MT_SETUP 0x05 -#define MT_SETUP_ACKNOWLEDGE 0x0d -#define MT_RESUME 0x26 -#define MT_RESUME_ACKNOWLEDGE 0x2e -#define MT_RESUME_REJECT 0x22 -#define MT_SUSPEND 0x25 -#define MT_SUSPEND_ACKNOWLEDGE 0x2d -#define MT_SUSPEND_REJECT 0x21 -#define MT_USER_INFORMATION 0x20 -#define MT_DISCONNECT 0x45 -#define MT_RELEASE 0x4d -#define MT_RELEASE_COMPLETE 0x5a -#define MT_RESTART 0x46 -#define MT_RESTART_ACKNOWLEDGE 0x4e -#define MT_SEGMENT 0x60 -#define MT_CONGESTION_CONTROL 0x79 -#define MT_INFORMATION 0x7b -#define MT_FACILITY 0x62 -#define MT_NOTIFY 0x6e -#define MT_STATUS 0x7d -#define MT_STATUS_ENQUIRY 0x75 -#define MT_DL_ESTABLISHED 0xfe - -#define IE_SEGMENT 0x00 -#define IE_BEARER 0x04 -#define IE_CAUSE 0x08 -#define IE_CALL_ID 0x10 -#define IE_CALL_STATE 0x14 -#define IE_CHANNEL_ID 0x18 -#define IE_FACILITY 0x1c -#define IE_PROGRESS 0x1e -#define IE_NET_FAC 0x20 -#define IE_NOTIFY 0x27 -#define IE_DISPLAY 0x28 -#define IE_DATE 0x29 -#define IE_KEYPAD 0x2c -#define IE_SIGNAL 0x34 -#define IE_SPID 0x3a -#define IE_ENDPOINT_ID 0x3b -#define IE_INFORATE 0x40 -#define IE_E2E_TDELAY 0x42 -#define IE_TDELAY_SEL 0x43 -#define IE_PACK_BINPARA 0x44 -#define IE_PACK_WINSIZE 0x45 -#define IE_PACK_SIZE 0x46 -#define IE_CUG 0x47 -#define IE_REV_CHARGE 0x4a -#define IE_CONNECT_PN 0x4c -#define IE_CONNECT_SUB 0x4d -#define IE_CALLING_PN 0x6c -#define IE_CALLING_SUB 0x6d -#define IE_CALLED_PN 0x70 -#define IE_CALLED_SUB 0x71 -#define IE_REDIR_NR 0x74 -#define IE_TRANS_SEL 0x78 -#define IE_RESTART_IND 0x79 -#define IE_LLC 0x7c -#define IE_HLC 0x7d -#define IE_USER_USER 0x7e -#define IE_ESCAPE 0x7f -#define IE_SHIFT 0x90 -#define IE_MORE_DATA 0xa0 -#define IE_COMPLETE 0xa1 -#define IE_CONGESTION 0xb0 -#define IE_REPEAT 0xd0 - -#define IE_MANDATORY 0x0100 -/* mandatory not in every case */ -#define IE_MANDATORY_1 0x0200 - -#define ERR_IE_COMPREHENSION 1 -#define ERR_IE_UNRECOGNIZED -1 -#define ERR_IE_LENGTH -2 -#define ERR_IE_SEQUENCE -3 - -#else /* only l3ni1_process */ - -/* l3ni1 specific data in l3 process */ -typedef struct -{ unsigned char invoke_id; /* used invoke id in remote ops, 0 = not active */ - ulong ll_id; /* remebered ll id */ - u8 remote_operation; /* handled remote operation, 0 = not active */ - int proc; /* rememered procedure */ - ulong remote_result; /* result of remote operation for statcallb */ - char uus1_data[35]; /* data send during alerting or disconnect */ -} ni1_proc_priv; - -/* l3dni1 specific data in protocol stack */ -typedef struct -{ unsigned char last_invoke_id; /* last used value for invoking */ - unsigned char invoke_used[32]; /* 256 bits for 256 values */ -} ni1_stk_priv; - -#endif /* only l3dni1_process */ diff --git a/drivers/isdn/hisax/lmgr.c b/drivers/isdn/hisax/lmgr.c deleted file mode 100644 index 5b63eb6601aa..000000000000 --- a/drivers/isdn/hisax/lmgr.c +++ /dev/null @@ -1,50 +0,0 @@ -/* $Id: lmgr.c,v 1.7.6.2 2001/09/23 22:24:50 kai Exp $ - * - * Layermanagement module - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include "hisax.h" - -static void -error_handling_dchan(struct PStack *st, int Error) -{ - switch (Error) { - case 'C': - case 'D': - case 'G': - case 'H': - st->l2.l2tei(st, MDL_ERROR | REQUEST, NULL); - break; - } -} - -static void -hisax_manager(struct PStack *st, int pr, void *arg) -{ - long Code; - - switch (pr) { - case (MDL_ERROR | INDICATION): - Code = (long) arg; - HiSax_putstatus(st->l1.hardware, "manager: MDL_ERROR", - " %c %s", (char)Code, - test_bit(FLG_LAPD, &st->l2.flag) ? - "D-channel" : "B-channel"); - if (test_bit(FLG_LAPD, &st->l2.flag)) - error_handling_dchan(st, Code); - break; - } -} - -void -setstack_manager(struct PStack *st) -{ - st->ma.layer = hisax_manager; -} diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c deleted file mode 100644 index 93398676f78f..000000000000 --- a/drivers/isdn/hisax/mic.c +++ /dev/null @@ -1,235 +0,0 @@ -/* $Id: mic.c,v 1.12.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for mic cards - * - * Author Stephan von Krawczynski - * Copyright by Stephan von Krawczynski <skraw@ithnet.com> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *mic_revision = "$Revision: 1.12.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define MIC_ISAC 2 -#define MIC_HSCX 1 -#define MIC_ADR 7 - -/* CARD_ADR (Write) */ -#define MIC_RESET 0x3 /* same as DOS driver */ - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.mic.adr, cs->hw.mic.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.mic.adr, cs->hw.mic.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.mic.adr, cs->hw.mic.isac, 0, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.mic.adr, - cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.mic.adr, - cs->hw.mic.hscx, offset + (hscx ? 0x40 : 0), value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.mic.adr, \ - cs->hw.mic.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.mic.adr, \ - cs->hw.mic.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.mic.adr, \ - cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.mic.adr, \ - cs->hw.mic.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -mic_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.mic.adr, cs->hw.mic.isac, ISAC_MASK, 0x0); - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.mic.adr, cs->hw.mic.hscx, HSCX_MASK + 0x40, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_mic(struct IsdnCardState *cs) -{ - int bytecnt = 8; - - if (cs->hw.mic.cfg_reg) - release_region(cs->hw.mic.cfg_reg, bytecnt); -} - -static int -mic_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - return (0); - case CARD_RELEASE: - release_io_mic(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscx(cs); /* /RTSA := ISAC RST */ - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -int setup_mic(struct IsdnCard *card) -{ - int bytecnt; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, mic_revision); - printk(KERN_INFO "HiSax: mic driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_MIC) - return (0); - - bytecnt = 8; - cs->hw.mic.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - cs->hw.mic.adr = cs->hw.mic.cfg_reg + MIC_ADR; - cs->hw.mic.isac = cs->hw.mic.cfg_reg + MIC_ISAC; - cs->hw.mic.hscx = cs->hw.mic.cfg_reg + MIC_HSCX; - - if (!request_region(cs->hw.mic.cfg_reg, bytecnt, "mic isdn")) { - printk(KERN_WARNING - "HiSax: ith mic config port %x-%x already in use\n", - cs->hw.mic.cfg_reg, - cs->hw.mic.cfg_reg + bytecnt); - return (0); - } - printk(KERN_INFO "mic: defined at 0x%x IRQ %d\n", - cs->hw.mic.cfg_reg, cs->irq); - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &mic_card_msg; - cs->irq_func = &mic_interrupt; - ISACVersion(cs, "mic:"); - if (HscxVersion(cs, "mic:")) { - printk(KERN_WARNING - "mic: wrong HSCX versions check IO address\n"); - release_io_mic(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c deleted file mode 100644 index d7b011c8d692..000000000000 --- a/drivers/isdn/hisax/netjet.c +++ /dev/null @@ -1,985 +0,0 @@ -/* $Id: netjet.c,v 1.29.2.4 2004/02/11 13:21:34 keil Exp $ - * - * low level stuff for Traverse Technologie NETJet ISDN cards - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Traverse Technologies Australia for documents and information - * - * 16-Apr-2002 - led code added - Guy Ellis (guy@traverse.com.au) - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" -#include <linux/interrupt.h> -#include <linux/ppp_defs.h> -#include <linux/slab.h> -#include <asm/io.h> -#include "netjet.h" - -/* Interface functions */ - -u_char -NETjet_ReadIC(struct IsdnCardState *cs, u_char offset) -{ - u_char ret; - - cs->hw.njet.auxd &= 0xfc; - cs->hw.njet.auxd |= (offset >> 4) & 3; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - ret = bytein(cs->hw.njet.isac + ((offset & 0xf) << 2)); - return (ret); -} - -void -NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - cs->hw.njet.auxd &= 0xfc; - cs->hw.njet.auxd |= (offset >> 4) & 3; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - byteout(cs->hw.njet.isac + ((offset & 0xf) << 2), value); -} - -void -NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - cs->hw.njet.auxd &= 0xfc; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - insb(cs->hw.njet.isac, data, size); -} - -void -NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - cs->hw.njet.auxd &= 0xfc; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - outsb(cs->hw.njet.isac, data, size); -} - -static void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill) -{ - u_int mask = 0x000000ff, val = 0, *p = pos; - u_int i; - - val |= fill; - if (chan) { - val <<= 8; - mask <<= 8; - } - mask ^= 0xffffffff; - for (i = 0; i < cnt; i++) { - *p &= mask; - *p++ |= val; - if (p > bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send; - } -} - -static void -mode_tiger(struct BCState *bcs, int mode, int bc) -{ - struct IsdnCardState *cs = bcs->cs; - u_char led; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "Tiger mode %d bchan %d/%d", - mode, bc, bcs->channel); - bcs->mode = mode; - bcs->channel = bc; - switch (mode) { - case (L1_MODE_NULL): - fill_mem(bcs, bcs->hw.tiger.send, - NETJET_DMA_TXSIZE, bc, 0xff); - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "Tiger stat rec %d/%d send %d", - bcs->hw.tiger.r_tot, bcs->hw.tiger.r_err, - bcs->hw.tiger.s_tot); - if ((cs->bcs[0].mode == L1_MODE_NULL) && - (cs->bcs[1].mode == L1_MODE_NULL)) { - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_DMACTRL, - cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); - } - if (cs->typ == ISDN_CTYPE_NETJET_S) - { - // led off - led = bc & 0x01; - led = 0x01 << (6 + led); // convert to mask - led = ~led; - cs->hw.njet.auxd &= led; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - } - break; - case (L1_MODE_TRANS): - break; - case (L1_MODE_HDLC_56K): - case (L1_MODE_HDLC): - fill_mem(bcs, bcs->hw.tiger.send, - NETJET_DMA_TXSIZE, bc, 0xff); - bcs->hw.tiger.r_state = HDLC_ZERO_SEARCH; - bcs->hw.tiger.r_tot = 0; - bcs->hw.tiger.r_bitcnt = 0; - bcs->hw.tiger.r_one = 0; - bcs->hw.tiger.r_err = 0; - bcs->hw.tiger.s_tot = 0; - if (!cs->hw.njet.dmactrl) { - fill_mem(bcs, bcs->hw.tiger.send, - NETJET_DMA_TXSIZE, !bc, 0xff); - cs->hw.njet.dmactrl = 1; - byteout(cs->hw.njet.base + NETJET_DMACTRL, - cs->hw.njet.dmactrl); - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0x0f); - /* was 0x3f now 0x0f for TJ300 and TJ320 GE 13/07/00 */ - } - bcs->hw.tiger.sendp = bcs->hw.tiger.send; - bcs->hw.tiger.free = NETJET_DMA_TXSIZE; - test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag); - if (cs->typ == ISDN_CTYPE_NETJET_S) - { - // led on - led = bc & 0x01; - led = 0x01 << (6 + led); // convert to mask - cs->hw.njet.auxd |= led; - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - } - break; - } - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "tiger: set %x %x %x %x/%x pulse=%d", - bytein(cs->hw.njet.base + NETJET_DMACTRL), - bytein(cs->hw.njet.base + NETJET_IRQMASK0), - bytein(cs->hw.njet.base + NETJET_IRQSTAT0), - inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), - inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), - bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); -} - -static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s) { - char tmp[128]; - char *t = tmp; - int i = count, j; - u_char *p = buf; - - t += sprintf(t, "tiger %s(%4d)", s, count); - while (i > 0) { - if (i > 16) - j = 16; - else - j = i; - QuickHex(t, p, j); - debugl1(cs, "%s", tmp); - p += j; - i -= j; - t = tmp; - t += sprintf(t, "tiger %s ", s); - } -} - -// macro for 64k - -#define MAKE_RAW_BYTE for (j = 0; j < 8; j++) { \ - bitcnt++; \ - s_val >>= 1; \ - if (val & 1) { \ - s_one++; \ - s_val |= 0x80; \ - } else { \ - s_one = 0; \ - s_val &= 0x7f; \ - } \ - if (bitcnt == 8) { \ - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \ - bitcnt = 0; \ - } \ - if (s_one == 5) { \ - s_val >>= 1; \ - s_val &= 0x7f; \ - bitcnt++; \ - s_one = 0; \ - } \ - if (bitcnt == 8) { \ - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \ - bitcnt = 0; \ - } \ - val >>= 1; \ - } - -static int make_raw_data(struct BCState *bcs) { -// this make_raw is for 64k - register u_int i, s_cnt = 0; - register u_char j; - register u_char val; - register u_char s_one = 0; - register u_char s_val = 0; - register u_char bitcnt = 0; - u_int fcs; - - if (!bcs->tx_skb) { - debugl1(bcs->cs, "tiger make_raw: NULL skb"); - return (1); - } - bcs->hw.tiger.sendbuf[s_cnt++] = HDLC_FLAG_VALUE; - fcs = PPP_INITFCS; - for (i = 0; i < bcs->tx_skb->len; i++) { - val = bcs->tx_skb->data[i]; - fcs = PPP_FCS(fcs, val); - MAKE_RAW_BYTE; - } - fcs ^= 0xffff; - val = fcs & 0xff; - MAKE_RAW_BYTE; - val = (fcs >> 8) & 0xff; - MAKE_RAW_BYTE; - val = HDLC_FLAG_VALUE; - for (j = 0; j < 8; j++) { - bitcnt++; - s_val >>= 1; - if (val & 1) - s_val |= 0x80; - else - s_val &= 0x7f; - if (bitcnt == 8) { - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; - bitcnt = 0; - } - val >>= 1; - } - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger make_raw: in %u out %d.%d", - bcs->tx_skb->len, s_cnt, bitcnt); - if (bitcnt) { - while (8 > bitcnt++) { - s_val >>= 1; - s_val |= 0x80; - } - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; - bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix - } - bcs->hw.tiger.sendcnt = s_cnt; - bcs->tx_cnt -= bcs->tx_skb->len; - bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf; - return (0); -} - -// macro for 56k - -#define MAKE_RAW_BYTE_56K for (j = 0; j < 8; j++) { \ - bitcnt++; \ - s_val >>= 1; \ - if (val & 1) { \ - s_one++; \ - s_val |= 0x80; \ - } else { \ - s_one = 0; \ - s_val &= 0x7f; \ - } \ - if (bitcnt == 7) { \ - s_val >>= 1; \ - s_val |= 0x80; \ - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \ - bitcnt = 0; \ - } \ - if (s_one == 5) { \ - s_val >>= 1; \ - s_val &= 0x7f; \ - bitcnt++; \ - s_one = 0; \ - } \ - if (bitcnt == 7) { \ - s_val >>= 1; \ - s_val |= 0x80; \ - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; \ - bitcnt = 0; \ - } \ - val >>= 1; \ - } - -static int make_raw_data_56k(struct BCState *bcs) { -// this make_raw is for 56k - register u_int i, s_cnt = 0; - register u_char j; - register u_char val; - register u_char s_one = 0; - register u_char s_val = 0; - register u_char bitcnt = 0; - u_int fcs; - - if (!bcs->tx_skb) { - debugl1(bcs->cs, "tiger make_raw_56k: NULL skb"); - return (1); - } - val = HDLC_FLAG_VALUE; - for (j = 0; j < 8; j++) { - bitcnt++; - s_val >>= 1; - if (val & 1) - s_val |= 0x80; - else - s_val &= 0x7f; - if (bitcnt == 7) { - s_val >>= 1; - s_val |= 0x80; - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; - bitcnt = 0; - } - val >>= 1; - } - fcs = PPP_INITFCS; - for (i = 0; i < bcs->tx_skb->len; i++) { - val = bcs->tx_skb->data[i]; - fcs = PPP_FCS(fcs, val); - MAKE_RAW_BYTE_56K; - } - fcs ^= 0xffff; - val = fcs & 0xff; - MAKE_RAW_BYTE_56K; - val = (fcs >> 8) & 0xff; - MAKE_RAW_BYTE_56K; - val = HDLC_FLAG_VALUE; - for (j = 0; j < 8; j++) { - bitcnt++; - s_val >>= 1; - if (val & 1) - s_val |= 0x80; - else - s_val &= 0x7f; - if (bitcnt == 7) { - s_val >>= 1; - s_val |= 0x80; - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; - bitcnt = 0; - } - val >>= 1; - } - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger make_raw_56k: in %u out %d.%d", - bcs->tx_skb->len, s_cnt, bitcnt); - if (bitcnt) { - while (8 > bitcnt++) { - s_val >>= 1; - s_val |= 0x80; - } - bcs->hw.tiger.sendbuf[s_cnt++] = s_val; - bcs->hw.tiger.sendbuf[s_cnt++] = 0xff; // NJ<->NJ thoughput bug fix - } - bcs->hw.tiger.sendcnt = s_cnt; - bcs->tx_cnt -= bcs->tx_skb->len; - bcs->hw.tiger.sp = bcs->hw.tiger.sendbuf; - return (0); -} - -static void got_frame(struct BCState *bcs, int count) { - struct sk_buff *skb; - - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "TIGER: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.tiger.rcvbuf, count); - skb_queue_tail(&bcs->rqueue, skb); - } - test_and_set_bit(B_RCVBUFREADY, &bcs->event); - schedule_work(&bcs->tqueue); - - if (bcs->cs->debug & L1_DEB_RECEIVE_FRAME) - printframe(bcs->cs, bcs->hw.tiger.rcvbuf, count, "rec"); -} - - - -static void read_raw(struct BCState *bcs, u_int *buf, int cnt) { - int i; - register u_char j; - register u_char val; - u_int *pend = bcs->hw.tiger.rec + NETJET_DMA_RXSIZE - 1; - register u_char state = bcs->hw.tiger.r_state; - register u_char r_one = bcs->hw.tiger.r_one; - register u_char r_val = bcs->hw.tiger.r_val; - register u_int bitcnt = bcs->hw.tiger.r_bitcnt; - u_int *p = buf; - int bits; - u_char mask; - - if (bcs->mode == L1_MODE_HDLC) { // it's 64k - mask = 0xff; - bits = 8; - } - else { // it's 56K - mask = 0x7f; - bits = 7; - } - for (i = 0; i < cnt; i++) { - val = bcs->channel ? ((*p >> 8) & 0xff) : (*p & 0xff); - p++; - if (p > pend) - p = bcs->hw.tiger.rec; - if ((val & mask) == mask) { - state = HDLC_ZERO_SEARCH; - bcs->hw.tiger.r_tot++; - bitcnt = 0; - r_one = 0; - continue; - } - for (j = 0; j < bits; j++) { - if (state == HDLC_ZERO_SEARCH) { - if (val & 1) { - r_one++; - } else { - r_one = 0; - state = HDLC_FLAG_SEARCH; - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger read_raw: zBit(%d,%d,%d) %x", - bcs->hw.tiger.r_tot, i, j, val); - } - } else if (state == HDLC_FLAG_SEARCH) { - if (val & 1) { - r_one++; - if (r_one > 6) { - state = HDLC_ZERO_SEARCH; - } - } else { - if (r_one == 6) { - bitcnt = 0; - r_val = 0; - state = HDLC_FLAG_FOUND; - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger read_raw: flag(%d,%d,%d) %x", - bcs->hw.tiger.r_tot, i, j, val); - } - r_one = 0; - } - } else if (state == HDLC_FLAG_FOUND) { - if (val & 1) { - r_one++; - if (r_one > 6) { - state = HDLC_ZERO_SEARCH; - } else { - r_val >>= 1; - r_val |= 0x80; - bitcnt++; - } - } else { - if (r_one == 6) { - bitcnt = 0; - r_val = 0; - r_one = 0; - val >>= 1; - continue; - } else if (r_one != 5) { - r_val >>= 1; - r_val &= 0x7f; - bitcnt++; - } - r_one = 0; - } - if ((state != HDLC_ZERO_SEARCH) && - !(bitcnt & 7)) { - state = HDLC_FRAME_FOUND; - bcs->hw.tiger.r_fcs = PPP_INITFCS; - bcs->hw.tiger.rcvbuf[0] = r_val; - bcs->hw.tiger.r_fcs = PPP_FCS(bcs->hw.tiger.r_fcs, r_val); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger read_raw: byte1(%d,%d,%d) rval %x val %x i %x", - bcs->hw.tiger.r_tot, i, j, r_val, val, - bcs->cs->hw.njet.irqstat0); - } - } else if (state == HDLC_FRAME_FOUND) { - if (val & 1) { - r_one++; - if (r_one > 6) { - state = HDLC_ZERO_SEARCH; - bitcnt = 0; - } else { - r_val >>= 1; - r_val |= 0x80; - bitcnt++; - } - } else { - if (r_one == 6) { - r_val = 0; - r_one = 0; - bitcnt++; - if (bitcnt & 7) { - debugl1(bcs->cs, "tiger: frame not byte aligned"); - state = HDLC_FLAG_SEARCH; - bcs->hw.tiger.r_err++; -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - } else { - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger frame end(%d,%d): fcs(%x) i %x", - i, j, bcs->hw.tiger.r_fcs, bcs->cs->hw.njet.irqstat0); - if (bcs->hw.tiger.r_fcs == PPP_GOODFCS) { - got_frame(bcs, (bitcnt >> 3) - 3); - } else { - if (bcs->cs->debug) { - debugl1(bcs->cs, "tiger FCS error"); - printframe(bcs->cs, bcs->hw.tiger.rcvbuf, - (bitcnt >> 3) - 1, "rec"); - bcs->hw.tiger.r_err++; - } -#ifdef ERROR_STATISTIC - bcs->err_crc++; -#endif - } - state = HDLC_FLAG_FOUND; - } - bitcnt = 0; - } else if (r_one == 5) { - val >>= 1; - r_one = 0; - continue; - } else { - r_val >>= 1; - r_val &= 0x7f; - bitcnt++; - } - r_one = 0; - } - if ((state == HDLC_FRAME_FOUND) && - !(bitcnt & 7)) { - if ((bitcnt >> 3) >= HSCX_BUFMAX) { - debugl1(bcs->cs, "tiger: frame too big"); - r_val = 0; - state = HDLC_FLAG_SEARCH; - bcs->hw.tiger.r_err++; -#ifdef ERROR_STATISTIC - bcs->err_inv++; -#endif - } else { - bcs->hw.tiger.rcvbuf[(bitcnt >> 3) - 1] = r_val; - bcs->hw.tiger.r_fcs = - PPP_FCS(bcs->hw.tiger.r_fcs, r_val); - } - } - } - val >>= 1; - } - bcs->hw.tiger.r_tot++; - } - bcs->hw.tiger.r_state = state; - bcs->hw.tiger.r_one = r_one; - bcs->hw.tiger.r_val = r_val; - bcs->hw.tiger.r_bitcnt = bitcnt; -} - -void read_tiger(struct IsdnCardState *cs) { - u_int *p; - int cnt = NETJET_DMA_RXSIZE / 2; - - if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_READ) { - debugl1(cs, "tiger warn read double dma %x/%x", - cs->hw.njet.irqstat0, cs->hw.njet.last_is0); -#ifdef ERROR_STATISTIC - if (cs->bcs[0].mode) - cs->bcs[0].err_rdo++; - if (cs->bcs[1].mode) - cs->bcs[1].err_rdo++; -#endif - return; - } else { - cs->hw.njet.last_is0 &= ~NETJET_IRQM0_READ; - cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ); - } - if (cs->hw.njet.irqstat0 & NETJET_IRQM0_READ_1) - p = cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1; - else - p = cs->bcs[0].hw.tiger.rec + cnt - 1; - if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K)) - read_raw(cs->bcs, p, cnt); - - if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K)) - read_raw(cs->bcs + 1, p, cnt); - cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_READ; -} - -static void write_raw(struct BCState *bcs, u_int *buf, int cnt); - -void netjet_fill_dma(struct BCState *bcs) -{ - register u_int *p, *sp; - register int cnt; - - if (!bcs->tx_skb) - return; - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger fill_dma1: c%d %4lx", bcs->channel, - bcs->Flag); - if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag)) - return; - if (bcs->mode == L1_MODE_HDLC) { // it's 64k - if (make_raw_data(bcs)) - return; - } - else { // it's 56k - if (make_raw_data_56k(bcs)) - return; - } - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger fill_dma2: c%d %4lx", bcs->channel, - bcs->Flag); - if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) { - write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free); - } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { - p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR)); - sp = bcs->hw.tiger.sendp; - if (p == bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send - 1; - if (sp == bcs->hw.tiger.s_end) - sp = bcs->hw.tiger.send - 1; - cnt = p - sp; - if (cnt < 0) { - write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free); - } else { - p++; - cnt++; - if (p > bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send; - p++; - cnt++; - if (p > bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send; - write_raw(bcs, p, bcs->hw.tiger.free - cnt); - } - } else if (test_and_clear_bit(BC_FLG_EMPTY, &bcs->Flag)) { - p = bus_to_virt(inl(bcs->cs->hw.njet.base + NETJET_DMA_READ_ADR)); - cnt = bcs->hw.tiger.s_end - p; - if (cnt < 2) { - p = bcs->hw.tiger.send + 1; - cnt = NETJET_DMA_TXSIZE / 2 - 2; - } else { - p++; - p++; - if (cnt <= (NETJET_DMA_TXSIZE / 2)) - cnt += NETJET_DMA_TXSIZE / 2; - cnt--; - cnt--; - } - write_raw(bcs, p, cnt); - } - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger fill_dma3: c%d %4lx", bcs->channel, - bcs->Flag); -} - -static void write_raw(struct BCState *bcs, u_int *buf, int cnt) { - u_int mask, val, *p = buf; - u_int i, s_cnt; - - if (cnt <= 0) - return; - if (test_bit(BC_FLG_BUSY, &bcs->Flag)) { - if (bcs->hw.tiger.sendcnt > cnt) { - s_cnt = cnt; - bcs->hw.tiger.sendcnt -= cnt; - } else { - s_cnt = bcs->hw.tiger.sendcnt; - bcs->hw.tiger.sendcnt = 0; - } - if (bcs->channel) - mask = 0xffff00ff; - else - mask = 0xffffff00; - for (i = 0; i < s_cnt; i++) { - val = bcs->channel ? ((bcs->hw.tiger.sp[i] << 8) & 0xff00) : - (bcs->hw.tiger.sp[i]); - *p &= mask; - *p++ |= val; - if (p > bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send; - } - bcs->hw.tiger.s_tot += s_cnt; - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger write_raw: c%d %p-%p %d/%d %d %x", bcs->channel, - buf, p, s_cnt, cnt, - bcs->hw.tiger.sendcnt, bcs->cs->hw.njet.irqstat0); - if (bcs->cs->debug & L1_DEB_HSCX_FIFO) - printframe(bcs->cs, bcs->hw.tiger.sp, s_cnt, "snd"); - bcs->hw.tiger.sp += s_cnt; - bcs->hw.tiger.sendp = p; - if (!bcs->hw.tiger.sendcnt) { - if (!bcs->tx_skb) { - debugl1(bcs->cs, "tiger write_raw: NULL skb s_cnt %d", s_cnt); - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->tx_skb->len; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - } - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.tiger.free = cnt - s_cnt; - if (bcs->hw.tiger.free > (NETJET_DMA_TXSIZE / 2)) - test_and_set_bit(BC_FLG_HALF, &bcs->Flag); - else { - test_and_clear_bit(BC_FLG_HALF, &bcs->Flag); - test_and_set_bit(BC_FLG_NOFRAME, &bcs->Flag); - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - netjet_fill_dma(bcs); - } else { - mask ^= 0xffffffff; - if (s_cnt < cnt) { - for (i = s_cnt; i < cnt; i++) { - *p++ |= mask; - if (p > bcs->hw.tiger.s_end) - p = bcs->hw.tiger.send; - } - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger write_raw: fill rest %d", - cnt - s_cnt); - } - test_and_set_bit(B_XMTBUFREADY, &bcs->event); - schedule_work(&bcs->tqueue); - } - } - } else if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) { - test_and_set_bit(BC_FLG_HALF, &bcs->Flag); - fill_mem(bcs, buf, cnt, bcs->channel, 0xff); - bcs->hw.tiger.free += cnt; - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger write_raw: fill half"); - } else if (test_and_clear_bit(BC_FLG_HALF, &bcs->Flag)) { - test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag); - fill_mem(bcs, buf, cnt, bcs->channel, 0xff); - if (bcs->cs->debug & L1_DEB_HSCX) - debugl1(bcs->cs, "tiger write_raw: fill full"); - } -} - -void write_tiger(struct IsdnCardState *cs) { - u_int *p, cnt = NETJET_DMA_TXSIZE / 2; - - if ((cs->hw.njet.irqstat0 & cs->hw.njet.last_is0) & NETJET_IRQM0_WRITE) { - debugl1(cs, "tiger warn write double dma %x/%x", - cs->hw.njet.irqstat0, cs->hw.njet.last_is0); -#ifdef ERROR_STATISTIC - if (cs->bcs[0].mode) - cs->bcs[0].err_tx++; - if (cs->bcs[1].mode) - cs->bcs[1].err_tx++; -#endif - return; - } else { - cs->hw.njet.last_is0 &= ~NETJET_IRQM0_WRITE; - cs->hw.njet.last_is0 |= (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE); - } - if (cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE_1) - p = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1; - else - p = cs->bcs[0].hw.tiger.send + cnt - 1; - if ((cs->bcs[0].mode == L1_MODE_HDLC) || (cs->bcs[0].mode == L1_MODE_HDLC_56K)) - write_raw(cs->bcs, p, cnt); - if ((cs->bcs[1].mode == L1_MODE_HDLC) || (cs->bcs[1].mode == L1_MODE_HDLC_56K)) - write_raw(cs->bcs + 1, p, cnt); - cs->hw.njet.irqstat0 &= ~NETJET_IRQM0_WRITE; -} - -static void -tiger_l2l1(struct PStack *st, int pr, void *arg) -{ - struct BCState *bcs = st->l1.bcs; - struct sk_buff *skb = arg; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - printk(KERN_WARNING "tiger_l2l1: this shouldn't happen\n"); - } else { - bcs->tx_skb = skb; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - mode_tiger(bcs, st->l1.mode, st->l1.bc); - /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */ - spin_unlock_irqrestore(&bcs->cs->lock, flags); - bcs->cs->cardmsg(bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc)); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */ - bcs->cs->cardmsg(bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc)); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - mode_tiger(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - - -static void -close_tigerstate(struct BCState *bcs) -{ - mode_tiger(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.tiger.rcvbuf); - bcs->hw.tiger.rcvbuf = NULL; - kfree(bcs->hw.tiger.sendbuf); - bcs->hw.tiger.sendbuf = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static int -open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.tiger.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for tiger.rcvbuf\n"); - return (1); - } - if (!(bcs->hw.tiger.sendbuf = kmalloc(RAW_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for tiger.sendbuf\n"); - return (1); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - bcs->hw.tiger.sendcnt = 0; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_tiger(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_tigerstate(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = tiger_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - - -void -inittiger(struct IsdnCardState *cs) -{ - cs->bcs[0].hw.tiger.send = kmalloc_array(NETJET_DMA_TXSIZE, - sizeof(unsigned int), - GFP_KERNEL | GFP_DMA); - if (!cs->bcs[0].hw.tiger.send) { - printk(KERN_WARNING - "HiSax: No memory for tiger.send\n"); - return; - } - cs->bcs[0].hw.tiger.s_irq = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE / 2 - 1; - cs->bcs[0].hw.tiger.s_end = cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1; - cs->bcs[1].hw.tiger.send = cs->bcs[0].hw.tiger.send; - cs->bcs[1].hw.tiger.s_irq = cs->bcs[0].hw.tiger.s_irq; - cs->bcs[1].hw.tiger.s_end = cs->bcs[0].hw.tiger.s_end; - - memset(cs->bcs[0].hw.tiger.send, 0xff, NETJET_DMA_TXSIZE * sizeof(unsigned int)); - debugl1(cs, "tiger: send buf %p - %p", cs->bcs[0].hw.tiger.send, - cs->bcs[0].hw.tiger.send + NETJET_DMA_TXSIZE - 1); - outl(virt_to_bus(cs->bcs[0].hw.tiger.send), - cs->hw.njet.base + NETJET_DMA_READ_START); - outl(virt_to_bus(cs->bcs[0].hw.tiger.s_irq), - cs->hw.njet.base + NETJET_DMA_READ_IRQ); - outl(virt_to_bus(cs->bcs[0].hw.tiger.s_end), - cs->hw.njet.base + NETJET_DMA_READ_END); - cs->bcs[0].hw.tiger.rec = kmalloc_array(NETJET_DMA_RXSIZE, - sizeof(unsigned int), - GFP_KERNEL | GFP_DMA); - if (!cs->bcs[0].hw.tiger.rec) { - printk(KERN_WARNING - "HiSax: No memory for tiger.rec\n"); - return; - } - debugl1(cs, "tiger: rec buf %p - %p", cs->bcs[0].hw.tiger.rec, - cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1); - cs->bcs[1].hw.tiger.rec = cs->bcs[0].hw.tiger.rec; - memset(cs->bcs[0].hw.tiger.rec, 0xff, NETJET_DMA_RXSIZE * sizeof(unsigned int)); - outl(virt_to_bus(cs->bcs[0].hw.tiger.rec), - cs->hw.njet.base + NETJET_DMA_WRITE_START); - outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE / 2 - 1), - cs->hw.njet.base + NETJET_DMA_WRITE_IRQ); - outl(virt_to_bus(cs->bcs[0].hw.tiger.rec + NETJET_DMA_RXSIZE - 1), - cs->hw.njet.base + NETJET_DMA_WRITE_END); - debugl1(cs, "tiger: dmacfg %x/%x pulse=%d", - inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR), - inl(cs->hw.njet.base + NETJET_DMA_READ_ADR), - bytein(cs->hw.njet.base + NETJET_PULSE_CNT)); - cs->hw.njet.last_is0 = 0; - cs->bcs[0].BC_SetStack = setstack_tiger; - cs->bcs[1].BC_SetStack = setstack_tiger; - cs->bcs[0].BC_Close = close_tigerstate; - cs->bcs[1].BC_Close = close_tigerstate; -} - -static void -releasetiger(struct IsdnCardState *cs) -{ - kfree(cs->bcs[0].hw.tiger.send); - cs->bcs[0].hw.tiger.send = NULL; - cs->bcs[1].hw.tiger.send = NULL; - kfree(cs->bcs[0].hw.tiger.rec); - cs->bcs[0].hw.tiger.rec = NULL; - cs->bcs[1].hw.tiger.rec = NULL; -} - -void -release_io_netjet(struct IsdnCardState *cs) -{ - byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, 0); - releasetiger(cs); - release_region(cs->hw.njet.base, 256); -} diff --git a/drivers/isdn/hisax/netjet.h b/drivers/isdn/hisax/netjet.h deleted file mode 100644 index 70590d5d5e64..000000000000 --- a/drivers/isdn/hisax/netjet.h +++ /dev/null @@ -1,69 +0,0 @@ -/* $Id: netjet.h,v 2.8.2.2 2004/01/12 22:52:28 keil Exp $ - * - * NETjet common header file - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * by Matt Henderson, - * Traverse Technologies P/L www.traverse.com.au - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define NETJET_CTRL 0x00 -#define NETJET_DMACTRL 0x01 -#define NETJET_AUXCTRL 0x02 -#define NETJET_AUXDATA 0x03 -#define NETJET_IRQMASK0 0x04 -#define NETJET_IRQMASK1 0x05 -#define NETJET_IRQSTAT0 0x06 -#define NETJET_IRQSTAT1 0x07 -#define NETJET_DMA_READ_START 0x08 -#define NETJET_DMA_READ_IRQ 0x0c -#define NETJET_DMA_READ_END 0x10 -#define NETJET_DMA_READ_ADR 0x14 -#define NETJET_DMA_WRITE_START 0x18 -#define NETJET_DMA_WRITE_IRQ 0x1c -#define NETJET_DMA_WRITE_END 0x20 -#define NETJET_DMA_WRITE_ADR 0x24 -#define NETJET_PULSE_CNT 0x28 - -#define NETJET_ISAC_OFF 0xc0 -#define NETJET_ISACIRQ 0x10 -#define NETJET_IRQM0_READ 0x0c -#define NETJET_IRQM0_READ_1 0x04 -#define NETJET_IRQM0_READ_2 0x08 -#define NETJET_IRQM0_WRITE 0x03 -#define NETJET_IRQM0_WRITE_1 0x01 -#define NETJET_IRQM0_WRITE_2 0x02 - -#define NETJET_DMA_TXSIZE 512 -#define NETJET_DMA_RXSIZE 128 - -#define HDLC_ZERO_SEARCH 0 -#define HDLC_FLAG_SEARCH 1 -#define HDLC_FLAG_FOUND 2 -#define HDLC_FRAME_FOUND 3 -#define HDLC_NULL 4 -#define HDLC_PART 5 -#define HDLC_FULL 6 - -#define HDLC_FLAG_VALUE 0x7e - -u_char NETjet_ReadIC(struct IsdnCardState *cs, u_char offset); -void NETjet_WriteIC(struct IsdnCardState *cs, u_char offset, u_char value); -void NETjet_ReadICfifo(struct IsdnCardState *cs, u_char *data, int size); -void NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size); - -void read_tiger(struct IsdnCardState *cs); -void write_tiger(struct IsdnCardState *cs); - -void netjet_fill_dma(struct BCState *bcs); -void netjet_interrupt(int intno, void *dev_id); -void inittiger(struct IsdnCardState *cs); -void release_io_netjet(struct IsdnCardState *cs); diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c deleted file mode 100644 index dfbcd2eaa81a..000000000000 --- a/drivers/isdn/hisax/niccy.c +++ /dev/null @@ -1,380 +0,0 @@ -/* $Id: niccy.c,v 1.21.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for Dr. Neuhaus NICCY PnP and NICCY PCI and - * compatible (SAGEM cybermodem) - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Dr. Neuhaus and SAGEM for information - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" -#include <linux/pci.h> -#include <linux/isapnp.h> - -static const char *niccy_revision = "$Revision: 1.21.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define ISAC_PCI_DATA 0 -#define HSCX_PCI_DATA 1 -#define ISAC_PCI_ADDR 2 -#define HSCX_PCI_ADDR 3 -#define ISAC_PNP 0 -#define HSCX_PNP 1 - -/* SUB Types */ -#define NICCY_PNP 1 -#define NICCY_PCI 2 - -/* PCI stuff */ -#define PCI_IRQ_CTRL_REG 0x38 -#define PCI_IRQ_ENABLE 0x1f00 -#define PCI_IRQ_DISABLE 0xff0000 -#define PCI_IRQ_ASSERT 0x800000 - -static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return ret; -} - -static inline void readfifo(unsigned int ale, unsigned int adr, u_char off, - u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - -static inline void writereg(unsigned int ale, unsigned int adr, u_char off, - u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void writefifo(unsigned int ale, unsigned int adr, u_char off, - u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset); -} - -static void WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value); -} - -static void ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size); -} - -static void WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size); -} - -static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return readreg(cs->hw.niccy.hscx_ale, - cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)); -} - -static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, - u_char value) -{ - writereg(cs->hw.niccy.hscx_ale, - cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value); -} - -#define READHSCX(cs, nr, reg) readreg(cs->hw.niccy.hscx_ale, \ - cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.niccy.hscx_ale, \ - cs->hw.niccy.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.niccy.hscx_ale, \ - cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.niccy.hscx_ale, \ - cs->hw.niccy.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t niccy_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (cs->subtyp == NICCY_PCI) { - int ival; - ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */ - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - } - val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, - HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, - HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, - 0xFF); - writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0); - writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void release_io_niccy(struct IsdnCardState *cs) -{ - if (cs->subtyp == NICCY_PCI) { - int val; - - val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - val &= PCI_IRQ_DISABLE; - outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - release_region(cs->hw.niccy.cfg_reg, 0x40); - release_region(cs->hw.niccy.isac, 4); - } else { - release_region(cs->hw.niccy.isac, 2); - release_region(cs->hw.niccy.isac_ale, 2); - } -} - -static void niccy_reset(struct IsdnCardState *cs) -{ - if (cs->subtyp == NICCY_PCI) { - int val; - - val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - val |= PCI_IRQ_ENABLE; - outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG); - } - inithscxisac(cs, 3); -} - -static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - niccy_reset(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return 0; - case CARD_RELEASE: - release_io_niccy(cs); - return 0; - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - niccy_reset(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return 0; - case CARD_TEST: - return 0; - } - return 0; -} - -#ifdef __ISAPNP__ -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_niccy(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, niccy_revision); - printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_NICCY) - return 0; -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d = NULL; - int err; - - pnp_c = pnp_find_card(ISAPNP_VENDOR('S', 'D', 'A'), - ISAPNP_FUNCTION(0x0150), pnp_c); - if (pnp_c) { - pnp_d = pnp_find_dev(pnp_c, - ISAPNP_VENDOR('S', 'D', 'A'), - ISAPNP_FUNCTION(0x0150), pnp_d); - if (!pnp_d) { - printk(KERN_ERR "NiccyPnP: PnP error card " - "found, no device\n"); - return 0; - } - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev " - "ret(%d)\n", __func__, err); - return 0; - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[2] = pnp_port_start(pnp_d, 1); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1] || - !card->para[2]) { - printk(KERN_ERR "NiccyPnP:some resources are " - "missing %ld/%lx/%lx\n", - card->para[0], card->para[1], - card->para[2]); - pnp_disable_dev(pnp_d); - return 0; - } - } else - printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n"); - } -#endif - if (card->para[1]) { - cs->hw.niccy.isac = card->para[1] + ISAC_PNP; - cs->hw.niccy.hscx = card->para[1] + HSCX_PNP; - cs->hw.niccy.isac_ale = card->para[2] + ISAC_PNP; - cs->hw.niccy.hscx_ale = card->para[2] + HSCX_PNP; - cs->hw.niccy.cfg_reg = 0; - cs->subtyp = NICCY_PNP; - cs->irq = card->para[0]; - if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) { - printk(KERN_WARNING "HiSax: NICCY data port %x-%x " - "already in use\n", - cs->hw.niccy.isac, cs->hw.niccy.isac + 1); - return 0; - } - if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) { - printk(KERN_WARNING "HiSax: NICCY address port %x-%x " - "already in use\n", - cs->hw.niccy.isac_ale, - cs->hw.niccy.isac_ale + 1); - release_region(cs->hw.niccy.isac, 2); - return 0; - } - } else { -#ifdef CONFIG_PCI - static struct pci_dev *niccy_dev; - - u_int pci_ioaddr; - cs->subtyp = 0; - if ((niccy_dev = hisax_find_pci_device(PCI_VENDOR_ID_SATSAGEM, - PCI_DEVICE_ID_SATSAGEM_NICCY, - niccy_dev))) { - if (pci_enable_device(niccy_dev)) - return 0; - /* get IRQ */ - if (!niccy_dev->irq) { - printk(KERN_WARNING - "Niccy: No IRQ for PCI card found\n"); - return 0; - } - cs->irq = niccy_dev->irq; - cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0); - if (!cs->hw.niccy.cfg_reg) { - printk(KERN_WARNING - "Niccy: No IO-Adr for PCI cfg found\n"); - return 0; - } - pci_ioaddr = pci_resource_start(niccy_dev, 1); - if (!pci_ioaddr) { - printk(KERN_WARNING - "Niccy: No IO-Adr for PCI card found\n"); - return 0; - } - cs->subtyp = NICCY_PCI; - } else { - printk(KERN_WARNING "Niccy: No PCI card found\n"); - return 0; - } - cs->irq_flags |= IRQF_SHARED; - cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA; - cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR; - cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA; - cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR; - if (!request_region(cs->hw.niccy.isac, 4, "niccy")) { - printk(KERN_WARNING - "HiSax: NICCY data port %x-%x already in use\n", - cs->hw.niccy.isac, cs->hw.niccy.isac + 4); - return 0; - } - if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) { - printk(KERN_WARNING - "HiSax: NICCY pci port %x-%x already in use\n", - cs->hw.niccy.cfg_reg, - cs->hw.niccy.cfg_reg + 0x40); - release_region(cs->hw.niccy.isac, 4); - return 0; - } -#else - printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n"); - printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n"); - return 0; -#endif /* CONFIG_PCI */ - } - printk(KERN_INFO "HiSax: NICCY %s config irq:%d data:0x%X ale:0x%X\n", - (cs->subtyp == 1) ? "PnP" : "PCI", - cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale); - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &niccy_card_msg; - cs->irq_func = &niccy_interrupt; - ISACVersion(cs, "Niccy:"); - if (HscxVersion(cs, "Niccy:")) { - printk(KERN_WARNING "Niccy: wrong HSCX versions check IO " - "address\n"); - release_io_niccy(cs); - return 0; - } - return 1; -} diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c deleted file mode 100644 index 32b4bbd18eb9..000000000000 --- a/drivers/isdn/hisax/nj_s.c +++ /dev/null @@ -1,294 +0,0 @@ -/* $Id: nj_s.c,v 2.13.2.4 2004/01/16 01:53:48 keil Exp $ - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "isdnl1.h" -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/ppp_defs.h> -#include "netjet.h" - -static const char *NETjet_S_revision = "$Revision: 2.13.2.4 $"; - -static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) -{ - return (5); -} - -static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) -{ -} - -static irqreturn_t -netjet_s_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, s1val, s0val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - s1val = bytein(cs->hw.njet.base + NETJET_IRQSTAT1); - if (!(s1val & NETJET_ISACIRQ)) { - val = NETjet_ReadIC(cs, ISAC_ISTA); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "tiger: i1 %x %x", s1val, val); - if (val) { - isac_interrupt(cs, val); - NETjet_WriteIC(cs, ISAC_MASK, 0xFF); - NETjet_WriteIC(cs, ISAC_MASK, 0x0); - } - s1val = 1; - } else - s1val = 0; - /* - * read/write stat0 is better, because lower IRQ rate - * Note the IRQ is on for 125 us if a condition match - * thats long on modern CPU and so the IRQ is reentered - * all the time. - */ - s0val = bytein(cs->hw.njet.base + NETJET_IRQSTAT0); - if ((s0val | s1val) == 0) { // shared IRQ - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (s0val) - byteout(cs->hw.njet.base + NETJET_IRQSTAT0, s0val); - /* start new code 13/07/00 GE */ - /* set bits in sval to indicate which page is free */ - if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) - /* the 2nd write page is free */ - s0val = 0x08; - else /* the 1st write page is free */ - s0val = 0x04; - if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) - /* the 2nd read page is free */ - s0val |= 0x02; - else /* the 1st read page is free */ - s0val |= 0x01; - if (s0val != cs->hw.njet.last_is0) /* we have a DMA interrupt */ - { - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - printk(KERN_WARNING "nj LOCK_ATOMIC s0val %x->%x\n", - cs->hw.njet.last_is0, s0val); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } - cs->hw.njet.irqstat0 = s0val; - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) - /* we have a read dma int */ - read_tiger(cs); - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) - /* we have a write dma int */ - write_tiger(cs); - /* end new code 13/07/00 GE */ - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -reset_netjet_s(struct IsdnCardState *cs) -{ - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - /* now edge triggered for TJ320 GE 13/07/00 */ - /* see comment in IRQ function */ - if (cs->subtyp) /* TJ320 */ - cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */ - else - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - cs->hw.njet.auxd = 0; - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); -} - -static int -NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_netjet_s(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_netjet(cs); - return (0); - case CARD_INIT: - reset_netjet_s(cs); - inittiger(cs); - spin_lock_irqsave(&cs->lock, flags); - clear_pending_isac_ints(cs); - initisac(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int njs_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs) -{ - u32 cfg; - - if (pci_enable_device(dev_netjet)) - return (0); - pci_set_master(dev_netjet); - cs->irq = dev_netjet->irq; - if (!cs->irq) { - printk(KERN_WARNING "NETjet-S: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.njet.base = pci_resource_start(dev_netjet, 0); - if (!cs->hw.njet.base) { - printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n"); - return (0); - } - /* the TJ300 and TJ320 must be detected, the IRQ handling is different - * unfortunately the chips use the same device ID, but the TJ320 has - * the bit20 in status PCI cfg register set - */ - pci_read_config_dword(dev_netjet, 0x04, &cfg); - if (cfg & 0x00100000) - cs->subtyp = 1; /* TJ320 */ - else - cs->subtyp = 0; /* TJ300 */ - /* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */ - if ((dev_netjet->subsystem_vendor == 0x55) && - (dev_netjet->subsystem_device == 0x02)) { - printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n"); - printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n"); - return (0); - } - /* end new code */ - - return (1); -} - -static int njs_cs_init(struct IsdnCard *card, struct IsdnCardState *cs) -{ - - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; - - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - - cs->hw.njet.auxd = 0xC0; - cs->hw.njet.dmactrl = 0; - - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - - switch (((NETjet_ReadIC(cs, ISAC_RBCH) >> 5) & 3)) - { - case 0: - return 1; /* end loop */ - - case 3: - printk(KERN_WARNING "NETjet-S: NETspider-U PCI card found\n"); - return -1; /* continue looping */ - - default: - printk(KERN_WARNING "NETjet-S: No PCI card found\n"); - return 0; /* end loop & function */ - } - return 1; /* end loop */ -} - -static int njs_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs) -{ - const int bytecnt = 256; - - printk(KERN_INFO - "NETjet-S: %s card configured at %#lx IRQ %d\n", - cs->subtyp ? "TJ320" : "TJ300", cs->hw.njet.base, cs->irq); - if (!request_region(cs->hw.njet.base, bytecnt, "netjet-s isdn")) { - printk(KERN_WARNING - "HiSax: NETjet-S config port %#lx-%#lx already in use\n", - cs->hw.njet.base, - cs->hw.njet.base + bytecnt); - return (0); - } - cs->readisac = &NETjet_ReadIC; - cs->writeisac = &NETjet_WriteIC; - cs->readisacfifo = &NETjet_ReadICfifo; - cs->writeisacfifo = &NETjet_WriteICfifo; - cs->BC_Read_Reg = &dummyrr; - cs->BC_Write_Reg = &dummywr; - cs->BC_Send_Data = &netjet_fill_dma; - setup_isac(cs); - cs->cardmsg = &NETjet_S_card_msg; - cs->irq_func = &netjet_s_interrupt; - cs->irq_flags |= IRQF_SHARED; - ISACVersion(cs, "NETjet-S:"); - - return (1); -} - -static struct pci_dev *dev_netjet = NULL; - -int setup_netjet_s(struct IsdnCard *card) -{ - int ret; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - -#ifdef __BIG_ENDIAN -#error "not running on big endian machines now" -#endif - strcpy(tmp, NETjet_S_revision); - printk(KERN_INFO "HiSax: Traverse Tech. NETjet-S driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_NETJET_S) - return (0); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - - for (;;) - { - if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { - ret = njs_pci_probe(dev_netjet, cs); - if (!ret) - return (0); - } else { - printk(KERN_WARNING "NETjet-S: No PCI card found\n"); - return (0); - } - - ret = njs_cs_init(card, cs); - if (!ret) - return (0); - if (ret > 0) - break; - /* otherwise, ret < 0, continue looping */ - } - - return njs_cs_init_rest(card, cs); -} diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c deleted file mode 100644 index 4e8adbede361..000000000000 --- a/drivers/isdn/hisax/nj_u.c +++ /dev/null @@ -1,258 +0,0 @@ -/* $Id: nj_u.c,v 2.14.2.3 2004/01/13 14:31:26 keil Exp $ - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "icc.h" -#include "isdnl1.h" -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/ppp_defs.h> -#include "netjet.h" - -static const char *NETjet_U_revision = "$Revision: 2.14.2.3 $"; - -static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off) -{ - return (5); -} - -static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value) -{ -} - -static irqreturn_t -netjet_u_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, sval; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (!((sval = bytein(cs->hw.njet.base + NETJET_IRQSTAT1)) & - NETJET_ISACIRQ)) { - val = NETjet_ReadIC(cs, ICC_ISTA); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "tiger: i1 %x %x", sval, val); - if (val) { - icc_interrupt(cs, val); - NETjet_WriteIC(cs, ICC_MASK, 0xFF); - NETjet_WriteIC(cs, ICC_MASK, 0x0); - } - } - /* start new code 13/07/00 GE */ - /* set bits in sval to indicate which page is free */ - if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ)) - /* the 2nd write page is free */ - sval = 0x08; - else /* the 1st write page is free */ - sval = 0x04; - if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) < - inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ)) - /* the 2nd read page is free */ - sval = sval | 0x02; - else /* the 1st read page is free */ - sval = sval | 0x01; - if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */ - { - if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; - } - cs->hw.njet.irqstat0 = sval; - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_READ)) - /* we have a read dma int */ - read_tiger(cs); - if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) != - (cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE)) - /* we have a write dma int */ - write_tiger(cs); - /* end new code 13/07/00 GE */ - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -reset_netjet_u(struct IsdnCardState *cs) -{ - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - cs->hw.njet.ctrl_reg = 0x40; /* Reset Off and status read clear */ - /* now edge triggered for TJ320 GE 13/07/00 */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - cs->hw.njet.auxd = 0xC0; - cs->hw.njet.dmactrl = 0; - byteout(cs->hw.njet.auxa, 0); - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); -} - -static int -NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_netjet_u(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_netjet(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inittiger(cs); - reset_netjet_u(cs); - clear_pending_icc_ints(cs); - initicc(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ICC_MASK, 0); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int nju_pci_probe(struct pci_dev *dev_netjet, struct IsdnCardState *cs) -{ - if (pci_enable_device(dev_netjet)) - return (0); - pci_set_master(dev_netjet); - cs->irq = dev_netjet->irq; - if (!cs->irq) { - printk(KERN_WARNING "NETspider-U: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.njet.base = pci_resource_start(dev_netjet, 0); - if (!cs->hw.njet.base) { - printk(KERN_WARNING "NETspider-U: No IO-Adr for PCI card found\n"); - return (0); - } - - return (1); -} - -static int nju_cs_init(struct IsdnCard *card, struct IsdnCardState *cs) -{ - cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA; - cs->hw.njet.isac = cs->hw.njet.base | NETJET_ISAC_OFF; - mdelay(10); - - cs->hw.njet.ctrl_reg = 0xff; /* Reset On */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - - cs->hw.njet.ctrl_reg = 0x00; /* Reset Off and status read clear */ - byteout(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg); - mdelay(10); - - cs->hw.njet.auxd = 0xC0; - cs->hw.njet.dmactrl = 0; - - byteout(cs->hw.njet.auxa, 0); - byteout(cs->hw.njet.base + NETJET_AUXCTRL, ~NETJET_ISACIRQ); - byteout(cs->hw.njet.base + NETJET_IRQMASK1, NETJET_ISACIRQ); - byteout(cs->hw.njet.auxa, cs->hw.njet.auxd); - - switch (((NETjet_ReadIC(cs, ICC_RBCH) >> 5) & 3)) - { - case 3: - return 1; /* end loop */ - - case 0: - printk(KERN_WARNING "NETspider-U: NETjet-S PCI card found\n"); - return -1; /* continue looping */ - - default: - printk(KERN_WARNING "NETspider-U: No PCI card found\n"); - return 0; /* end loop & function */ - } - return 1; /* end loop */ -} - -static int nju_cs_init_rest(struct IsdnCard *card, struct IsdnCardState *cs) -{ - const int bytecnt = 256; - - printk(KERN_INFO - "NETspider-U: PCI card configured at %#lx IRQ %d\n", - cs->hw.njet.base, cs->irq); - if (!request_region(cs->hw.njet.base, bytecnt, "netspider-u isdn")) { - printk(KERN_WARNING - "HiSax: NETspider-U config port %#lx-%#lx " - "already in use\n", - cs->hw.njet.base, - cs->hw.njet.base + bytecnt); - return (0); - } - setup_icc(cs); - cs->readisac = &NETjet_ReadIC; - cs->writeisac = &NETjet_WriteIC; - cs->readisacfifo = &NETjet_ReadICfifo; - cs->writeisacfifo = &NETjet_WriteICfifo; - cs->BC_Read_Reg = &dummyrr; - cs->BC_Write_Reg = &dummywr; - cs->BC_Send_Data = &netjet_fill_dma; - cs->cardmsg = &NETjet_U_card_msg; - cs->irq_func = &netjet_u_interrupt; - cs->irq_flags |= IRQF_SHARED; - ICCVersion(cs, "NETspider-U:"); - - return (1); -} - -static struct pci_dev *dev_netjet = NULL; - -int setup_netjet_u(struct IsdnCard *card) -{ - int ret; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - -#ifdef __BIG_ENDIAN -#error "not running on big endian machines now" -#endif - - strcpy(tmp, NETjet_U_revision); - printk(KERN_INFO "HiSax: Traverse Tech. NETspider-U driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_NETJET_U) - return (0); - test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags); - - for (;;) - { - if ((dev_netjet = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_300, dev_netjet))) { - ret = nju_pci_probe(dev_netjet, cs); - if (!ret) - return (0); - } else { - printk(KERN_WARNING "NETspider-U: No PCI card found\n"); - return (0); - } - - ret = nju_cs_init(card, cs); - if (!ret) - return (0); - if (ret > 0) - break; - /* ret < 0 == continue looping */ - } - - return nju_cs_init_rest(card, cs); -} diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c deleted file mode 100644 index 6b8c3fbe3965..000000000000 --- a/drivers/isdn/hisax/q931.c +++ /dev/null @@ -1,1513 +0,0 @@ -/* $Id: q931.c,v 1.12.2.3 2004/01/13 14:31:26 keil Exp $ - * - * code to decode ITU Q.931 call control messages - * - * Author Jan den Ouden - * Copyright by Jan den Ouden - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Changelog: - * - * Pauline Middelink general improvements - * Beat Doebeli cause texts, display information element - * Karsten Keil cause texts, display information element for 1TR6 - * - */ - - -#include "hisax.h" -#include "l3_1tr6.h" - -void -iecpy(u_char *dest, u_char *iestart, int ieoffset) -{ - u_char *p; - int l; - - p = iestart + ieoffset + 2; - l = iestart[1] - ieoffset; - while (l--) - *dest++ = *p++; - *dest++ = '\0'; -} - -/* - * According to Table 4-2/Q.931 - */ -static -struct MessageType { - u_char nr; - char *descr; -} mtlist[] = { - - { - 0x1, "ALERTING" - }, - { - 0x2, "CALL PROCEEDING" - }, - { - 0x7, "CONNECT" - }, - { - 0xf, "CONNECT ACKNOWLEDGE" - }, - { - 0x3, "PROGRESS" - }, - { - 0x5, "SETUP" - }, - { - 0xd, "SETUP ACKNOWLEDGE" - }, - { - 0x24, "HOLD" - }, - { - 0x28, "HOLD ACKNOWLEDGE" - }, - { - 0x30, "HOLD REJECT" - }, - { - 0x31, "RETRIEVE" - }, - { - 0x33, "RETRIEVE ACKNOWLEDGE" - }, - { - 0x37, "RETRIEVE REJECT" - }, - { - 0x26, "RESUME" - }, - { - 0x2e, "RESUME ACKNOWLEDGE" - }, - { - 0x22, "RESUME REJECT" - }, - { - 0x25, "SUSPEND" - }, - { - 0x2d, "SUSPEND ACKNOWLEDGE" - }, - { - 0x21, "SUSPEND REJECT" - }, - { - 0x20, "USER INFORMATION" - }, - { - 0x45, "DISCONNECT" - }, - { - 0x4d, "RELEASE" - }, - { - 0x5a, "RELEASE COMPLETE" - }, - { - 0x46, "RESTART" - }, - { - 0x4e, "RESTART ACKNOWLEDGE" - }, - { - 0x60, "SEGMENT" - }, - { - 0x79, "CONGESTION CONTROL" - }, - { - 0x7b, "INFORMATION" - }, - { - 0x62, "FACILITY" - }, - { - 0x6e, "NOTIFY" - }, - { - 0x7d, "STATUS" - }, - { - 0x75, "STATUS ENQUIRY" - } -}; - -#define MTSIZE ARRAY_SIZE(mtlist) - -static -struct MessageType mt_n0[] = -{ - {MT_N0_REG_IND, "REGister INDication"}, - {MT_N0_CANC_IND, "CANCel INDication"}, - {MT_N0_FAC_STA, "FACility STAtus"}, - {MT_N0_STA_ACK, "STAtus ACKnowledge"}, - {MT_N0_STA_REJ, "STAtus REJect"}, - {MT_N0_FAC_INF, "FACility INFormation"}, - {MT_N0_INF_ACK, "INFormation ACKnowledge"}, - {MT_N0_INF_REJ, "INFormation REJect"}, - {MT_N0_CLOSE, "CLOSE"}, - {MT_N0_CLO_ACK, "CLOse ACKnowledge"} -}; - -#define MT_N0_LEN ARRAY_SIZE(mt_n0) - -static -struct MessageType mt_n1[] = -{ - {MT_N1_ESC, "ESCape"}, - {MT_N1_ALERT, "ALERT"}, - {MT_N1_CALL_SENT, "CALL SENT"}, - {MT_N1_CONN, "CONNect"}, - {MT_N1_CONN_ACK, "CONNect ACKnowledge"}, - {MT_N1_SETUP, "SETUP"}, - {MT_N1_SETUP_ACK, "SETUP ACKnowledge"}, - {MT_N1_RES, "RESume"}, - {MT_N1_RES_ACK, "RESume ACKnowledge"}, - {MT_N1_RES_REJ, "RESume REJect"}, - {MT_N1_SUSP, "SUSPend"}, - {MT_N1_SUSP_ACK, "SUSPend ACKnowledge"}, - {MT_N1_SUSP_REJ, "SUSPend REJect"}, - {MT_N1_USER_INFO, "USER INFO"}, - {MT_N1_DET, "DETach"}, - {MT_N1_DISC, "DISConnect"}, - {MT_N1_REL, "RELease"}, - {MT_N1_REL_ACK, "RELease ACKnowledge"}, - {MT_N1_CANC_ACK, "CANCel ACKnowledge"}, - {MT_N1_CANC_REJ, "CANCel REJect"}, - {MT_N1_CON_CON, "CONgestion CONtrol"}, - {MT_N1_FAC, "FACility"}, - {MT_N1_FAC_ACK, "FACility ACKnowledge"}, - {MT_N1_FAC_CAN, "FACility CANcel"}, - {MT_N1_FAC_REG, "FACility REGister"}, - {MT_N1_FAC_REJ, "FACility REJect"}, - {MT_N1_INFO, "INFOrmation"}, - {MT_N1_REG_ACK, "REGister ACKnowledge"}, - {MT_N1_REG_REJ, "REGister REJect"}, - {MT_N1_STAT, "STATus"} -}; - -#define MT_N1_LEN ARRAY_SIZE(mt_n1) - - -static int -prbits(char *dest, u_char b, int start, int len) -{ - char *dp = dest; - - b = b << (8 - start); - while (len--) { - if (b & 0x80) - *dp++ = '1'; - else - *dp++ = '0'; - b = b << 1; - } - return (dp - dest); -} - -static -u_char * -skipext(u_char *p) -{ - while (!(*p++ & 0x80)); - return (p); -} - -/* - * Cause Values According to Q.850 - * edescr: English description - * ddescr: German description used by Swissnet II (Swiss Telecom - * not yet written... - */ - -static -struct CauseValue { - u_char nr; - char *edescr; - char *ddescr; -} cvlist[] = { - - { - 0x01, "Unallocated (unassigned) number", "Nummer nicht zugeteilt" - }, - { - 0x02, "No route to specified transit network", "" - }, - { - 0x03, "No route to destination", "" - }, - { - 0x04, "Send special information tone", "" - }, - { - 0x05, "Misdialled trunk prefix", "" - }, - { - 0x06, "Channel unacceptable", "Kanal nicht akzeptierbar" - }, - { - 0x07, "Channel awarded and being delivered in an established channel", "" - }, - { - 0x08, "Preemption", "" - }, - { - 0x09, "Preemption - circuit reserved for reuse", "" - }, - { - 0x10, "Normal call clearing", "Normale Ausloesung" - }, - { - 0x11, "User busy", "TNB besetzt" - }, - { - 0x12, "No user responding", "" - }, - { - 0x13, "No answer from user (user alerted)", "" - }, - { - 0x14, "Subscriber absent", "" - }, - { - 0x15, "Call rejected", "" - }, - { - 0x16, "Number changed", "" - }, - { - 0x1a, "non-selected user clearing", "" - }, - { - 0x1b, "Destination out of order", "" - }, - { - 0x1c, "Invalid number format (address incomplete)", "" - }, - { - 0x1d, "Facility rejected", "" - }, - { - 0x1e, "Response to Status enquiry", "" - }, - { - 0x1f, "Normal, unspecified", "" - }, - { - 0x22, "No circuit/channel available", "" - }, - { - 0x26, "Network out of order", "" - }, - { - 0x27, "Permanent frame mode connection out-of-service", "" - }, - { - 0x28, "Permanent frame mode connection operational", "" - }, - { - 0x29, "Temporary failure", "" - }, - { - 0x2a, "Switching equipment congestion", "" - }, - { - 0x2b, "Access information discarded", "" - }, - { - 0x2c, "Requested circuit/channel not available", "" - }, - { - 0x2e, "Precedence call blocked", "" - }, - { - 0x2f, "Resource unavailable, unspecified", "" - }, - { - 0x31, "Quality of service unavailable", "" - }, - { - 0x32, "Requested facility not subscribed", "" - }, - { - 0x35, "Outgoing calls barred within CUG", "" - }, - { - 0x37, "Incoming calls barred within CUG", "" - }, - { - 0x39, "Bearer capability not authorized", "" - }, - { - 0x3a, "Bearer capability not presently available", "" - }, - { - 0x3e, "Inconsistency in designated outgoing access information and subscriber class ", " " - }, - { - 0x3f, "Service or option not available, unspecified", "" - }, - { - 0x41, "Bearer capability not implemented", "" - }, - { - 0x42, "Channel type not implemented", "" - }, - { - 0x43, "Requested facility not implemented", "" - }, - { - 0x44, "Only restricted digital information bearer capability is available", "" - }, - { - 0x4f, "Service or option not implemented", "" - }, - { - 0x51, "Invalid call reference value", "" - }, - { - 0x52, "Identified channel does not exist", "" - }, - { - 0x53, "A suspended call exists, but this call identity does not", "" - }, - { - 0x54, "Call identity in use", "" - }, - { - 0x55, "No call suspended", "" - }, - { - 0x56, "Call having the requested call identity has been cleared", "" - }, - { - 0x57, "User not member of CUG", "" - }, - { - 0x58, "Incompatible destination", "" - }, - { - 0x5a, "Non-existent CUG", "" - }, - { - 0x5b, "Invalid transit network selection", "" - }, - { - 0x5f, "Invalid message, unspecified", "" - }, - { - 0x60, "Mandatory information element is missing", "" - }, - { - 0x61, "Message type non-existent or not implemented", "" - }, - { - 0x62, "Message not compatible with call state or message type non-existent or not implemented ", " " - }, - { - 0x63, "Information element/parameter non-existent or not implemented", "" - }, - { - 0x64, "Invalid information element contents", "" - }, - { - 0x65, "Message not compatible with call state", "" - }, - { - 0x66, "Recovery on timer expiry", "" - }, - { - 0x67, "Parameter non-existent or not implemented - passed on", "" - }, - { - 0x6e, "Message with unrecognized parameter discarded", "" - }, - { - 0x6f, "Protocol error, unspecified", "" - }, - { - 0x7f, "Interworking, unspecified", "" - }, -}; - -#define CVSIZE ARRAY_SIZE(cvlist) - -static -int -prcause(char *dest, u_char *p) -{ - u_char *end; - char *dp = dest; - int i, cause; - - end = p + p[1] + 1; - p += 2; - dp += sprintf(dp, " coding "); - dp += prbits(dp, *p, 7, 2); - dp += sprintf(dp, " location "); - dp += prbits(dp, *p, 4, 4); - *dp++ = '\n'; - p = skipext(p); - - cause = 0x7f & *p++; - - /* locate cause value */ - for (i = 0; i < CVSIZE; i++) - if (cvlist[i].nr == cause) - break; - - /* display cause value if it exists */ - if (i == CVSIZE) - dp += sprintf(dp, "Unknown cause type %x!\n", cause); - else - dp += sprintf(dp, " cause value %x : %s \n", cause, cvlist[i].edescr); - - while (!0) { - if (p > end) - break; - dp += sprintf(dp, " diag attribute %d ", *p++ & 0x7f); - dp += sprintf(dp, " rej %d ", *p & 0x7f); - if (*p & 0x80) { - *dp++ = '\n'; - break; - } else - dp += sprintf(dp, " av %d\n", (*++p) & 0x7f); - } - return (dp - dest); - -} - -static -struct MessageType cause_1tr6[] = -{ - {CAUSE_InvCRef, "Invalid Call Reference"}, - {CAUSE_BearerNotImpl, "Bearer Service Not Implemented"}, - {CAUSE_CIDunknown, "Caller Identity unknown"}, - {CAUSE_CIDinUse, "Caller Identity in Use"}, - {CAUSE_NoChans, "No Channels available"}, - {CAUSE_FacNotImpl, "Facility Not Implemented"}, - {CAUSE_FacNotSubscr, "Facility Not Subscribed"}, - {CAUSE_OutgoingBarred, "Outgoing calls barred"}, - {CAUSE_UserAccessBusy, "User Access Busy"}, - {CAUSE_NegativeGBG, "Negative GBG"}, - {CAUSE_UnknownGBG, "Unknown GBG"}, - {CAUSE_NoSPVknown, "No SPV known"}, - {CAUSE_DestNotObtain, "Destination not obtainable"}, - {CAUSE_NumberChanged, "Number changed"}, - {CAUSE_OutOfOrder, "Out Of Order"}, - {CAUSE_NoUserResponse, "No User Response"}, - {CAUSE_UserBusy, "User Busy"}, - {CAUSE_IncomingBarred, "Incoming Barred"}, - {CAUSE_CallRejected, "Call Rejected"}, - {CAUSE_NetworkCongestion, "Network Congestion"}, - {CAUSE_RemoteUser, "Remote User initiated"}, - {CAUSE_LocalProcErr, "Local Procedure Error"}, - {CAUSE_RemoteProcErr, "Remote Procedure Error"}, - {CAUSE_RemoteUserSuspend, "Remote User Suspend"}, - {CAUSE_RemoteUserResumed, "Remote User Resumed"}, - {CAUSE_UserInfoDiscarded, "User Info Discarded"} -}; - -static int cause_1tr6_len = ARRAY_SIZE(cause_1tr6); - -static int -prcause_1tr6(char *dest, u_char *p) -{ - char *dp = dest; - int i, cause; - - p++; - if (0 == *p) { - dp += sprintf(dp, " OK (cause length=0)\n"); - return (dp - dest); - } else if (*p > 1) { - dp += sprintf(dp, " coding "); - dp += prbits(dp, p[2], 7, 2); - dp += sprintf(dp, " location "); - dp += prbits(dp, p[2], 4, 4); - *dp++ = '\n'; - } - p++; - cause = 0x7f & *p; - - /* locate cause value */ - for (i = 0; i < cause_1tr6_len; i++) - if (cause_1tr6[i].nr == cause) - break; - - /* display cause value if it exists */ - if (i == cause_1tr6_len) - dp += sprintf(dp, "Unknown cause type %x!\n", cause); - else - dp += sprintf(dp, " cause value %x : %s \n", cause, cause_1tr6[i].descr); - - return (dp - dest); - -} - -static int -prchident(char *dest, u_char *p) -{ - char *dp = dest; - - p += 2; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - return (dp - dest); -} - -static int -prcalled(char *dest, u_char *p) -{ - int l; - char *dp = dest; - - p++; - l = *p++ - 1; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - dp += sprintf(dp, " number digits "); - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} -static int -prcalling(char *dest, u_char *p) -{ - int l; - char *dp = dest; - - p++; - l = *p++ - 1; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if (!(*p & 0x80)) { - dp += sprintf(dp, " octet 3a "); - dp += prbits(dp, *++p, 8, 8); - *dp++ = '\n'; - l--; - } - p++; - - dp += sprintf(dp, " number digits "); - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} - -static -int -prbearer(char *dest, u_char *p) -{ - char *dp = dest, ch; - - p += 2; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - dp += sprintf(dp, " octet 4 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if ((*p++ & 0x1f) == 0x18) { - dp += sprintf(dp, " octet 4.1 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - /* check for user information layer 1 */ - if ((*p & 0x60) == 0x20) { - ch = ' '; - do { - dp += sprintf(dp, " octet 5%c ", ch); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if (ch == ' ') - ch = 'a'; - else - ch++; - } - while (!(*p++ & 0x80)); - } - /* check for user information layer 2 */ - if ((*p & 0x60) == 0x40) { - dp += sprintf(dp, " octet 6 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - /* check for user information layer 3 */ - if ((*p & 0x60) == 0x60) { - dp += sprintf(dp, " octet 7 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - return (dp - dest); -} - - -static -int -prbearer_ni1(char *dest, u_char *p) -{ - char *dp = dest; - u_char len; - - p++; - len = *p++; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p, 8, 8); - switch (*p++) { - case 0x80: - dp += sprintf(dp, " Speech"); - break; - case 0x88: - dp += sprintf(dp, " Unrestricted digital information"); - break; - case 0x90: - dp += sprintf(dp, " 3.1 kHz audio"); - break; - default: - dp += sprintf(dp, " Unknown information-transfer capability"); - } - *dp++ = '\n'; - dp += sprintf(dp, " octet 4 "); - dp += prbits(dp, *p, 8, 8); - switch (*p++) { - case 0x90: - dp += sprintf(dp, " 64 kbps, circuit mode"); - break; - case 0xc0: - dp += sprintf(dp, " Packet mode"); - break; - default: - dp += sprintf(dp, " Unknown transfer mode"); - } - *dp++ = '\n'; - if (len > 2) { - dp += sprintf(dp, " octet 5 "); - dp += prbits(dp, *p, 8, 8); - switch (*p++) { - case 0x21: - dp += sprintf(dp, " Rate adaption\n"); - dp += sprintf(dp, " octet 5a "); - dp += prbits(dp, *p, 8, 8); - break; - case 0xa2: - dp += sprintf(dp, " u-law"); - break; - default: - dp += sprintf(dp, " Unknown UI layer 1 protocol"); - } - *dp++ = '\n'; - } - return (dp - dest); -} - -static int -general(char *dest, u_char *p) -{ - char *dp = dest; - char ch = ' '; - int l, octet = 3; - - p++; - l = *p++; - /* Iterate over all octets in the information element */ - while (l--) { - dp += sprintf(dp, " octet %d%c ", octet, ch); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - - /* last octet in group? */ - if (*p & 0x80) { - octet++; - ch = ' '; - } else if (ch == ' ') - ch = 'a'; - else - ch++; - } - return (dp - dest); -} - -static int -general_ni1(char *dest, u_char *p) -{ - char *dp = dest; - char ch = ' '; - int l, octet = 3; - - p++; - l = *p++; - /* Iterate over all octets in the information element */ - while (l--) { - dp += sprintf(dp, " octet %d%c ", octet, ch); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - - /* last octet in group? */ - if (*p++ & 0x80) { - octet++; - ch = ' '; - } else if (ch == ' ') - ch = 'a'; - else - ch++; - } - return (dp - dest); -} - -static int -prcharge(char *dest, u_char *p) -{ - char *dp = dest; - int l; - - p++; - l = *p++ - 1; - dp += sprintf(dp, " GEA "); - dp += prbits(dp, *p++, 8, 8); - dp += sprintf(dp, " Anzahl: "); - /* Iterate over all octets in the * information element */ - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} -static int -prtext(char *dest, u_char *p) -{ - char *dp = dest; - int l; - - p++; - l = *p++; - dp += sprintf(dp, " "); - /* Iterate over all octets in the * information element */ - while (l--) - *dp++ = *p++; - *dp++ = '\n'; - return (dp - dest); -} - -static int -prfeatureind(char *dest, u_char *p) -{ - char *dp = dest; - - p += 2; /* skip id, len */ - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p, 8, 8); - *dp++ = '\n'; - if (!(*p++ & 0x80)) { - dp += sprintf(dp, " octet 4 "); - dp += prbits(dp, *p++, 8, 8); - *dp++ = '\n'; - } - dp += sprintf(dp, " Status: "); - switch (*p) { - case 0: - dp += sprintf(dp, "Idle"); - break; - case 1: - dp += sprintf(dp, "Active"); - break; - case 2: - dp += sprintf(dp, "Prompt"); - break; - case 3: - dp += sprintf(dp, "Pending"); - break; - default: - dp += sprintf(dp, "(Reserved)"); - break; - } - *dp++ = '\n'; - return (dp - dest); -} - -static -struct DTag { /* Display tags */ - u_char nr; - char *descr; -} dtaglist[] = { - { 0x82, "Continuation" }, - { 0x83, "Called address" }, - { 0x84, "Cause" }, - { 0x85, "Progress indicator" }, - { 0x86, "Notification indicator" }, - { 0x87, "Prompt" }, - { 0x88, "Accumlated digits" }, - { 0x89, "Status" }, - { 0x8a, "Inband" }, - { 0x8b, "Calling address" }, - { 0x8c, "Reason" }, - { 0x8d, "Calling party name" }, - { 0x8e, "Called party name" }, - { 0x8f, "Original called name" }, - { 0x90, "Redirecting name" }, - { 0x91, "Connected name" }, - { 0x92, "Originating restrictions" }, - { 0x93, "Date & time of day" }, - { 0x94, "Call Appearance ID" }, - { 0x95, "Feature address" }, - { 0x96, "Redirection name" }, - { 0x9e, "Text" }, -}; -#define DTAGSIZE ARRAY_SIZE(dtaglist) - -static int -disptext_ni1(char *dest, u_char *p) -{ - char *dp = dest; - int l, tag, len, i; - - p++; - l = *p++ - 1; - if (*p++ != 0x80) { - dp += sprintf(dp, " Unknown display type\n"); - return (dp - dest); - } - /* Iterate over all tag,length,text fields */ - while (l > 0) { - tag = *p++; - len = *p++; - l -= len + 2; - /* Don't space or skip */ - if ((tag == 0x80) || (tag == 0x81)) p++; - else { - for (i = 0; i < DTAGSIZE; i++) - if (tag == dtaglist[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != DTAGSIZE) { - dp += sprintf(dp, " %s: ", dtaglist[i].descr); - while (len--) - *dp++ = *p++; - } else { - dp += sprintf(dp, " (unknown display tag %2x): ", tag); - while (len--) - *dp++ = *p++; - } - dp += sprintf(dp, "\n"); - } - } - return (dp - dest); -} -static int -display(char *dest, u_char *p) -{ - char *dp = dest; - char ch = ' '; - int l, octet = 3; - - p++; - l = *p++; - /* Iterate over all octets in the * display-information element */ - dp += sprintf(dp, " \""); - while (l--) { - dp += sprintf(dp, "%c", *p++); - - /* last octet in group? */ - if (*p & 0x80) { - octet++; - ch = ' '; - } else if (ch == ' ') - ch = 'a'; - - else - ch++; - } - *dp++ = '\"'; - *dp++ = '\n'; - return (dp - dest); -} - -static int -prfacility(char *dest, u_char *p) -{ - char *dp = dest; - int l, l2; - - p++; - l = *p++; - dp += sprintf(dp, " octet 3 "); - dp += prbits(dp, *p++, 8, 8); - dp += sprintf(dp, "\n"); - l -= 1; - - while (l > 0) { - dp += sprintf(dp, " octet 4 "); - dp += prbits(dp, *p++, 8, 8); - dp += sprintf(dp, "\n"); - dp += sprintf(dp, " octet 5 %d\n", l2 = *p++ & 0x7f); - l -= 2; - dp += sprintf(dp, " contents "); - while (l2--) { - dp += sprintf(dp, "%2x ", *p++); - l--; - } - dp += sprintf(dp, "\n"); - } - - return (dp - dest); -} - -static -struct InformationElement { - u_char nr; - char *descr; - int (*f) (char *, u_char *); -} ielist[] = { - - { - 0x00, "Segmented message", general - }, - { - 0x04, "Bearer capability", prbearer - }, - { - 0x08, "Cause", prcause - }, - { - 0x10, "Call identity", general - }, - { - 0x14, "Call state", general - }, - { - 0x18, "Channel identification", prchident - }, - { - 0x1c, "Facility", prfacility - }, - { - 0x1e, "Progress indicator", general - }, - { - 0x20, "Network-specific facilities", general - }, - { - 0x27, "Notification indicator", general - }, - { - 0x28, "Display", display - }, - { - 0x29, "Date/Time", general - }, - { - 0x2c, "Keypad facility", general - }, - { - 0x34, "Signal", general - }, - { - 0x40, "Information rate", general - }, - { - 0x42, "End-to-end delay", general - }, - { - 0x43, "Transit delay selection and indication", general - }, - { - 0x44, "Packet layer binary parameters", general - }, - { - 0x45, "Packet layer window size", general - }, - { - 0x46, "Packet size", general - }, - { - 0x47, "Closed user group", general - }, - { - 0x4a, "Reverse charge indication", general - }, - { - 0x6c, "Calling party number", prcalling - }, - { - 0x6d, "Calling party subaddress", general - }, - { - 0x70, "Called party number", prcalled - }, - { - 0x71, "Called party subaddress", general - }, - { - 0x74, "Redirecting number", general - }, - { - 0x78, "Transit network selection", general - }, - { - 0x79, "Restart indicator", general - }, - { - 0x7c, "Low layer compatibility", general - }, - { - 0x7d, "High layer compatibility", general - }, - { - 0x7e, "User-user", general - }, - { - 0x7f, "Escape for extension", general - }, -}; - - -#define IESIZE ARRAY_SIZE(ielist) - -static -struct InformationElement ielist_ni1[] = { - { 0x04, "Bearer Capability", prbearer_ni1 }, - { 0x08, "Cause", prcause }, - { 0x14, "Call State", general_ni1 }, - { 0x18, "Channel Identification", prchident }, - { 0x1e, "Progress Indicator", general_ni1 }, - { 0x27, "Notification Indicator", general_ni1 }, - { 0x2c, "Keypad Facility", prtext }, - { 0x32, "Information Request", general_ni1 }, - { 0x34, "Signal", general_ni1 }, - { 0x38, "Feature Activation", general_ni1 }, - { 0x39, "Feature Indication", prfeatureind }, - { 0x3a, "Service Profile Identification (SPID)", prtext }, - { 0x3b, "Endpoint Identifier", general_ni1 }, - { 0x6c, "Calling Party Number", prcalling }, - { 0x6d, "Calling Party Subaddress", general_ni1 }, - { 0x70, "Called Party Number", prcalled }, - { 0x71, "Called Party Subaddress", general_ni1 }, - { 0x74, "Redirecting Number", general_ni1 }, - { 0x78, "Transit Network Selection", general_ni1 }, - { 0x7c, "Low Layer Compatibility", general_ni1 }, - { 0x7d, "High Layer Compatibility", general_ni1 }, -}; - - -#define IESIZE_NI1 ARRAY_SIZE(ielist_ni1) - -static -struct InformationElement ielist_ni1_cs5[] = { - { 0x1d, "Operator system access", general_ni1 }, - { 0x2a, "Display text", disptext_ni1 }, -}; - -#define IESIZE_NI1_CS5 ARRAY_SIZE(ielist_ni1_cs5) - -static -struct InformationElement ielist_ni1_cs6[] = { - { 0x7b, "Call appearance", general_ni1 }, -}; - -#define IESIZE_NI1_CS6 ARRAY_SIZE(ielist_ni1_cs6) - -static struct InformationElement we_0[] = -{ - {WE0_cause, "Cause", prcause_1tr6}, - {WE0_connAddr, "Connecting Address", prcalled}, - {WE0_callID, "Call IDentity", general}, - {WE0_chanID, "Channel IDentity", general}, - {WE0_netSpecFac, "Network Specific Facility", general}, - {WE0_display, "Display", general}, - {WE0_keypad, "Keypad", general}, - {WE0_origAddr, "Origination Address", prcalled}, - {WE0_destAddr, "Destination Address", prcalled}, - {WE0_userInfo, "User Info", general} -}; - -#define WE_0_LEN ARRAY_SIZE(we_0) - -static struct InformationElement we_6[] = -{ - {WE6_serviceInd, "Service Indicator", general}, - {WE6_chargingInfo, "Charging Information", prcharge}, - {WE6_date, "Date", prtext}, - {WE6_facSelect, "Facility Select", general}, - {WE6_facStatus, "Facility Status", general}, - {WE6_statusCalled, "Status Called", general}, - {WE6_addTransAttr, "Additional Transmission Attributes", general} -}; -#define WE_6_LEN ARRAY_SIZE(we_6) - -int -QuickHex(char *txt, u_char *p, int cnt) -{ - register int i; - register char *t = txt; - - for (i = 0; i < cnt; i++) { - *t++ = ' '; - *t++ = hex_asc_hi(p[i]); - *t++ = hex_asc_lo(p[i]); - } - *t++ = 0; - return (t - txt); -} - -void -LogFrame(struct IsdnCardState *cs, u_char *buf, int size) -{ - char *dp; - - if (size < 1) - return; - dp = cs->dlog; - if (size < MAX_DLOG_SPACE / 3 - 10) { - *dp++ = 'H'; - *dp++ = 'E'; - *dp++ = 'X'; - *dp++ = ':'; - dp += QuickHex(dp, buf, size); - dp--; - *dp++ = '\n'; - *dp = 0; - HiSax_putstatus(cs, NULL, cs->dlog); - } else - HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size); -} - -void -dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir) -{ - u_char *bend, *buf; - char *dp; - unsigned char pd, cr_l, cr, mt; - unsigned char sapi, tei, ftyp; - int i, cset = 0, cs_old = 0, cs_fest = 0; - int size, finish = 0; - - if (skb->len < 3) - return; - /* display header */ - dp = cs->dlog; - dp += jiftime(dp, jiffies); - *dp++ = ' '; - sapi = skb->data[0] >> 2; - tei = skb->data[1] >> 1; - ftyp = skb->data[2]; - buf = skb->data; - dp += sprintf(dp, "frame %s ", dir ? "network->user" : "user->network"); - size = skb->len; - - if (tei == GROUP_TEI) { - if (sapi == CTRL_SAPI) { /* sapi 0 */ - if (ftyp == 3) { - dp += sprintf(dp, "broadcast\n"); - buf += 3; - size -= 3; - } else { - dp += sprintf(dp, "no UI broadcast\n"); - finish = 1; - } - } else if (sapi == TEI_SAPI) { - dp += sprintf(dp, "tei management\n"); - finish = 1; - } else { - dp += sprintf(dp, "unknown sapi %d broadcast\n", sapi); - finish = 1; - } - } else { - if (sapi == CTRL_SAPI) { - if (!(ftyp & 1)) { /* IFrame */ - dp += sprintf(dp, "with tei %d\n", tei); - buf += 4; - size -= 4; - } else { - dp += sprintf(dp, "SFrame with tei %d\n", tei); - finish = 1; - } - } else { - dp += sprintf(dp, "unknown sapi %d tei %d\n", sapi, tei); - finish = 1; - } - } - bend = skb->data + skb->len; - if (buf >= bend) { - dp += sprintf(dp, "frame too short\n"); - finish = 1; - } - if (finish) { - *dp = 0; - HiSax_putstatus(cs, NULL, cs->dlog); - return; - } - if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */ - /* locate message type */ - pd = *buf++; - cr_l = *buf++; - if (cr_l) - cr = *buf++; - else - cr = 0; - mt = *buf++; - if (pd == PROTO_DIS_N0) { /* N0 */ - for (i = 0; i < MT_N0_LEN; i++) - if (mt_n0[i].nr == mt) - break; - /* display message type if it exists */ - if (i == MT_N0_LEN) - dp += sprintf(dp, "callref %d %s size %d unknown message type N0 %x!\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt); - else - dp += sprintf(dp, "callref %d %s size %d message type %s\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt_n0[i].descr); - } else { /* N1 */ - for (i = 0; i < MT_N1_LEN; i++) - if (mt_n1[i].nr == mt) - break; - /* display message type if it exists */ - if (i == MT_N1_LEN) - dp += sprintf(dp, "callref %d %s size %d unknown message type N1 %x!\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt); - else - dp += sprintf(dp, "callref %d %s size %d message type %s\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt_n1[i].descr); - } - - /* display each information element */ - while (buf < bend) { - /* Is it a single octet information element? */ - if (*buf & 0x80) { - switch ((*buf >> 4) & 7) { - case 1: - dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - cs_old = cset; - cset = *buf & 7; - cs_fest = *buf & 8; - break; - case 3: - dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); - break; - case 2: - if (*buf == 0xa0) { - dp += sprintf(dp, " More data\n"); - break; - } - if (*buf == 0xa1) { - dp += sprintf(dp, " Sending complete\n"); - } - break; - /* fall through */ - default: - dp += sprintf(dp, " Reserved %x\n", *buf); - break; - } - buf++; - continue; - } - /* No, locate it in the table */ - if (cset == 0) { - for (i = 0; i < WE_0_LEN; i++) - if (*buf == we_0[i].nr) - break; - - /* When found, give appropriate msg */ - if (i != WE_0_LEN) { - dp += sprintf(dp, " %s\n", we_0[i].descr); - dp += we_0[i].f(dp, buf); - } else - dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); - } else if (cset == 6) { - for (i = 0; i < WE_6_LEN; i++) - if (*buf == we_6[i].nr) - break; - - /* When found, give appropriate msg */ - if (i != WE_6_LEN) { - dp += sprintf(dp, " %s\n", we_6[i].descr); - dp += we_6[i].f(dp, buf); - } else - dp += sprintf(dp, " Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); - } else - dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); - /* Skip to next element */ - if (cs_fest == 8) { - cset = cs_old; - cs_old = 0; - cs_fest = 0; - } - buf += buf[1] + 2; - } - } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_NI1)) { /* NI-1 */ - /* locate message type */ - buf++; - cr_l = *buf++; - if (cr_l) - cr = *buf++; - else - cr = 0; - mt = *buf++; - for (i = 0; i < MTSIZE; i++) - if (mtlist[i].nr == mt) - break; - - /* display message type if it exists */ - if (i == MTSIZE) - dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt); - else - dp += sprintf(dp, "callref %d %s size %d message type %s\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mtlist[i].descr); - - /* display each information element */ - while (buf < bend) { - /* Is it a single octet information element? */ - if (*buf & 0x80) { - switch ((*buf >> 4) & 7) { - case 1: - dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - cs_old = cset; - cset = *buf & 7; - cs_fest = *buf & 8; - break; - default: - dp += sprintf(dp, " Unknown single-octet IE %x\n", *buf); - break; - } - buf++; - continue; - } - /* No, locate it in the table */ - if (cset == 0) { - for (i = 0; i < IESIZE_NI1; i++) - if (*buf == ielist_ni1[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != IESIZE_NI1) { - dp += sprintf(dp, " %s\n", ielist_ni1[i].descr); - dp += ielist_ni1[i].f(dp, buf); - } else - dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); - } else if (cset == 5) { - for (i = 0; i < IESIZE_NI1_CS5; i++) - if (*buf == ielist_ni1_cs5[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != IESIZE_NI1_CS5) { - dp += sprintf(dp, " %s\n", ielist_ni1_cs5[i].descr); - dp += ielist_ni1_cs5[i].f(dp, buf); - } else - dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); - } else if (cset == 6) { - for (i = 0; i < IESIZE_NI1_CS6; i++) - if (*buf == ielist_ni1_cs6[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != IESIZE_NI1_CS6) { - dp += sprintf(dp, " %s\n", ielist_ni1_cs6[i].descr); - dp += ielist_ni1_cs6[i].f(dp, buf); - } else - dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); - } else - dp += sprintf(dp, " Unknown Codeset %d attribute %x attribute size %d\n", cset, *buf, buf[1]); - - /* Skip to next element */ - if (cs_fest == 8) { - cset = cs_old; - cs_old = 0; - cs_fest = 0; - } - buf += buf[1] + 2; - } - } else if ((buf[0] == 8) && (cs->protocol == ISDN_PTYPE_EURO)) { /* EURO */ - /* locate message type */ - buf++; - cr_l = *buf++; - if (cr_l) - cr = *buf++; - else - cr = 0; - mt = *buf++; - for (i = 0; i < MTSIZE; i++) - if (mtlist[i].nr == mt) - break; - - /* display message type if it exists */ - if (i == MTSIZE) - dp += sprintf(dp, "callref %d %s size %d unknown message type %x!\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mt); - else - dp += sprintf(dp, "callref %d %s size %d message type %s\n", - cr & 0x7f, (cr & 0x80) ? "called" : "caller", - size, mtlist[i].descr); - - /* display each information element */ - while (buf < bend) { - /* Is it a single octet information element? */ - if (*buf & 0x80) { - switch ((*buf >> 4) & 7) { - case 1: - dp += sprintf(dp, " Shift %x\n", *buf & 0xf); - break; - case 3: - dp += sprintf(dp, " Congestion level %x\n", *buf & 0xf); - break; - case 5: - dp += sprintf(dp, " Repeat indicator %x\n", *buf & 0xf); - break; - case 2: - if (*buf == 0xa0) { - dp += sprintf(dp, " More data\n"); - break; - } - if (*buf == 0xa1) { - dp += sprintf(dp, " Sending complete\n"); - } - break; - /* fall through */ - default: - dp += sprintf(dp, " Reserved %x\n", *buf); - break; - } - buf++; - continue; - } - /* No, locate it in the table */ - for (i = 0; i < IESIZE; i++) - if (*buf == ielist[i].nr) - break; - - /* When not found, give appropriate msg */ - if (i != IESIZE) { - dp += sprintf(dp, " %s\n", ielist[i].descr); - dp += ielist[i].f(dp, buf); - } else - dp += sprintf(dp, " attribute %x attribute size %d\n", *buf, buf[1]); - - /* Skip to next element */ - buf += buf[1] + 2; - } - } else { - dp += sprintf(dp, "Unknown protocol %x!", buf[0]); - } - *dp = 0; - HiSax_putstatus(cs, NULL, cs->dlog); -} diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c deleted file mode 100644 index 4e7d0aa227ad..000000000000 --- a/drivers/isdn/hisax/s0box.c +++ /dev/null @@ -1,260 +0,0 @@ -/* $Id: s0box.c,v 2.6.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for Creatix S0BOX - * - * Author Enrik Berkhan - * Copyright by Enrik Berkhan <enrik@starfleet.inka.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *s0box_revision = "$Revision: 2.6.2.4 $"; - -static inline void -writereg(unsigned int padr, signed int addr, u_char off, u_char val) { - outb_p(0x1c, padr + 2); - outb_p(0x14, padr + 2); - outb_p((addr + off) & 0x7f, padr); - outb_p(0x16, padr + 2); - outb_p(val, padr); - outb_p(0x17, padr + 2); - outb_p(0x14, padr + 2); - outb_p(0x1c, padr + 2); -} - -static u_char nibtab[] = { 1, 9, 5, 0xd, 3, 0xb, 7, 0xf, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 8, 4, 0xc, 2, 0xa, 6, 0xe }; - -static inline u_char -readreg(unsigned int padr, signed int addr, u_char off) { - register u_char n1, n2; - - outb_p(0x1c, padr + 2); - outb_p(0x14, padr + 2); - outb_p((addr + off) | 0x80, padr); - outb_p(0x16, padr + 2); - outb_p(0x17, padr + 2); - n1 = (inb_p(padr + 1) >> 3) & 0x17; - outb_p(0x16, padr + 2); - n2 = (inb_p(padr + 1) >> 3) & 0x17; - outb_p(0x14, padr + 2); - outb_p(0x1c, padr + 2); - return nibtab[n1] | (nibtab[n2] << 4); -} - -static inline void -read_fifo(unsigned int padr, signed int adr, u_char *data, int size) -{ - int i; - register u_char n1, n2; - - outb_p(0x1c, padr + 2); - outb_p(0x14, padr + 2); - outb_p(adr | 0x80, padr); - outb_p(0x16, padr + 2); - for (i = 0; i < size; i++) { - outb_p(0x17, padr + 2); - n1 = (inb_p(padr + 1) >> 3) & 0x17; - outb_p(0x16, padr + 2); - n2 = (inb_p(padr + 1) >> 3) & 0x17; - *(data++) = nibtab[n1] | (nibtab[n2] << 4); - } - outb_p(0x14, padr + 2); - outb_p(0x1c, padr + 2); - return; -} - -static inline void -write_fifo(unsigned int padr, signed int adr, u_char *data, int size) -{ - int i; - outb_p(0x1c, padr + 2); - outb_p(0x14, padr + 2); - outb_p(adr & 0x7f, padr); - for (i = 0; i < size; i++) { - outb_p(0x16, padr + 2); - outb_p(*(data++), padr); - outb_p(0x17, padr + 2); - } - outb_p(0x14, padr + 2); - outb_p(0x1c, padr + 2); - return; -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.isacfifo, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset)); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[hscx], offset, value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[nr], reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscxfifo[nr], ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -s0box_interrupt(int intno, void *dev_id) -{ -#define MAXCOUNT 5 - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - int count = 0; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - count++; - val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_ISTA); - if (val && count < MAXCOUNT) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_ISTA); - if (val && count < MAXCOUNT) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - if (count >= MAXCOUNT) - printk(KERN_WARNING "S0Box: more than %d loops in s0box_interrupt\n", count); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.isac, ISAC_MASK, 0x0); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); - writereg(cs->hw.teles3.cfg_reg, cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_s0box(struct IsdnCardState *cs) -{ - release_region(cs->hw.teles3.cfg_reg, 8); -} - -static int -S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - break; - case CARD_RELEASE: - release_io_s0box(cs); - break; - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case CARD_TEST: - break; - } - return (0); -} - -int setup_s0box(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, s0box_revision); - printk(KERN_INFO "HiSax: S0Box IO driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_S0BOX) - return (0); - - cs->hw.teles3.cfg_reg = card->para[1]; - cs->hw.teles3.hscx[0] = -0x20; - cs->hw.teles3.hscx[1] = 0x0; - cs->hw.teles3.isac = 0x20; - cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e; - cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; - cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; - cs->irq = card->para[0]; - if (!request_region(cs->hw.teles3.cfg_reg, 8, "S0Box parallel I/O")) { - printk(KERN_WARNING "HiSax: S0Box ports %x-%x already in use\n", - cs->hw.teles3.cfg_reg, - cs->hw.teles3.cfg_reg + 7); - return 0; - } - printk(KERN_INFO "HiSax: S0Box config irq:%d isac:0x%x cfg:0x%x\n", - cs->irq, - cs->hw.teles3.isac, cs->hw.teles3.cfg_reg); - printk(KERN_INFO "HiSax: hscx A:0x%x hscx B:0x%x\n", - cs->hw.teles3.hscx[0], cs->hw.teles3.hscx[1]); - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &S0Box_card_msg; - cs->irq_func = &s0box_interrupt; - ISACVersion(cs, "S0Box:"); - if (HscxVersion(cs, "S0Box:")) { - printk(KERN_WARNING - "S0Box: wrong HSCX versions check IO address\n"); - release_io_s0box(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c deleted file mode 100644 index db906cb37a3f..000000000000 --- a/drivers/isdn/hisax/saphir.c +++ /dev/null @@ -1,296 +0,0 @@ -/* $Id: saphir.c,v 1.10.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for HST Saphir 1 - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to HST High Soft Tech GmbH - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static char *saphir_rev = "$Revision: 1.10.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define ISAC_DATA 0 -#define HSCX_DATA 1 -#define ADDRESS_REG 2 -#define IRQ_REG 3 -#define SPARE_REG 4 -#define RESET_REG 5 - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, - offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, - offset + (hscx ? 0x40 : 0), value); -} - -#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \ - cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \ - cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \ - cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \ - cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -saphir_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - /* Watchdog */ - if (cs->hw.saphir.timer.function) - mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ); - else - printk(KERN_WARNING "saphir: Spurious timer!\n"); - writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0); - writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0); - writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -SaphirWatchDog(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.saphir.timer); - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - /* 5 sec WatchDog, so read at least every 4 sec */ - cs->readisac(cs, ISAC_RBCH); - spin_unlock_irqrestore(&cs->lock, flags); - mod_timer(&cs->hw.saphir.timer, jiffies + 1 * HZ); -} - -static void -release_io_saphir(struct IsdnCardState *cs) -{ - byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff); - del_timer(&cs->hw.saphir.timer); - cs->hw.saphir.timer.function = NULL; - if (cs->hw.saphir.cfg_reg) - release_region(cs->hw.saphir.cfg_reg, 6); -} - -static int -saphir_reset(struct IsdnCardState *cs) -{ - u_char irq_val; - - switch (cs->irq) { - case 5: irq_val = 0; - break; - case 3: irq_val = 1; - break; - case 11: - irq_val = 2; - break; - case 12: - irq_val = 3; - break; - case 15: - irq_val = 4; - break; - default: - printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n", - cs->irq); - return (1); - } - byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); - byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1); - mdelay(10); - byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0); - mdelay(10); - byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val); - byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02); - return (0); -} - -static int -saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - saphir_reset(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_saphir(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - - -int setup_saphir(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, saphir_rev); - printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_HSTSAPHIR) - return (0); - - /* IO-Ports */ - cs->hw.saphir.cfg_reg = card->para[1]; - cs->hw.saphir.isac = card->para[1] + ISAC_DATA; - cs->hw.saphir.hscx = card->para[1] + HSCX_DATA; - cs->hw.saphir.ale = card->para[1] + ADDRESS_REG; - cs->irq = card->para[0]; - if (!request_region(cs->hw.saphir.cfg_reg, 6, "saphir")) { - printk(KERN_WARNING - "HiSax: HST Saphir config port %x-%x already in use\n", - cs->hw.saphir.cfg_reg, - cs->hw.saphir.cfg_reg + 5); - return (0); - } - - printk(KERN_INFO "HiSax: HST Saphir config irq:%d io:0x%X\n", - cs->irq, cs->hw.saphir.cfg_reg); - - setup_isac(cs); - timer_setup(&cs->hw.saphir.timer, SaphirWatchDog, 0); - cs->hw.saphir.timer.expires = jiffies + 4 * HZ; - add_timer(&cs->hw.saphir.timer); - if (saphir_reset(cs)) { - release_io_saphir(cs); - return (0); - } - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &saphir_card_msg; - cs->irq_func = &saphir_interrupt; - ISACVersion(cs, "saphir:"); - if (HscxVersion(cs, "saphir:")) { - printk(KERN_WARNING - "saphir: wrong HSCX versions check IO address\n"); - release_io_saphir(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c deleted file mode 100644 index c0b97b893495..000000000000 --- a/drivers/isdn/hisax/sedlbauer.c +++ /dev/null @@ -1,873 +0,0 @@ -/* $Id: sedlbauer.c,v 1.34.2.6 2004/01/24 20:47:24 keil Exp $ - * - * low level stuff for Sedlbauer cards - * includes support for the Sedlbauer speed star (speed star II), - * support for the Sedlbauer speed fax+, - * support for the Sedlbauer ISDN-Controller PC/104 and - * support for the Sedlbauer speed pci - * derived from the original file asuscom.c from Karsten Keil - * - * Author Marcus Niemann - * Copyright by Marcus Niemann <niemann@www-bib.fh-bielefeld.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Karsten Keil - * Sedlbauer AG for informations - * Edgar Toernig - * - */ - -/* Supported cards: - * Card: Chip: Configuration: Comment: - * --------------------------------------------------------------------- - * Speed Card ISAC_HSCX DIP-SWITCH - * Speed Win ISAC_HSCX ISAPNP - * Speed Fax+ ISAC_ISAR ISAPNP Full analog support - * Speed Star ISAC_HSCX CARDMGR - * Speed Win2 IPAC ISAPNP - * ISDN PC/104 IPAC DIP-SWITCH - * Speed Star2 IPAC CARDMGR - * Speed PCI IPAC PCI PNP - * Speed Fax+ ISAC_ISAR PCI PNP Full analog support - * - * Important: - * For the sedlbauer speed fax+ to work properly you have to download - * the firmware onto the card. - * For example: hisaxctrl <DriverID> 9 ISAR.BIN - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "ipac.h" -#include "hscx.h" -#include "isar.h" -#include "isdnl1.h" -#include <linux/pci.h> -#include <linux/isapnp.h> - -static const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $"; - -static const char *Sedlbauer_Types[] = -{"None", "speed card/win", "speed star", "speed fax+", - "speed win II / ISDN PC/104", "speed star II", "speed pci", - "speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"}; - -#define PCI_SUBVENDOR_SPEEDFAX_PYRAMID 0x51 -#define PCI_SUBVENDOR_HST_SAPHIR3 0x52 -#define PCI_SUBVENDOR_SEDLBAUER_PCI 0x53 -#define PCI_SUBVENDOR_SPEEDFAX_PCI 0x54 -#define PCI_SUB_ID_SEDLBAUER 0x01 - -#define SEDL_SPEED_CARD_WIN 1 -#define SEDL_SPEED_STAR 2 -#define SEDL_SPEED_FAX 3 -#define SEDL_SPEED_WIN2_PC104 4 -#define SEDL_SPEED_STAR2 5 -#define SEDL_SPEED_PCI 6 -#define SEDL_SPEEDFAX_PYRAMID 7 -#define SEDL_SPEEDFAX_PCI 8 -#define HST_SAPHIR3 9 - -#define SEDL_CHIP_TEST 0 -#define SEDL_CHIP_ISAC_HSCX 1 -#define SEDL_CHIP_ISAC_ISAR 2 -#define SEDL_CHIP_IPAC 3 - -#define SEDL_BUS_ISA 1 -#define SEDL_BUS_PCI 2 -#define SEDL_BUS_PCMCIA 3 - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define SEDL_HSCX_ISA_RESET_ON 0 -#define SEDL_HSCX_ISA_RESET_OFF 1 -#define SEDL_HSCX_ISA_ISAC 2 -#define SEDL_HSCX_ISA_HSCX 3 -#define SEDL_HSCX_ISA_ADR 4 - -#define SEDL_HSCX_PCMCIA_RESET 0 -#define SEDL_HSCX_PCMCIA_ISAC 1 -#define SEDL_HSCX_PCMCIA_HSCX 2 -#define SEDL_HSCX_PCMCIA_ADR 4 - -#define SEDL_ISAR_ISA_ISAC 4 -#define SEDL_ISAR_ISA_ISAR 6 -#define SEDL_ISAR_ISA_ADR 8 -#define SEDL_ISAR_ISA_ISAR_RESET_ON 10 -#define SEDL_ISAR_ISA_ISAR_RESET_OFF 12 - -#define SEDL_IPAC_ANY_ADR 0 -#define SEDL_IPAC_ANY_IPAC 2 - -#define SEDL_IPAC_PCI_BASE 0 -#define SEDL_IPAC_PCI_ADR 0xc0 -#define SEDL_IPAC_PCI_IPAC 0xc8 -#define SEDL_ISAR_PCI_ADR 0xc8 -#define SEDL_ISAR_PCI_ISAC 0xd0 -#define SEDL_ISAR_PCI_ISAR 0xe0 -#define SEDL_ISAR_PCI_ISAR_RESET_ON 0x01 -#define SEDL_ISAR_PCI_ISAR_RESET_OFF 0x18 -#define SEDL_ISAR_PCI_LED1 0x08 -#define SEDL_ISAR_PCI_LED2 0x10 - -#define SEDL_RESET 0x3 /* same as DOS driver */ - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - - byteout(ale, off); - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - insb(adr, data, size); -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - byteout(ale, off); - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - byteout(ale, off); - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0, data, size); -} - -static u_char -ReadISAC_IPAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset | 0x80)); -} - -static void -WriteISAC_IPAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, offset | 0x80, value); -} - -static void -ReadISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - readfifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); -} - -static void -WriteISACfifo_IPAC(struct IsdnCardState *cs, u_char *data, int size) -{ - writefifo(cs->hw.sedl.adr, cs->hw.sedl.isac, 0x80, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.sedl.adr, - cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.sedl.adr, - cs->hw.sedl.hscx, offset + (hscx ? 0x40 : 0), value); -} - -/* ISAR access routines - * mode = 0 access with IRQ on - * mode = 1 access with IRQ off - * mode = 2 access with IRQ off and using last offset - */ - -static u_char -ReadISAR(struct IsdnCardState *cs, int mode, u_char offset) -{ - if (mode == 0) - return (readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset)); - else if (mode == 1) - byteout(cs->hw.sedl.adr, offset); - return (bytein(cs->hw.sedl.hscx)); -} - -static void -WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value) -{ - if (mode == 0) - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, offset, value); - else { - if (mode == 1) - byteout(cs->hw.sedl.adr, offset); - byteout(cs->hw.sedl.hscx, value); - } -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.sedl.adr, \ - cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0)) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.sedl.adr, \ - cs->hw.sedl.hscx, reg + (nr ? 0x40 : 0), data) - -#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.sedl.adr, \ - cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.sedl.adr, \ - cs->hw.sedl.hscx, (nr ? 0x40 : 0), ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -sedlbauer_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if ((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && (*cs->busy_flag == 1)) { - /* The card tends to generate interrupts while being removed - causing us to just crash the kernel. bad. */ - spin_unlock_irqrestore(&cs->lock, flags); - printk(KERN_WARNING "Sedlbauer: card not available!\n"); - return IRQ_NONE; - } - - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_MASK + 0x40, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -sedlbauer_interrupt_ipac(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char ista, val, icnt = 5; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA); -Start_IPAC: - if (cs->debug & L1_DEB_IPAC) - debugl1(cs, "IPAC ISTA %02X", ista); - if (ista & 0x0f) { - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, HSCX_ISTA + 0x40); - if (ista & 0x01) - val |= 0x01; - if (ista & 0x04) - val |= 0x02; - if (ista & 0x08) - val |= 0x04; - if (val) - hscx_int_main(cs, val); - } - if (ista & 0x20) { - val = 0xfe & readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA | 0x80); - if (val) { - isac_interrupt(cs, val); - } - } - if (ista & 0x10) { - val = 0x01; - isac_interrupt(cs, val); - } - ista = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ISTA); - if ((ista & 0x3f) && icnt) { - icnt--; - goto Start_IPAC; - } - if (!icnt) - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Sedlbauer IRQ LOOP"); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xC0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t -sedlbauer_interrupt_isar(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - int cnt = 5; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT); -Start_ISAR: - if (val & ISAR_IRQSTA) - isar_int_main(cs); - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT); - if ((val & ISAR_IRQSTA) && --cnt) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "ISAR IntStat after IntRoutine"); - goto Start_ISAR; - } - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_ISTA); - if (val && --cnt) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - if (!cnt) - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "Sedlbauer IRQ LOOP"); - - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, 0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, ISAC_MASK, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, ISAR_IRQBIT, ISAR_IRQMSK); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_sedlbauer(struct IsdnCardState *cs) -{ - int bytecnt = 8; - - if (cs->subtyp == SEDL_SPEED_FAX) { - bytecnt = 16; - } else if (cs->hw.sedl.bus == SEDL_BUS_PCI) { - bytecnt = 256; - } - if (cs->hw.sedl.cfg_reg) - release_region(cs->hw.sedl.cfg_reg, bytecnt); -} - -static void -reset_sedlbauer(struct IsdnCardState *cs) -{ - printk(KERN_INFO "Sedlbauer: resetting card\n"); - - if (!((cs->hw.sedl.bus == SEDL_BUS_PCMCIA) && - (cs->hw.sedl.chip == SEDL_CHIP_ISAC_HSCX))) { - if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x20); - mdelay(2); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_POTA2, 0x0); - mdelay(10); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_CONF, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ACFG, 0xff); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_AOE, 0x0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_MASK, 0xc0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_PCFG, 0x12); - } else if ((cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) && - (cs->hw.sedl.bus == SEDL_BUS_PCI)) { - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_on); - mdelay(2); - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off); - mdelay(10); - } else { - byteout(cs->hw.sedl.reset_on, SEDL_RESET); /* Reset On */ - mdelay(2); - byteout(cs->hw.sedl.reset_off, 0); /* Reset Off */ - mdelay(10); - } - } -} - -static int -Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_sedlbauer(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - if (cs->hw.sedl.bus == SEDL_BUS_PCI) - /* disable all IRQ */ - byteout(cs->hw.sedl.cfg_reg + 5, 0); - if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - spin_lock_irqsave(&cs->lock, flags); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, - ISAR_IRQBIT, 0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, - ISAC_MASK, 0xFF); - reset_sedlbauer(cs); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, - ISAR_IRQBIT, 0); - writereg(cs->hw.sedl.adr, cs->hw.sedl.isac, - ISAC_MASK, 0xFF); - spin_unlock_irqrestore(&cs->lock, flags); - } - release_io_sedlbauer(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - if (cs->hw.sedl.bus == SEDL_BUS_PCI) - /* enable all IRQ */ - byteout(cs->hw.sedl.cfg_reg + 5, 0x02); - reset_sedlbauer(cs); - if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - clear_pending_isac_ints(cs); - writereg(cs->hw.sedl.adr, cs->hw.sedl.hscx, - ISAR_IRQBIT, 0); - initisac(cs); - initisar(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - /* RESET Receiver and Transmitter */ - cs->writeisac(cs, ISAC_CMDR, 0x41); - } else { - inithscxisac(cs, 3); - } - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - case MDL_INFO_CONN: - if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) - return (0); - spin_lock_irqsave(&cs->lock, flags); - if ((long) arg) - cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED2; - else - cs->hw.sedl.reset_off &= ~SEDL_ISAR_PCI_LED1; - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case MDL_INFO_REL: - if (cs->subtyp != SEDL_SPEEDFAX_PYRAMID) - return (0); - spin_lock_irqsave(&cs->lock, flags); - if ((long) arg) - cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED2; - else - cs->hw.sedl.reset_off |= SEDL_ISAR_PCI_LED1; - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - return (0); -} - -#ifdef __ISAPNP__ -static struct isapnp_device_id sedl_ids[] = { - { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), - ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), - (unsigned long) "Speed win" }, - { ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02), - ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02), - (unsigned long) "Speed Fax+" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &sedl_ids[0]; -static struct pnp_card *pnp_c = NULL; - -static int setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) -{ - struct IsdnCardState *cs = card->cs; - struct pnp_dev *pnp_d; - - if (!isapnp_present()) - return -1; - - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - - if (card->para[0] == -1 || !card->para[1]) { - printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n", - card->para[0], card->para[1]); - pnp_disable_dev(pnp_d); - return (0); - } - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (ipid->function == ISAPNP_FUNCTION(0x2)) { - cs->subtyp = SEDL_SPEED_FAX; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - *bytecnt = 16; - } else { - cs->subtyp = SEDL_SPEED_CARD_WIN; - cs->hw.sedl.chip = SEDL_CHIP_TEST; - } - - return (1); - } else { - printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n"); - return (0); - } - } - ipid++; - pnp_c = NULL; - } - - printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n"); - return -1; -} -#else - -static int setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt) -{ - return -1; -} -#endif /* __ISAPNP__ */ - -#ifdef CONFIG_PCI -static struct pci_dev *dev_sedl = NULL; - -static int setup_sedlbauer_pci(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - u16 sub_vendor_id, sub_id; - - if ((dev_sedl = hisax_find_pci_device(PCI_VENDOR_ID_TIGERJET, - PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) { - if (pci_enable_device(dev_sedl)) - return (0); - cs->irq = dev_sedl->irq; - if (!cs->irq) { - printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0); - } else { - printk(KERN_WARNING "Sedlbauer: No PCI card found\n"); - return (0); - } - cs->irq_flags |= IRQF_SHARED; - cs->hw.sedl.bus = SEDL_BUS_PCI; - sub_vendor_id = dev_sedl->subsystem_vendor; - sub_id = dev_sedl->subsystem_device; - printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n", - sub_vendor_id, sub_id); - printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n", - cs->hw.sedl.cfg_reg); - if (sub_id != PCI_SUB_ID_SEDLBAUER) { - printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id); - return (0); - } - if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PYRAMID; - } else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - cs->subtyp = SEDL_SPEEDFAX_PCI; - } else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = HST_SAPHIR3; - } else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) { - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - cs->subtyp = SEDL_SPEED_PCI; - } else { - printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n", - sub_vendor_id); - return (0); - } - - cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON; - cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF; - byteout(cs->hw.sedl.cfg_reg, 0xff); - byteout(cs->hw.sedl.cfg_reg, 0x00); - byteout(cs->hw.sedl.cfg_reg + 2, 0xdd); - byteout(cs->hw.sedl.cfg_reg + 5, 0); /* disable all IRQ */ - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_on); - mdelay(2); - byteout(cs->hw.sedl.cfg_reg + 3, cs->hw.sedl.reset_off); - mdelay(10); - - return (1); -} - -#else - -static int setup_sedlbauer_pci(struct IsdnCard *card) -{ - return (1); -} - -#endif /* CONFIG_PCI */ - -int setup_sedlbauer(struct IsdnCard *card) -{ - int bytecnt = 8, ver, val, rc; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, Sedlbauer_revision); - printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp)); - - if (cs->typ == ISDN_CTYPE_SEDLBAUER) { - cs->subtyp = SEDL_SPEED_CARD_WIN; - cs->hw.sedl.bus = SEDL_BUS_ISA; - cs->hw.sedl.chip = SEDL_CHIP_TEST; - } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_PCMCIA) { - cs->subtyp = SEDL_SPEED_STAR; - cs->hw.sedl.bus = SEDL_BUS_PCMCIA; - cs->hw.sedl.chip = SEDL_CHIP_TEST; - } else if (cs->typ == ISDN_CTYPE_SEDLBAUER_FAX) { - cs->subtyp = SEDL_SPEED_FAX; - cs->hw.sedl.bus = SEDL_BUS_ISA; - cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR; - } else - return (0); - - bytecnt = 8; - if (card->para[1]) { - cs->hw.sedl.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - bytecnt = 16; - } - } else { - rc = setup_sedlbauer_isapnp(card, &bytecnt); - if (!rc) - return (0); - if (rc > 0) - goto ready; - - /* Probe for Sedlbauer speed pci */ - rc = setup_sedlbauer_pci(card); - if (!rc) - return (0); - - bytecnt = 256; - } - -ready: - - /* In case of the sedlbauer pcmcia card, this region is in use, - * reserved for us by the card manager. So we do not check it - * here, it would fail. - */ - if (cs->hw.sedl.bus != SEDL_BUS_PCMCIA && - !request_region(cs->hw.sedl.cfg_reg, bytecnt, "sedlbauer isdn")) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.sedl.cfg_reg, - cs->hw.sedl.cfg_reg + bytecnt); - return (0); - } - - printk(KERN_INFO - "Sedlbauer: defined at 0x%x-0x%x IRQ %d\n", - cs->hw.sedl.cfg_reg, - cs->hw.sedl.cfg_reg + bytecnt, - cs->irq); - - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Sedl_card_msg; - -/* - * testing ISA and PCMCIA Cards for IPAC, default is ISAC - * do not test for PCI card, because ports are different - * and PCI card uses only IPAC (for the moment) - */ - if (cs->hw.sedl.bus != SEDL_BUS_PCI) { - val = readreg(cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR, - cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC, IPAC_ID); - printk(KERN_DEBUG "Sedlbauer: testing IPAC version %x\n", val); - if ((val == 1) || (val == 2)) { - /* IPAC */ - cs->subtyp = SEDL_SPEED_WIN2_PC104; - if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { - cs->subtyp = SEDL_SPEED_STAR2; - } - cs->hw.sedl.chip = SEDL_CHIP_IPAC; - } else { - /* ISAC_HSCX oder ISAC_ISAR */ - if (cs->hw.sedl.chip == SEDL_CHIP_TEST) { - cs->hw.sedl.chip = SEDL_CHIP_ISAC_HSCX; - } - } - } - -/* - * hw.sedl.chip is now properly set - */ - printk(KERN_INFO "Sedlbauer: %s detected\n", - Sedlbauer_Types[cs->subtyp]); - - setup_isac(cs); - if (cs->hw.sedl.chip == SEDL_CHIP_IPAC) { - if (cs->hw.sedl.bus == SEDL_BUS_PCI) { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_PCI_IPAC; - } else { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_IPAC_ANY_IPAC; - } - test_and_set_bit(HW_IPAC, &cs->HW_Flags); - cs->readisac = &ReadISAC_IPAC; - cs->writeisac = &WriteISAC_IPAC; - cs->readisacfifo = &ReadISACfifo_IPAC; - cs->writeisacfifo = &WriteISACfifo_IPAC; - cs->irq_func = &sedlbauer_interrupt_ipac; - val = readreg(cs->hw.sedl.adr, cs->hw.sedl.isac, IPAC_ID); - printk(KERN_INFO "Sedlbauer: IPAC version %x\n", val); - } else { - /* ISAC_HSCX oder ISAC_ISAR */ - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - if (cs->hw.sedl.bus == SEDL_BUS_PCI) { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + - SEDL_ISAR_PCI_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + - SEDL_ISAR_PCI_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + - SEDL_ISAR_PCI_ISAR; - } else { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + - SEDL_ISAR_ISA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + - SEDL_ISAR_ISA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + - SEDL_ISAR_ISA_ISAR; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + - SEDL_ISAR_ISA_ISAR_RESET_ON; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + - SEDL_ISAR_ISA_ISAR_RESET_OFF; - } - cs->bcs[0].hw.isar.reg = &cs->hw.sedl.isar; - cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar; - test_and_set_bit(HW_ISAR, &cs->HW_Flags); - cs->irq_func = &sedlbauer_interrupt_isar; - cs->auxcmd = &isar_auxcmd; - ISACVersion(cs, "Sedlbauer:"); - cs->BC_Read_Reg = &ReadISAR; - cs->BC_Write_Reg = &WriteISAR; - cs->BC_Send_Data = &isar_fill_fifo; - bytecnt = 3; - while (bytecnt) { - ver = ISARVersion(cs, "Sedlbauer:"); - if (ver < 0) - printk(KERN_WARNING - "Sedlbauer: wrong ISAR version (ret = %d)\n", ver); - else - break; - reset_sedlbauer(cs); - bytecnt--; - } - if (!bytecnt) { - release_io_sedlbauer(cs); - return (0); - } - } else { - if (cs->hw.sedl.bus == SEDL_BUS_PCMCIA) { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET; - cs->irq_flags |= IRQF_SHARED; - } else { - cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR; - cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC; - cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_HSCX; - cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_ON; - cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_RESET_OFF; - } - cs->irq_func = &sedlbauer_interrupt; - ISACVersion(cs, "Sedlbauer:"); - - if (HscxVersion(cs, "Sedlbauer:")) { - printk(KERN_WARNING - "Sedlbauer: wrong HSCX versions check IO address\n"); - release_io_sedlbauer(cs); - return (0); - } - } - } - return (1); -} diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c deleted file mode 100644 index 92ef62d4caf4..000000000000 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ /dev/null @@ -1,209 +0,0 @@ -/*====================================================================== - - A Sedlbauer PCMCIA client driver - - This driver is for the Sedlbauer Speed Star and Speed Star II, - which are ISDN PCMCIA Cards. - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - <dahinds@users.sourceforge.net>. Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Modifications from dummy_cs.c are Copyright (C) 1999-2001 Marcus Niemann - <maniemann@users.sourceforge.net>. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in - which case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - - ======================================================================*/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <asm/io.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> -#include "hisax_cfg.h" - -MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Sedlbauer cards"); -MODULE_AUTHOR("Marcus Niemann"); -MODULE_LICENSE("Dual MPL/GPL"); - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -static int protocol = 2; /* EURO-ISDN Default */ -module_param(protocol, int, 0); - -static int sedlbauer_config(struct pcmcia_device *link); -static void sedlbauer_release(struct pcmcia_device *link); - -static void sedlbauer_detach(struct pcmcia_device *p_dev); - -typedef struct local_info_t { - struct pcmcia_device *p_dev; - int stop; - int cardnr; -} local_info_t; - -static int sedlbauer_probe(struct pcmcia_device *link) -{ - local_info_t *local; - - dev_dbg(&link->dev, "sedlbauer_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(local_info_t), GFP_KERNEL); - if (!local) return -ENOMEM; - local->cardnr = -1; - - local->p_dev = link; - link->priv = local; - - return sedlbauer_config(link); -} /* sedlbauer_attach */ - -static void sedlbauer_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "sedlbauer_detach(0x%p)\n", link); - - ((local_info_t *)link->priv)->stop = 1; - sedlbauer_release(link); - - /* This points to the parent local_info_t struct */ - kfree(link->priv); -} /* sedlbauer_detach */ - -static int sedlbauer_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - p_dev->io_lines = 3; - return pcmcia_request_io(p_dev); -} - -static int sedlbauer_config(struct pcmcia_device *link) -{ - int ret; - IsdnCard_t icard; - - dev_dbg(&link->dev, "sedlbauer_config(0x%p)\n", link); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC | - CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, sedlbauer_config_check, NULL); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - icard.para[0] = link->irq; - icard.para[1] = link->resource[0]->start; - icard.protocol = protocol; - icard.typ = ISDN_CTYPE_SEDLBAUER_PCMCIA; - - ret = hisax_init_pcmcia(link, - &(((local_info_t *)link->priv)->stop), &icard); - if (ret < 0) { - printk(KERN_ERR "sedlbauer_cs: failed to initialize SEDLBAUER PCMCIA %d with %pR\n", - ret, link->resource[0]); - sedlbauer_release(link); - return -ENODEV; - } else - ((local_info_t *)link->priv)->cardnr = ret; - - return 0; - -failed: - sedlbauer_release(link); - return -ENODEV; - -} /* sedlbauer_config */ - -static void sedlbauer_release(struct pcmcia_device *link) -{ - local_info_t *local = link->priv; - dev_dbg(&link->dev, "sedlbauer_release(0x%p)\n", link); - - if (local) { - if (local->cardnr >= 0) { - /* no unregister function with hisax */ - HiSax_closecard(local->cardnr); - } - } - - pcmcia_disable_device(link); -} /* sedlbauer_release */ - -static int sedlbauer_suspend(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->stop = 1; - - return 0; -} - -static int sedlbauer_resume(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->stop = 0; - - return 0; -} - - -static const struct pcmcia_device_id sedlbauer_ids[] = { - PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a), - PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90), - PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce), - PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe), - PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c), - PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae), -/* PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", 0x81fb79f5), */ /* too generic*/ - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids); - -static struct pcmcia_driver sedlbauer_driver = { - .owner = THIS_MODULE, - .name = "sedlbauer_cs", - .probe = sedlbauer_probe, - .remove = sedlbauer_detach, - .id_table = sedlbauer_ids, - .suspend = sedlbauer_suspend, - .resume = sedlbauer_resume, -}; -module_pcmcia_driver(sedlbauer_driver); diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c deleted file mode 100644 index 18cee6360d0a..000000000000 --- a/drivers/isdn/hisax/sportster.c +++ /dev/null @@ -1,267 +0,0 @@ -/* $Id: sportster.c,v 1.16.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for USR Sportster internal TA - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Christian "naddy" Weisgerber (3Com, US Robotics) for documentation - * - * - */ -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *sportster_revision = "$Revision: 1.16.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -#define SPORTSTER_ISAC 0xC000 -#define SPORTSTER_HSCXA 0x0000 -#define SPORTSTER_HSCXB 0x4000 -#define SPORTSTER_RES_IRQ 0x8000 -#define SPORTSTER_RESET 0x80 -#define SPORTSTER_INTE 0x40 - -static inline int -calc_off(unsigned int base, unsigned int off) -{ - return (base + ((off & 0xfc) << 8) + ((off & 3) << 1)); -} - -static inline void -read_fifo(unsigned int adr, u_char *data, int size) -{ - insb(adr, data, size); -} - -static void -write_fifo(unsigned int adr, u_char *data, int size) -{ - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (bytein(calc_off(cs->hw.spt.isac, offset))); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - byteout(calc_off(cs->hw.spt.isac, offset), value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo(cs->hw.spt.isac, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo(cs->hw.spt.isac, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (bytein(calc_off(cs->hw.spt.hscx[hscx], offset))); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - byteout(calc_off(cs->hw.spt.hscx[hscx], offset), value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) bytein(calc_off(cs->hw.spt.hscx[nr], reg)) -#define WRITEHSCX(cs, nr, reg, data) byteout(calc_off(cs->hw.spt.hscx[nr], reg), data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.spt.hscx[nr], ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.spt.hscx[nr], ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -sportster_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = READHSCX(cs, 1, HSCX_ISTA); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = ReadISAC(cs, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = READHSCX(cs, 1, HSCX_ISTA); - if (val) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = ReadISAC(cs, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - /* get a new irq impulse if there any pending */ - bytein(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ + 1); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_sportster(struct IsdnCardState *cs) -{ - int i, adr; - - byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, 0); - for (i = 0; i < 64; i++) { - adr = cs->hw.spt.cfg_reg + i * 1024; - release_region(adr, 8); - } -} - -static void -reset_sportster(struct IsdnCardState *cs) -{ - cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */ - byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); - mdelay(10); - cs->hw.spt.res_irq &= ~SPORTSTER_RESET; /* Reset Off */ - byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); - mdelay(10); -} - -static int -Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_sportster(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_sportster(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - reset_sportster(cs); - inithscxisac(cs, 1); - cs->hw.spt.res_irq |= SPORTSTER_INTE; /* IRQ On */ - byteout(cs->hw.spt.cfg_reg + SPORTSTER_RES_IRQ, cs->hw.spt.res_irq); - inithscxisac(cs, 2); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int get_io_range(struct IsdnCardState *cs) -{ - int i, j, adr; - - for (i = 0; i < 64; i++) { - adr = cs->hw.spt.cfg_reg + i * 1024; - if (!request_region(adr, 8, "sportster")) { - printk(KERN_WARNING "HiSax: USR Sportster config port " - "%x-%x already in use\n", - adr, adr + 8); - break; - } - } - if (i == 64) - return (1); - else { - for (j = 0; j < i; j++) { - adr = cs->hw.spt.cfg_reg + j * 1024; - release_region(adr, 8); - } - return (0); - } -} - -int setup_sportster(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, sportster_revision); - printk(KERN_INFO "HiSax: USR Sportster driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_SPORTSTER) - return (0); - - cs->hw.spt.cfg_reg = card->para[1]; - cs->irq = card->para[0]; - if (!get_io_range(cs)) - return (0); - cs->hw.spt.isac = cs->hw.spt.cfg_reg + SPORTSTER_ISAC; - cs->hw.spt.hscx[0] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXA; - cs->hw.spt.hscx[1] = cs->hw.spt.cfg_reg + SPORTSTER_HSCXB; - - switch (cs->irq) { - case 5: cs->hw.spt.res_irq = 1; - break; - case 7: cs->hw.spt.res_irq = 2; - break; - case 10:cs->hw.spt.res_irq = 3; - break; - case 11:cs->hw.spt.res_irq = 4; - break; - case 12:cs->hw.spt.res_irq = 5; - break; - case 14:cs->hw.spt.res_irq = 6; - break; - case 15:cs->hw.spt.res_irq = 7; - break; - default:release_io_sportster(cs); - printk(KERN_WARNING "Sportster: wrong IRQ\n"); - return (0); - } - printk(KERN_INFO "HiSax: USR Sportster config irq:%d cfg:0x%X\n", - cs->irq, cs->hw.spt.cfg_reg); - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Sportster_card_msg; - cs->irq_func = &sportster_interrupt; - ISACVersion(cs, "Sportster:"); - if (HscxVersion(cs, "Sportster:")) { - printk(KERN_WARNING - "Sportster: wrong HSCX versions check IO address\n"); - release_io_sportster(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h deleted file mode 100644 index b421b86ca7da..000000000000 --- a/drivers/isdn/hisax/st5481.h +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> - * 2001 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. - * - */ - -#ifndef _ST5481_H_ -#define _ST5481_H_ - - -// USB IDs, the Product Id is in the range 0x4810-0x481F - -#define ST_VENDOR_ID 0x0483 -#define ST5481_PRODUCT_ID 0x4810 -#define ST5481_PRODUCT_ID_MASK 0xFFF0 - -// ST5481 endpoints when using alternative setting 3 (2B+D). -// To get the endpoint address, OR with 0x80 for IN endpoints. - -#define EP_CTRL 0x00U /* Control endpoint */ -#define EP_INT 0x01U /* Interrupt endpoint */ -#define EP_B1_OUT 0x02U /* B1 channel out */ -#define EP_B1_IN 0x03U /* B1 channel in */ -#define EP_B2_OUT 0x04U /* B2 channel out */ -#define EP_B2_IN 0x05U /* B2 channel in */ -#define EP_D_OUT 0x06U /* D channel out */ -#define EP_D_IN 0x07U /* D channel in */ - -// Number of isochronous packets. With 20 packets we get -// 50 interrupts/sec for each endpoint. - -#define NUM_ISO_PACKETS_D 20 -#define NUM_ISO_PACKETS_B 20 - -// Size of each isochronous packet. -// In outgoing direction we need to match ISDN data rates: -// D: 2 bytes / msec -> 16 kbit / s -// B: 16 bytes / msec -> 64 kbit / s -#define SIZE_ISO_PACKETS_D_IN 16 -#define SIZE_ISO_PACKETS_D_OUT 2 -#define SIZE_ISO_PACKETS_B_IN 32 -#define SIZE_ISO_PACKETS_B_OUT 8 - -// If we overrun/underrun, we send one packet with +/- 2 bytes -#define B_FLOW_ADJUST 2 - -// Registers that are written using vendor specific device request -// on endpoint 0. - -#define LBA 0x02 /* S loopback */ -#define SET_DEFAULT 0x06 /* Soft reset */ -#define LBB 0x1D /* S maintenance loopback */ -#define STT 0x1e /* S force transmission signals */ -#define SDA_MIN 0x20 /* SDA-sin minimal value */ -#define SDA_MAX 0x21 /* SDA-sin maximal value */ -#define SDELAY_VALUE 0x22 /* Delay between Tx and Rx clock */ -#define IN_D_COUNTER 0x36 /* D receive channel fifo counter */ -#define OUT_D_COUNTER 0x37 /* D transmit channel fifo counter */ -#define IN_B1_COUNTER 0x38 /* B1 receive channel fifo counter */ -#define OUT_B1_COUNTER 0x39 /* B1 transmit channel fifo counter */ -#define IN_B2_COUNTER 0x3a /* B2 receive channel fifo counter */ -#define OUT_B2_COUNTER 0x3b /* B2 transmit channel fifo counter */ -#define FFCTRL_IN_D 0x3C /* D receive channel fifo threshold low */ -#define FFCTRH_IN_D 0x3D /* D receive channel fifo threshold high */ -#define FFCTRL_OUT_D 0x3E /* D transmit channel fifo threshold low */ -#define FFCTRH_OUT_D 0x3F /* D transmit channel fifo threshold high */ -#define FFCTRL_IN_B1 0x40 /* B1 receive channel fifo threshold low */ -#define FFCTRH_IN_B1 0x41 /* B1 receive channel fifo threshold high */ -#define FFCTRL_OUT_B1 0x42 /* B1 transmit channel fifo threshold low */ -#define FFCTRH_OUT_B1 0x43 /* B1 transmit channel fifo threshold high */ -#define FFCTRL_IN_B2 0x44 /* B2 receive channel fifo threshold low */ -#define FFCTRH_IN_B2 0x45 /* B2 receive channel fifo threshold high */ -#define FFCTRL_OUT_B2 0x46 /* B2 transmit channel fifo threshold low */ -#define FFCTRH_OUT_B2 0x47 /* B2 transmit channel fifo threshold high */ -#define MPMSK 0x4A /* Multi purpose interrupt MASK register */ -#define FFMSK_D 0x4c /* D fifo interrupt MASK register */ -#define FFMSK_B1 0x4e /* B1 fifo interrupt MASK register */ -#define FFMSK_B2 0x50 /* B2 fifo interrupt MASK register */ -#define GPIO_DIR 0x52 /* GPIO pins direction registers */ -#define GPIO_OUT 0x53 /* GPIO pins output register */ -#define GPIO_IN 0x54 /* GPIO pins input register */ -#define TXCI 0x56 /* CI command to be transmitted */ - - -// Format of the interrupt packet received on endpoint 1: -// -// +--------+--------+--------+--------+--------+--------+ -// !MPINT !FFINT_D !FFINT_B1!FFINT_B2!CCIST !GPIO_INT! -// +--------+--------+--------+--------+--------+--------+ - -// Offsets in the interrupt packet - -#define MPINT 0 -#define FFINT_D 1 -#define FFINT_B1 2 -#define FFINT_B2 3 -#define CCIST 4 -#define GPIO_INT 5 -#define INT_PKT_SIZE 6 - -// MPINT -#define LSD_INT 0x80 /* S line activity detected */ -#define RXCI_INT 0x40 /* Indicate primitive arrived */ -#define DEN_INT 0x20 /* Signal enabling data out of D Tx fifo */ -#define DCOLL_INT 0x10 /* D channel collision */ -#define AMIVN_INT 0x04 /* AMI violation number reached 2 */ -#define INFOI_INT 0x04 /* INFOi changed */ -#define DRXON_INT 0x02 /* Reception channel active */ -#define GPCHG_INT 0x01 /* GPIO pin value changed */ - -// FFINT_x -#define IN_OVERRUN 0x80 /* In fifo overrun */ -#define OUT_UNDERRUN 0x40 /* Out fifo underrun */ -#define IN_UP 0x20 /* In fifo thresholdh up-crossed */ -#define IN_DOWN 0x10 /* In fifo thresholdl down-crossed */ -#define OUT_UP 0x08 /* Out fifo thresholdh up-crossed */ -#define OUT_DOWN 0x04 /* Out fifo thresholdl down-crossed */ -#define IN_COUNTER_ZEROED 0x02 /* In down-counter reached 0 */ -#define OUT_COUNTER_ZEROED 0x01 /* Out down-counter reached 0 */ - -#define ANY_REC_INT (IN_OVERRUN + IN_UP + IN_DOWN + IN_COUNTER_ZEROED) -#define ANY_XMIT_INT (OUT_UNDERRUN + OUT_UP + OUT_DOWN + OUT_COUNTER_ZEROED) - - -// Level 1 commands that are sent using the TXCI device request -#define ST5481_CMD_DR 0x0 /* Deactivation Request */ -#define ST5481_CMD_RES 0x1 /* state machine RESet */ -#define ST5481_CMD_TM1 0x2 /* Test Mode 1 */ -#define ST5481_CMD_TM2 0x3 /* Test Mode 2 */ -#define ST5481_CMD_PUP 0x7 /* Power UP */ -#define ST5481_CMD_AR8 0x8 /* Activation Request class 1 */ -#define ST5481_CMD_AR10 0x9 /* Activation Request class 2 */ -#define ST5481_CMD_ARL 0xA /* Activation Request Loopback */ -#define ST5481_CMD_PDN 0xF /* Power DoWn */ - -// Turn on/off the LEDs using the GPIO device request. -// To use the B LEDs, number_of_leds must be set to 4 -#define B1_LED 0x10U -#define B2_LED 0x20U -#define GREEN_LED 0x40U -#define RED_LED 0x80U - -// D channel out states -enum { - ST_DOUT_NONE, - - ST_DOUT_SHORT_INIT, - ST_DOUT_SHORT_WAIT_DEN, - - ST_DOUT_LONG_INIT, - ST_DOUT_LONG_WAIT_DEN, - ST_DOUT_NORMAL, - - ST_DOUT_WAIT_FOR_UNDERRUN, - ST_DOUT_WAIT_FOR_NOT_BUSY, - ST_DOUT_WAIT_FOR_STOP, - ST_DOUT_WAIT_FOR_RESET, -}; - -#define DOUT_STATE_COUNT (ST_DOUT_WAIT_FOR_RESET + 1) - -// D channel out events -enum { - EV_DOUT_START_XMIT, - EV_DOUT_COMPLETE, - EV_DOUT_DEN, - EV_DOUT_RESETED, - EV_DOUT_STOPPED, - EV_DOUT_COLL, - EV_DOUT_UNDERRUN, -}; - -#define DOUT_EVENT_COUNT (EV_DOUT_UNDERRUN + 1) - -// ---------------------------------------------------------------------- - -enum { - ST_L1_F3, - ST_L1_F4, - ST_L1_F6, - ST_L1_F7, - ST_L1_F8, -}; - -#define L1_STATE_COUNT (ST_L1_F8 + 1) - -// The first 16 entries match the Level 1 indications that -// are found at offset 4 (CCIST) in the interrupt packet - -enum { - EV_IND_DP, // 0000 Deactivation Pending - EV_IND_1, // 0001 - EV_IND_2, // 0010 - EV_IND_3, // 0011 - EV_IND_RSY, // 0100 ReSYnchronizing - EV_IND_5, // 0101 - EV_IND_6, // 0110 - EV_IND_7, // 0111 - EV_IND_AP, // 1000 Activation Pending - EV_IND_9, // 1001 - EV_IND_10, // 1010 - EV_IND_11, // 1011 - EV_IND_AI8, // 1100 Activation Indication class 8 - EV_IND_AI10,// 1101 Activation Indication class 10 - EV_IND_AIL, // 1110 Activation Indication Loopback - EV_IND_DI, // 1111 Deactivation Indication - EV_PH_ACTIVATE_REQ, - EV_PH_DEACTIVATE_REQ, - EV_TIMER3, -}; - -#define L1_EVENT_COUNT (EV_TIMER3 + 1) - -#define ERR(format, arg...) \ - printk(KERN_ERR "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) - -#define WARNING(format, arg...) \ - printk(KERN_WARNING "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) - -#define INFO(format, arg...) \ - printk(KERN_INFO "%s:%s: " format "\n" , __FILE__, __func__ , ## arg) - -#include <linux/isdn/hdlc.h> -#include "fsm.h" -#include "hisax_if.h" -#include <linux/skbuff.h> - -/* ====================================================================== - * FIFO handling - */ - -/* Generic FIFO structure */ -struct fifo { - u_char r, w, count, size; - spinlock_t lock; -}; - -/* - * Init an FIFO - */ -static inline void fifo_init(struct fifo *fifo, int size) -{ - fifo->r = fifo->w = fifo->count = 0; - fifo->size = size; - spin_lock_init(&fifo->lock); -} - -/* - * Add an entry to the FIFO - */ -static inline int fifo_add(struct fifo *fifo) -{ - unsigned long flags; - int index; - - if (!fifo) { - return -1; - } - - spin_lock_irqsave(&fifo->lock, flags); - if (fifo->count == fifo->size) { - // FIFO full - index = -1; - } else { - // Return index where to get the next data to add to the FIFO - index = fifo->w++ & (fifo->size - 1); - fifo->count++; - } - spin_unlock_irqrestore(&fifo->lock, flags); - return index; -} - -/* - * Remove an entry from the FIFO with the index returned. - */ -static inline int fifo_remove(struct fifo *fifo) -{ - unsigned long flags; - int index; - - if (!fifo) { - return -1; - } - - spin_lock_irqsave(&fifo->lock, flags); - if (!fifo->count) { - // FIFO empty - index = -1; - } else { - // Return index where to get the next data from the FIFO - index = fifo->r++ & (fifo->size - 1); - fifo->count--; - } - spin_unlock_irqrestore(&fifo->lock, flags); - - return index; -} - -/* ====================================================================== - * control pipe - */ -typedef void (*ctrl_complete_t)(void *); - -typedef struct ctrl_msg { - struct usb_ctrlrequest dr; - ctrl_complete_t complete; - void *context; -} ctrl_msg; - -/* FIFO of ctrl messages waiting to be sent */ -#define MAX_EP0_MSG 16 -struct ctrl_msg_fifo { - struct fifo f; - struct ctrl_msg data[MAX_EP0_MSG]; -}; - -#define MAX_DFRAME_LEN_L1 300 -#define HSCX_BUFMAX 4096 - -struct st5481_ctrl { - struct ctrl_msg_fifo msg_fifo; - unsigned long busy; - struct urb *urb; -}; - -struct st5481_intr { - // struct evt_fifo evt_fifo; - struct urb *urb; -}; - -struct st5481_d_out { - struct isdnhdlc_vars hdlc_state; - struct urb *urb[2]; /* double buffering */ - unsigned long busy; - struct sk_buff *tx_skb; - struct FsmInst fsm; -}; - -struct st5481_b_out { - struct isdnhdlc_vars hdlc_state; - struct urb *urb[2]; /* double buffering */ - u_char flow_event; - u_long busy; - struct sk_buff *tx_skb; -}; - -struct st5481_in { - struct isdnhdlc_vars hdlc_state; - struct urb *urb[2]; /* double buffering */ - int mode; - int bufsize; - unsigned int num_packets; - unsigned int packet_size; - unsigned char ep, counter; - unsigned char *rcvbuf; - struct st5481_adapter *adapter; - struct hisax_if *hisax_if; -}; - -int st5481_setup_in(struct st5481_in *in); -void st5481_release_in(struct st5481_in *in); -void st5481_in_mode(struct st5481_in *in, int mode); - -struct st5481_bcs { - struct hisax_b_if b_if; - struct st5481_adapter *adapter; - struct st5481_in b_in; - struct st5481_b_out b_out; - int channel; - int mode; -}; - -struct st5481_adapter { - int number_of_leds; - struct usb_device *usb_dev; - struct hisax_d_if hisax_d_if; - - struct st5481_ctrl ctrl; - struct st5481_intr intr; - struct st5481_in d_in; - struct st5481_d_out d_out; - - unsigned char leds; - unsigned int led_counter; - - unsigned long event; - - struct FsmInst l1m; - struct FsmTimer timer; - - struct st5481_bcs bcs[2]; -}; - -#define TIMER3_VALUE 7000 - -/* ====================================================================== - * - */ - -/* - * Submit an URB with error reporting. This is a macro so - * the __func__ returns the caller function name. - */ -#define SUBMIT_URB(urb, mem_flags) \ - ({ \ - int status; \ - if ((status = usb_submit_urb(urb, mem_flags)) < 0) { \ - WARNING("usb_submit_urb failed,status=%d", status); \ - } \ - status; \ - }) - -/* - * USB double buffering, return the URB index (0 or 1). - */ -static inline int get_buf_nr(struct urb *urbs[], struct urb *urb) -{ - return (urbs[0] == urb ? 0 : 1); -} - -/* ---------------------------------------------------------------------- */ - -/* B Channel */ - -int st5481_setup_b(struct st5481_bcs *bcs); -void st5481_release_b(struct st5481_bcs *bcs); -void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg); - -/* D Channel */ - -int st5481_setup_d(struct st5481_adapter *adapter); -void st5481_release_d(struct st5481_adapter *adapter); -void st5481_b_l2l1(struct hisax_if *b_if, int pr, void *arg); -int st5481_d_init(void); -void st5481_d_exit(void); - -/* USB */ -void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command); -int st5481_setup_isocpipes(struct urb *urb[2], struct usb_device *dev, - unsigned int pipe, int num_packets, - int packet_size, int buf_size, - usb_complete_t complete, void *context); -void st5481_release_isocpipes(struct urb *urb[2]); - -void st5481_usb_pipe_reset(struct st5481_adapter *adapter, - u_char pipe, ctrl_complete_t complete, void *context); -void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter, - u8 request, u16 value, - ctrl_complete_t complete, void *context); -int st5481_setup_usb(struct st5481_adapter *adapter); -void st5481_release_usb(struct st5481_adapter *adapter); -void st5481_start(struct st5481_adapter *adapter); -void st5481_stop(struct st5481_adapter *adapter); - -// ---------------------------------------------------------------------- -// debugging macros - -#define __debug_variable st5481_debug -#include "hisax_debug.h" - -extern int st5481_debug; - -#ifdef CONFIG_HISAX_DEBUG - -#define DBG_ISO_PACKET(level, urb) \ - if (level & __debug_variable) dump_iso_packet(__func__, urb) - -static void __attribute__((unused)) -dump_iso_packet(const char *name, struct urb *urb) -{ - int i, j; - int len, ofs; - u_char *data; - - printk(KERN_DEBUG "%s: packets=%d,errors=%d\n", - name, urb->number_of_packets, urb->error_count); - for (i = 0; i < urb->number_of_packets; ++i) { - if (urb->pipe & USB_DIR_IN) { - len = urb->iso_frame_desc[i].actual_length; - } else { - len = urb->iso_frame_desc[i].length; - } - ofs = urb->iso_frame_desc[i].offset; - printk(KERN_DEBUG "len=%.2d,ofs=%.3d ", len, ofs); - if (len) { - data = urb->transfer_buffer + ofs; - for (j = 0; j < len; j++) { - printk("%.2x", data[j]); - } - } - printk("\n"); - } -} - -static inline const char *ST5481_CMD_string(int evt) -{ - static char s[16]; - - switch (evt) { - case ST5481_CMD_DR: return "DR"; - case ST5481_CMD_RES: return "RES"; - case ST5481_CMD_TM1: return "TM1"; - case ST5481_CMD_TM2: return "TM2"; - case ST5481_CMD_PUP: return "PUP"; - case ST5481_CMD_AR8: return "AR8"; - case ST5481_CMD_AR10: return "AR10"; - case ST5481_CMD_ARL: return "ARL"; - case ST5481_CMD_PDN: return "PDN"; - } - - sprintf(s, "0x%x", evt); - return s; -} - -#else - -#define DBG_ISO_PACKET(level, urb) do {} while (0) - -#endif - - - -#endif diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c deleted file mode 100644 index f64a36007800..000000000000 --- a/drivers/isdn/hisax/st5481_b.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> - * 2001 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. - * - */ - -#include <linux/init.h> -#include <linux/gfp.h> -#include <linux/usb.h> -#include <linux/netdevice.h> -#include <linux/bitrev.h> -#include "st5481.h" - -static inline void B_L1L2(struct st5481_bcs *bcs, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if; - - ifc->l1l2(ifc, pr, arg); -} - -/* - * Encode and transmit next frame. - */ -static void usb_b_out(struct st5481_bcs *bcs, int buf_nr) -{ - struct st5481_b_out *b_out = &bcs->b_out; - struct st5481_adapter *adapter = bcs->adapter; - struct urb *urb; - unsigned int packet_size, offset; - int len, buf_size, bytes_sent; - int i; - struct sk_buff *skb; - - if (test_and_set_bit(buf_nr, &b_out->busy)) { - DBG(4, "ep %d urb %d busy", (bcs->channel + 1) * 2, buf_nr); - return; - } - urb = b_out->urb[buf_nr]; - - // Adjust isoc buffer size according to flow state - if (b_out->flow_event & (OUT_DOWN | OUT_UNDERRUN)) { - buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST; - packet_size = SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST; - DBG(4, "B%d,adjust flow,add %d bytes", bcs->channel + 1, B_FLOW_ADJUST); - } else if (b_out->flow_event & OUT_UP) { - buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST; - packet_size = SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST; - DBG(4, "B%d,adjust flow,remove %d bytes", bcs->channel + 1, B_FLOW_ADJUST); - } else { - buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT; - packet_size = 8; - } - b_out->flow_event = 0; - - len = 0; - while (len < buf_size) { - if ((skb = b_out->tx_skb)) { - DBG_SKB(0x100, skb); - DBG(4, "B%d,len=%d", bcs->channel + 1, skb->len); - - if (bcs->mode == L1_MODE_TRANS) { - bytes_sent = buf_size - len; - if (skb->len < bytes_sent) - bytes_sent = skb->len; - { /* swap tx bytes to get hearable audio data */ - register unsigned char *src = skb->data; - register unsigned char *dest = urb->transfer_buffer + len; - register unsigned int count; - for (count = 0; count < bytes_sent; count++) - *dest++ = bitrev8(*src++); - } - len += bytes_sent; - } else { - len += isdnhdlc_encode(&b_out->hdlc_state, - skb->data, skb->len, &bytes_sent, - urb->transfer_buffer + len, buf_size-len); - } - - skb_pull(skb, bytes_sent); - - if (!skb->len) { - // Frame sent - b_out->tx_skb = NULL; - B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long) skb->truesize); - dev_kfree_skb_any(skb); - -/* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */ -/* st5481B_sched_event(bcs, B_XMTBUFREADY); */ -/* } */ - } - } else { - if (bcs->mode == L1_MODE_TRANS) { - memset(urb->transfer_buffer + len, 0xff, buf_size-len); - len = buf_size; - } else { - // Send flags - len += isdnhdlc_encode(&b_out->hdlc_state, - NULL, 0, &bytes_sent, - urb->transfer_buffer + len, buf_size-len); - } - } - } - - // Prepare the URB - for (i = 0, offset = 0; offset < len; i++) { - urb->iso_frame_desc[i].offset = offset; - urb->iso_frame_desc[i].length = packet_size; - offset += packet_size; - packet_size = SIZE_ISO_PACKETS_B_OUT; - } - urb->transfer_buffer_length = len; - urb->number_of_packets = i; - urb->dev = adapter->usb_dev; - - DBG_ISO_PACKET(0x200, urb); - - SUBMIT_URB(urb, GFP_NOIO); -} - -/* - * Start transferring (flags or data) on the B channel, since - * FIFO counters has been set to a non-zero value. - */ -static void st5481B_start_xfer(void *context) -{ - struct st5481_bcs *bcs = context; - - DBG(4, "B%d", bcs->channel + 1); - - // Start transmitting (flags or data) on B channel - - usb_b_out(bcs, 0); - usb_b_out(bcs, 1); -} - -/* - * If the adapter has only 2 LEDs, the green - * LED will blink with a rate depending - * on the number of channels opened. - */ -static void led_blink(struct st5481_adapter *adapter) -{ - u_char leds = adapter->leds; - - // 50 frames/sec for each channel - if (++adapter->led_counter % 50) { - return; - } - - if (adapter->led_counter % 100) { - leds |= GREEN_LED; - } else { - leds &= ~GREEN_LED; - } - - st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, leds, NULL, NULL); -} - -static void usb_b_out_complete(struct urb *urb) -{ - struct st5481_bcs *bcs = urb->context; - struct st5481_b_out *b_out = &bcs->b_out; - struct st5481_adapter *adapter = bcs->adapter; - int buf_nr; - - buf_nr = get_buf_nr(b_out->urb, urb); - test_and_clear_bit(buf_nr, &b_out->busy); - - if (unlikely(urb->status < 0)) { - switch (urb->status) { - case -ENOENT: - case -ESHUTDOWN: - case -ECONNRESET: - DBG(4, "urb killed status %d", urb->status); - return; // Give up - default: - WARNING("urb status %d", urb->status); - if (b_out->busy == 0) { - st5481_usb_pipe_reset(adapter, (bcs->channel + 1) * 2 | USB_DIR_OUT, NULL, NULL); - } - break; - } - } - - usb_b_out(bcs, buf_nr); - - if (adapter->number_of_leds == 2) - led_blink(adapter); -} - -/* - * Start or stop the transfer on the B channel. - */ -static void st5481B_mode(struct st5481_bcs *bcs, int mode) -{ - struct st5481_b_out *b_out = &bcs->b_out; - struct st5481_adapter *adapter = bcs->adapter; - - DBG(4, "B%d,mode=%d", bcs->channel + 1, mode); - - if (bcs->mode == mode) - return; - - bcs->mode = mode; - - // Cancel all USB transfers on this B channel - usb_unlink_urb(b_out->urb[0]); - usb_unlink_urb(b_out->urb[1]); - b_out->busy = 0; - - st5481_in_mode(&bcs->b_in, mode); - if (bcs->mode != L1_MODE_NULL) { - // Open the B channel - if (bcs->mode != L1_MODE_TRANS) { - u32 features = HDLC_BITREVERSE; - if (bcs->mode == L1_MODE_HDLC_56K) - features |= HDLC_56KBIT; - isdnhdlc_out_init(&b_out->hdlc_state, features); - } - st5481_usb_pipe_reset(adapter, (bcs->channel + 1) * 2, NULL, NULL); - - // Enable B channel interrupts - st5481_usb_device_ctrl_msg(adapter, FFMSK_B1 + (bcs->channel * 2), - OUT_UP + OUT_DOWN + OUT_UNDERRUN, NULL, NULL); - - // Enable B channel FIFOs - st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel * 2), 32, st5481B_start_xfer, bcs); - if (adapter->number_of_leds == 4) { - if (bcs->channel == 0) { - adapter->leds |= B1_LED; - } else { - adapter->leds |= B2_LED; - } - } - } else { - // Disable B channel interrupts - st5481_usb_device_ctrl_msg(adapter, FFMSK_B1+(bcs->channel * 2), 0, NULL, NULL); - - // Disable B channel FIFOs - st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel * 2), 0, NULL, NULL); - - if (adapter->number_of_leds == 4) { - if (bcs->channel == 0) { - adapter->leds &= ~B1_LED; - } else { - adapter->leds &= ~B2_LED; - } - } else { - st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL); - } - if (b_out->tx_skb) { - dev_kfree_skb_any(b_out->tx_skb); - b_out->tx_skb = NULL; - } - - } -} - -static int st5481_setup_b_out(struct st5481_bcs *bcs) -{ - struct usb_device *dev = bcs->adapter->usb_dev; - struct usb_interface *intf; - struct usb_host_interface *altsetting = NULL; - struct usb_host_endpoint *endpoint; - struct st5481_b_out *b_out = &bcs->b_out; - - DBG(4, ""); - - intf = usb_ifnum_to_if(dev, 0); - if (intf) - altsetting = usb_altnum_to_altsetting(intf, 3); - if (!altsetting) - return -ENXIO; - - // Allocate URBs and buffers for the B channel out - endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2]; - - DBG(4, "endpoint address=%02x,packet size=%d", - endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize)); - - // Allocate memory for 8000bytes/sec + extra bytes if underrun - return st5481_setup_isocpipes(b_out->urb, dev, - usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress), - NUM_ISO_PACKETS_B, SIZE_ISO_PACKETS_B_OUT, - NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST, - usb_b_out_complete, bcs); -} - -static void st5481_release_b_out(struct st5481_bcs *bcs) -{ - struct st5481_b_out *b_out = &bcs->b_out; - - DBG(4, ""); - - st5481_release_isocpipes(b_out->urb); -} - -int st5481_setup_b(struct st5481_bcs *bcs) -{ - int retval; - - DBG(4, ""); - - retval = st5481_setup_b_out(bcs); - if (retval) - goto err; - bcs->b_in.bufsize = HSCX_BUFMAX; - bcs->b_in.num_packets = NUM_ISO_PACKETS_B; - bcs->b_in.packet_size = SIZE_ISO_PACKETS_B_IN; - bcs->b_in.ep = (bcs->channel ? EP_B2_IN : EP_B1_IN) | USB_DIR_IN; - bcs->b_in.counter = bcs->channel ? IN_B2_COUNTER : IN_B1_COUNTER; - bcs->b_in.adapter = bcs->adapter; - bcs->b_in.hisax_if = &bcs->b_if.ifc; - retval = st5481_setup_in(&bcs->b_in); - if (retval) - goto err_b_out; - - - return 0; - -err_b_out: - st5481_release_b_out(bcs); -err: - return retval; -} - -/* - * Release buffers and URBs for the B channels - */ -void st5481_release_b(struct st5481_bcs *bcs) -{ - DBG(4, ""); - - st5481_release_in(&bcs->b_in); - st5481_release_b_out(bcs); -} - -/* - * st5481_b_l2l1 is the entry point for upper layer routines that want to - * transmit on the B channel. PH_DATA | REQUEST is a normal packet that - * we either start transmitting (if idle) or queue (if busy). - * PH_PULL | REQUEST can be called to request a callback message - * (PH_PULL | CONFIRM) - * once the link is idle. After a "pull" callback, the upper layer - * routines can use PH_PULL | INDICATION to send data. - */ -void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg) -{ - struct st5481_bcs *bcs = ifc->priv; - struct sk_buff *skb = arg; - long mode; - - DBG(4, ""); - - switch (pr) { - case PH_DATA | REQUEST: - BUG_ON(bcs->b_out.tx_skb); - bcs->b_out.tx_skb = skb; - break; - case PH_ACTIVATE | REQUEST: - mode = (long) arg; - DBG(4, "B%d,PH_ACTIVATE_REQUEST %ld", bcs->channel + 1, mode); - st5481B_mode(bcs, mode); - B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL); - break; - case PH_DEACTIVATE | REQUEST: - DBG(4, "B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1); - st5481B_mode(bcs, L1_MODE_NULL); - B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL); - break; - default: - WARNING("pr %#x\n", pr); - } -} diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c deleted file mode 100644 index e88c5c71fca7..000000000000 --- a/drivers/isdn/hisax/st5481_d.c +++ /dev/null @@ -1,780 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> - * 2001 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. - * - */ - -#include <linux/init.h> -#include <linux/gfp.h> -#include <linux/usb.h> -#include <linux/netdevice.h> -#include "st5481.h" - -static void ph_connect(struct st5481_adapter *adapter); -static void ph_disconnect(struct st5481_adapter *adapter); - -static struct Fsm l1fsm; - -static char *strL1State[] = -{ - "ST_L1_F3", - "ST_L1_F4", - "ST_L1_F6", - "ST_L1_F7", - "ST_L1_F8", -}; - -static char *strL1Event[] = -{ - "EV_IND_DP", - "EV_IND_1", - "EV_IND_2", - "EV_IND_3", - "EV_IND_RSY", - "EV_IND_5", - "EV_IND_6", - "EV_IND_7", - "EV_IND_AP", - "EV_IND_9", - "EV_IND_10", - "EV_IND_11", - "EV_IND_AI8", - "EV_IND_AI10", - "EV_IND_AIL", - "EV_IND_DI", - "EV_PH_ACTIVATE_REQ", - "EV_PH_DEACTIVATE_REQ", - "EV_TIMER3", -}; - -static inline void D_L1L2(struct st5481_adapter *adapter, int pr, void *arg) -{ - struct hisax_if *ifc = (struct hisax_if *) &adapter->hisax_d_if; - - ifc->l1l2(ifc, pr, arg); -} - -static void -l1_go_f3(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - if (fi->state == ST_L1_F7) - ph_disconnect(adapter); - - FsmChangeState(fi, ST_L1_F3); - D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); -} - -static void -l1_go_f6(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - if (fi->state == ST_L1_F7) - ph_disconnect(adapter); - - FsmChangeState(fi, ST_L1_F6); -} - -static void -l1_go_f7(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - FsmDelTimer(&adapter->timer, 0); - ph_connect(adapter); - FsmChangeState(fi, ST_L1_F7); - D_L1L2(adapter, PH_ACTIVATE | INDICATION, NULL); -} - -static void -l1_go_f8(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - if (fi->state == ST_L1_F7) - ph_disconnect(adapter); - - FsmChangeState(fi, ST_L1_F8); -} - -static void -l1_timer3(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - st5481_ph_command(adapter, ST5481_CMD_DR); - FsmChangeState(fi, ST_L1_F3); - D_L1L2(adapter, PH_DEACTIVATE | INDICATION, NULL); -} - -static void -l1_ignore(struct FsmInst *fi, int event, void *arg) -{ -} - -static void -l1_activate(struct FsmInst *fi, int event, void *arg) -{ - struct st5481_adapter *adapter = fi->userdata; - - st5481_ph_command(adapter, ST5481_CMD_DR); - st5481_ph_command(adapter, ST5481_CMD_PUP); - FsmRestartTimer(&adapter->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); - st5481_ph_command(adapter, ST5481_CMD_AR8); - FsmChangeState(fi, ST_L1_F4); -} - -static struct FsmNode L1FnList[] __initdata = -{ - {ST_L1_F3, EV_IND_DP, l1_ignore}, - {ST_L1_F3, EV_IND_AP, l1_go_f6}, - {ST_L1_F3, EV_IND_AI8, l1_go_f7}, - {ST_L1_F3, EV_IND_AI10, l1_go_f7}, - {ST_L1_F3, EV_PH_ACTIVATE_REQ, l1_activate}, - - {ST_L1_F4, EV_TIMER3, l1_timer3}, - {ST_L1_F4, EV_IND_DP, l1_go_f3}, - {ST_L1_F4, EV_IND_AP, l1_go_f6}, - {ST_L1_F4, EV_IND_AI8, l1_go_f7}, - {ST_L1_F4, EV_IND_AI10, l1_go_f7}, - - {ST_L1_F6, EV_TIMER3, l1_timer3}, - {ST_L1_F6, EV_IND_DP, l1_go_f3}, - {ST_L1_F6, EV_IND_AP, l1_ignore}, - {ST_L1_F6, EV_IND_AI8, l1_go_f7}, - {ST_L1_F6, EV_IND_AI10, l1_go_f7}, - {ST_L1_F7, EV_IND_RSY, l1_go_f8}, - - {ST_L1_F7, EV_IND_DP, l1_go_f3}, - {ST_L1_F7, EV_IND_AP, l1_go_f6}, - {ST_L1_F7, EV_IND_AI8, l1_ignore}, - {ST_L1_F7, EV_IND_AI10, l1_ignore}, - {ST_L1_F7, EV_IND_RSY, l1_go_f8}, - - {ST_L1_F8, EV_TIMER3, l1_timer3}, - {ST_L1_F8, EV_IND_DP, l1_go_f3}, - {ST_L1_F8, EV_IND_AP, l1_go_f6}, - {ST_L1_F8, EV_IND_AI8, l1_go_f8}, - {ST_L1_F8, EV_IND_AI10, l1_go_f8}, - {ST_L1_F8, EV_IND_RSY, l1_ignore}, -}; - -static __printf(2, 3) - void l1m_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - char buf[256]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - DBG(8, "%s", buf); - va_end(args); -} - -/* ====================================================================== - * D-Channel out - */ - -/* - D OUT state machine: - ==================== - - Transmit short frame (< 16 bytes of encoded data): - - L1 FRAME D_OUT_STATE USB D CHANNEL - -------- ----------- --- --------- - - FIXME - - -> [xx..xx] SHORT_INIT -> [7Exx..xxC1C27EFF] - SHORT_WAIT_DEN <> OUT_D_COUNTER=16 - - END_OF_SHORT <- DEN_EVENT -> 7Exx - xxxx - xxxx - xxxx - xxxx - xxxx - C1C1 - 7EFF - WAIT_FOR_RESET_IDLE <- D_UNDERRUN <- (8ms) - IDLE <> Reset pipe - - - - Transmit long frame (>= 16 bytes of encoded data): - - L1 FRAME D_OUT_STATE USB D CHANNEL - -------- ----------- --- --------- - - -> [xx...xx] IDLE - WAIT_FOR_STOP <> OUT_D_COUNTER=0 - WAIT_FOR_RESET <> Reset pipe - STOP - INIT_LONG_FRAME -> [7Exx..xx] - WAIT_DEN <> OUT_D_COUNTER=16 - OUT_NORMAL <- DEN_EVENT -> 7Exx - END_OF_FRAME_BUSY -> [xxxx] xxxx - END_OF_FRAME_NOT_BUSY -> [xxxx] xxxx - -> [xxxx] xxxx - -> [C1C2] xxxx - -> [7EFF] xxxx - xxxx - xxxx - .... - xxxx - C1C2 - 7EFF - <- D_UNDERRUN <- (> 8ms) - WAIT_FOR_STOP <> OUT_D_COUNTER=0 - WAIT_FOR_RESET <> Reset pipe - STOP - -*/ - -static struct Fsm dout_fsm; - -static char *strDoutState[] = -{ - "ST_DOUT_NONE", - - "ST_DOUT_SHORT_INIT", - "ST_DOUT_SHORT_WAIT_DEN", - - "ST_DOUT_LONG_INIT", - "ST_DOUT_LONG_WAIT_DEN", - "ST_DOUT_NORMAL", - - "ST_DOUT_WAIT_FOR_UNDERRUN", - "ST_DOUT_WAIT_FOR_NOT_BUSY", - "ST_DOUT_WAIT_FOR_STOP", - "ST_DOUT_WAIT_FOR_RESET", -}; - -static char *strDoutEvent[] = -{ - "EV_DOUT_START_XMIT", - "EV_DOUT_COMPLETE", - "EV_DOUT_DEN", - "EV_DOUT_RESETED", - "EV_DOUT_STOPPED", - "EV_DOUT_COLL", - "EV_DOUT_UNDERRUN", -}; - -static __printf(2, 3) - void dout_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - char buf[256]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - DBG(0x2, "%s", buf); - va_end(args); -} - -static void dout_stop_event(void *context) -{ - struct st5481_adapter *adapter = context; - - FsmEvent(&adapter->d_out.fsm, EV_DOUT_STOPPED, NULL); -} - -/* - * Start the transfer of a D channel frame. - */ -static void usb_d_out(struct st5481_adapter *adapter, int buf_nr) -{ - struct st5481_d_out *d_out = &adapter->d_out; - struct urb *urb; - unsigned int num_packets, packet_offset; - int len, buf_size, bytes_sent; - struct sk_buff *skb; - struct usb_iso_packet_descriptor *desc; - - if (d_out->fsm.state != ST_DOUT_NORMAL) - return; - - if (test_and_set_bit(buf_nr, &d_out->busy)) { - DBG(2, "ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); - return; - } - urb = d_out->urb[buf_nr]; - - skb = d_out->tx_skb; - - buf_size = NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT; - - if (skb) { - len = isdnhdlc_encode(&d_out->hdlc_state, - skb->data, skb->len, &bytes_sent, - urb->transfer_buffer, buf_size); - skb_pull(skb, bytes_sent); - } else { - // Send flags or idle - len = isdnhdlc_encode(&d_out->hdlc_state, - NULL, 0, &bytes_sent, - urb->transfer_buffer, buf_size); - } - - if (len < buf_size) { - FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN); - } - if (skb && !skb->len) { - d_out->tx_skb = NULL; - D_L1L2(adapter, PH_DATA | CONFIRM, NULL); - dev_kfree_skb_any(skb); - } - - // Prepare the URB - urb->transfer_buffer_length = len; - num_packets = 0; - packet_offset = 0; - while (packet_offset < len) { - desc = &urb->iso_frame_desc[num_packets]; - desc->offset = packet_offset; - desc->length = SIZE_ISO_PACKETS_D_OUT; - if (len - packet_offset < desc->length) - desc->length = len - packet_offset; - num_packets++; - packet_offset += desc->length; - } - urb->number_of_packets = num_packets; - - // Prepare the URB - urb->dev = adapter->usb_dev; - // Need to transmit the next buffer 2ms after the DEN_EVENT - urb->transfer_flags = 0; - urb->start_frame = usb_get_current_frame_number(adapter->usb_dev) + 2; - - DBG_ISO_PACKET(0x20, urb); - - if (usb_submit_urb(urb, GFP_KERNEL) < 0) { - // There is another URB queued up - urb->transfer_flags = URB_ISO_ASAP; - SUBMIT_URB(urb, GFP_KERNEL); - } -} - -static void fifo_reseted(void *context) -{ - struct st5481_adapter *adapter = context; - - FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL); -} - -static void usb_d_out_complete(struct urb *urb) -{ - struct st5481_adapter *adapter = urb->context; - struct st5481_d_out *d_out = &adapter->d_out; - long buf_nr; - - DBG(2, ""); - - buf_nr = get_buf_nr(d_out->urb, urb); - test_and_clear_bit(buf_nr, &d_out->busy); - - if (unlikely(urb->status < 0)) { - switch (urb->status) { - case -ENOENT: - case -ESHUTDOWN: - case -ECONNRESET: - DBG(1, "urb killed status %d", urb->status); - break; - default: - WARNING("urb status %d", urb->status); - if (d_out->busy == 0) { - st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter); - } - break; - } - return; // Give up - } - - FsmEvent(&adapter->d_out.fsm, EV_DOUT_COMPLETE, (void *) buf_nr); -} - -/* ====================================================================== */ - -static void dout_start_xmit(struct FsmInst *fsm, int event, void *arg) -{ - // FIXME unify? - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - struct urb *urb; - int len, bytes_sent; - struct sk_buff *skb; - int buf_nr = 0; - - skb = d_out->tx_skb; - - DBG(2, "len=%d", skb->len); - - isdnhdlc_out_init(&d_out->hdlc_state, HDLC_DCHANNEL | HDLC_BITREVERSE); - - if (test_and_set_bit(buf_nr, &d_out->busy)) { - WARNING("ep %d urb %d busy %#lx", EP_D_OUT, buf_nr, d_out->busy); - return; - } - urb = d_out->urb[buf_nr]; - - DBG_SKB(0x10, skb); - len = isdnhdlc_encode(&d_out->hdlc_state, - skb->data, skb->len, &bytes_sent, - urb->transfer_buffer, 16); - skb_pull(skb, bytes_sent); - - if (len < 16) - FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_INIT); - else - FsmChangeState(&d_out->fsm, ST_DOUT_LONG_INIT); - - if (skb->len == 0) { - d_out->tx_skb = NULL; - D_L1L2(adapter, PH_DATA | CONFIRM, NULL); - dev_kfree_skb_any(skb); - } - -// Prepare the URB - urb->transfer_buffer_length = len; - - urb->iso_frame_desc[0].offset = 0; - urb->iso_frame_desc[0].length = len; - urb->number_of_packets = 1; - - // Prepare the URB - urb->dev = adapter->usb_dev; - urb->transfer_flags = URB_ISO_ASAP; - - DBG_ISO_PACKET(0x20, urb); - SUBMIT_URB(urb, GFP_KERNEL); -} - -static void dout_short_fifo(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_SHORT_WAIT_DEN); - st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL); -} - -static void dout_end_short_frame(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_UNDERRUN); -} - -static void dout_long_enable_fifo(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 16, NULL, NULL); - FsmChangeState(&d_out->fsm, ST_DOUT_LONG_WAIT_DEN); -} - -static void dout_long_den(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_NORMAL); - usb_d_out(adapter, 0); - usb_d_out(adapter, 1); -} - -static void dout_reset(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_RESET); - st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter); -} - -static void dout_stop(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_STOP); - st5481_usb_device_ctrl_msg(adapter, OUT_D_COUNTER, 0, dout_stop_event, adapter); -} - -static void dout_underrun(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - if (test_bit(0, &d_out->busy) || test_bit(1, &d_out->busy)) { - FsmChangeState(&d_out->fsm, ST_DOUT_WAIT_FOR_NOT_BUSY); - } else { - dout_stop(fsm, event, arg); - } -} - -static void dout_check_busy(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - if (!test_bit(0, &d_out->busy) && !test_bit(1, &d_out->busy)) - dout_stop(fsm, event, arg); -} - -static void dout_reseted(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - struct st5481_d_out *d_out = &adapter->d_out; - - FsmChangeState(&d_out->fsm, ST_DOUT_NONE); - // FIXME locking - if (d_out->tx_skb) - FsmEvent(&d_out->fsm, EV_DOUT_START_XMIT, NULL); -} - -static void dout_complete(struct FsmInst *fsm, int event, void *arg) -{ - struct st5481_adapter *adapter = fsm->userdata; - long buf_nr = (long) arg; - - usb_d_out(adapter, buf_nr); -} - -static void dout_ignore(struct FsmInst *fsm, int event, void *arg) -{ -} - -static struct FsmNode DoutFnList[] __initdata = -{ - {ST_DOUT_NONE, EV_DOUT_START_XMIT, dout_start_xmit}, - - {ST_DOUT_SHORT_INIT, EV_DOUT_COMPLETE, dout_short_fifo}, - - {ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_DEN, dout_end_short_frame}, - {ST_DOUT_SHORT_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun}, - - {ST_DOUT_LONG_INIT, EV_DOUT_COMPLETE, dout_long_enable_fifo}, - - {ST_DOUT_LONG_WAIT_DEN, EV_DOUT_DEN, dout_long_den}, - {ST_DOUT_LONG_WAIT_DEN, EV_DOUT_UNDERRUN, dout_underrun}, - - {ST_DOUT_NORMAL, EV_DOUT_UNDERRUN, dout_underrun}, - {ST_DOUT_NORMAL, EV_DOUT_COMPLETE, dout_complete}, - - {ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_UNDERRUN, dout_underrun}, - {ST_DOUT_WAIT_FOR_UNDERRUN, EV_DOUT_COMPLETE, dout_ignore}, - - {ST_DOUT_WAIT_FOR_NOT_BUSY, EV_DOUT_COMPLETE, dout_check_busy}, - - {ST_DOUT_WAIT_FOR_STOP, EV_DOUT_STOPPED, dout_reset}, - - {ST_DOUT_WAIT_FOR_RESET, EV_DOUT_RESETED, dout_reseted}, -}; - -void st5481_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) -{ - struct st5481_adapter *adapter = hisax_d_if->priv; - struct sk_buff *skb = arg; - - switch (pr) { - case PH_ACTIVATE | REQUEST: - FsmEvent(&adapter->l1m, EV_PH_ACTIVATE_REQ, NULL); - break; - case PH_DEACTIVATE | REQUEST: - FsmEvent(&adapter->l1m, EV_PH_DEACTIVATE_REQ, NULL); - break; - case PH_DATA | REQUEST: - DBG(2, "PH_DATA REQUEST len %d", skb->len); - BUG_ON(adapter->d_out.tx_skb); - adapter->d_out.tx_skb = skb; - FsmEvent(&adapter->d_out.fsm, EV_DOUT_START_XMIT, NULL); - break; - default: - WARNING("pr %#x\n", pr); - break; - } -} - -/* ====================================================================== - */ - -/* - * Start receiving on the D channel since entered state F7. - */ -static void ph_connect(struct st5481_adapter *adapter) -{ - struct st5481_d_out *d_out = &adapter->d_out; - struct st5481_in *d_in = &adapter->d_in; - - DBG(8, ""); - - FsmChangeState(&d_out->fsm, ST_DOUT_NONE); - - // st5481_usb_device_ctrl_msg(adapter, FFMSK_D, OUT_UNDERRUN, NULL, NULL); - st5481_usb_device_ctrl_msg(adapter, FFMSK_D, 0xfc, NULL, NULL); - st5481_in_mode(d_in, L1_MODE_HDLC); - -#ifdef LOOPBACK - // Turn loopback on (data sent on B and D looped back) - st5481_usb_device_ctrl_msg(cs, LBB, 0x04, NULL, NULL); -#endif - - st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, NULL, NULL); - - // Turn on the green LED to tell that we are in state F7 - adapter->leds |= GREEN_LED; - st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL); -} - -/* - * Stop receiving on the D channel since not in state F7. - */ -static void ph_disconnect(struct st5481_adapter *adapter) -{ - DBG(8, ""); - - st5481_in_mode(&adapter->d_in, L1_MODE_NULL); - - // Turn off the green LED to tell that we left state F7 - adapter->leds &= ~GREEN_LED; - st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL); -} - -static int st5481_setup_d_out(struct st5481_adapter *adapter) -{ - struct usb_device *dev = adapter->usb_dev; - struct usb_interface *intf; - struct usb_host_interface *altsetting = NULL; - struct usb_host_endpoint *endpoint; - struct st5481_d_out *d_out = &adapter->d_out; - - DBG(2, ""); - - intf = usb_ifnum_to_if(dev, 0); - if (intf) - altsetting = usb_altnum_to_altsetting(intf, 3); - if (!altsetting) - return -ENXIO; - - // Allocate URBs and buffers for the D channel out - endpoint = &altsetting->endpoint[EP_D_OUT-1]; - - DBG(2, "endpoint address=%02x,packet size=%d", - endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize)); - - return st5481_setup_isocpipes(d_out->urb, dev, - usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress), - NUM_ISO_PACKETS_D, SIZE_ISO_PACKETS_D_OUT, - NUM_ISO_PACKETS_D * SIZE_ISO_PACKETS_D_OUT, - usb_d_out_complete, adapter); -} - -static void st5481_release_d_out(struct st5481_adapter *adapter) -{ - struct st5481_d_out *d_out = &adapter->d_out; - - DBG(2, ""); - - st5481_release_isocpipes(d_out->urb); -} - -int st5481_setup_d(struct st5481_adapter *adapter) -{ - int retval; - - DBG(2, ""); - - retval = st5481_setup_d_out(adapter); - if (retval) - goto err; - adapter->d_in.bufsize = MAX_DFRAME_LEN_L1; - adapter->d_in.num_packets = NUM_ISO_PACKETS_D; - adapter->d_in.packet_size = SIZE_ISO_PACKETS_D_IN; - adapter->d_in.ep = EP_D_IN | USB_DIR_IN; - adapter->d_in.counter = IN_D_COUNTER; - adapter->d_in.adapter = adapter; - adapter->d_in.hisax_if = &adapter->hisax_d_if.ifc; - retval = st5481_setup_in(&adapter->d_in); - if (retval) - goto err_d_out; - - adapter->l1m.fsm = &l1fsm; - adapter->l1m.state = ST_L1_F3; - adapter->l1m.debug = st5481_debug & 0x100; - adapter->l1m.userdata = adapter; - adapter->l1m.printdebug = l1m_debug; - FsmInitTimer(&adapter->l1m, &adapter->timer); - - adapter->d_out.fsm.fsm = &dout_fsm; - adapter->d_out.fsm.state = ST_DOUT_NONE; - adapter->d_out.fsm.debug = st5481_debug & 0x100; - adapter->d_out.fsm.userdata = adapter; - adapter->d_out.fsm.printdebug = dout_debug; - - return 0; - -err_d_out: - st5481_release_d_out(adapter); -err: - return retval; -} - -void st5481_release_d(struct st5481_adapter *adapter) -{ - DBG(2, ""); - - st5481_release_in(&adapter->d_in); - st5481_release_d_out(adapter); -} - -/* ====================================================================== - * init / exit - */ - -int __init st5481_d_init(void) -{ - int retval; - - l1fsm.state_count = L1_STATE_COUNT; - l1fsm.event_count = L1_EVENT_COUNT; - l1fsm.strEvent = strL1Event; - l1fsm.strState = strL1State; - retval = FsmNew(&l1fsm, L1FnList, ARRAY_SIZE(L1FnList)); - if (retval) - goto err; - - dout_fsm.state_count = DOUT_STATE_COUNT; - dout_fsm.event_count = DOUT_EVENT_COUNT; - dout_fsm.strEvent = strDoutEvent; - dout_fsm.strState = strDoutState; - retval = FsmNew(&dout_fsm, DoutFnList, ARRAY_SIZE(DoutFnList)); - if (retval) - goto err_l1; - - return 0; - -err_l1: - FsmFree(&l1fsm); -err: - return retval; -} - -// can't be __exit -void st5481_d_exit(void) -{ - FsmFree(&l1fsm); - FsmFree(&dout_fsm); -} diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c deleted file mode 100644 index 54ef9e4f8cbc..000000000000 --- a/drivers/isdn/hisax/st5481_init.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> - * 2001 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. - * - */ - -/* - * TODO: - * - * b layer1 delay? - * hotplug / unregister issues - * mod_inc/dec_use_count - * unify parts of d/b channel usb handling - * file header - * avoid copy to isoc buffer? - * improve usb delay? - * merge l1 state machines? - * clean up debug - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/usb.h> -#include <linux/slab.h> -#include "st5481.h" - -MODULE_DESCRIPTION("ISDN4Linux: driver for ST5481 USB ISDN adapter"); -MODULE_AUTHOR("Frode Isaksen"); -MODULE_LICENSE("GPL"); - -static int protocol = 2; /* EURO-ISDN Default */ -module_param(protocol, int, 0); - -static int number_of_leds = 2; /* 2 LEDs on the adpater default */ -module_param(number_of_leds, int, 0); - -#ifdef CONFIG_HISAX_DEBUG -static int debug = 0; -module_param(debug, int, 0); -#endif -int st5481_debug; - -/* ====================================================================== - * registration/deregistration with the USB layer - */ - -/* - * This function will be called when the adapter is plugged - * into the USB bus. - */ -static int probe_st5481(struct usb_interface *intf, - const struct usb_device_id *id) -{ - struct usb_device *dev = interface_to_usbdev(intf); - struct st5481_adapter *adapter; - struct hisax_b_if *b_if[2]; - int retval, i; - - printk(KERN_INFO "st541: found adapter VendorId %04x, ProductId %04x, LEDs %d\n", - le16_to_cpu(dev->descriptor.idVendor), - le16_to_cpu(dev->descriptor.idProduct), - number_of_leds); - - adapter = kzalloc(sizeof(struct st5481_adapter), GFP_KERNEL); - if (!adapter) - return -ENOMEM; - - adapter->number_of_leds = number_of_leds; - adapter->usb_dev = dev; - - adapter->hisax_d_if.owner = THIS_MODULE; - adapter->hisax_d_if.ifc.priv = adapter; - adapter->hisax_d_if.ifc.l2l1 = st5481_d_l2l1; - - for (i = 0; i < 2; i++) { - adapter->bcs[i].adapter = adapter; - adapter->bcs[i].channel = i; - adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i]; - adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1; - } - - retval = st5481_setup_usb(adapter); - if (retval < 0) - goto err; - - retval = st5481_setup_d(adapter); - if (retval < 0) - goto err_usb; - - retval = st5481_setup_b(&adapter->bcs[0]); - if (retval < 0) - goto err_d; - - retval = st5481_setup_b(&adapter->bcs[1]); - if (retval < 0) - goto err_b; - - for (i = 0; i < 2; i++) - b_if[i] = &adapter->bcs[i].b_if; - - if (hisax_register(&adapter->hisax_d_if, b_if, "st5481_usb", - protocol) != 0) - goto err_b1; - - st5481_start(adapter); - - usb_set_intfdata(intf, adapter); - return 0; - -err_b1: - st5481_release_b(&adapter->bcs[1]); -err_b: - st5481_release_b(&adapter->bcs[0]); -err_d: - st5481_release_d(adapter); -err_usb: - st5481_release_usb(adapter); -err: - kfree(adapter); - return -EIO; -} - -/* - * This function will be called when the adapter is removed - * from the USB bus. - */ -static void disconnect_st5481(struct usb_interface *intf) -{ - struct st5481_adapter *adapter = usb_get_intfdata(intf); - - DBG(1, ""); - - usb_set_intfdata(intf, NULL); - if (!adapter) - return; - - st5481_stop(adapter); - st5481_release_b(&adapter->bcs[1]); - st5481_release_b(&adapter->bcs[0]); - st5481_release_d(adapter); - // we would actually better wait for completion of outstanding urbs - mdelay(2); - st5481_release_usb(adapter); - - hisax_unregister(&adapter->hisax_d_if); - - kfree(adapter); -} - -/* - * The last 4 bits in the Product Id is set with 4 pins on the chip. - */ -static struct usb_device_id st5481_ids[] = { - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x0) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x1) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x2) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x3) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x4) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x5) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x6) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x7) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x8) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0x9) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xA) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xB) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xC) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xD) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xE) }, - { USB_DEVICE(ST_VENDOR_ID, ST5481_PRODUCT_ID + 0xF) }, - { } -}; -MODULE_DEVICE_TABLE(usb, st5481_ids); - -static struct usb_driver st5481_usb_driver = { - .name = "st5481_usb", - .probe = probe_st5481, - .disconnect = disconnect_st5481, - .id_table = st5481_ids, - .disable_hub_initiated_lpm = 1, -}; - -static int __init st5481_usb_init(void) -{ - int retval; - -#ifdef CONFIG_HISAX_DEBUG - st5481_debug = debug; -#endif - - printk(KERN_INFO "hisax_st5481: ST5481 USB ISDN driver $Revision: 2.4.2.3 $\n"); - - retval = st5481_d_init(); - if (retval < 0) - goto out; - - retval = usb_register(&st5481_usb_driver); - if (retval < 0) - goto out_d_exit; - - return 0; - -out_d_exit: - st5481_d_exit(); -out: - return retval; -} - -static void __exit st5481_usb_exit(void) -{ - usb_deregister(&st5481_usb_driver); - st5481_d_exit(); -} - -module_init(st5481_usb_init); -module_exit(st5481_usb_exit); diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c deleted file mode 100644 index f207fda691c7..000000000000 --- a/drivers/isdn/hisax/st5481_usb.c +++ /dev/null @@ -1,659 +0,0 @@ -/* - * Driver for ST5481 USB ISDN modem - * - * Author Frode Isaksen - * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com> - * 2001 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. - * - */ - -#include <linux/init.h> -#include <linux/usb.h> -#include <linux/slab.h> -#include "st5481.h" - -static int st5481_isoc_flatten(struct urb *urb); - -/* ====================================================================== - * control pipe - */ - -/* - * Send the next endpoint 0 request stored in the FIFO. - * Called either by the completion or by usb_ctrl_msg. - */ -static void usb_next_ctrl_msg(struct urb *urb, - struct st5481_adapter *adapter) -{ - struct st5481_ctrl *ctrl = &adapter->ctrl; - int r_index; - - if (test_and_set_bit(0, &ctrl->busy)) { - return; - } - - if ((r_index = fifo_remove(&ctrl->msg_fifo.f)) < 0) { - test_and_clear_bit(0, &ctrl->busy); - return; - } - urb->setup_packet = - (unsigned char *)&ctrl->msg_fifo.data[r_index]; - - DBG(1, "request=0x%02x,value=0x%04x,index=%x", - ((struct ctrl_msg *)urb->setup_packet)->dr.bRequest, - ((struct ctrl_msg *)urb->setup_packet)->dr.wValue, - ((struct ctrl_msg *)urb->setup_packet)->dr.wIndex); - - // Prepare the URB - urb->dev = adapter->usb_dev; - - SUBMIT_URB(urb, GFP_ATOMIC); -} - -/* - * Asynchronous endpoint 0 request (async version of usb_control_msg). - * The request will be queued up in a FIFO if the endpoint is busy. - */ -static void usb_ctrl_msg(struct st5481_adapter *adapter, - u8 request, u8 requesttype, u16 value, u16 index, - ctrl_complete_t complete, void *context) -{ - struct st5481_ctrl *ctrl = &adapter->ctrl; - int w_index; - struct ctrl_msg *ctrl_msg; - - if ((w_index = fifo_add(&ctrl->msg_fifo.f)) < 0) { - WARNING("control msg FIFO full"); - return; - } - ctrl_msg = &ctrl->msg_fifo.data[w_index]; - - ctrl_msg->dr.bRequestType = requesttype; - ctrl_msg->dr.bRequest = request; - ctrl_msg->dr.wValue = cpu_to_le16p(&value); - ctrl_msg->dr.wIndex = cpu_to_le16p(&index); - ctrl_msg->dr.wLength = 0; - ctrl_msg->complete = complete; - ctrl_msg->context = context; - - usb_next_ctrl_msg(ctrl->urb, adapter); -} - -/* - * Asynchronous endpoint 0 device request. - */ -void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter, - u8 request, u16 value, - ctrl_complete_t complete, void *context) -{ - usb_ctrl_msg(adapter, request, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, 0, complete, context); -} - -/* - * Asynchronous pipe reset (async version of usb_clear_halt). - */ -void st5481_usb_pipe_reset(struct st5481_adapter *adapter, - u_char pipe, - ctrl_complete_t complete, void *context) -{ - DBG(1, "pipe=%02x", pipe); - - usb_ctrl_msg(adapter, - USB_REQ_CLEAR_FEATURE, USB_DIR_OUT | USB_RECIP_ENDPOINT, - 0, pipe, complete, context); -} - - -/* - Physical level functions -*/ - -void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command) -{ - DBG(8, "command=%s", ST5481_CMD_string(command)); - - st5481_usb_device_ctrl_msg(adapter, TXCI, command, NULL, NULL); -} - -/* - * The request on endpoint 0 has completed. - * Call the user provided completion routine and try - * to send the next request. - */ -static void usb_ctrl_complete(struct urb *urb) -{ - struct st5481_adapter *adapter = urb->context; - struct st5481_ctrl *ctrl = &adapter->ctrl; - struct ctrl_msg *ctrl_msg; - - if (unlikely(urb->status < 0)) { - switch (urb->status) { - case -ENOENT: - case -ESHUTDOWN: - case -ECONNRESET: - DBG(1, "urb killed status %d", urb->status); - return; // Give up - default: - WARNING("urb status %d", urb->status); - break; - } - } - - ctrl_msg = (struct ctrl_msg *)urb->setup_packet; - - if (ctrl_msg->dr.bRequest == USB_REQ_CLEAR_FEATURE) { - /* Special case handling for pipe reset */ - le16_to_cpus(&ctrl_msg->dr.wIndex); - usb_reset_endpoint(adapter->usb_dev, ctrl_msg->dr.wIndex); - } - - if (ctrl_msg->complete) - ctrl_msg->complete(ctrl_msg->context); - - clear_bit(0, &ctrl->busy); - - // Try to send next control message - usb_next_ctrl_msg(urb, adapter); - return; -} - -/* ====================================================================== - * interrupt pipe - */ - -/* - * The interrupt endpoint will be called when any - * of the 6 registers changes state (depending on masks). - * Decode the register values and schedule a private event. - * Called at interrupt. - */ -static void usb_int_complete(struct urb *urb) -{ - u8 *data = urb->transfer_buffer; - u8 irqbyte; - struct st5481_adapter *adapter = urb->context; - int j; - int status; - - switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - DBG(2, "urb shutting down with status: %d", urb->status); - return; - default: - WARNING("nonzero urb status received: %d", urb->status); - goto exit; - } - - - DBG_PACKET(2, data, INT_PKT_SIZE); - - if (urb->actual_length == 0) { - goto exit; - } - - irqbyte = data[MPINT]; - if (irqbyte & DEN_INT) - FsmEvent(&adapter->d_out.fsm, EV_DOUT_DEN, NULL); - - if (irqbyte & DCOLL_INT) - FsmEvent(&adapter->d_out.fsm, EV_DOUT_COLL, NULL); - - irqbyte = data[FFINT_D]; - if (irqbyte & OUT_UNDERRUN) - FsmEvent(&adapter->d_out.fsm, EV_DOUT_UNDERRUN, NULL); - - if (irqbyte & OUT_DOWN) - ;// printk("OUT_DOWN\n"); - - irqbyte = data[MPINT]; - if (irqbyte & RXCI_INT) - FsmEvent(&adapter->l1m, data[CCIST] & 0x0f, NULL); - - for (j = 0; j < 2; j++) - adapter->bcs[j].b_out.flow_event |= data[FFINT_B1 + j]; - - urb->actual_length = 0; - -exit: - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status) - WARNING("usb_submit_urb failed with result %d", status); -} - -/* ====================================================================== - * initialization - */ - -int st5481_setup_usb(struct st5481_adapter *adapter) -{ - struct usb_device *dev = adapter->usb_dev; - struct st5481_ctrl *ctrl = &adapter->ctrl; - struct st5481_intr *intr = &adapter->intr; - struct usb_interface *intf; - struct usb_host_interface *altsetting = NULL; - struct usb_host_endpoint *endpoint; - int status; - struct urb *urb; - u8 *buf; - - DBG(2, ""); - - if ((status = usb_reset_configuration(dev)) < 0) { - WARNING("reset_configuration failed,status=%d", status); - return status; - } - - intf = usb_ifnum_to_if(dev, 0); - if (intf) - altsetting = usb_altnum_to_altsetting(intf, 3); - if (!altsetting) - return -ENXIO; - - // Check if the config is sane - if (altsetting->desc.bNumEndpoints != 7) { - WARNING("expecting 7 got %d endpoints!", altsetting->desc.bNumEndpoints); - return -EINVAL; - } - - // The descriptor is wrong for some early samples of the ST5481 chip - altsetting->endpoint[3].desc.wMaxPacketSize = cpu_to_le16(32); - altsetting->endpoint[4].desc.wMaxPacketSize = cpu_to_le16(32); - - // Use alternative setting 3 on interface 0 to have 2B+D - if ((status = usb_set_interface(dev, 0, 3)) < 0) { - WARNING("usb_set_interface failed,status=%d", status); - return status; - } - - // Allocate URB for control endpoint - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - return -ENOMEM; - } - ctrl->urb = urb; - - // Fill the control URB - usb_fill_control_urb(urb, dev, - usb_sndctrlpipe(dev, 0), - NULL, NULL, 0, usb_ctrl_complete, adapter); - - - fifo_init(&ctrl->msg_fifo.f, ARRAY_SIZE(ctrl->msg_fifo.data)); - - // Allocate URBs and buffers for interrupt endpoint - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - goto err1; - } - intr->urb = urb; - - buf = kmalloc(INT_PKT_SIZE, GFP_KERNEL); - if (!buf) { - goto err2; - } - - endpoint = &altsetting->endpoint[EP_INT-1]; - - // Fill the interrupt URB - usb_fill_int_urb(urb, dev, - usb_rcvintpipe(dev, endpoint->desc.bEndpointAddress), - buf, INT_PKT_SIZE, - usb_int_complete, adapter, - endpoint->desc.bInterval); - - return 0; -err2: - usb_free_urb(intr->urb); - intr->urb = NULL; -err1: - usb_free_urb(ctrl->urb); - ctrl->urb = NULL; - - return -ENOMEM; -} - -/* - * Release buffers and URBs for the interrupt and control - * endpoint. - */ -void st5481_release_usb(struct st5481_adapter *adapter) -{ - struct st5481_intr *intr = &adapter->intr; - struct st5481_ctrl *ctrl = &adapter->ctrl; - - DBG(1, ""); - - // Stop and free Control and Interrupt URBs - usb_kill_urb(ctrl->urb); - kfree(ctrl->urb->transfer_buffer); - usb_free_urb(ctrl->urb); - ctrl->urb = NULL; - - usb_kill_urb(intr->urb); - kfree(intr->urb->transfer_buffer); - usb_free_urb(intr->urb); - intr->urb = NULL; -} - -/* - * Initialize the adapter. - */ -void st5481_start(struct st5481_adapter *adapter) -{ - static const u8 init_cmd_table[] = { - SET_DEFAULT, 0, - STT, 0, - SDA_MIN, 0x0d, - SDA_MAX, 0x29, - SDELAY_VALUE, 0x14, - GPIO_DIR, 0x01, - GPIO_OUT, RED_LED, -// FFCTRL_OUT_D,4, -// FFCTRH_OUT_D,12, - FFCTRL_OUT_B1, 6, - FFCTRH_OUT_B1, 20, - FFCTRL_OUT_B2, 6, - FFCTRH_OUT_B2, 20, - MPMSK, RXCI_INT + DEN_INT + DCOLL_INT, - 0 - }; - struct st5481_intr *intr = &adapter->intr; - int i = 0; - u8 request, value; - - DBG(8, ""); - - adapter->leds = RED_LED; - - // Start receiving on the interrupt endpoint - SUBMIT_URB(intr->urb, GFP_KERNEL); - - while ((request = init_cmd_table[i++])) { - value = init_cmd_table[i++]; - st5481_usb_device_ctrl_msg(adapter, request, value, NULL, NULL); - } - st5481_ph_command(adapter, ST5481_CMD_PUP); -} - -/* - * Reset the adapter to default values. - */ -void st5481_stop(struct st5481_adapter *adapter) -{ - DBG(8, ""); - - st5481_usb_device_ctrl_msg(adapter, SET_DEFAULT, 0, NULL, NULL); -} - -/* ====================================================================== - * isochronous USB helpers - */ - -static void -fill_isoc_urb(struct urb *urb, struct usb_device *dev, - unsigned int pipe, void *buf, int num_packets, - int packet_size, usb_complete_t complete, - void *context) -{ - int k; - - usb_fill_int_urb(urb, dev, pipe, buf, num_packets * packet_size, - complete, context, 1); - - urb->number_of_packets = num_packets; - urb->transfer_flags = URB_ISO_ASAP; - for (k = 0; k < num_packets; k++) { - urb->iso_frame_desc[k].offset = packet_size * k; - urb->iso_frame_desc[k].length = packet_size; - urb->iso_frame_desc[k].actual_length = 0; - } -} - -int -st5481_setup_isocpipes(struct urb *urb[2], struct usb_device *dev, - unsigned int pipe, int num_packets, - int packet_size, int buf_size, - usb_complete_t complete, void *context) -{ - int j, retval; - unsigned char *buf; - - for (j = 0; j < 2; j++) { - retval = -ENOMEM; - urb[j] = usb_alloc_urb(num_packets, GFP_KERNEL); - if (!urb[j]) - goto err; - - // Allocate memory for 2000bytes/sec (16Kb/s) - buf = kmalloc(buf_size, GFP_KERNEL); - if (!buf) - goto err; - - // Fill the isochronous URB - fill_isoc_urb(urb[j], dev, pipe, buf, - num_packets, packet_size, complete, - context); - } - return 0; - -err: - for (j = 0; j < 2; j++) { - if (urb[j]) { - kfree(urb[j]->transfer_buffer); - urb[j]->transfer_buffer = NULL; - usb_free_urb(urb[j]); - urb[j] = NULL; - } - } - return retval; -} - -void st5481_release_isocpipes(struct urb *urb[2]) -{ - int j; - - for (j = 0; j < 2; j++) { - usb_kill_urb(urb[j]); - kfree(urb[j]->transfer_buffer); - usb_free_urb(urb[j]); - urb[j] = NULL; - } -} - -/* - * Decode frames received on the B/D channel. - * Note that this function will be called continuously - * with 64Kbit/s / 16Kbit/s of data and hence it will be - * called 50 times per second with 20 ISOC descriptors. - * Called at interrupt. - */ -static void usb_in_complete(struct urb *urb) -{ - struct st5481_in *in = urb->context; - unsigned char *ptr; - struct sk_buff *skb; - int len, count, status; - - if (unlikely(urb->status < 0)) { - switch (urb->status) { - case -ENOENT: - case -ESHUTDOWN: - case -ECONNRESET: - DBG(1, "urb killed status %d", urb->status); - return; // Give up - default: - WARNING("urb status %d", urb->status); - break; - } - } - - DBG_ISO_PACKET(0x80, urb); - - len = st5481_isoc_flatten(urb); - ptr = urb->transfer_buffer; - while (len > 0) { - if (in->mode == L1_MODE_TRANS) { - memcpy(in->rcvbuf, ptr, len); - status = len; - len = 0; - } else { - status = isdnhdlc_decode(&in->hdlc_state, ptr, len, &count, - in->rcvbuf, in->bufsize); - ptr += count; - len -= count; - } - - if (status > 0) { - // Good frame received - DBG(4, "count=%d", status); - DBG_PACKET(0x400, in->rcvbuf, status); - if (!(skb = dev_alloc_skb(status))) { - WARNING("receive out of memory\n"); - break; - } - skb_put_data(skb, in->rcvbuf, status); - in->hisax_if->l1l2(in->hisax_if, PH_DATA | INDICATION, skb); - } else if (status == -HDLC_CRC_ERROR) { - INFO("CRC error"); - } else if (status == -HDLC_FRAMING_ERROR) { - INFO("framing error"); - } else if (status == -HDLC_LENGTH_ERROR) { - INFO("length error"); - } - } - - // Prepare URB for next transfer - urb->dev = in->adapter->usb_dev; - urb->actual_length = 0; - - SUBMIT_URB(urb, GFP_ATOMIC); -} - -int st5481_setup_in(struct st5481_in *in) -{ - struct usb_device *dev = in->adapter->usb_dev; - int retval; - - DBG(4, ""); - - in->rcvbuf = kmalloc(in->bufsize, GFP_KERNEL); - retval = -ENOMEM; - if (!in->rcvbuf) - goto err; - - retval = st5481_setup_isocpipes(in->urb, dev, - usb_rcvisocpipe(dev, in->ep), - in->num_packets, in->packet_size, - in->num_packets * in->packet_size, - usb_in_complete, in); - if (retval) - goto err_free; - return 0; - -err_free: - kfree(in->rcvbuf); -err: - return retval; -} - -void st5481_release_in(struct st5481_in *in) -{ - DBG(2, ""); - - st5481_release_isocpipes(in->urb); -} - -/* - * Make the transfer_buffer contiguous by - * copying from the iso descriptors if necessary. - */ -static int st5481_isoc_flatten(struct urb *urb) -{ - struct usb_iso_packet_descriptor *pipd, *pend; - unsigned char *src, *dst; - unsigned int len; - - if (urb->status < 0) { - return urb->status; - } - for (pipd = &urb->iso_frame_desc[0], - pend = &urb->iso_frame_desc[urb->number_of_packets], - dst = urb->transfer_buffer; - pipd < pend; - pipd++) { - - if (pipd->status < 0) { - return (pipd->status); - } - - len = pipd->actual_length; - pipd->actual_length = 0; - src = urb->transfer_buffer + pipd->offset; - - if (src != dst) { - // Need to copy since isoc buffers not full - while (len--) { - *dst++ = *src++; - } - } else { - // No need to copy, just update destination buffer - dst += len; - } - } - // Return size of flattened buffer - return (dst - (unsigned char *)urb->transfer_buffer); -} - -static void st5481_start_rcv(void *context) -{ - struct st5481_in *in = context; - struct st5481_adapter *adapter = in->adapter; - - DBG(4, ""); - - in->urb[0]->dev = adapter->usb_dev; - SUBMIT_URB(in->urb[0], GFP_KERNEL); - - in->urb[1]->dev = adapter->usb_dev; - SUBMIT_URB(in->urb[1], GFP_KERNEL); -} - -void st5481_in_mode(struct st5481_in *in, int mode) -{ - if (in->mode == mode) - return; - - in->mode = mode; - - usb_unlink_urb(in->urb[0]); - usb_unlink_urb(in->urb[1]); - - if (in->mode != L1_MODE_NULL) { - if (in->mode != L1_MODE_TRANS) { - u32 features = HDLC_BITREVERSE; - - if (in->mode == L1_MODE_HDLC_56K) - features |= HDLC_56KBIT; - isdnhdlc_rcv_init(&in->hdlc_state, features); - } - st5481_usb_pipe_reset(in->adapter, in->ep, NULL, NULL); - st5481_usb_device_ctrl_msg(in->adapter, in->counter, - in->packet_size, - NULL, NULL); - st5481_start_rcv(in); - } else { - st5481_usb_device_ctrl_msg(in->adapter, in->counter, - 0, NULL, NULL); - } -} diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c deleted file mode 100644 index 9195f9fd628f..000000000000 --- a/drivers/isdn/hisax/tei.c +++ /dev/null @@ -1,465 +0,0 @@ -/* $Id: tei.c,v 2.20.2.3 2004/01/13 14:31:26 keil Exp $ - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil <keil@isdn4linux.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 - * - * Thanks to Jan den Ouden - * Fritz Elfert - * - */ - -#include "hisax.h" -#include "isdnl2.h" -#include <linux/gfp.h> -#include <linux/init.h> -#include <linux/random.h> - -const char *tei_revision = "$Revision: 2.20.2.3 $"; - -#define ID_REQUEST 1 -#define ID_ASSIGNED 2 -#define ID_DENIED 3 -#define ID_CHK_REQ 4 -#define ID_CHK_RES 5 -#define ID_REMOVE 6 -#define ID_VERIFY 7 - -#define TEI_ENTITY_ID 0xf - -static struct Fsm teifsm; - -void tei_handler(struct PStack *st, u_char pr, struct sk_buff *skb); - -enum { - ST_TEI_NOP, - ST_TEI_IDREQ, - ST_TEI_IDVERIFY, -}; - -#define TEI_STATE_COUNT (ST_TEI_IDVERIFY + 1) - -static char *strTeiState[] = -{ - "ST_TEI_NOP", - "ST_TEI_IDREQ", - "ST_TEI_IDVERIFY", -}; - -enum { - EV_IDREQ, - EV_ASSIGN, - EV_DENIED, - EV_CHKREQ, - EV_REMOVE, - EV_VERIFY, - EV_T202, -}; - -#define TEI_EVENT_COUNT (EV_T202 + 1) - -static char *strTeiEvent[] = -{ - "EV_IDREQ", - "EV_ASSIGN", - "EV_DENIED", - "EV_CHKREQ", - "EV_REMOVE", - "EV_VERIFY", - "EV_T202", -}; - -static unsigned int -random_ri(void) -{ - unsigned int x; - - get_random_bytes(&x, sizeof(x)); - return (x & 0xffff); -} - -static struct PStack * -findtei(struct PStack *st, int tei) -{ - struct PStack *ptr = *(st->l1.stlistp); - - if (tei == 127) - return (NULL); - - while (ptr) - if (ptr->l2.tei == tei) - return (ptr); - else - ptr = ptr->next; - return (NULL); -} - -static void -put_tei_msg(struct PStack *st, u_char m_id, unsigned int ri, u_char tei) -{ - struct sk_buff *skb; - u_char *bp; - - if (!(skb = alloc_skb(8, GFP_ATOMIC))) { - printk(KERN_WARNING "HiSax: No skb for TEI manager\n"); - return; - } - bp = skb_put(skb, 3); - bp[0] = (TEI_SAPI << 2); - bp[1] = (GROUP_TEI << 1) | 0x1; - bp[2] = UI; - bp = skb_put(skb, 5); - bp[0] = TEI_ENTITY_ID; - bp[1] = ri >> 8; - bp[2] = ri & 0xff; - bp[3] = m_id; - bp[4] = (tei << 1) | 1; - st->l2.l2l1(st, PH_DATA | REQUEST, skb); -} - -static void -tei_id_request(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (st->l2.tei != -1) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "assign request for already assigned tei %d", - st->l2.tei); - return; - } - st->ma.ri = random_ri(); - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "assign request ri %d", st->ma.ri); - put_tei_msg(st, ID_REQUEST, st->ma.ri, 127); - FsmChangeState(&st->ma.tei_m, ST_TEI_IDREQ); - FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 1); - st->ma.N202 = 3; -} - -static void -tei_id_assign(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *ost, *st = fi->userdata; - struct sk_buff *skb = arg; - struct IsdnCardState *cs; - int ri, tei; - - ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; - tei = skb->data[4] >> 1; - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ - if (ri != ost->ma.ri) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "possible duplicate assignment tei %d", tei); - ost->l2.l2tei(ost, MDL_ERROR | RESPONSE, NULL); - } - } else if (ri == st->ma.ri) { - FsmDelTimer(&st->ma.t202, 1); - FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) tei); - cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); - } -} - -static void -tei_id_test_dup(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *ost, *st = fi->userdata; - struct sk_buff *skb = arg; - int tei, ri; - - ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; - tei = skb->data[4] >> 1; - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "foreign identity assign ri %d tei %d", ri, tei); - if ((ost = findtei(st, tei))) { /* same tei is in use */ - if (ri != ost->ma.ri) { /* and it wasn't our request */ - st->ma.tei_m.printdebug(&st->ma.tei_m, - "possible duplicate assignment tei %d", tei); - FsmEvent(&ost->ma.tei_m, EV_VERIFY, NULL); - } - } -} - -static void -tei_id_denied(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int ri, tei; - - ri = ((unsigned int) skb->data[1] << 8) + skb->data[2]; - tei = skb->data[4] >> 1; - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "identity denied ri %d tei %d", ri, tei); -} - -static void -tei_id_chk_req(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - int tei; - - tei = skb->data[4] >> 1; - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "identity check req tei %d", tei); - if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { - FsmDelTimer(&st->ma.t202, 4); - FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - put_tei_msg(st, ID_CHK_RES, random_ri(), st->l2.tei); - } -} - -static void -tei_id_remove(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct sk_buff *skb = arg; - struct IsdnCardState *cs; - int tei; - - tei = skb->data[4] >> 1; - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "identity remove tei %d", tei); - if ((st->l2.tei != -1) && ((tei == GROUP_TEI) || (tei == st->l2.tei))) { - FsmDelTimer(&st->ma.t202, 5); - FsmChangeState(&st->ma.tei_m, ST_TEI_NOP); - st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL); - cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); - } -} - -static void -tei_id_verify(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "id verify request for tei %d", st->l2.tei); - put_tei_msg(st, ID_VERIFY, 0, st->l2.tei); - FsmChangeState(&st->ma.tei_m, ST_TEI_IDVERIFY); - FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 2); - st->ma.N202 = 2; -} - -static void -tei_id_req_tout(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct IsdnCardState *cs; - - if (--st->ma.N202) { - st->ma.ri = random_ri(); - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "assign req(%d) ri %d", 4 - st->ma.N202, - st->ma.ri); - put_tei_msg(st, ID_REQUEST, st->ma.ri, 127); - FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 3); - } else { - st->ma.tei_m.printdebug(&st->ma.tei_m, "assign req failed"); - st->l3.l3l2(st, MDL_ERROR | RESPONSE, NULL); - cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); - FsmChangeState(fi, ST_TEI_NOP); - } -} - -static void -tei_id_ver_tout(struct FsmInst *fi, int event, void *arg) -{ - struct PStack *st = fi->userdata; - struct IsdnCardState *cs; - - if (--st->ma.N202) { - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "id verify req(%d) for tei %d", - 3 - st->ma.N202, st->l2.tei); - put_tei_msg(st, ID_VERIFY, 0, st->l2.tei); - FsmAddTimer(&st->ma.t202, st->ma.T202, EV_T202, NULL, 4); - } else { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "verify req for tei %d failed", st->l2.tei); - st->l3.l3l2(st, MDL_REMOVE | REQUEST, NULL); - cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_REMOVE | REQUEST, NULL); - FsmChangeState(fi, ST_TEI_NOP); - } -} - -static void -tei_l1l2(struct PStack *st, int pr, void *arg) -{ - struct sk_buff *skb = arg; - int mt; - - if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { - dev_kfree_skb(skb); - return; - } - - if (pr == (PH_DATA | INDICATION)) { - if (skb->len < 3) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "short mgr frame %ld/3", skb->len); - } else if ((skb->data[0] != ((TEI_SAPI << 2) | 2)) || - (skb->data[1] != ((GROUP_TEI << 1) | 1))) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "wrong mgr sapi/tei %x/%x", - skb->data[0], skb->data[1]); - } else if ((skb->data[2] & 0xef) != UI) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "mgr frame is not ui %x", skb->data[2]); - } else { - skb_pull(skb, 3); - if (skb->len < 5) { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "short mgr frame %ld/5", skb->len); - } else if (skb->data[0] != TEI_ENTITY_ID) { - /* wrong management entity identifier, ignore */ - st->ma.tei_m.printdebug(&st->ma.tei_m, - "tei handler wrong entity id %x", - skb->data[0]); - } else { - mt = skb->data[3]; - if (mt == ID_ASSIGNED) - FsmEvent(&st->ma.tei_m, EV_ASSIGN, skb); - else if (mt == ID_DENIED) - FsmEvent(&st->ma.tei_m, EV_DENIED, skb); - else if (mt == ID_CHK_REQ) - FsmEvent(&st->ma.tei_m, EV_CHKREQ, skb); - else if (mt == ID_REMOVE) - FsmEvent(&st->ma.tei_m, EV_REMOVE, skb); - else { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "tei handler wrong mt %x\n", mt); - } - } - } - } else { - st->ma.tei_m.printdebug(&st->ma.tei_m, - "tei handler wrong pr %x\n", pr); - } - dev_kfree_skb(skb); -} - -static void -tei_l2tei(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs; - - if (test_bit(FLG_FIXED_TEI, &st->l2.flag)) { - if (pr == (MDL_ASSIGN | INDICATION)) { - if (st->ma.debug) - st->ma.tei_m.printdebug(&st->ma.tei_m, - "fixed assign tei %d", st->l2.tei); - st->l3.l3l2(st, MDL_ASSIGN | REQUEST, (void *) (long) st->l2.tei); - cs = (struct IsdnCardState *) st->l1.hardware; - cs->cardmsg(cs, MDL_ASSIGN | REQUEST, NULL); - } - return; - } - switch (pr) { - case (MDL_ASSIGN | INDICATION): - FsmEvent(&st->ma.tei_m, EV_IDREQ, arg); - break; - case (MDL_ERROR | REQUEST): - FsmEvent(&st->ma.tei_m, EV_VERIFY, arg); - break; - default: - break; - } -} - -static void -tei_debug(struct FsmInst *fi, char *fmt, ...) -{ - va_list args; - struct PStack *st = fi->userdata; - - va_start(args, fmt); - VHiSax_putstatus(st->l1.hardware, "tei ", fmt, args); - va_end(args); -} - -void -setstack_tei(struct PStack *st) -{ - st->l2.l2tei = tei_l2tei; - st->ma.T202 = 2000; /* T202 2000 milliseconds */ - st->l1.l1tei = tei_l1l2; - st->ma.debug = 1; - st->ma.tei_m.fsm = &teifsm; - st->ma.tei_m.state = ST_TEI_NOP; - st->ma.tei_m.debug = 1; - st->ma.tei_m.userdata = st; - st->ma.tei_m.userint = 0; - st->ma.tei_m.printdebug = tei_debug; - FsmInitTimer(&st->ma.tei_m, &st->ma.t202); -} - -void -init_tei(struct IsdnCardState *cs, int protocol) -{ -} - -void -release_tei(struct IsdnCardState *cs) -{ - struct PStack *st = cs->stlist; - - while (st) { - FsmDelTimer(&st->ma.t202, 1); - st = st->next; - } -} - -static struct FsmNode TeiFnList[] __initdata = -{ - {ST_TEI_NOP, EV_IDREQ, tei_id_request}, - {ST_TEI_NOP, EV_ASSIGN, tei_id_test_dup}, - {ST_TEI_NOP, EV_VERIFY, tei_id_verify}, - {ST_TEI_NOP, EV_REMOVE, tei_id_remove}, - {ST_TEI_NOP, EV_CHKREQ, tei_id_chk_req}, - {ST_TEI_IDREQ, EV_T202, tei_id_req_tout}, - {ST_TEI_IDREQ, EV_ASSIGN, tei_id_assign}, - {ST_TEI_IDREQ, EV_DENIED, tei_id_denied}, - {ST_TEI_IDVERIFY, EV_T202, tei_id_ver_tout}, - {ST_TEI_IDVERIFY, EV_REMOVE, tei_id_remove}, - {ST_TEI_IDVERIFY, EV_CHKREQ, tei_id_chk_req}, -}; - -int __init -TeiNew(void) -{ - teifsm.state_count = TEI_STATE_COUNT; - teifsm.event_count = TEI_EVENT_COUNT; - teifsm.strEvent = strTeiEvent; - teifsm.strState = strTeiState; - return FsmNew(&teifsm, TeiFnList, ARRAY_SIZE(TeiFnList)); -} - -void -TeiFree(void) -{ - FsmFree(&teifsm); -} diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c deleted file mode 100644 index 247aa33076b1..000000000000 --- a/drivers/isdn/hisax/teleint.c +++ /dev/null @@ -1,334 +0,0 @@ -/* $Id: teleint.c,v 1.16.2.5 2004/01/19 15:31:50 keil Exp $ - * - * low level stuff for TeleInt isdn cards - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hfc_2bs0.h" -#include "isdnl1.h" - -static const char *TeleInt_revision = "$Revision: 1.16.2.5 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static inline u_char -readreg(unsigned int ale, unsigned int adr, u_char off) -{ - register u_char ret; - int max_delay = 2000; - - byteout(ale, off); - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) - ret = HFC_BUSY & bytein(ale); - if (!max_delay) { - printk(KERN_WARNING "TeleInt Busy not inactive\n"); - return (0); - } - ret = bytein(adr); - return (ret); -} - -static inline void -readfifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - register u_char ret; - register int max_delay = 20000; - register int i; - - byteout(ale, off); - for (i = 0; i < size; i++) { - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) - ret = HFC_BUSY & bytein(ale); - if (!max_delay) { - printk(KERN_WARNING "TeleInt Busy not inactive\n"); - return; - } - data[i] = bytein(adr); - } -} - - -static inline void -writereg(unsigned int ale, unsigned int adr, u_char off, u_char data) -{ - register u_char ret; - int max_delay = 2000; - - byteout(ale, off); - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) - ret = HFC_BUSY & bytein(ale); - if (!max_delay) { - printk(KERN_WARNING "TeleInt Busy not inactive\n"); - return; - } - byteout(adr, data); -} - -static inline void -writefifo(unsigned int ale, unsigned int adr, u_char off, u_char *data, int size) -{ - register u_char ret; - register int max_delay = 20000; - register int i; - - byteout(ale, off); - for (i = 0; i < size; i++) { - ret = HFC_BUSY & bytein(ale); - while (ret && --max_delay) - ret = HFC_BUSY & bytein(ale); - if (!max_delay) { - printk(KERN_WARNING "TeleInt Busy not inactive\n"); - return; - } - byteout(adr, data[i]); - } -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - cs->hw.hfc.cip = offset; - return (readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - cs->hw.hfc.cip = offset; - writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - cs->hw.hfc.cip = 0; - readfifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - cs->hw.hfc.cip = 0; - writefifo(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, 0, data, size); -} - -static u_char -ReadHFC(struct IsdnCardState *cs, int data, u_char reg) -{ - register u_char ret; - - if (data) { - cs->hw.hfc.cip = reg; - byteout(cs->hw.hfc.addr | 1, reg); - ret = bytein(cs->hw.hfc.addr); - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) - debugl1(cs, "hfc RD %02x %02x", reg, ret); - } else - ret = bytein(cs->hw.hfc.addr | 1); - return (ret); -} - -static void -WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value) -{ - byteout(cs->hw.hfc.addr | 1, reg); - cs->hw.hfc.cip = reg; - if (data) - byteout(cs->hw.hfc.addr, value); - if (cs->debug & L1_DEB_HSCX_FIFO && (data != 2)) - debugl1(cs, "hfc W%c %02x %02x", data ? 'D' : 'C', reg, value); -} - -static irqreturn_t -TeleInt_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - val = readreg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_ISTA); - if (val) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0xFF); - writereg(cs->hw.hfc.addr | 1, cs->hw.hfc.addr, ISAC_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -TeleInt_Timer(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, hw.hfc.timer); - int stat = 0; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (cs->bcs[0].mode) { - stat |= 1; - main_irq_hfc(&cs->bcs[0]); - } - if (cs->bcs[1].mode) { - stat |= 2; - main_irq_hfc(&cs->bcs[1]); - } - spin_unlock_irqrestore(&cs->lock, flags); - stat = HZ / 100; - if (!stat) - stat = 1; - cs->hw.hfc.timer.expires = jiffies + stat; - add_timer(&cs->hw.hfc.timer); -} - -static void -release_io_TeleInt(struct IsdnCardState *cs) -{ - del_timer(&cs->hw.hfc.timer); - releasehfc(cs); - if (cs->hw.hfc.addr) - release_region(cs->hw.hfc.addr, 2); -} - -static void -reset_TeleInt(struct IsdnCardState *cs) -{ - printk(KERN_INFO "TeleInt: resetting card\n"); - cs->hw.hfc.cirm |= HFC_RESET; - byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset On */ - mdelay(10); - cs->hw.hfc.cirm &= ~HFC_RESET; - byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); /* Reset Off */ - mdelay(10); -} - -static int -TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - int delay; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_TeleInt(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_TeleInt(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - reset_TeleInt(cs); - inithfc(cs); - clear_pending_isac_ints(cs); - initisac(cs); - /* Reenable all IRQ */ - cs->writeisac(cs, ISAC_MASK, 0); - cs->writeisac(cs, ISAC_CMDR, 0x41); - spin_unlock_irqrestore(&cs->lock, flags); - delay = HZ / 100; - if (!delay) - delay = 1; - cs->hw.hfc.timer.expires = jiffies + delay; - add_timer(&cs->hw.hfc.timer); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -int setup_TeleInt(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, TeleInt_revision); - printk(KERN_INFO "HiSax: TeleInt driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_TELEINT) - return (0); - - cs->hw.hfc.addr = card->para[1] & 0x3fe; - cs->irq = card->para[0]; - cs->hw.hfc.cirm = HFC_CIRM; - cs->hw.hfc.isac_spcr = 0x00; - cs->hw.hfc.cip = 0; - cs->hw.hfc.ctmt = HFC_CTMT | HFC_CLTIMER; - cs->bcs[0].hw.hfc.send = NULL; - cs->bcs[1].hw.hfc.send = NULL; - cs->hw.hfc.fifosize = 7 * 1024 + 512; - timer_setup(&cs->hw.hfc.timer, TeleInt_Timer, 0); - if (!request_region(cs->hw.hfc.addr, 2, "TeleInt isdn")) { - printk(KERN_WARNING - "HiSax: TeleInt config port %x-%x already in use\n", - cs->hw.hfc.addr, - cs->hw.hfc.addr + 2); - return (0); - } - /* HW IO = IO */ - byteout(cs->hw.hfc.addr, cs->hw.hfc.addr & 0xff); - byteout(cs->hw.hfc.addr | 1, ((cs->hw.hfc.addr & 0x300) >> 8) | 0x54); - switch (cs->irq) { - case 3: - cs->hw.hfc.cirm |= HFC_INTA; - break; - case 4: - cs->hw.hfc.cirm |= HFC_INTB; - break; - case 5: - cs->hw.hfc.cirm |= HFC_INTC; - break; - case 7: - cs->hw.hfc.cirm |= HFC_INTD; - break; - case 10: - cs->hw.hfc.cirm |= HFC_INTE; - break; - case 11: - cs->hw.hfc.cirm |= HFC_INTF; - break; - default: - printk(KERN_WARNING "TeleInt: wrong IRQ\n"); - release_io_TeleInt(cs); - return (0); - } - byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.cirm); - byteout(cs->hw.hfc.addr | 1, cs->hw.hfc.ctmt); - - printk(KERN_INFO "TeleInt: defined at 0x%x IRQ %d\n", - cs->hw.hfc.addr, cs->irq); - - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHFC; - cs->BC_Write_Reg = &WriteHFC; - cs->cardmsg = &TeleInt_card_msg; - cs->irq_func = &TeleInt_interrupt; - ISACVersion(cs, "TeleInt:"); - return (1); -} diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c deleted file mode 100644 index ce9eabdd2f6e..000000000000 --- a/drivers/isdn/hisax/teles0.c +++ /dev/null @@ -1,364 +0,0 @@ -/* $Id: teles0.c,v 2.15.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for Teles Memory IO isdn cards - * - * Author Karsten Keil - * based on the teles driver from Jan den Ouden - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Jan den Ouden - * Fritz Elfert - * Beat Doebeli - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isdnl1.h" -#include "isac.h" -#include "hscx.h" - -static const char *teles0_revision = "$Revision: 2.15.2.4 $"; - -#define TELES_IOMEM_SIZE 0x400 -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static inline u_char -readisac(void __iomem *adr, u_char off) -{ - return readb(adr + ((off & 1) ? 0x2ff : 0x100) + off); -} - -static inline void -writeisac(void __iomem *adr, u_char off, u_char data) -{ - writeb(data, adr + ((off & 1) ? 0x2ff : 0x100) + off); mb(); -} - - -static inline u_char -readhscx(void __iomem *adr, int hscx, u_char off) -{ - return readb(adr + (hscx ? 0x1c0 : 0x180) + - ((off & 1) ? 0x1ff : 0) + off); -} - -static inline void -writehscx(void __iomem *adr, int hscx, u_char off, u_char data) -{ - writeb(data, adr + (hscx ? 0x1c0 : 0x180) + - ((off & 1) ? 0x1ff : 0) + off); mb(); -} - -static inline void -read_fifo_isac(void __iomem *adr, u_char *data, int size) -{ - register int i; - register u_char __iomem *ad = adr + 0x100; - for (i = 0; i < size; i++) - data[i] = readb(ad); -} - -static inline void -write_fifo_isac(void __iomem *adr, u_char *data, int size) -{ - register int i; - register u_char __iomem *ad = adr + 0x100; - for (i = 0; i < size; i++) { - writeb(data[i], ad); mb(); - } -} - -static inline void -read_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size) -{ - register int i; - register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180); - for (i = 0; i < size; i++) - data[i] = readb(ad); -} - -static inline void -write_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size) -{ - int i; - register u_char __iomem *ad = adr + (hscx ? 0x1c0 : 0x180); - for (i = 0; i < size; i++) { - writeb(data[i], ad); mb(); - } -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readisac(cs->hw.teles0.membase, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writeisac(cs->hw.teles0.membase, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo_isac(cs->hw.teles0.membase, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo_isac(cs->hw.teles0.membase, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readhscx(cs->hw.teles0.membase, hscx, offset)); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writehscx(cs->hw.teles0.membase, hscx, offset, value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg) -#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -teles0_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - int count = 0; - - spin_lock_irqsave(&cs->lock, flags); - val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readisac(cs->hw.teles0.membase, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - count++; - val = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); - if (val && count < 5) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readisac(cs->hw.teles0.membase, ISAC_ISTA); - if (val && count < 5) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); - writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); - writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); - writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); - writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); - writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_teles0(struct IsdnCardState *cs) -{ - if (cs->hw.teles0.cfg_reg) - release_region(cs->hw.teles0.cfg_reg, 8); - iounmap(cs->hw.teles0.membase); - release_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE); -} - -static int -reset_teles0(struct IsdnCardState *cs) -{ - u_char cfval; - - if (cs->hw.teles0.cfg_reg) { - switch (cs->irq) { - case 2: - case 9: - cfval = 0x00; - break; - case 3: - cfval = 0x02; - break; - case 4: - cfval = 0x04; - break; - case 5: - cfval = 0x06; - break; - case 10: - cfval = 0x08; - break; - case 11: - cfval = 0x0A; - break; - case 12: - cfval = 0x0C; - break; - case 15: - cfval = 0x0E; - break; - default: - return (1); - } - cfval |= ((cs->hw.teles0.phymem >> 9) & 0xF0); - byteout(cs->hw.teles0.cfg_reg + 4, cfval); - HZDELAY(HZ / 10 + 1); - byteout(cs->hw.teles0.cfg_reg + 4, cfval | 1); - HZDELAY(HZ / 10 + 1); - } - writeb(0, cs->hw.teles0.membase + 0x80); mb(); - HZDELAY(HZ / 5 + 1); - writeb(1, cs->hw.teles0.membase + 0x80); mb(); - HZDELAY(HZ / 5 + 1); - return (0); -} - -static int -Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_teles0(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_teles0(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -int setup_teles0(struct IsdnCard *card) -{ - u_char val; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, teles0_revision); - printk(KERN_INFO "HiSax: Teles 8.0/16.0 driver Rev. %s\n", HiSax_getrev(tmp)); - if ((cs->typ != ISDN_CTYPE_16_0) && (cs->typ != ISDN_CTYPE_8_0)) - return (0); - - if (cs->typ == ISDN_CTYPE_16_0) - cs->hw.teles0.cfg_reg = card->para[2]; - else /* 8.0 */ - cs->hw.teles0.cfg_reg = 0; - - if (card->para[1] < 0x10000) { - card->para[1] <<= 4; - printk(KERN_INFO - "Teles0: membase configured DOSish, assuming 0x%lx\n", - (unsigned long) card->para[1]); - } - cs->irq = card->para[0]; - if (cs->hw.teles0.cfg_reg) { - if (!request_region(cs->hw.teles0.cfg_reg, 8, "teles cfg")) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.teles0.cfg_reg, - cs->hw.teles0.cfg_reg + 8); - return (0); - } - } - if (cs->hw.teles0.cfg_reg) { - if ((val = bytein(cs->hw.teles0.cfg_reg + 0)) != 0x51) { - printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", - cs->hw.teles0.cfg_reg + 0, val); - release_region(cs->hw.teles0.cfg_reg, 8); - return (0); - } - if ((val = bytein(cs->hw.teles0.cfg_reg + 1)) != 0x93) { - printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", - cs->hw.teles0.cfg_reg + 1, val); - release_region(cs->hw.teles0.cfg_reg, 8); - return (0); - } - val = bytein(cs->hw.teles0.cfg_reg + 2); /* 0x1e=without AB - * 0x1f=with AB - * 0x1c 16.3 ??? - */ - if (val != 0x1e && val != 0x1f) { - printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n", - cs->hw.teles0.cfg_reg + 2, val); - release_region(cs->hw.teles0.cfg_reg, 8); - return (0); - } - } - /* 16.0 and 8.0 designed for IOM1 */ - test_and_set_bit(HW_IOM1, &cs->HW_Flags); - cs->hw.teles0.phymem = card->para[1]; - if (!request_mem_region(cs->hw.teles0.phymem, TELES_IOMEM_SIZE, "teles iomem")) { - printk(KERN_WARNING - "HiSax: %s memory region %lx-%lx already in use\n", - CardType[card->typ], - cs->hw.teles0.phymem, - cs->hw.teles0.phymem + TELES_IOMEM_SIZE); - if (cs->hw.teles0.cfg_reg) - release_region(cs->hw.teles0.cfg_reg, 8); - return (0); - } - cs->hw.teles0.membase = ioremap(cs->hw.teles0.phymem, TELES_IOMEM_SIZE); - printk(KERN_INFO - "HiSax: %s config irq:%d mem:%p cfg:0x%X\n", - CardType[cs->typ], cs->irq, - cs->hw.teles0.membase, cs->hw.teles0.cfg_reg); - if (reset_teles0(cs)) { - printk(KERN_WARNING "Teles0: wrong IRQ\n"); - release_io_teles0(cs); - return (0); - } - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Teles_card_msg; - cs->irq_func = &teles0_interrupt; - ISACVersion(cs, "Teles0:"); - if (HscxVersion(cs, "Teles0:")) { - printk(KERN_WARNING - "Teles0: wrong HSCX versions check IO/MEM addresses\n"); - release_io_teles0(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c deleted file mode 100644 index 1eef693f04f0..000000000000 --- a/drivers/isdn/hisax/teles3.c +++ /dev/null @@ -1,498 +0,0 @@ -/* $Id: teles3.c,v 2.19.2.4 2004/01/13 23:48:39 keil Exp $ - * - * low level stuff for Teles 16.3 & PNP isdn cards - * - * Author Karsten Keil - * Copyright by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Thanks to Jan den Ouden - * Fritz Elfert - * Beat Doebeli - * - */ -#include <linux/init.h> -#include <linux/isapnp.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" - -static const char *teles3_revision = "$Revision: 2.19.2.4 $"; - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -static inline u_char -readreg(unsigned int adr, u_char off) -{ - return (bytein(adr + off)); -} - -static inline void -writereg(unsigned int adr, u_char off, u_char data) -{ - byteout(adr + off, data); -} - - -static inline void -read_fifo(unsigned int adr, u_char *data, int size) -{ - insb(adr, data, size); -} - -static void -write_fifo(unsigned int adr, u_char *data, int size) -{ - outsb(adr, data, size); -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readreg(cs->hw.teles3.isac, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writereg(cs->hw.teles3.isac, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo(cs->hw.teles3.isacfifo, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo(cs->hw.teles3.isacfifo, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readreg(cs->hw.teles3.hscx[hscx], offset)); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writereg(cs->hw.teles3.hscx[hscx], offset, value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readreg(cs->hw.teles3.hscx[nr], reg) -#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.teles3.hscx[nr], reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo(cs->hw.teles3.hscxfifo[nr], ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -teles3_interrupt(int intno, void *dev_id) -{ -#define MAXCOUNT 5 - struct IsdnCardState *cs = dev_id; - u_char val; - u_long flags; - int count = 0; - - spin_lock_irqsave(&cs->lock, flags); - val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA); -Start_HSCX: - if (val) - hscx_int_main(cs, val); - val = readreg(cs->hw.teles3.isac, ISAC_ISTA); -Start_ISAC: - if (val) - isac_interrupt(cs, val); - count++; - val = readreg(cs->hw.teles3.hscx[1], HSCX_ISTA); - if (val && count < MAXCOUNT) { - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "HSCX IntStat after IntRoutine"); - goto Start_HSCX; - } - val = readreg(cs->hw.teles3.isac, ISAC_ISTA); - if (val && count < MAXCOUNT) { - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ISAC IntStat after IntRoutine"); - goto Start_ISAC; - } - if (count >= MAXCOUNT) - printk(KERN_WARNING "Teles3: more than %d loops in teles3_interrupt\n", count); - writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0xFF); - writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0xFF); - writereg(cs->hw.teles3.isac, ISAC_MASK, 0xFF); - writereg(cs->hw.teles3.isac, ISAC_MASK, 0x0); - writereg(cs->hw.teles3.hscx[0], HSCX_MASK, 0x0); - writereg(cs->hw.teles3.hscx[1], HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static inline void -release_ioregs(struct IsdnCardState *cs, int mask) -{ - if (mask & 1) - release_region(cs->hw.teles3.isac + 32, 32); - if (mask & 2) - release_region(cs->hw.teles3.hscx[0] + 32, 32); - if (mask & 4) - release_region(cs->hw.teles3.hscx[1] + 32, 32); -} - -static void -release_io_teles3(struct IsdnCardState *cs) -{ - if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - release_region(cs->hw.teles3.hscx[1], 96); - } else { - if (cs->hw.teles3.cfg_reg) { - if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - release_region(cs->hw.teles3.cfg_reg, 1); - } else { - release_region(cs->hw.teles3.cfg_reg, 8); - } - } - release_ioregs(cs, 0x7); - } -} - -static int -reset_teles3(struct IsdnCardState *cs) -{ - u_char irqcfg; - - if (cs->typ != ISDN_CTYPE_TELESPCMCIA) { - if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) { - switch (cs->irq) { - case 2: - case 9: - irqcfg = 0x00; - break; - case 3: - irqcfg = 0x02; - break; - case 4: - irqcfg = 0x04; - break; - case 5: - irqcfg = 0x06; - break; - case 10: - irqcfg = 0x08; - break; - case 11: - irqcfg = 0x0A; - break; - case 12: - irqcfg = 0x0C; - break; - case 15: - irqcfg = 0x0E; - break; - default: - return (1); - } - byteout(cs->hw.teles3.cfg_reg + 4, irqcfg); - HZDELAY(HZ / 10 + 1); - byteout(cs->hw.teles3.cfg_reg + 4, irqcfg | 1); - HZDELAY(HZ / 10 + 1); - } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - byteout(cs->hw.teles3.cfg_reg, 0xff); - HZDELAY(2); - byteout(cs->hw.teles3.cfg_reg, 0x00); - HZDELAY(2); - } else { - /* Reset off for 16.3 PnP , thanks to Georg Acher */ - byteout(cs->hw.teles3.isac + 0x3c, 0); - HZDELAY(2); - byteout(cs->hw.teles3.isac + 0x3c, 1); - HZDELAY(2); - } - } - return (0); -} - -static int -Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - spin_lock_irqsave(&cs->lock, flags); - reset_teles3(cs); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_RELEASE: - release_io_teles3(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -#ifdef __ISAPNP__ - -static struct isapnp_device_id teles_ids[] = { - { ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), - ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), - (unsigned long) "Teles 16.3 PnP" }, - { ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0), - ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0), - (unsigned long) "Creatix 16.3 PnP" }, - { ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002), - ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002), - (unsigned long) "Compaq ISDN S0" }, - { 0, } -}; - -static struct isapnp_device_id *ipid = &teles_ids[0]; -static struct pnp_card *pnp_c = NULL; -#endif - -int setup_teles3(struct IsdnCard *card) -{ - u_char val; - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, teles3_revision); - printk(KERN_INFO "HiSax: Teles IO driver Rev. %s\n", HiSax_getrev(tmp)); - if ((cs->typ != ISDN_CTYPE_16_3) && (cs->typ != ISDN_CTYPE_PNP) - && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) - return (0); - -#ifdef __ISAPNP__ - if (!card->para[1] && isapnp_present()) { - struct pnp_dev *pnp_d; - while (ipid->card_vendor) { - if ((pnp_c = pnp_find_card(ipid->card_vendor, - ipid->card_device, pnp_c))) { - pnp_d = NULL; - if ((pnp_d = pnp_find_dev(pnp_c, - ipid->vendor, ipid->function, pnp_d))) { - int err; - - printk(KERN_INFO "HiSax: %s detected\n", - (char *)ipid->driver_data); - pnp_disable_dev(pnp_d); - err = pnp_activate_dev(pnp_d); - if (err < 0) { - printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n", - __func__, err); - return (0); - } - card->para[3] = pnp_port_start(pnp_d, 2); - card->para[2] = pnp_port_start(pnp_d, 1); - card->para[1] = pnp_port_start(pnp_d, 0); - card->para[0] = pnp_irq(pnp_d, 0); - if (card->para[0] == -1 || !card->para[1] || !card->para[2]) { - printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n", - card->para[0], card->para[1], card->para[2]); - pnp_disable_dev(pnp_d); - return (0); - } - break; - } else { - printk(KERN_ERR "Teles PnP: PnP error card found, no device\n"); - } - } - ipid++; - pnp_c = NULL; - } - if (!ipid->card_vendor) { - printk(KERN_INFO "Teles PnP: no ISAPnP card found\n"); - return (0); - } - } -#endif - if (cs->typ == ISDN_CTYPE_16_3) { - cs->hw.teles3.cfg_reg = card->para[1]; - switch (cs->hw.teles3.cfg_reg) { - case 0x180: - case 0x280: - case 0x380: - cs->hw.teles3.cfg_reg |= 0xc00; - break; - } - cs->hw.teles3.isac = cs->hw.teles3.cfg_reg - 0x420; - cs->hw.teles3.hscx[0] = cs->hw.teles3.cfg_reg - 0xc20; - cs->hw.teles3.hscx[1] = cs->hw.teles3.cfg_reg - 0x820; - } else if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - cs->hw.teles3.cfg_reg = 0; - cs->hw.teles3.hscx[0] = card->para[1] - 0x20; - cs->hw.teles3.hscx[1] = card->para[1]; - cs->hw.teles3.isac = card->para[1] + 0x20; - } else if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - cs->hw.teles3.cfg_reg = card->para[3]; - cs->hw.teles3.isac = card->para[2] - 32; - cs->hw.teles3.hscx[0] = card->para[1] - 32; - cs->hw.teles3.hscx[1] = card->para[1]; - } else { /* PNP */ - cs->hw.teles3.cfg_reg = 0; - cs->hw.teles3.isac = card->para[1] - 32; - cs->hw.teles3.hscx[0] = card->para[2] - 32; - cs->hw.teles3.hscx[1] = card->para[2]; - } - cs->irq = card->para[0]; - cs->hw.teles3.isacfifo = cs->hw.teles3.isac + 0x3e; - cs->hw.teles3.hscxfifo[0] = cs->hw.teles3.hscx[0] + 0x3e; - cs->hw.teles3.hscxfifo[1] = cs->hw.teles3.hscx[1] + 0x3e; - if (cs->typ == ISDN_CTYPE_TELESPCMCIA) { - if (!request_region(cs->hw.teles3.hscx[1], 96, "HiSax Teles PCMCIA")) { - printk(KERN_WARNING - "HiSax: %s ports %x-%x already in use\n", - CardType[cs->typ], - cs->hw.teles3.hscx[1], - cs->hw.teles3.hscx[1] + 96); - return (0); - } - cs->irq_flags |= IRQF_SHARED; /* cardbus can share */ - } else { - if (cs->hw.teles3.cfg_reg) { - if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - if (!request_region(cs->hw.teles3.cfg_reg, 1, "teles3 cfg")) { - printk(KERN_WARNING - "HiSax: %s config port %x already in use\n", - CardType[card->typ], - cs->hw.teles3.cfg_reg); - return (0); - } - } else { - if (!request_region(cs->hw.teles3.cfg_reg, 8, "teles3 cfg")) { - printk(KERN_WARNING - "HiSax: %s config port %x-%x already in use\n", - CardType[card->typ], - cs->hw.teles3.cfg_reg, - cs->hw.teles3.cfg_reg + 8); - return (0); - } - } - } - if (!request_region(cs->hw.teles3.isac + 32, 32, "HiSax isac")) { - printk(KERN_WARNING - "HiSax: %s isac ports %x-%x already in use\n", - CardType[cs->typ], - cs->hw.teles3.isac + 32, - cs->hw.teles3.isac + 64); - if (cs->hw.teles3.cfg_reg) { - if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - release_region(cs->hw.teles3.cfg_reg, 1); - } else { - release_region(cs->hw.teles3.cfg_reg, 8); - } - } - return (0); - } - if (!request_region(cs->hw.teles3.hscx[0] + 32, 32, "HiSax hscx A")) { - printk(KERN_WARNING - "HiSax: %s hscx A ports %x-%x already in use\n", - CardType[cs->typ], - cs->hw.teles3.hscx[0] + 32, - cs->hw.teles3.hscx[0] + 64); - if (cs->hw.teles3.cfg_reg) { - if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - release_region(cs->hw.teles3.cfg_reg, 1); - } else { - release_region(cs->hw.teles3.cfg_reg, 8); - } - } - release_ioregs(cs, 1); - return (0); - } - if (!request_region(cs->hw.teles3.hscx[1] + 32, 32, "HiSax hscx B")) { - printk(KERN_WARNING - "HiSax: %s hscx B ports %x-%x already in use\n", - CardType[cs->typ], - cs->hw.teles3.hscx[1] + 32, - cs->hw.teles3.hscx[1] + 64); - if (cs->hw.teles3.cfg_reg) { - if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) { - release_region(cs->hw.teles3.cfg_reg, 1); - } else { - release_region(cs->hw.teles3.cfg_reg, 8); - } - } - release_ioregs(cs, 3); - return (0); - } - } - if ((cs->hw.teles3.cfg_reg) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA)) { - if ((val = bytein(cs->hw.teles3.cfg_reg + 0)) != 0x51) { - printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", - cs->hw.teles3.cfg_reg + 0, val); - release_io_teles3(cs); - return (0); - } - if ((val = bytein(cs->hw.teles3.cfg_reg + 1)) != 0x93) { - printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", - cs->hw.teles3.cfg_reg + 1, val); - release_io_teles3(cs); - return (0); - } - val = bytein(cs->hw.teles3.cfg_reg + 2);/* 0x1e=without AB - * 0x1f=with AB - * 0x1c 16.3 ??? - * 0x39 16.3 1.1 - * 0x38 16.3 1.3 - * 0x46 16.3 with AB + Video (Teles-Vision) - */ - if (val != 0x46 && val != 0x39 && val != 0x38 && val != 0x1c && val != 0x1e && val != 0x1f) { - printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n", - cs->hw.teles3.cfg_reg + 2, val); - release_io_teles3(cs); - return (0); - } - } - printk(KERN_INFO - "HiSax: %s config irq:%d isac:0x%X cfg:0x%X\n", - CardType[cs->typ], cs->irq, - cs->hw.teles3.isac + 32, cs->hw.teles3.cfg_reg); - printk(KERN_INFO - "HiSax: hscx A:0x%X hscx B:0x%X\n", - cs->hw.teles3.hscx[0] + 32, cs->hw.teles3.hscx[1] + 32); - - setup_isac(cs); - if (reset_teles3(cs)) { - printk(KERN_WARNING "Teles3: wrong IRQ\n"); - release_io_teles3(cs); - return (0); - } - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &Teles_card_msg; - cs->irq_func = &teles3_interrupt; - ISACVersion(cs, "Teles3:"); - if (HscxVersion(cs, "Teles3:")) { - printk(KERN_WARNING - "Teles3: wrong HSCX versions check IO address\n"); - release_io_teles3(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c deleted file mode 100644 index bcc37e955622..000000000000 --- a/drivers/isdn/hisax/teles_cs.c +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* $Id: teles_cs.c,v 1.1.2.2 2004/01/25 15:07:06 keil Exp $ */ -/*====================================================================== - - A teles S0 PCMCIA client driver - - Based on skeleton by David Hinds, dhinds@allegro.stanford.edu - Written by Christof Petig, christof.petig@wtal.de - - Also inspired by ELSA PCMCIA driver - by Klaus Lichtenwalder <Lichtenwalder@ACM.org> - - Extensions to new hisax_pcmcia by Karsten Keil - - minor changes to be compatible with kernel 2.4.x - by Jan.Schubert@GMX.li - - ======================================================================*/ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/ioport.h> -#include <asm/io.h> - -#include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> -#include <pcmcia/ds.h> -#include "hisax_cfg.h" - -MODULE_DESCRIPTION("ISDN4Linux: PCMCIA client driver for Teles PCMCIA cards"); -MODULE_AUTHOR("Christof Petig, christof.petig@wtal.de, Karsten Keil, kkeil@suse.de"); -MODULE_LICENSE("GPL"); - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -static int protocol = 2; /* EURO-ISDN Default */ -module_param(protocol, int, 0); - -static int teles_cs_config(struct pcmcia_device *link); -static void teles_cs_release(struct pcmcia_device *link); -static void teles_detach(struct pcmcia_device *p_dev); - -typedef struct local_info_t { - struct pcmcia_device *p_dev; - int busy; - int cardnr; -} local_info_t; - -static int teles_probe(struct pcmcia_device *link) -{ - local_info_t *local; - - dev_dbg(&link->dev, "teles_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(local_info_t), GFP_KERNEL); - if (!local) return -ENOMEM; - local->cardnr = -1; - - local->p_dev = link; - link->priv = local; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - return teles_cs_config(link); -} /* teles_attach */ - -static void teles_detach(struct pcmcia_device *link) -{ - local_info_t *info = link->priv; - - dev_dbg(&link->dev, "teles_detach(0x%p)\n", link); - - info->busy = 1; - teles_cs_release(link); - - kfree(info); -} /* teles_detach */ - -static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data) -{ - int j; - - p_dev->io_lines = 5; - p_dev->resource[0]->end = 96; - p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) { - printk(KERN_INFO "(teles_cs: looks like the 96 model)\n"); - if (!pcmcia_request_io(p_dev)) - return 0; - } else { - printk(KERN_INFO "(teles_cs: looks like the 97 model)\n"); - for (j = 0x2f0; j > 0x100; j -= 0x10) { - p_dev->resource[0]->start = j; - if (!pcmcia_request_io(p_dev)) - return 0; - } - } - return -ENODEV; -} - -static int teles_cs_config(struct pcmcia_device *link) -{ - int i; - IsdnCard_t icard; - - dev_dbg(&link->dev, "teles_config(0x%p)\n", link); - - i = pcmcia_loop_config(link, teles_cs_configcheck, NULL); - if (i != 0) - goto cs_failed; - - if (!link->irq) - goto cs_failed; - - i = pcmcia_enable_device(link); - if (i != 0) - goto cs_failed; - - icard.para[0] = link->irq; - icard.para[1] = link->resource[0]->start; - icard.protocol = protocol; - icard.typ = ISDN_CTYPE_TELESPCMCIA; - - i = hisax_init_pcmcia(link, &(((local_info_t *)link->priv)->busy), &icard); - if (i < 0) { - printk(KERN_ERR "teles_cs: failed to initialize Teles PCMCIA %d at i/o %#x\n", - i, (unsigned int) link->resource[0]->start); - teles_cs_release(link); - return -ENODEV; - } - - ((local_info_t *)link->priv)->cardnr = i; - return 0; - -cs_failed: - teles_cs_release(link); - return -ENODEV; -} /* teles_cs_config */ - -static void teles_cs_release(struct pcmcia_device *link) -{ - local_info_t *local = link->priv; - - dev_dbg(&link->dev, "teles_cs_release(0x%p)\n", link); - - if (local) { - if (local->cardnr >= 0) { - /* no unregister function with hisax */ - HiSax_closecard(local->cardnr); - } - } - - pcmcia_disable_device(link); -} /* teles_cs_release */ - -static int teles_suspend(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->busy = 1; - - return 0; -} - -static int teles_resume(struct pcmcia_device *link) -{ - local_info_t *dev = link->priv; - - dev->busy = 0; - - return 0; -} - - -static const struct pcmcia_device_id teles_ids[] = { - PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, teles_ids); - -static struct pcmcia_driver teles_cs_driver = { - .owner = THIS_MODULE, - .name = "teles_cs", - .probe = teles_probe, - .remove = teles_detach, - .id_table = teles_ids, - .suspend = teles_suspend, - .resume = teles_resume, -}; -module_pcmcia_driver(teles_cs_driver); diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c deleted file mode 100644 index 33eeb4602c7e..000000000000 --- a/drivers/isdn/hisax/telespci.c +++ /dev/null @@ -1,349 +0,0 @@ -/* $Id: telespci.c,v 2.23.2.3 2004/01/13 14:31:26 keil Exp $ - * - * low level stuff for Teles PCI isdn cards - * - * Author Ton van Rosmalen - * Karsten Keil - * Copyright by Ton van Rosmalen - * by Karsten Keil <keil@isdn4linux.de> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "isac.h" -#include "hscx.h" -#include "isdnl1.h" -#include <linux/pci.h> - -static const char *telespci_revision = "$Revision: 2.23.2.3 $"; - -#define ZORAN_PO_RQ_PEN 0x02000000 -#define ZORAN_PO_WR 0x00800000 -#define ZORAN_PO_GID0 0x00000000 -#define ZORAN_PO_GID1 0x00100000 -#define ZORAN_PO_GREG0 0x00000000 -#define ZORAN_PO_GREG1 0x00010000 -#define ZORAN_PO_DMASK 0xFF - -#define WRITE_ADDR_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG0) -#define READ_DATA_ISAC (ZORAN_PO_GID0 | ZORAN_PO_GREG1) -#define WRITE_DATA_ISAC (ZORAN_PO_WR | ZORAN_PO_GID0 | ZORAN_PO_GREG1) -#define WRITE_ADDR_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG0) -#define READ_DATA_HSCX (ZORAN_PO_GID1 | ZORAN_PO_GREG1) -#define WRITE_DATA_HSCX (ZORAN_PO_WR | ZORAN_PO_GID1 | ZORAN_PO_GREG1) - -#define ZORAN_WAIT_NOBUSY do { \ - portdata = readl(adr + 0x200); \ - } while (portdata & ZORAN_PO_RQ_PEN) - -static inline u_char -readisac(void __iomem *adr, u_char off) -{ - register unsigned int portdata; - - ZORAN_WAIT_NOBUSY; - - /* set address for ISAC */ - writel(WRITE_ADDR_ISAC | off, adr + 0x200); - ZORAN_WAIT_NOBUSY; - - /* read data from ISAC */ - writel(READ_DATA_ISAC, adr + 0x200); - ZORAN_WAIT_NOBUSY; - return ((u_char)(portdata & ZORAN_PO_DMASK)); -} - -static inline void -writeisac(void __iomem *adr, u_char off, u_char data) -{ - register unsigned int portdata; - - ZORAN_WAIT_NOBUSY; - - /* set address for ISAC */ - writel(WRITE_ADDR_ISAC | off, adr + 0x200); - ZORAN_WAIT_NOBUSY; - - /* write data to ISAC */ - writel(WRITE_DATA_ISAC | data, adr + 0x200); - ZORAN_WAIT_NOBUSY; -} - -static inline u_char -readhscx(void __iomem *adr, int hscx, u_char off) -{ - register unsigned int portdata; - - ZORAN_WAIT_NOBUSY; - /* set address for HSCX */ - writel(WRITE_ADDR_HSCX | ((hscx ? 0x40 : 0) + off), adr + 0x200); - ZORAN_WAIT_NOBUSY; - - /* read data from HSCX */ - writel(READ_DATA_HSCX, adr + 0x200); - ZORAN_WAIT_NOBUSY; - return ((u_char)(portdata & ZORAN_PO_DMASK)); -} - -static inline void -writehscx(void __iomem *adr, int hscx, u_char off, u_char data) -{ - register unsigned int portdata; - - ZORAN_WAIT_NOBUSY; - /* set address for HSCX */ - writel(WRITE_ADDR_HSCX | ((hscx ? 0x40 : 0) + off), adr + 0x200); - ZORAN_WAIT_NOBUSY; - - /* write data to HSCX */ - writel(WRITE_DATA_HSCX | data, adr + 0x200); - ZORAN_WAIT_NOBUSY; -} - -static inline void -read_fifo_isac(void __iomem *adr, u_char *data, int size) -{ - register unsigned int portdata; - register int i; - - ZORAN_WAIT_NOBUSY; - /* read data from ISAC */ - for (i = 0; i < size; i++) { - /* set address for ISAC fifo */ - writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200); - ZORAN_WAIT_NOBUSY; - writel(READ_DATA_ISAC, adr + 0x200); - ZORAN_WAIT_NOBUSY; - data[i] = (u_char)(portdata & ZORAN_PO_DMASK); - } -} - -static void -write_fifo_isac(void __iomem *adr, u_char *data, int size) -{ - register unsigned int portdata; - register int i; - - ZORAN_WAIT_NOBUSY; - /* write data to ISAC */ - for (i = 0; i < size; i++) { - /* set address for ISAC fifo */ - writel(WRITE_ADDR_ISAC | 0x1E, adr + 0x200); - ZORAN_WAIT_NOBUSY; - writel(WRITE_DATA_ISAC | data[i], adr + 0x200); - ZORAN_WAIT_NOBUSY; - } -} - -static inline void -read_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size) -{ - register unsigned int portdata; - register int i; - - ZORAN_WAIT_NOBUSY; - /* read data from HSCX */ - for (i = 0; i < size; i++) { - /* set address for HSCX fifo */ - writel(WRITE_ADDR_HSCX | (hscx ? 0x5F : 0x1F), adr + 0x200); - ZORAN_WAIT_NOBUSY; - writel(READ_DATA_HSCX, adr + 0x200); - ZORAN_WAIT_NOBUSY; - data[i] = (u_char) (portdata & ZORAN_PO_DMASK); - } -} - -static inline void -write_fifo_hscx(void __iomem *adr, int hscx, u_char *data, int size) -{ - unsigned int portdata; - register int i; - - ZORAN_WAIT_NOBUSY; - /* write data to HSCX */ - for (i = 0; i < size; i++) { - /* set address for HSCX fifo */ - writel(WRITE_ADDR_HSCX | (hscx ? 0x5F : 0x1F), adr + 0x200); - ZORAN_WAIT_NOBUSY; - writel(WRITE_DATA_HSCX | data[i], adr + 0x200); - ZORAN_WAIT_NOBUSY; - udelay(10); - } -} - -/* Interface functions */ - -static u_char -ReadISAC(struct IsdnCardState *cs, u_char offset) -{ - return (readisac(cs->hw.teles0.membase, offset)); -} - -static void -WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value) -{ - writeisac(cs->hw.teles0.membase, offset, value); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - read_fifo_isac(cs->hw.teles0.membase, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - write_fifo_isac(cs->hw.teles0.membase, data, size); -} - -static u_char -ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset) -{ - return (readhscx(cs->hw.teles0.membase, hscx, offset)); -} - -static void -WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value) -{ - writehscx(cs->hw.teles0.membase, hscx, offset, value); -} - -/* - * fast interrupt HSCX stuff goes here - */ - -#define READHSCX(cs, nr, reg) readhscx(cs->hw.teles0.membase, nr, reg) -#define WRITEHSCX(cs, nr, reg, data) writehscx(cs->hw.teles0.membase, nr, reg, data) -#define READHSCXFIFO(cs, nr, ptr, cnt) read_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) -#define WRITEHSCXFIFO(cs, nr, ptr, cnt) write_fifo_hscx(cs->hw.teles0.membase, nr, ptr, cnt) - -#include "hscx_irq.c" - -static irqreturn_t -telespci_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char hval, ival; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - hval = readhscx(cs->hw.teles0.membase, 1, HSCX_ISTA); - if (hval) - hscx_int_main(cs, hval); - ival = readisac(cs->hw.teles0.membase, ISAC_ISTA); - if ((hval | ival) == 0) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } - if (ival) - isac_interrupt(cs, ival); - /* Clear interrupt register for Zoran PCI controller */ - writel(0x70000000, cs->hw.teles0.membase + 0x3C); - - writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0xFF); - writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0xFF); - writeisac(cs->hw.teles0.membase, ISAC_MASK, 0xFF); - writeisac(cs->hw.teles0.membase, ISAC_MASK, 0x0); - writehscx(cs->hw.teles0.membase, 0, HSCX_MASK, 0x0); - writehscx(cs->hw.teles0.membase, 1, HSCX_MASK, 0x0); - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -release_io_telespci(struct IsdnCardState *cs) -{ - iounmap(cs->hw.teles0.membase); -} - -static int -TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - u_long flags; - - switch (mt) { - case CARD_RESET: - return (0); - case CARD_RELEASE: - release_io_telespci(cs); - return (0); - case CARD_INIT: - spin_lock_irqsave(&cs->lock, flags); - inithscxisac(cs, 3); - spin_unlock_irqrestore(&cs->lock, flags); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static struct pci_dev *dev_tel = NULL; - -int setup_telespci(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - - strcpy(tmp, telespci_revision); - printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_TELESPCI) - return (0); - - if ((dev_tel = hisax_find_pci_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) { - if (pci_enable_device(dev_tel)) - return (0); - cs->irq = dev_tel->irq; - if (!cs->irq) { - printk(KERN_WARNING "Teles: No IRQ for PCI card found\n"); - return (0); - } - cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0), - PAGE_SIZE); - printk(KERN_INFO "Found: Zoran, base-address: 0x%llx, irq: 0x%x\n", - (unsigned long long)pci_resource_start(dev_tel, 0), - dev_tel->irq); - } else { - printk(KERN_WARNING "TelesPCI: No PCI card found\n"); - return (0); - } - - /* Initialize Zoran PCI controller */ - writel(0x00000000, cs->hw.teles0.membase + 0x28); - writel(0x01000000, cs->hw.teles0.membase + 0x28); - writel(0x01000000, cs->hw.teles0.membase + 0x28); - writel(0x7BFFFFFF, cs->hw.teles0.membase + 0x2C); - writel(0x70000000, cs->hw.teles0.membase + 0x3C); - writel(0x61000000, cs->hw.teles0.membase + 0x40); - /* writel(0x00800000, cs->hw.teles0.membase + 0x200); */ - - printk(KERN_INFO - "HiSax: Teles PCI config irq:%d mem:%p\n", - cs->irq, - cs->hw.teles0.membase); - - setup_isac(cs); - cs->readisac = &ReadISAC; - cs->writeisac = &WriteISAC; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadHSCX; - cs->BC_Write_Reg = &WriteHSCX; - cs->BC_Send_Data = &hscx_fill_fifo; - cs->cardmsg = &TelesPCI_card_msg; - cs->irq_func = &telespci_interrupt; - cs->irq_flags |= IRQF_SHARED; - ISACVersion(cs, "TelesPCI:"); - if (HscxVersion(cs, "TelesPCI:")) { - printk(KERN_WARNING - "TelesPCI: wrong HSCX versions check IO/MEM addresses\n"); - release_io_telespci(cs); - return (0); - } - return (1); -} diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c deleted file mode 100644 index 36eefaa3a7d9..000000000000 --- a/drivers/isdn/hisax/w6692.c +++ /dev/null @@ -1,1085 +0,0 @@ -/* $Id: w6692.c,v 1.18.2.4 2004/02/11 13:21:34 keil Exp $ - * - * Winbond W6692 specific routines - * - * Author Petr Novak - * Copyright by Petr Novak <petr.novak@i.cz> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/init.h> -#include "hisax.h" -#include "w6692.h" -#include "isdnl1.h" -#include <linux/interrupt.h> -#include <linux/pci.h> -#include <linux/slab.h> - -/* table entry in the PCI devices list */ -typedef struct { - int vendor_id; - int device_id; - char *vendor_name; - char *card_name; -} PCI_ENTRY; - -static const PCI_ENTRY id_list[] = -{ - {PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"}, - {PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"}, - {0, 0, "U.S.Robotics", "ISDN PCI Card TA"} -}; - -#define W6692_SV_USR 0x16ec -#define W6692_SD_USR 0x3409 -#define W6692_WINBOND 0 -#define W6692_DYNALINK 1 -#define W6692_USR 2 - -static const char *w6692_revision = "$Revision: 1.18.2.4 $"; - -#define DBUSY_TIMER_VALUE 80 - -static char *W6692Ver[] = -{"W6692 V00", "W6692 V01", "W6692 V10", - "W6692 V11"}; - -static void -W6692Version(struct IsdnCardState *cs, char *s) -{ - int val; - - val = cs->readW6692(cs, W_D_RBCH); - printk(KERN_INFO "%s Winbond W6692 version (%x): %s\n", s, val, W6692Ver[(val >> 6) & 3]); -} - -static void -ph_command(struct IsdnCardState *cs, unsigned int command) -{ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_command %x", command); - cs->writeisac(cs, W_CIX, command); -} - - -static void -W6692_new_ph(struct IsdnCardState *cs) -{ - switch (cs->dc.w6692.ph_state) { - case (W_L1CMD_RST): - ph_command(cs, W_L1CMD_DRC); - l1_msg(cs, HW_RESET | INDICATION, NULL); - /* fall through */ - case (W_L1IND_CD): - l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL); - break; - case (W_L1IND_DRD): - l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL); - break; - case (W_L1IND_CE): - l1_msg(cs, HW_POWERUP | CONFIRM, NULL); - break; - case (W_L1IND_LD): - l1_msg(cs, HW_RSYNC | INDICATION, NULL); - break; - case (W_L1IND_ARD): - l1_msg(cs, HW_INFO2 | INDICATION, NULL); - break; - case (W_L1IND_AI8): - l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL); - break; - case (W_L1IND_AI10): - l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL); - break; - default: - break; - } -} - -static void -W6692_bh(struct work_struct *work) -{ - struct IsdnCardState *cs = - container_of(work, struct IsdnCardState, tqueue); - struct PStack *stptr; - - if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) { - if (cs->debug) - debugl1(cs, "D-Channel Busy cleared"); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | CONFIRM, NULL); - stptr = stptr->next; - } - } - if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) - W6692_new_ph(cs); - if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) - DChannel_proc_rcv(cs); - if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) - DChannel_proc_xmt(cs); -/* - if (test_and_clear_bit(D_RX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_RX_END, NULL); - if (test_and_clear_bit(D_TX_MON1, &cs->event)) - arcofi_fsm(cs, ARCOFI_TX_END, NULL); -*/ -} - -static void -W6692_empty_fifo(struct IsdnCardState *cs, int count) -{ - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "W6692_empty_fifo"); - - if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692_empty_fifo overrun %d", - cs->rcvidx + count); - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK); - cs->rcvidx = 0; - return; - } - ptr = cs->rcvbuf + cs->rcvidx; - cs->rcvidx += count; - cs->readW6692fifo(cs, ptr, count); - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "W6692_empty_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -static void -W6692_fill_fifo(struct IsdnCardState *cs) -{ - int count, more; - u_char *ptr; - - if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO)) - debugl1(cs, "W6692_fill_fifo"); - - if (!cs->tx_skb) - return; - - count = cs->tx_skb->len; - if (count <= 0) - return; - - more = 0; - if (count > W_D_FIFO_THRESH) { - more = !0; - count = W_D_FIFO_THRESH; - } - ptr = cs->tx_skb->data; - skb_pull(cs->tx_skb, count); - cs->tx_cnt += count; - cs->writeW6692fifo(cs, ptr, count); - cs->writeW6692(cs, W_D_CMDR, more ? W_D_CMDR_XMS : (W_D_CMDR_XMS | W_D_CMDR_XME)); - if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - debugl1(cs, "W6692_fill_fifo dbusytimer running"); - del_timer(&cs->dbusytimer); - } - cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000); - add_timer(&cs->dbusytimer); - if (cs->debug & L1_DEB_ISAC_FIFO) { - char *t = cs->dlog; - - t += sprintf(t, "W6692_fill_fifo cnt %d", count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", cs->dlog); - } -} - -static void -W6692B_empty_fifo(struct BCState *bcs, int count) -{ - u_char *ptr; - struct IsdnCardState *cs = bcs->cs; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "W6692B_empty_fifo"); - - if (bcs->hw.w6692.rcvidx + count > HSCX_BUFMAX) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692B_empty_fifo: incoming packet too large"); - cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - bcs->hw.w6692.rcvidx = 0; - return; - } - ptr = bcs->hw.w6692.rcvbuf + bcs->hw.w6692.rcvidx; - bcs->hw.w6692.rcvidx += count; - READW6692BFIFO(cs, bcs->channel, ptr, count); - cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RACT); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "W6692B_empty_fifo %c cnt %d", - bcs->channel + '1', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -W6692B_fill_fifo(struct BCState *bcs) -{ - struct IsdnCardState *cs = bcs->cs; - int more, count; - u_char *ptr; - - if (!bcs->tx_skb) - return; - if (bcs->tx_skb->len <= 0) - return; - - more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0; - if (bcs->tx_skb->len > W_B_FIFO_THRESH) { - more = 1; - count = W_B_FIFO_THRESH; - } else - count = bcs->tx_skb->len; - - if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO)) - debugl1(cs, "W6692B_fill_fifo%s%d", (more ? " " : " last "), count); - - ptr = bcs->tx_skb->data; - skb_pull(bcs->tx_skb, count); - bcs->tx_cnt -= count; - bcs->hw.w6692.count += count; - WRITEW6692BFIFO(cs, bcs->channel, ptr, count); - cs->BC_Write_Reg(cs, bcs->channel, W_B_CMDR, W_B_CMDR_RACT | W_B_CMDR_XMS | (more ? 0 : W_B_CMDR_XME)); - if (cs->debug & L1_DEB_HSCX_FIFO) { - char *t = bcs->blog; - - t += sprintf(t, "W6692B_fill_fifo %c cnt %d", - bcs->channel + '1', count); - QuickHex(t, ptr, count); - debugl1(cs, "%s", bcs->blog); - } -} - -static void -W6692B_interrupt(struct IsdnCardState *cs, u_char bchan) -{ - u_char val; - u_char r; - struct BCState *bcs; - struct sk_buff *skb; - int count; - - bcs = (cs->bcs->channel == bchan) ? cs->bcs : (cs->bcs + 1); - val = cs->BC_Read_Reg(cs, bchan, W_B_EXIR); - debugl1(cs, "W6692B chan %d B_EXIR 0x%02X", bchan, val); - - if (!test_bit(BC_FLG_INIT, &bcs->Flag)) { - debugl1(cs, "W6692B not INIT yet"); - return; - } - if (val & W_B_EXI_RME) { /* RME */ - r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); - if (r & (W_B_STAR_RDOV | W_B_STAR_CRCE | W_B_STAR_RMB)) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B STAR %x", r); - if ((r & W_B_STAR_RDOV) && bcs->mode) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B RDOV mode=%d", - bcs->mode); - if (r & W_B_STAR_CRCE) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B CRC error"); - cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); - } else { - count = cs->BC_Read_Reg(cs, bchan, W_B_RBCL) & (W_B_FIFO_THRESH - 1); - if (count == 0) - count = W_B_FIFO_THRESH; - W6692B_empty_fifo(bcs, count); - if ((count = bcs->hw.w6692.rcvidx) > 0) { - if (cs->debug & L1_DEB_HSCX_FIFO) - debugl1(cs, "W6692 Bchan Frame %d", count); - if (!(skb = dev_alloc_skb(count))) - printk(KERN_WARNING "W6692: Bchan receive out of memory\n"); - else { - skb_put_data(skb, - bcs->hw.w6692.rcvbuf, - count); - skb_queue_tail(&bcs->rqueue, skb); - } - } - } - bcs->hw.w6692.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - if (val & W_B_EXI_RMR) { /* RMR */ - W6692B_empty_fifo(bcs, W_B_FIFO_THRESH); - r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); - if (r & W_B_STAR_RDOV) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B RDOV(RMR) mode=%d", bcs->mode); - cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RACK | W_B_CMDR_RRST | W_B_CMDR_RACT); - if (bcs->mode != L1_MODE_TRANS) - bcs->hw.w6692.rcvidx = 0; - } - if (bcs->mode == L1_MODE_TRANS) { - /* receive audio data */ - if (!(skb = dev_alloc_skb(W_B_FIFO_THRESH))) - printk(KERN_WARNING "HiSax: receive out of memory\n"); - else { - skb_put_data(skb, bcs->hw.w6692.rcvbuf, - W_B_FIFO_THRESH); - skb_queue_tail(&bcs->rqueue, skb); - } - bcs->hw.w6692.rcvidx = 0; - schedule_event(bcs, B_RCVBUFREADY); - } - } - if (val & W_B_EXI_XDUN) { /* XDUN */ - cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B EXIR %x Lost TX", val); - if (bcs->mode == 1) - W6692B_fill_fifo(bcs); - else { - /* Here we lost an TX interrupt, so - * restart transmitting the whole frame. - */ - if (bcs->tx_skb) { - skb_push(bcs->tx_skb, bcs->hw.w6692.count); - bcs->tx_cnt += bcs->hw.w6692.count; - bcs->hw.w6692.count = 0; - } - } - return; - } - if (val & W_B_EXI_XFR) { /* XFR */ - r = cs->BC_Read_Reg(cs, bchan, W_B_STAR); - if (r & W_B_STAR_XDOW) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 B STAR %x XDOW", r); - cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_XRST | W_B_CMDR_RACT); - if (bcs->tx_skb && (bcs->mode != 1)) { - skb_push(bcs->tx_skb, bcs->hw.w6692.count); - bcs->tx_cnt += bcs->hw.w6692.count; - bcs->hw.w6692.count = 0; - } - } - if (bcs->tx_skb) { - if (bcs->tx_skb->len) { - W6692B_fill_fifo(bcs); - return; - } else { - if (test_bit(FLG_LLI_L1WAKEUP, &bcs->st->lli.flag) && - (PACKET_NOACK != bcs->tx_skb->pkt_type)) { - u_long flags; - spin_lock_irqsave(&bcs->aclock, flags); - bcs->ackcnt += bcs->hw.w6692.count; - spin_unlock_irqrestore(&bcs->aclock, flags); - schedule_event(bcs, B_ACKPENDING); - } - dev_kfree_skb_irq(bcs->tx_skb); - bcs->hw.w6692.count = 0; - bcs->tx_skb = NULL; - } - } - if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) { - bcs->hw.w6692.count = 0; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - W6692B_fill_fifo(bcs); - } else { - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - schedule_event(bcs, B_XMTBUFREADY); - } - } -} - -static irqreturn_t -W6692_interrupt(int intno, void *dev_id) -{ - struct IsdnCardState *cs = dev_id; - u_char val, exval, v1; - struct sk_buff *skb; - u_int count; - u_long flags; - int icnt = 5; - - spin_lock_irqsave(&cs->lock, flags); - val = cs->readW6692(cs, W_ISTA); - if (!val) { - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_NONE; - } -StartW6692: - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "W6692 ISTA %x", val); - - if (val & W_INT_D_RME) { /* RME */ - exval = cs->readW6692(cs, W_D_RSTA); - if (exval & (W_D_RSTA_RDOV | W_D_RSTA_CRCE | W_D_RSTA_RMB)) { - if (exval & W_D_RSTA_RDOV) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 RDOV"); - if (exval & W_D_RSTA_CRCE) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 D-channel CRC error"); - if (exval & W_D_RSTA_RMB) - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 D-channel ABORT"); - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RACK | W_D_CMDR_RRST); - } else { - count = cs->readW6692(cs, W_D_RBCL) & (W_D_FIFO_THRESH - 1); - if (count == 0) - count = W_D_FIFO_THRESH; - W6692_empty_fifo(cs, count); - if ((count = cs->rcvidx) > 0) { - cs->rcvidx = 0; - if (!(skb = alloc_skb(count, GFP_ATOMIC))) - printk(KERN_WARNING "HiSax: D receive out of memory\n"); - else { - skb_put_data(skb, cs->rcvbuf, count); - skb_queue_tail(&cs->rq, skb); - } - } - } - cs->rcvidx = 0; - schedule_event(cs, D_RCVBUFREADY); - } - if (val & W_INT_D_RMR) { /* RMR */ - W6692_empty_fifo(cs, W_D_FIFO_THRESH); - } - if (val & W_INT_D_XFR) { /* XFR */ - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { - if (cs->tx_skb->len) { - W6692_fill_fifo(cs); - goto afterXFR; - } else { - dev_kfree_skb_irq(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } - } - if ((cs->tx_skb = skb_dequeue(&cs->sq))) { - cs->tx_cnt = 0; - W6692_fill_fifo(cs); - } else - schedule_event(cs, D_XMTBUFREADY); - } -afterXFR: - if (val & (W_INT_XINT0 | W_INT_XINT1)) { /* XINT0/1 - never */ - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "W6692 spurious XINT!"); - } - if (val & W_INT_D_EXI) { /* EXI */ - exval = cs->readW6692(cs, W_D_EXIR); - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692 D_EXIR %02x", exval); - if (exval & (W_D_EXI_XDUN | W_D_EXI_XCOL)) { /* Transmit underrun/collision */ - debugl1(cs, "W6692 D-chan underrun/collision"); - printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL\n"); - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - if (cs->tx_skb) { /* Restart frame */ - skb_push(cs->tx_skb, cs->tx_cnt); - cs->tx_cnt = 0; - W6692_fill_fifo(cs); - } else { - printk(KERN_WARNING "HiSax: W6692 XDUN/XCOL no skb\n"); - debugl1(cs, "W6692 XDUN/XCOL no skb"); - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); - } - } - if (exval & W_D_EXI_RDOV) { /* RDOV */ - debugl1(cs, "W6692 D-channel RDOV"); - printk(KERN_WARNING "HiSax: W6692 D-RDOV\n"); - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST); - } - if (exval & W_D_EXI_TIN2) { /* TIN2 - never */ - debugl1(cs, "W6692 spurious TIN2 interrupt"); - } - if (exval & W_D_EXI_MOC) { /* MOC - not supported */ - debugl1(cs, "W6692 spurious MOC interrupt"); - v1 = cs->readW6692(cs, W_MOSR); - debugl1(cs, "W6692 MOSR %02x", v1); - } - if (exval & W_D_EXI_ISC) { /* ISC - Level1 change */ - v1 = cs->readW6692(cs, W_CIR); - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "W6692 ISC CIR=0x%02X", v1); - if (v1 & W_CIR_ICC) { - cs->dc.w6692.ph_state = v1 & W_CIR_COD_MASK; - if (cs->debug & L1_DEB_ISAC) - debugl1(cs, "ph_state_change %x", cs->dc.w6692.ph_state); - schedule_event(cs, D_L1STATECHANGE); - } - if (v1 & W_CIR_SCC) { - v1 = cs->readW6692(cs, W_SQR); - debugl1(cs, "W6692 SCC SQR=0x%02X", v1); - } - } - if (exval & W_D_EXI_WEXP) { - debugl1(cs, "W6692 spurious WEXP interrupt!"); - } - if (exval & W_D_EXI_TEXP) { - debugl1(cs, "W6692 spurious TEXP interrupt!"); - } - } - if (val & W_INT_B1_EXI) { - debugl1(cs, "W6692 B channel 1 interrupt"); - W6692B_interrupt(cs, 0); - } - if (val & W_INT_B2_EXI) { - debugl1(cs, "W6692 B channel 2 interrupt"); - W6692B_interrupt(cs, 1); - } - val = cs->readW6692(cs, W_ISTA); - if (val && icnt) { - icnt--; - goto StartW6692; - } - if (!icnt) { - printk(KERN_WARNING "W6692 IRQ LOOP\n"); - cs->writeW6692(cs, W_IMASK, 0xff); - } - spin_unlock_irqrestore(&cs->lock, flags); - return IRQ_HANDLED; -} - -static void -W6692_l1hw(struct PStack *st, int pr, void *arg) -{ - struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware; - struct sk_buff *skb = arg; - u_long flags; - int val; - - switch (pr) { - case (PH_DATA | REQUEST): - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - skb_queue_tail(&cs->sq, skb); -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA Queued", 0); -#endif - } else { - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA", 0); -#endif - W6692_fill_fifo(cs); - } - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | INDICATION): - spin_lock_irqsave(&cs->lock, flags); - if (cs->tx_skb) { - if (cs->debug & L1_DEB_WARN) - debugl1(cs, " l2l1 tx_skb exist this shouldn't happen"); - skb_queue_tail(&cs->sq, skb); - spin_unlock_irqrestore(&cs->lock, flags); - break; - } - if (cs->debug & DEB_DLOG_HEX) - LogFrame(cs, skb->data, skb->len); - if (cs->debug & DEB_DLOG_VERBOSE) - dlogframe(cs, skb, 0); - cs->tx_skb = skb; - cs->tx_cnt = 0; -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - Logl2Frame(cs, skb, "PH_DATA_PULLED", 0); -#endif - W6692_fill_fifo(cs); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (PH_PULL | REQUEST): -#ifdef L2FRAME_DEBUG /* psa */ - if (cs->debug & L1_DEB_LAPD) - debugl1(cs, "-> PH_REQUEST_PULL"); -#endif - if (!cs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (HW_RESET | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - if (cs->dc.w6692.ph_state == W_L1IND_DRD) { - ph_command(cs, W_L1CMD_ECK); - spin_unlock_irqrestore(&cs->lock, flags); - } else { - ph_command(cs, W_L1CMD_RST); - cs->dc.w6692.ph_state = W_L1CMD_RST; - spin_unlock_irqrestore(&cs->lock, flags); - W6692_new_ph(cs); - } - break; - case (HW_ENABLE | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, W_L1CMD_ECK); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_INFO3 | REQUEST): - spin_lock_irqsave(&cs->lock, flags); - ph_command(cs, W_L1CMD_AR8); - spin_unlock_irqrestore(&cs->lock, flags); - break; - case (HW_TESTLOOP | REQUEST): - val = 0; - if (1 & (long) arg) - val |= 0x0c; - if (2 & (long) arg) - val |= 0x3; - /* !!! not implemented yet */ - break; - case (HW_DEACTIVATE | RESPONSE): - skb_queue_purge(&cs->rq); - skb_queue_purge(&cs->sq); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_skb = NULL; - } - if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) - del_timer(&cs->dbusytimer); - if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags)) - schedule_event(cs, D_CLEARBUSY); - break; - default: - if (cs->debug & L1_DEB_WARN) - debugl1(cs, "W6692_l1hw unknown %04x", pr); - break; - } -} - -static void -setstack_W6692(struct PStack *st, struct IsdnCardState *cs) -{ - st->l1.l1hw = W6692_l1hw; -} - -static void -DC_Close_W6692(struct IsdnCardState *cs) -{ -} - -static void -dbusy_timer_handler(struct timer_list *t) -{ - struct IsdnCardState *cs = from_timer(cs, t, dbusytimer); - struct PStack *stptr; - int rbch, star; - u_long flags; - - spin_lock_irqsave(&cs->lock, flags); - if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) { - rbch = cs->readW6692(cs, W_D_RBCH); - star = cs->readW6692(cs, W_D_STAR); - if (cs->debug) - debugl1(cs, "D-Channel Busy D_RBCH %02x D_STAR %02x", - rbch, star); - if (star & W_D_STAR_XBZ) { /* D-Channel Busy */ - test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags); - stptr = cs->stlist; - while (stptr != NULL) { - stptr->l1.l1l2(stptr, PH_PAUSE | INDICATION, NULL); - stptr = stptr->next; - } - } else { - /* discard frame; reset transceiver */ - test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags); - if (cs->tx_skb) { - dev_kfree_skb_any(cs->tx_skb); - cs->tx_cnt = 0; - cs->tx_skb = NULL; - } else { - printk(KERN_WARNING "HiSax: W6692 D-Channel Busy no skb\n"); - debugl1(cs, "D-Channel Busy no skb"); - } - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); /* Transmitter reset */ - spin_unlock_irqrestore(&cs->lock, flags); - cs->irq_func(cs->irq, cs); - return; - } - } - spin_unlock_irqrestore(&cs->lock, flags); -} - -static void -W6692Bmode(struct BCState *bcs, int mode, int bchan) -{ - struct IsdnCardState *cs = bcs->cs; - - if (cs->debug & L1_DEB_HSCX) - debugl1(cs, "w6692 %c mode %d ichan %d", - '1' + bchan, mode, bchan); - bcs->mode = mode; - bcs->channel = bchan; - bcs->hw.w6692.bchan = bchan; - - switch (mode) { - case (L1_MODE_NULL): - cs->BC_Write_Reg(cs, bchan, W_B_MODE, 0); - break; - case (L1_MODE_TRANS): - cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_MMS); - break; - case (L1_MODE_HDLC): - cs->BC_Write_Reg(cs, bchan, W_B_MODE, W_B_MODE_ITF); - cs->BC_Write_Reg(cs, bchan, W_B_ADM1, 0xff); - cs->BC_Write_Reg(cs, bchan, W_B_ADM2, 0xff); - break; - } - if (mode) - cs->BC_Write_Reg(cs, bchan, W_B_CMDR, W_B_CMDR_RRST | - W_B_CMDR_RACT | W_B_CMDR_XRST); - cs->BC_Write_Reg(cs, bchan, W_B_EXIM, 0x00); -} - -static void -W6692_l2l1(struct PStack *st, int pr, void *arg) -{ - struct sk_buff *skb = arg; - struct BCState *bcs = st->l1.bcs; - u_long flags; - - switch (pr) { - case (PH_DATA | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->tx_skb) { - skb_queue_tail(&bcs->squeue, skb); - } else { - bcs->tx_skb = skb; - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->hw.w6692.count = 0; - bcs->cs->BC_Send_Data(bcs); - } - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | INDICATION): - if (bcs->tx_skb) { - printk(KERN_WARNING "W6692_l2l1: this shouldn't happen\n"); - break; - } - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->tx_skb = skb; - bcs->hw.w6692.count = 0; - bcs->cs->BC_Send_Data(bcs); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - break; - case (PH_PULL | REQUEST): - if (!bcs->tx_skb) { - test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - st->l1.l1l2(st, PH_PULL | CONFIRM, NULL); - } else - test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags); - break; - case (PH_ACTIVATE | REQUEST): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_set_bit(BC_FLG_ACTIV, &bcs->Flag); - W6692Bmode(bcs, st->l1.mode, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | REQUEST): - l1_msg_b(st, pr, arg); - break; - case (PH_DEACTIVATE | CONFIRM): - spin_lock_irqsave(&bcs->cs->lock, flags); - test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - W6692Bmode(bcs, 0, st->l1.bc); - spin_unlock_irqrestore(&bcs->cs->lock, flags); - st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL); - break; - } -} - -static void -close_w6692state(struct BCState *bcs) -{ - W6692Bmode(bcs, 0, bcs->channel); - if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) { - kfree(bcs->hw.w6692.rcvbuf); - bcs->hw.w6692.rcvbuf = NULL; - kfree(bcs->blog); - bcs->blog = NULL; - skb_queue_purge(&bcs->rqueue); - skb_queue_purge(&bcs->squeue); - if (bcs->tx_skb) { - dev_kfree_skb_any(bcs->tx_skb); - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - } - } -} - -static int -open_w6692state(struct IsdnCardState *cs, struct BCState *bcs) -{ - if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) { - if (!(bcs->hw.w6692.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for w6692.rcvbuf\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - return (1); - } - if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) { - printk(KERN_WARNING - "HiSax: No memory for bcs->blog\n"); - test_and_clear_bit(BC_FLG_INIT, &bcs->Flag); - kfree(bcs->hw.w6692.rcvbuf); - bcs->hw.w6692.rcvbuf = NULL; - return (2); - } - skb_queue_head_init(&bcs->rqueue); - skb_queue_head_init(&bcs->squeue); - } - bcs->tx_skb = NULL; - test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag); - bcs->event = 0; - bcs->hw.w6692.rcvidx = 0; - bcs->tx_cnt = 0; - return (0); -} - -static int -setstack_w6692(struct PStack *st, struct BCState *bcs) -{ - bcs->channel = st->l1.bc; - if (open_w6692state(st->l1.hardware, bcs)) - return (-1); - st->l1.bcs = bcs; - st->l2.l2l1 = W6692_l2l1; - setstack_manager(st); - bcs->st = st; - setstack_l1_B(st); - return (0); -} - -static void resetW6692(struct IsdnCardState *cs) -{ - cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST); - mdelay(10); - cs->writeW6692(cs, W_D_CTL, 0x00); - mdelay(10); - cs->writeW6692(cs, W_IMASK, 0xff); - cs->writeW6692(cs, W_D_SAM, 0xff); - cs->writeW6692(cs, W_D_TAM, 0xff); - cs->writeW6692(cs, W_D_EXIM, 0x00); - cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT); - cs->writeW6692(cs, W_IMASK, 0x18); - if (cs->subtyp == W6692_USR) { - /* seems that USR implemented some power control features - * Pin 79 is connected to the oscilator circuit so we - * have to handle it here - */ - cs->writeW6692(cs, W_PCTL, 0x80); - cs->writeW6692(cs, W_XDATA, 0x00); - } -} - -static void initW6692(struct IsdnCardState *cs, int part) -{ - if (part & 1) { - cs->setstack_d = setstack_W6692; - cs->DC_Close = DC_Close_W6692; - timer_setup(&cs->dbusytimer, dbusy_timer_handler, 0); - resetW6692(cs); - ph_command(cs, W_L1CMD_RST); - cs->dc.w6692.ph_state = W_L1CMD_RST; - W6692_new_ph(cs); - ph_command(cs, W_L1CMD_ECK); - - cs->bcs[0].BC_SetStack = setstack_w6692; - cs->bcs[1].BC_SetStack = setstack_w6692; - cs->bcs[0].BC_Close = close_w6692state; - cs->bcs[1].BC_Close = close_w6692state; - W6692Bmode(cs->bcs, 0, 0); - W6692Bmode(cs->bcs + 1, 0, 0); - } - if (part & 2) { - /* Reenable all IRQ */ - cs->writeW6692(cs, W_IMASK, 0x18); - cs->writeW6692(cs, W_D_EXIM, 0x00); - cs->BC_Write_Reg(cs, 0, W_B_EXIM, 0x00); - cs->BC_Write_Reg(cs, 1, W_B_EXIM, 0x00); - /* Reset D-chan receiver and transmitter */ - cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_RRST | W_D_CMDR_XRST); - } -} - -/* Interface functions */ - -static u_char -ReadW6692(struct IsdnCardState *cs, u_char offset) -{ - return (inb(cs->hw.w6692.iobase + offset)); -} - -static void -WriteW6692(struct IsdnCardState *cs, u_char offset, u_char value) -{ - outb(value, cs->hw.w6692.iobase + offset); -} - -static void -ReadISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - insb(cs->hw.w6692.iobase + W_D_RFIFO, data, size); -} - -static void -WriteISACfifo(struct IsdnCardState *cs, u_char *data, int size) -{ - outsb(cs->hw.w6692.iobase + W_D_XFIFO, data, size); -} - -static u_char -ReadW6692B(struct IsdnCardState *cs, int bchan, u_char offset) -{ - return (inb(cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset)); -} - -static void -WriteW6692B(struct IsdnCardState *cs, int bchan, u_char offset, u_char value) -{ - outb(value, cs->hw.w6692.iobase + (bchan ? 0x40 : 0) + offset); -} - -static int -w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg) -{ - switch (mt) { - case CARD_RESET: - resetW6692(cs); - return (0); - case CARD_RELEASE: - cs->writeW6692(cs, W_IMASK, 0xff); - release_region(cs->hw.w6692.iobase, 256); - if (cs->subtyp == W6692_USR) { - cs->writeW6692(cs, W_XDATA, 0x04); - } - return (0); - case CARD_INIT: - initW6692(cs, 3); - return (0); - case CARD_TEST: - return (0); - } - return (0); -} - -static int id_idx; - -static struct pci_dev *dev_w6692 = NULL; - -int setup_w6692(struct IsdnCard *card) -{ - struct IsdnCardState *cs = card->cs; - char tmp[64]; - u_char found = 0; - u_char pci_irq = 0; - u_int pci_ioaddr = 0; - - strcpy(tmp, w6692_revision); - printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp)); - if (cs->typ != ISDN_CTYPE_W6692) - return (0); - - while (id_list[id_idx].vendor_id) { - dev_w6692 = hisax_find_pci_device(id_list[id_idx].vendor_id, - id_list[id_idx].device_id, - dev_w6692); - if (dev_w6692) { - if (pci_enable_device(dev_w6692)) - continue; - cs->subtyp = id_idx; - break; - } - id_idx++; - } - if (dev_w6692) { - found = 1; - pci_irq = dev_w6692->irq; - /* I think address 0 is allways the configuration area */ - /* and address 1 is the real IO space KKe 03.09.99 */ - pci_ioaddr = pci_resource_start(dev_w6692, 1); - /* USR ISDN PCI card TA need some special handling */ - if (cs->subtyp == W6692_WINBOND) { - if ((W6692_SV_USR == dev_w6692->subsystem_vendor) && - (W6692_SD_USR == dev_w6692->subsystem_device)) { - cs->subtyp = W6692_USR; - } - } - } - if (!found) { - printk(KERN_WARNING "W6692: No PCI card found\n"); - return (0); - } - cs->irq = pci_irq; - if (!cs->irq) { - printk(KERN_WARNING "W6692: No IRQ for PCI card found\n"); - return (0); - } - if (!pci_ioaddr) { - printk(KERN_WARNING "W6692: NO I/O Base Address found\n"); - return (0); - } - cs->hw.w6692.iobase = pci_ioaddr; - printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n", - id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name, - pci_ioaddr, pci_irq); - if (!request_region(cs->hw.w6692.iobase, 256, id_list[cs->subtyp].card_name)) { - printk(KERN_WARNING - "HiSax: %s I/O ports %x-%x already in use\n", - id_list[cs->subtyp].card_name, - cs->hw.w6692.iobase, - cs->hw.w6692.iobase + 255); - return (0); - } - - printk(KERN_INFO - "HiSax: %s config irq:%d I/O:%x\n", - id_list[cs->subtyp].card_name, cs->irq, - cs->hw.w6692.iobase); - - INIT_WORK(&cs->tqueue, W6692_bh); - cs->readW6692 = &ReadW6692; - cs->writeW6692 = &WriteW6692; - cs->readisacfifo = &ReadISACfifo; - cs->writeisacfifo = &WriteISACfifo; - cs->BC_Read_Reg = &ReadW6692B; - cs->BC_Write_Reg = &WriteW6692B; - cs->BC_Send_Data = &W6692B_fill_fifo; - cs->cardmsg = &w6692_card_msg; - cs->irq_func = &W6692_interrupt; - cs->irq_flags |= IRQF_SHARED; - W6692Version(cs, "W6692:"); - printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA)); - printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK)); - printk(KERN_INFO "W6692 D_EXIR=0x%X\n", ReadW6692(cs, W_D_EXIR)); - printk(KERN_INFO "W6692 D_EXIM=0x%X\n", ReadW6692(cs, W_D_EXIM)); - printk(KERN_INFO "W6692 D_RSTA=0x%X\n", ReadW6692(cs, W_D_RSTA)); - return (1); -} diff --git a/drivers/isdn/hisax/w6692.h b/drivers/isdn/hisax/w6692.h deleted file mode 100644 index 024b04d33e43..000000000000 --- a/drivers/isdn/hisax/w6692.h +++ /dev/null @@ -1,184 +0,0 @@ -/* $Id: w6692.h,v 1.4.2.2 2004/01/12 22:52:29 keil Exp $ - * - * Winbond W6692 specific defines - * - * Author Petr Novak - * Copyright by Petr Novak <petr.novak@i.cz> - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* map W6692 functions to ISAC functions */ -#define readW6692 readisac -#define writeW6692 writeisac -#define readW6692fifo readisacfifo -#define writeW6692fifo writeisacfifo - -/* B-channel FIFO read/write routines */ - -#define READW6692BFIFO(cs, bchan, ptr, count) \ - insb(cs->hw.w6692.iobase + W_B_RFIFO + (bchan ? 0x40 : 0), ptr, count) - -#define WRITEW6692BFIFO(cs, bchan, ptr, count) \ - outsb(cs->hw.w6692.iobase + W_B_XFIFO + (bchan ? 0x40 : 0), ptr, count) - -/* Specifications of W6692 registers */ - -#define W_D_RFIFO 0x00 /* R */ -#define W_D_XFIFO 0x04 /* W */ -#define W_D_CMDR 0x08 /* W */ -#define W_D_MODE 0x0c /* R/W */ -#define W_D_TIMR 0x10 /* R/W */ -#define W_ISTA 0x14 /* R_clr */ -#define W_IMASK 0x18 /* R/W */ -#define W_D_EXIR 0x1c /* R_clr */ -#define W_D_EXIM 0x20 /* R/W */ -#define W_D_STAR 0x24 /* R */ -#define W_D_RSTA 0x28 /* R */ -#define W_D_SAM 0x2c /* R/W */ -#define W_D_SAP1 0x30 /* R/W */ -#define W_D_SAP2 0x34 /* R/W */ -#define W_D_TAM 0x38 /* R/W */ -#define W_D_TEI1 0x3c /* R/W */ -#define W_D_TEI2 0x40 /* R/W */ -#define W_D_RBCH 0x44 /* R */ -#define W_D_RBCL 0x48 /* R */ -#define W_TIMR2 0x4c /* W */ -#define W_L1_RC 0x50 /* R/W */ -#define W_D_CTL 0x54 /* R/W */ -#define W_CIR 0x58 /* R */ -#define W_CIX 0x5c /* W */ -#define W_SQR 0x60 /* R */ -#define W_SQX 0x64 /* W */ -#define W_PCTL 0x68 /* R/W */ -#define W_MOR 0x6c /* R */ -#define W_MOX 0x70 /* R/W */ -#define W_MOSR 0x74 /* R_clr */ -#define W_MOCR 0x78 /* R/W */ -#define W_GCR 0x7c /* R/W */ - -#define W_B_RFIFO 0x80 /* R */ -#define W_B_XFIFO 0x84 /* W */ -#define W_B_CMDR 0x88 /* W */ -#define W_B_MODE 0x8c /* R/W */ -#define W_B_EXIR 0x90 /* R_clr */ -#define W_B_EXIM 0x94 /* R/W */ -#define W_B_STAR 0x98 /* R */ -#define W_B_ADM1 0x9c /* R/W */ -#define W_B_ADM2 0xa0 /* R/W */ -#define W_B_ADR1 0xa4 /* R/W */ -#define W_B_ADR2 0xa8 /* R/W */ -#define W_B_RBCL 0xac /* R */ -#define W_B_RBCH 0xb0 /* R */ - -#define W_XADDR 0xf4 /* R/W */ -#define W_XDATA 0xf8 /* R/W */ -#define W_EPCTL 0xfc /* W */ - -/* W6692 register bits */ - -#define W_D_CMDR_XRST 0x01 -#define W_D_CMDR_XME 0x02 -#define W_D_CMDR_XMS 0x08 -#define W_D_CMDR_STT 0x10 -#define W_D_CMDR_RRST 0x40 -#define W_D_CMDR_RACK 0x80 - -#define W_D_MODE_RLP 0x01 -#define W_D_MODE_DLP 0x02 -#define W_D_MODE_MFD 0x04 -#define W_D_MODE_TEE 0x08 -#define W_D_MODE_TMS 0x10 -#define W_D_MODE_RACT 0x40 -#define W_D_MODE_MMS 0x80 - -#define W_INT_B2_EXI 0x01 -#define W_INT_B1_EXI 0x02 -#define W_INT_D_EXI 0x04 -#define W_INT_XINT0 0x08 -#define W_INT_XINT1 0x10 -#define W_INT_D_XFR 0x20 -#define W_INT_D_RME 0x40 -#define W_INT_D_RMR 0x80 - -#define W_D_EXI_WEXP 0x01 -#define W_D_EXI_TEXP 0x02 -#define W_D_EXI_ISC 0x04 -#define W_D_EXI_MOC 0x08 -#define W_D_EXI_TIN2 0x10 -#define W_D_EXI_XCOL 0x20 -#define W_D_EXI_XDUN 0x40 -#define W_D_EXI_RDOV 0x80 - -#define W_D_STAR_DRDY 0x10 -#define W_D_STAR_XBZ 0x20 -#define W_D_STAR_XDOW 0x80 - -#define W_D_RSTA_RMB 0x10 -#define W_D_RSTA_CRCE 0x20 -#define W_D_RSTA_RDOV 0x40 - -#define W_D_CTL_SRST 0x20 - -#define W_CIR_SCC 0x80 -#define W_CIR_ICC 0x40 -#define W_CIR_COD_MASK 0x0f - -#define W_B_CMDR_XRST 0x01 -#define W_B_CMDR_XME 0x02 -#define W_B_CMDR_XMS 0x04 -#define W_B_CMDR_RACT 0x20 -#define W_B_CMDR_RRST 0x40 -#define W_B_CMDR_RACK 0x80 - -#define W_B_MODE_FTS0 0x01 -#define W_B_MODE_FTS1 0x02 -#define W_B_MODE_SW56 0x04 -#define W_B_MODE_BSW0 0x08 -#define W_B_MODE_BSW1 0x10 -#define W_B_MODE_EPCM 0x20 -#define W_B_MODE_ITF 0x40 -#define W_B_MODE_MMS 0x80 - -#define W_B_EXI_XDUN 0x01 -#define W_B_EXI_XFR 0x02 -#define W_B_EXI_RDOV 0x10 -#define W_B_EXI_RME 0x20 -#define W_B_EXI_RMR 0x40 - -#define W_B_STAR_XBZ 0x01 -#define W_B_STAR_XDOW 0x04 -#define W_B_STAR_RMB 0x10 -#define W_B_STAR_CRCE 0x20 -#define W_B_STAR_RDOV 0x40 - -#define W_B_RBCH_LOV 0x20 - -/* W6692 Layer1 commands */ - -#define W_L1CMD_ECK 0x00 -#define W_L1CMD_RST 0x01 -#define W_L1CMD_SCP 0x04 -#define W_L1CMD_SSP 0x02 -#define W_L1CMD_AR8 0x08 -#define W_L1CMD_AR10 0x09 -#define W_L1CMD_EAL 0x0a -#define W_L1CMD_DRC 0x0f - -/* W6692 Layer1 indications */ - -#define W_L1IND_CE 0x07 -#define W_L1IND_DRD 0x00 -#define W_L1IND_LD 0x04 -#define W_L1IND_ARD 0x08 -#define W_L1IND_TI 0x0a -#define W_L1IND_ATI 0x0b -#define W_L1IND_AI8 0x0c -#define W_L1IND_AI10 0x0d -#define W_L1IND_CD 0x0f - -/* FIFO thresholds */ -#define W_D_FIFO_THRESH 64 -#define W_B_FIFO_THRESH 64 diff --git a/drivers/isdn/hysdn/Kconfig b/drivers/isdn/hysdn/Kconfig deleted file mode 100644 index 1971ef850c9a..000000000000 --- a/drivers/isdn/hysdn/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config HYSDN - tristate "Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)" - depends on m && PROC_FS && PCI - help - Say Y here if you have one of Hypercope's active PCI ISDN cards - Champ, Ergo and Metro. You will then get a module called hysdn. - Please read the file <file:Documentation/isdn/README.hysdn> for more - information. - -config HYSDN_CAPI - bool "HYSDN CAPI 2.0 support" - depends on HYSDN && ISDN_CAPI - help - Say Y here if you like to use Hypercope's CAPI 2.0 interface. diff --git a/drivers/isdn/hysdn/Makefile b/drivers/isdn/hysdn/Makefile deleted file mode 100644 index e01f17f22ebb..000000000000 --- a/drivers/isdn/hysdn/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Makefile for the hysdn ISDN device driver - -# Each configuration option enables a list of files. - -obj-$(CONFIG_HYSDN) += hysdn.o - -# Multipart objects. - -hysdn-y := hysdn_procconf.o hysdn_proclog.o boardergo.o \ - hysdn_boot.o hysdn_sched.o hysdn_net.o hysdn_init.o -hysdn-$(CONFIG_HYSDN_CAPI) += hycapi.o diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c deleted file mode 100644 index 2aa2a0e08247..000000000000 --- a/drivers/isdn/hysdn/boardergo.c +++ /dev/null @@ -1,445 +0,0 @@ -/* $Id: boardergo.c,v 1.5.6.7 2001/11/06 21:58:19 kai Exp $ - * - * Linux driver for HYSDN cards, specific routines for ergo type boards. - * - * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * As all Linux supported cards Champ2, Ergo and Metro2/4 use the same - * DPRAM interface and layout with only minor differences all related - * stuff is done here, not in separate modules. - * - */ - -#include <linux/signal.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <asm/io.h> - -#include "hysdn_defs.h" -#include "boardergo.h" - -#define byteout(addr, val) outb(val, addr) -#define bytein(addr) inb(addr) - -/***************************************************/ -/* The cards interrupt handler. Called from system */ -/***************************************************/ -static irqreturn_t -ergo_interrupt(int intno, void *dev_id) -{ - hysdn_card *card = dev_id; /* parameter from irq */ - tErgDpram *dpr; - unsigned long flags; - unsigned char volatile b; - - if (!card) - return IRQ_NONE; /* error -> spurious interrupt */ - if (!card->irq_enabled) - return IRQ_NONE; /* other device interrupting or irq switched off */ - - spin_lock_irqsave(&card->hysdn_lock, flags); /* no further irqs allowed */ - - if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) { - spin_unlock_irqrestore(&card->hysdn_lock, flags); /* restore old state */ - return IRQ_NONE; /* no interrupt requested by E1 */ - } - /* clear any pending ints on the board */ - dpr = card->dpram; - b = dpr->ToPcInt; /* clear for ergo */ - b |= dpr->ToPcIntMetro; /* same for metro */ - b |= dpr->ToHyInt; /* and for champ */ - - /* start kernel task immediately after leaving all interrupts */ - if (!card->hw_lock) - schedule_work(&card->irq_queue); - spin_unlock_irqrestore(&card->hysdn_lock, flags); - return IRQ_HANDLED; -} /* ergo_interrupt */ - -/******************************************************************************/ -/* ergo_irq_bh will be called as part of the kernel clearing its shared work */ -/* queue sometime after a call to schedule_work has been made passing our */ -/* work_struct. This task is the only one handling data transfer from or to */ -/* the card after booting. The task may be queued from everywhere */ -/* (interrupts included). */ -/******************************************************************************/ -static void -ergo_irq_bh(struct work_struct *ugli_api) -{ - hysdn_card *card = container_of(ugli_api, hysdn_card, irq_queue); - tErgDpram *dpr; - int again; - unsigned long flags; - - if (card->state != CARD_STATE_RUN) - return; /* invalid call */ - - dpr = card->dpram; /* point to DPRAM */ - - spin_lock_irqsave(&card->hysdn_lock, flags); - if (card->hw_lock) { - spin_unlock_irqrestore(&card->hysdn_lock, flags); /* hardware currently unavailable */ - return; - } - card->hw_lock = 1; /* we now lock the hardware */ - - do { - again = 0; /* assume loop not to be repeated */ - - if (!dpr->ToHyFlag) { - /* we are able to send a buffer */ - - if (hysdn_sched_tx(card, dpr->ToHyBuf, &dpr->ToHySize, &dpr->ToHyChannel, - ERG_TO_HY_BUF_SIZE)) { - dpr->ToHyFlag = 1; /* enable tx */ - again = 1; /* restart loop */ - } - } /* we are able to send a buffer */ - if (dpr->ToPcFlag) { - /* a message has arrived for us, handle it */ - - if (hysdn_sched_rx(card, dpr->ToPcBuf, dpr->ToPcSize, dpr->ToPcChannel)) { - dpr->ToPcFlag = 0; /* we worked the data */ - again = 1; /* restart loop */ - } - } /* a message has arrived for us */ - if (again) { - dpr->ToHyInt = 1; - dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ - } else - card->hw_lock = 0; /* free hardware again */ - } while (again); /* until nothing more to do */ - - spin_unlock_irqrestore(&card->hysdn_lock, flags); -} /* ergo_irq_bh */ - - -/*********************************************************/ -/* stop the card (hardware reset) and disable interrupts */ -/*********************************************************/ -static void -ergo_stopcard(hysdn_card *card) -{ - unsigned long flags; - unsigned char val; - - hysdn_net_release(card); /* first release the net device if existing */ -#ifdef CONFIG_HYSDN_CAPI - hycapi_capi_stop(card); -#endif /* CONFIG_HYSDN_CAPI */ - spin_lock_irqsave(&card->hysdn_lock, flags); - val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */ - val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */ - byteout(card->iobase + PCI9050_INTR_REG, val); - card->irq_enabled = 0; - byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RESET); /* reset E1 processor */ - card->state = CARD_STATE_UNUSED; - card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */ - - spin_unlock_irqrestore(&card->hysdn_lock, flags); -} /* ergo_stopcard */ - -/**************************************************************************/ -/* enable or disable the cards error log. The event is queued if possible */ -/**************************************************************************/ -static void -ergo_set_errlog_state(hysdn_card *card, int on) -{ - unsigned long flags; - - if (card->state != CARD_STATE_RUN) { - card->err_log_state = ERRLOG_STATE_OFF; /* must be off */ - return; - } - spin_lock_irqsave(&card->hysdn_lock, flags); - - if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) || - ((card->err_log_state == ERRLOG_STATE_ON) && on)) { - spin_unlock_irqrestore(&card->hysdn_lock, flags); - return; /* nothing to do */ - } - if (on) - card->err_log_state = ERRLOG_STATE_START; /* request start */ - else - card->err_log_state = ERRLOG_STATE_STOP; /* request stop */ - - spin_unlock_irqrestore(&card->hysdn_lock, flags); - schedule_work(&card->irq_queue); -} /* ergo_set_errlog_state */ - -/******************************************/ -/* test the cards RAM and return 0 if ok. */ -/******************************************/ -static const char TestText[36] = "This Message is filler, why read it"; - -static int -ergo_testram(hysdn_card *card) -{ - tErgDpram *dpr = card->dpram; - - memset(dpr->TrapTable, 0, sizeof(dpr->TrapTable)); /* clear all Traps */ - dpr->ToHyInt = 1; /* E1 INTR state forced */ - - memcpy(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText, - sizeof(TestText)); - if (memcmp(&dpr->ToHyBuf[ERG_TO_HY_BUF_SIZE - sizeof(TestText)], TestText, - sizeof(TestText))) - return (-1); - - memcpy(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText, - sizeof(TestText)); - if (memcmp(&dpr->ToPcBuf[ERG_TO_PC_BUF_SIZE - sizeof(TestText)], TestText, - sizeof(TestText))) - return (-1); - - return (0); -} /* ergo_testram */ - -/*****************************************************************************/ -/* this function is intended to write stage 1 boot image to the cards buffer */ -/* this is done in two steps. First the 1024 hi-words are written (offs=0), */ -/* then the 1024 lo-bytes are written. The remaining DPRAM is cleared, the */ -/* PCI-write-buffers flushed and the card is taken out of reset. */ -/* The function then waits for a reaction of the E1 processor or a timeout. */ -/* Negative return values are interpreted as errors. */ -/*****************************************************************************/ -static int -ergo_writebootimg(struct HYSDN_CARD *card, unsigned char *buf, - unsigned long offs) -{ - unsigned char *dst; - tErgDpram *dpram; - int cnt = (BOOT_IMG_SIZE >> 2); /* number of words to move and swap (byte order!) */ - - if (card->debug_flags & LOG_POF_CARD) - hysdn_addlog(card, "ERGO: write bootldr offs=0x%lx ", offs); - - dst = card->dpram; /* pointer to start of DPRAM */ - dst += (offs + ERG_DPRAM_FILL_SIZE); /* offset in the DPRAM */ - while (cnt--) { - *dst++ = *(buf + 1); /* high byte */ - *dst++ = *buf; /* low byte */ - dst += 2; /* point to next longword */ - buf += 2; /* buffer only filled with words */ - } - - /* if low words (offs = 2) have been written, clear the rest of the DPRAM, */ - /* flush the PCI-write-buffer and take the E1 out of reset */ - if (offs) { - memset(card->dpram, 0, ERG_DPRAM_FILL_SIZE); /* fill the DPRAM still not cleared */ - dpram = card->dpram; /* get pointer to dpram structure */ - dpram->ToHyNoDpramErrLog = 0xFF; /* write a dpram register */ - while (!dpram->ToHyNoDpramErrLog); /* reread volatile register to flush PCI */ - - byteout(card->iobase + PCI9050_USER_IO, PCI9050_E1_RUN); /* start E1 processor */ - /* the interrupts are still masked */ - - msleep_interruptible(20); /* Timeout 20ms */ - - if (((tDpramBootSpooler *) card->dpram)->Len != DPRAM_SPOOLER_DATA_SIZE) { - if (card->debug_flags & LOG_POF_CARD) - hysdn_addlog(card, "ERGO: write bootldr no answer"); - return (-ERR_BOOTIMG_FAIL); - } - } /* start_boot_img */ - return (0); /* successful */ -} /* ergo_writebootimg */ - -/********************************************************************************/ -/* ergo_writebootseq writes the buffer containing len bytes to the E1 processor */ -/* using the boot spool mechanism. If everything works fine 0 is returned. In */ -/* case of errors a negative error value is returned. */ -/********************************************************************************/ -static int -ergo_writebootseq(struct HYSDN_CARD *card, unsigned char *buf, int len) -{ - tDpramBootSpooler *sp = (tDpramBootSpooler *) card->dpram; - unsigned char *dst; - unsigned char buflen; - int nr_write; - unsigned char tmp_rdptr; - unsigned char wr_mirror; - int i; - - if (card->debug_flags & LOG_POF_CARD) - hysdn_addlog(card, "ERGO: write boot seq len=%d ", len); - - dst = sp->Data; /* point to data in spool structure */ - buflen = sp->Len; /* maximum len of spooled data */ - wr_mirror = sp->WrPtr; /* only once read */ - - /* try until all bytes written or error */ - i = 0x1000; /* timeout value */ - while (len) { - - /* first determine the number of bytes that may be buffered */ - do { - tmp_rdptr = sp->RdPtr; /* first read the pointer */ - i--; /* decrement timeout */ - } while (i && (tmp_rdptr != sp->RdPtr)); /* wait for stable pointer */ - - if (!i) { - if (card->debug_flags & LOG_POF_CARD) - hysdn_addlog(card, "ERGO: write boot seq timeout"); - return (-ERR_BOOTSEQ_FAIL); /* value not stable -> timeout */ - } - if ((nr_write = tmp_rdptr - wr_mirror - 1) < 0) - nr_write += buflen; /* now we got number of free bytes - 1 in buffer */ - - if (!nr_write) - continue; /* no free bytes in buffer */ - - if (nr_write > len) - nr_write = len; /* limit if last few bytes */ - i = 0x1000; /* reset timeout value */ - - /* now we know how much bytes we may put in the puffer */ - len -= nr_write; /* we savely could adjust len before output */ - while (nr_write--) { - *(dst + wr_mirror) = *buf++; /* output one byte */ - if (++wr_mirror >= buflen) - wr_mirror = 0; - sp->WrPtr = wr_mirror; /* announce the next byte to E1 */ - } /* while (nr_write) */ - - } /* while (len) */ - return (0); -} /* ergo_writebootseq */ - -/***********************************************************************************/ -/* ergo_waitpofready waits for a maximum of 10 seconds for the completition of the */ -/* boot process. If the process has been successful 0 is returned otherwise a */ -/* negative error code is returned. */ -/***********************************************************************************/ -static int -ergo_waitpofready(struct HYSDN_CARD *card) -{ - tErgDpram *dpr = card->dpram; /* pointer to DPRAM structure */ - int timecnt = 10000 / 50; /* timeout is 10 secs max. */ - unsigned long flags; - int msg_size; - int i; - - if (card->debug_flags & LOG_POF_CARD) - hysdn_addlog(card, "ERGO: waiting for pof ready"); - while (timecnt--) { - /* wait until timeout */ - - if (dpr->ToPcFlag) { - /* data has arrived */ - - if ((dpr->ToPcChannel != CHAN_SYSTEM) || - (dpr->ToPcSize < MIN_RDY_MSG_SIZE) || - (dpr->ToPcSize > MAX_RDY_MSG_SIZE) || - ((*(unsigned long *) dpr->ToPcBuf) != RDY_MAGIC)) - break; /* an error occurred */ - - /* Check for additional data delivered during SysReady */ - msg_size = dpr->ToPcSize - RDY_MAGIC_SIZE; - if (msg_size > 0) - if (EvalSysrTokData(card, dpr->ToPcBuf + RDY_MAGIC_SIZE, msg_size)) - break; - - if (card->debug_flags & LOG_POF_RECORD) - hysdn_addlog(card, "ERGO: pof boot success"); - spin_lock_irqsave(&card->hysdn_lock, flags); - - card->state = CARD_STATE_RUN; /* now card is running */ - /* enable the cards interrupt */ - byteout(card->iobase + PCI9050_INTR_REG, - bytein(card->iobase + PCI9050_INTR_REG) | - (PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1)); - card->irq_enabled = 1; /* we are ready to receive interrupts */ - - dpr->ToPcFlag = 0; /* reset data indicator */ - dpr->ToHyInt = 1; - dpr->ToPcInt = 1; /* interrupt to E1 for all cards */ - - spin_unlock_irqrestore(&card->hysdn_lock, flags); - if ((hynet_enable & (1 << card->myid)) - && (i = hysdn_net_create(card))) - { - ergo_stopcard(card); - card->state = CARD_STATE_BOOTERR; - return (i); - } -#ifdef CONFIG_HYSDN_CAPI - if ((i = hycapi_capi_create(card))) { - printk(KERN_WARNING "HYSDN: failed to create capi-interface.\n"); - } -#endif /* CONFIG_HYSDN_CAPI */ - return (0); /* success */ - } /* data has arrived */ - msleep_interruptible(50); /* Timeout 50ms */ - } /* wait until timeout */ - - if (card->debug_flags & LOG_POF_CARD) - hysdn_addlog(card, "ERGO: pof boot ready timeout"); - return (-ERR_POF_TIMEOUT); -} /* ergo_waitpofready */ - - - -/************************************************************************************/ -/* release the cards hardware. Before releasing do a interrupt disable and hardware */ -/* reset. Also unmap dpram. */ -/* Use only during module release. */ -/************************************************************************************/ -static void -ergo_releasehardware(hysdn_card *card) -{ - ergo_stopcard(card); /* first stop the card if not already done */ - free_irq(card->irq, card); /* release interrupt */ - release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */ - release_region(card->iobase + PCI9050_USER_IO, 1); - iounmap(card->dpram); - card->dpram = NULL; /* release shared mem */ -} /* ergo_releasehardware */ - - -/*********************************************************************************/ -/* acquire the needed hardware ports and map dpram. If an error occurs a nonzero */ -/* value is returned. */ -/* Use only during module init. */ -/*********************************************************************************/ -int -ergo_inithardware(hysdn_card *card) -{ - if (!request_region(card->iobase + PCI9050_INTR_REG, 1, "HYSDN")) - return (-1); - if (!request_region(card->iobase + PCI9050_USER_IO, 1, "HYSDN")) { - release_region(card->iobase + PCI9050_INTR_REG, 1); - return (-1); /* ports already in use */ - } - card->memend = card->membase + ERG_DPRAM_PAGE_SIZE - 1; - if (!(card->dpram = ioremap(card->membase, ERG_DPRAM_PAGE_SIZE))) { - release_region(card->iobase + PCI9050_INTR_REG, 1); - release_region(card->iobase + PCI9050_USER_IO, 1); - return (-1); - } - - ergo_stopcard(card); /* disable interrupts */ - if (request_irq(card->irq, ergo_interrupt, IRQF_SHARED, "HYSDN", card)) { - ergo_releasehardware(card); /* return the acquired hardware */ - return (-1); - } - /* success, now setup the function pointers */ - card->stopcard = ergo_stopcard; - card->releasehardware = ergo_releasehardware; - card->testram = ergo_testram; - card->writebootimg = ergo_writebootimg; - card->writebootseq = ergo_writebootseq; - card->waitpofready = ergo_waitpofready; - card->set_errlog_state = ergo_set_errlog_state; - INIT_WORK(&card->irq_queue, ergo_irq_bh); - spin_lock_init(&card->hysdn_lock); - - return (0); -} /* ergo_inithardware */ diff --git a/drivers/isdn/hysdn/boardergo.h b/drivers/isdn/hysdn/boardergo.h deleted file mode 100644 index e99bd81c4034..000000000000 --- a/drivers/isdn/hysdn/boardergo.h +++ /dev/null @@ -1,100 +0,0 @@ -/* $Id: boardergo.h,v 1.2.6.1 2001/09/23 22:24:54 kai Exp $ - * - * Linux driver for HYSDN cards, definitions for ergo type boards (buffers..). - * - * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -/************************************************/ -/* defines for the dual port memory of the card */ -/************************************************/ -#define ERG_DPRAM_PAGE_SIZE 0x2000 /* DPRAM occupies a 8K page */ -#define BOOT_IMG_SIZE 4096 -#define ERG_DPRAM_FILL_SIZE (ERG_DPRAM_PAGE_SIZE - BOOT_IMG_SIZE) - -#define ERG_TO_HY_BUF_SIZE 0x0E00 /* 3072 bytes buffer size to card */ -#define ERG_TO_PC_BUF_SIZE 0x0E00 /* 3072 bytes to PC, too */ - -/* following DPRAM layout copied from OS2-driver boarderg.h */ -typedef struct ErgDpram_tag { - /*0000 */ unsigned char ToHyBuf[ERG_TO_HY_BUF_SIZE]; - /*0E00 */ unsigned char ToPcBuf[ERG_TO_PC_BUF_SIZE]; - - /*1C00 */ unsigned char bSoftUart[SIZE_RSV_SOFT_UART]; - /* size 0x1B0 */ - - /*1DB0 *//* tErrLogEntry */ unsigned char volatile ErrLogMsg[64]; - /* size 64 bytes */ - /*1DB0 unsigned long ulErrType; */ - /*1DB4 unsigned long ulErrSubtype; */ - /*1DB8 unsigned long ucTextSize; */ - /*1DB9 unsigned long ucText[ERRLOG_TEXT_SIZE]; *//* ASCIIZ of len ucTextSize-1 */ - /*1DF0 */ - - /*1DF0 */ unsigned short volatile ToHyChannel; - /*1DF2 */ unsigned short volatile ToHySize; - /*1DF4 */ unsigned char volatile ToHyFlag; - /* !=0: msg for Hy waiting */ - /*1DF5 */ unsigned char volatile ToPcFlag; - /* !=0: msg for PC waiting */ - /*1DF6 */ unsigned short volatile ToPcChannel; - /*1DF8 */ unsigned short volatile ToPcSize; - /*1DFA */ unsigned char bRes1DBA[0x1E00 - 0x1DFA]; - /* 6 bytes */ - - /*1E00 */ unsigned char bRestOfEntryTbl[0x1F00 - 0x1E00]; - /*1F00 */ unsigned long TrapTable[62]; - /*1FF8 */ unsigned char bRes1FF8[0x1FFB - 0x1FF8]; - /* low part of reset vetor */ - /*1FFB */ unsigned char ToPcIntMetro; - /* notes: - * - metro has 32-bit boot ram - accessing - * ToPcInt and ToHyInt would be the same; - * so we moved ToPcInt to 1FFB. - * Because on the PC side both vars are - * readonly (reseting on int from E1 to PC), - * we can read both vars on both cards - * without destroying anything. - * - 1FFB is the high byte of the reset vector, - * so E1 side should NOT change this byte - * when writing! - */ - /*1FFC */ unsigned char volatile ToHyNoDpramErrLog; - /* note: ToHyNoDpramErrLog is used to inform - * boot loader, not to use DPRAM based - * ErrLog; when DOS driver is rewritten - * this becomes obsolete - */ - /*1FFD */ unsigned char bRes1FFD; - /*1FFE */ unsigned char ToPcInt; - /* E1_intclear; on CHAMP2: E1_intset */ - /*1FFF */ unsigned char ToHyInt; - /* E1_intset; on CHAMP2: E1_intclear */ -} tErgDpram; - -/**********************************************/ -/* PCI9050 controller local register offsets: */ -/* copied from boarderg.c */ -/**********************************************/ -#define PCI9050_INTR_REG 0x4C /* Interrupt register */ -#define PCI9050_USER_IO 0x51 /* User I/O register */ - -/* bitmask for PCI9050_INTR_REG: */ -#define PCI9050_INTR_REG_EN1 0x01 /* 1= enable (def.), 0= disable */ -#define PCI9050_INTR_REG_POL1 0x02 /* 1= active high (def.), 0= active low */ -#define PCI9050_INTR_REG_STAT1 0x04 /* 1= intr. active, 0= intr. not active (def.) */ -#define PCI9050_INTR_REG_ENPCI 0x40 /* 1= PCI interrupts enable (def.) */ - -/* bitmask for PCI9050_USER_IO: */ -#define PCI9050_USER_IO_EN3 0x02 /* 1= disable , 0= enable (def.) */ -#define PCI9050_USER_IO_DIR3 0x04 /* 1= output (def.), 0= input */ -#define PCI9050_USER_IO_DAT3 0x08 /* 1= high (def.) , 0= low */ - -#define PCI9050_E1_RESET (PCI9050_USER_IO_DIR3) /* 0x04 */ -#define PCI9050_E1_RUN (PCI9050_USER_IO_DAT3 | PCI9050_USER_IO_DIR3) /* 0x0C */ diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c deleted file mode 100644 index a2c15cd7bf67..000000000000 --- a/drivers/isdn/hysdn/hycapi.c +++ /dev/null @@ -1,785 +0,0 @@ -/* $Id: hycapi.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $ - * - * Linux driver for HYSDN cards, CAPI2.0-Interface. - * - * Author Ulrich Albrecht <u.albrecht@hypercope.de> for Hypercope GmbH - * Copyright 2000 by Hypercope GmbH - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/signal.h> -#include <linux/kernel.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/slab.h> - -#define VER_DRIVER 0 -#define VER_CARDTYPE 1 -#define VER_HWID 2 -#define VER_SERIAL 3 -#define VER_OPTION 4 -#define VER_PROTO 5 -#define VER_PROFILE 6 -#define VER_CAPI 7 - -#include "hysdn_defs.h" -#include <linux/kernelcapi.h> - -static char hycapi_revision[] = "$Revision: 1.8.6.4 $"; - -unsigned int hycapi_enable = 0xffffffff; -module_param(hycapi_enable, uint, 0); - -typedef struct _hycapi_appl { - unsigned int ctrl_mask; - capi_register_params rp; - struct sk_buff *listen_req[CAPI_MAXCONTR]; -} hycapi_appl; - -static hycapi_appl hycapi_applications[CAPI_MAXAPPL]; - -static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb); - -static inline int _hycapi_appCheck(int app_id, int ctrl_no) -{ - if ((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) || - (app_id > CAPI_MAXAPPL)) - { - printk(KERN_ERR "HYCAPI: Invalid request app_id %d for controller %d", app_id, ctrl_no); - return -1; - } - return ((hycapi_applications[app_id - 1].ctrl_mask & (1 << (ctrl_no-1))) != 0); -} - -/****************************** -Kernel-Capi callback reset_ctr -******************************/ - -static void -hycapi_reset_ctr(struct capi_ctr *ctrl) -{ - hycapictrl_info *cinfo = ctrl->driverdata; - -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "HYCAPI hycapi_reset_ctr\n"); -#endif - capilib_release(&cinfo->ncci_head); - capi_ctr_down(ctrl); -} - -/****************************** -Kernel-Capi callback remove_ctr -******************************/ - -static void -hycapi_remove_ctr(struct capi_ctr *ctrl) -{ - int i; - hycapictrl_info *cinfo = NULL; - hysdn_card *card = NULL; -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "HYCAPI hycapi_remove_ctr\n"); -#endif - cinfo = (hycapictrl_info *)(ctrl->driverdata); - if (!cinfo) { - printk(KERN_ERR "No hycapictrl_info set!"); - return; - } - card = cinfo->card; - capi_ctr_suspend_output(ctrl); - for (i = 0; i < CAPI_MAXAPPL; i++) { - if (hycapi_applications[i].listen_req[ctrl->cnr - 1]) { - kfree_skb(hycapi_applications[i].listen_req[ctrl->cnr - 1]); - hycapi_applications[i].listen_req[ctrl->cnr - 1] = NULL; - } - } - detach_capi_ctr(ctrl); - ctrl->driverdata = NULL; - kfree(card->hyctrlinfo); - - - card->hyctrlinfo = NULL; -} - -/*********************************************************** - -Queue a CAPI-message to the controller. - -***********************************************************/ - -static void -hycapi_sendmsg_internal(struct capi_ctr *ctrl, struct sk_buff *skb) -{ - hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); - hysdn_card *card = cinfo->card; - - spin_lock_irq(&cinfo->lock); -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "hycapi_send_message\n"); -#endif - cinfo->skbs[cinfo->in_idx++] = skb; /* add to buffer list */ - if (cinfo->in_idx >= HYSDN_MAX_CAPI_SKB) - cinfo->in_idx = 0; /* wrap around */ - cinfo->sk_count++; /* adjust counter */ - if (cinfo->sk_count >= HYSDN_MAX_CAPI_SKB) { - /* inform upper layers we're full */ - printk(KERN_ERR "HYSDN Card%d: CAPI-buffer overrun!\n", - card->myid); - capi_ctr_suspend_output(ctrl); - } - cinfo->tx_skb = skb; - spin_unlock_irq(&cinfo->lock); - schedule_work(&card->irq_queue); -} - -/*********************************************************** -hycapi_register_internal - -Send down the CAPI_REGISTER-Command to the controller. -This functions will also be used if the adapter has been rebooted to -re-register any applications in the private list. - -************************************************************/ - -static void -hycapi_register_internal(struct capi_ctr *ctrl, __u16 appl, - capi_register_params *rp) -{ - char ExtFeatureDefaults[] = "49 /0/0/0/0,*/1,*/2,*/3,*/4,*/5,*/6,*/7,*/8,*/9,*"; - hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); - hysdn_card *card = cinfo->card; - struct sk_buff *skb; - __u16 len; - __u8 _command = 0xa0, _subcommand = 0x80; - __u16 MessageNumber = 0x0000; - __u16 MessageBufferSize = 0; - int slen = strlen(ExtFeatureDefaults); -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "hycapi_register_appl\n"); -#endif - MessageBufferSize = rp->level3cnt * rp->datablkcnt * rp->datablklen; - - len = CAPI_MSG_BASELEN + 8 + slen + 1; - if (!(skb = alloc_skb(len, GFP_ATOMIC))) { - printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", - card->myid); - return; - } - skb_put_data(skb, &len, sizeof(__u16)); - skb_put_data(skb, &appl, sizeof(__u16)); - skb_put_data(skb, &_command, sizeof(__u8)); - skb_put_data(skb, &_subcommand, sizeof(__u8)); - skb_put_data(skb, &MessageNumber, sizeof(__u16)); - skb_put_data(skb, &MessageBufferSize, sizeof(__u16)); - skb_put_data(skb, &(rp->level3cnt), sizeof(__u16)); - skb_put_data(skb, &(rp->datablkcnt), sizeof(__u16)); - skb_put_data(skb, &(rp->datablklen), sizeof(__u16)); - skb_put_data(skb, ExtFeatureDefaults, slen); - hycapi_applications[appl - 1].ctrl_mask |= (1 << (ctrl->cnr - 1)); - hycapi_send_message(ctrl, skb); -} - -/************************************************************ -hycapi_restart_internal - -After an adapter has been rebootet, re-register all applications and -send a LISTEN_REQ (if there has been such a thing ) - -*************************************************************/ - -static void hycapi_restart_internal(struct capi_ctr *ctrl) -{ - int i; - struct sk_buff *skb; -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_WARNING "HYSDN: hycapi_restart_internal"); -#endif - for (i = 0; i < CAPI_MAXAPPL; i++) { - if (_hycapi_appCheck(i + 1, ctrl->cnr) == 1) { - hycapi_register_internal(ctrl, i + 1, - &hycapi_applications[i].rp); - if (hycapi_applications[i].listen_req[ctrl->cnr - 1]) { - skb = skb_copy(hycapi_applications[i].listen_req[ctrl->cnr - 1], GFP_ATOMIC); - hycapi_sendmsg_internal(ctrl, skb); - } - } - } -} - -/************************************************************* -Register an application. -Error-checking is done for CAPI-compliance. - -The application is recorded in the internal list. -*************************************************************/ - -static void -hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl, - capi_register_params *rp) -{ - int MaxLogicalConnections = 0, MaxBDataBlocks = 0, MaxBDataLen = 0; - hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); - hysdn_card *card = cinfo->card; - int chk = _hycapi_appCheck(appl, ctrl->cnr); - if (chk < 0) { - return; - } - if (chk == 1) { - printk(KERN_INFO "HYSDN: apl %d already registered\n", appl); - return; - } - MaxBDataBlocks = rp->datablkcnt > CAPI_MAXDATAWINDOW ? CAPI_MAXDATAWINDOW : rp->datablkcnt; - rp->datablkcnt = MaxBDataBlocks; - MaxBDataLen = rp->datablklen < 1024 ? 1024 : rp->datablklen; - rp->datablklen = MaxBDataLen; - - MaxLogicalConnections = rp->level3cnt; - if (MaxLogicalConnections < 0) { - MaxLogicalConnections = card->bchans * -MaxLogicalConnections; - } - if (MaxLogicalConnections == 0) { - MaxLogicalConnections = card->bchans; - } - - rp->level3cnt = MaxLogicalConnections; - memcpy(&hycapi_applications[appl - 1].rp, - rp, sizeof(capi_register_params)); -} - -/********************************************************************* - -hycapi_release_internal - -Send down a CAPI_RELEASE to the controller. -*********************************************************************/ - -static void hycapi_release_internal(struct capi_ctr *ctrl, __u16 appl) -{ - hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); - hysdn_card *card = cinfo->card; - struct sk_buff *skb; - __u16 len; - __u8 _command = 0xa1, _subcommand = 0x80; - __u16 MessageNumber = 0x0000; - - capilib_release_appl(&cinfo->ncci_head, appl); - -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "hycapi_release_appl\n"); -#endif - len = CAPI_MSG_BASELEN; - if (!(skb = alloc_skb(len, GFP_ATOMIC))) { - printk(KERN_ERR "HYSDN card%d: memory squeeze in hycapi_register_appl\n", - card->myid); - return; - } - skb_put_data(skb, &len, sizeof(__u16)); - skb_put_data(skb, &appl, sizeof(__u16)); - skb_put_data(skb, &_command, sizeof(__u8)); - skb_put_data(skb, &_subcommand, sizeof(__u8)); - skb_put_data(skb, &MessageNumber, sizeof(__u16)); - hycapi_send_message(ctrl, skb); - hycapi_applications[appl - 1].ctrl_mask &= ~(1 << (ctrl->cnr - 1)); -} - -/****************************************************************** -hycapi_release_appl - -Release the application from the internal list an remove it's -registration at controller-level -******************************************************************/ - -static void -hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl) -{ - int chk; - - chk = _hycapi_appCheck(appl, ctrl->cnr); - if (chk < 0) { - printk(KERN_ERR "HYCAPI: Releasing invalid appl %d on controller %d\n", appl, ctrl->cnr); - return; - } - if (hycapi_applications[appl - 1].listen_req[ctrl->cnr - 1]) { - kfree_skb(hycapi_applications[appl - 1].listen_req[ctrl->cnr - 1]); - hycapi_applications[appl - 1].listen_req[ctrl->cnr - 1] = NULL; - } - if (chk == 1) - { - hycapi_release_internal(ctrl, appl); - } -} - - -/************************************************************** -Kill a single controller. -**************************************************************/ - -int hycapi_capi_release(hysdn_card *card) -{ - hycapictrl_info *cinfo = card->hyctrlinfo; - struct capi_ctr *ctrl; -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "hycapi_capi_release\n"); -#endif - if (cinfo) { - ctrl = &cinfo->capi_ctrl; - hycapi_remove_ctr(ctrl); - } - return 0; -} - -/************************************************************** -hycapi_capi_stop - -Stop CAPI-Output on a card. (e.g. during reboot) -***************************************************************/ - -int hycapi_capi_stop(hysdn_card *card) -{ - hycapictrl_info *cinfo = card->hyctrlinfo; - struct capi_ctr *ctrl; -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "hycapi_capi_stop\n"); -#endif - if (cinfo) { - ctrl = &cinfo->capi_ctrl; -/* ctrl->suspend_output(ctrl); */ - capi_ctr_down(ctrl); - } - return 0; -} - -/*************************************************************** -hycapi_send_message - -Send a message to the controller. - -Messages are parsed for their Command/Subcommand-type, and appropriate -action's are performed. - -Note that we have to muck around with a 64Bit-DATA_REQ as there are -firmware-releases that do not check the MsgLen-Indication! - -***************************************************************/ - -static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb) -{ - __u16 appl_id; - int _len, _len2; - __u8 msghead[64]; - hycapictrl_info *cinfo = ctrl->driverdata; - u16 retval = CAPI_NOERROR; - - appl_id = CAPIMSG_APPID(skb->data); - switch (_hycapi_appCheck(appl_id, ctrl->cnr)) - { - case 0: -/* printk(KERN_INFO "Need to register\n"); */ - hycapi_register_internal(ctrl, - appl_id, - &(hycapi_applications[appl_id - 1].rp)); - break; - case 1: - break; - default: - printk(KERN_ERR "HYCAPI: Controller mixup!\n"); - retval = CAPI_ILLAPPNR; - goto out; - } - switch (CAPIMSG_CMD(skb->data)) { - case CAPI_DISCONNECT_B3_RESP: - capilib_free_ncci(&cinfo->ncci_head, appl_id, - CAPIMSG_NCCI(skb->data)); - break; - case CAPI_DATA_B3_REQ: - _len = CAPIMSG_LEN(skb->data); - if (_len > 22) { - _len2 = _len - 22; - skb_copy_from_linear_data(skb, msghead, 22); - skb_copy_to_linear_data_offset(skb, _len2, - msghead, 22); - skb_pull(skb, _len2); - CAPIMSG_SETLEN(skb->data, 22); - retval = capilib_data_b3_req(&cinfo->ncci_head, - CAPIMSG_APPID(skb->data), - CAPIMSG_NCCI(skb->data), - CAPIMSG_MSGID(skb->data)); - } - break; - case CAPI_LISTEN_REQ: - if (hycapi_applications[appl_id - 1].listen_req[ctrl->cnr - 1]) - { - kfree_skb(hycapi_applications[appl_id - 1].listen_req[ctrl->cnr - 1]); - hycapi_applications[appl_id - 1].listen_req[ctrl->cnr - 1] = NULL; - } - if (!(hycapi_applications[appl_id -1].listen_req[ctrl->cnr - 1] = skb_copy(skb, GFP_ATOMIC))) - { - printk(KERN_ERR "HYSDN: memory squeeze in private_listen\n"); - } - break; - default: - break; - } -out: - if (retval == CAPI_NOERROR) - hycapi_sendmsg_internal(ctrl, skb); - else - dev_kfree_skb_any(skb); - - return retval; -} - -static int hycapi_proc_show(struct seq_file *m, void *v) -{ - struct capi_ctr *ctrl = m->private; - hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); - hysdn_card *card = cinfo->card; - char *s; - - seq_printf(m, "%-16s %s\n", "name", cinfo->cardname); - seq_printf(m, "%-16s 0x%x\n", "io", card->iobase); - seq_printf(m, "%-16s %d\n", "irq", card->irq); - - switch (card->brdtype) { - case BD_PCCARD: s = "HYSDN Hycard"; break; - case BD_ERGO: s = "HYSDN Ergo2"; break; - case BD_METRO: s = "HYSDN Metro4"; break; - case BD_CHAMP2: s = "HYSDN Champ2"; break; - case BD_PLEXUS: s = "HYSDN Plexus30"; break; - default: s = "???"; break; - } - seq_printf(m, "%-16s %s\n", "type", s); - if ((s = cinfo->version[VER_DRIVER]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != NULL) - seq_printf(m, "%-16s %s\n", "ver_serial", s); - - seq_printf(m, "%-16s %s\n", "cardname", cinfo->cardname); - - return 0; -} - -/************************************************************** -hycapi_load_firmware - -This does NOT load any firmware, but the callback somehow is needed -on capi-interface registration. - -**************************************************************/ - -static int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) -{ -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "hycapi_load_firmware\n"); -#endif - return 0; -} - - -static char *hycapi_procinfo(struct capi_ctr *ctrl) -{ - hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata); -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "%s\n", __func__); -#endif - if (!cinfo) - return ""; - sprintf(cinfo->infobuf, "%s %s 0x%x %d %s", - cinfo->cardname[0] ? cinfo->cardname : "-", - cinfo->version[VER_DRIVER] ? cinfo->version[VER_DRIVER] : "-", - cinfo->card ? cinfo->card->iobase : 0x0, - cinfo->card ? cinfo->card->irq : 0, - hycapi_revision - ); - return cinfo->infobuf; -} - -/****************************************************************** -hycapi_rx_capipkt - -Receive a capi-message. - -All B3_DATA_IND are converted to 64K-extension compatible format. -New nccis are created if necessary. -*******************************************************************/ - -void -hycapi_rx_capipkt(hysdn_card *card, unsigned char *buf, unsigned short len) -{ - struct sk_buff *skb; - hycapictrl_info *cinfo = card->hyctrlinfo; - struct capi_ctr *ctrl; - __u16 ApplId; - __u16 MsgLen, info; - __u16 len2, CapiCmd; - __u32 CP64[2] = {0, 0}; -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "hycapi_rx_capipkt\n"); -#endif - if (!cinfo) { - return; - } - ctrl = &cinfo->capi_ctrl; - if (len < CAPI_MSG_BASELEN) { - printk(KERN_ERR "HYSDN Card%d: invalid CAPI-message, length %d!\n", - card->myid, len); - return; - } - MsgLen = CAPIMSG_LEN(buf); - ApplId = CAPIMSG_APPID(buf); - CapiCmd = CAPIMSG_CMD(buf); - - if ((CapiCmd == CAPI_DATA_B3_IND) && (MsgLen < 30)) { - len2 = len + (30 - MsgLen); - if (!(skb = alloc_skb(len2, GFP_ATOMIC))) { - printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", - card->myid); - return; - } - skb_put_data(skb, buf, MsgLen); - skb_put_data(skb, CP64, 2 * sizeof(__u32)); - skb_put_data(skb, buf + MsgLen, len - MsgLen); - CAPIMSG_SETLEN(skb->data, 30); - } else { - if (!(skb = alloc_skb(len, GFP_ATOMIC))) { - printk(KERN_ERR "HYSDN Card%d: incoming packet dropped\n", - card->myid); - return; - } - skb_put_data(skb, buf, len); - } - switch (CAPIMSG_CMD(skb->data)) - { - case CAPI_CONNECT_B3_CONF: -/* Check info-field for error-indication: */ - info = CAPIMSG_U16(skb->data, 12); - switch (info) - { - case 0: - capilib_new_ncci(&cinfo->ncci_head, ApplId, CAPIMSG_NCCI(skb->data), - hycapi_applications[ApplId - 1].rp.datablkcnt); - - break; - case 0x0001: - printk(KERN_ERR "HYSDN Card%d: NCPI not supported by current " - "protocol. NCPI ignored.\n", card->myid); - break; - case 0x2001: - printk(KERN_ERR "HYSDN Card%d: Message not supported in" - " current state\n", card->myid); - break; - case 0x2002: - printk(KERN_ERR "HYSDN Card%d: invalid PLCI\n", card->myid); - break; - case 0x2004: - printk(KERN_ERR "HYSDN Card%d: out of NCCI\n", card->myid); - break; - case 0x3008: - printk(KERN_ERR "HYSDN Card%d: NCPI not supported\n", - card->myid); - break; - default: - printk(KERN_ERR "HYSDN Card%d: Info in CONNECT_B3_CONF: %d\n", - card->myid, info); - break; - } - break; - case CAPI_CONNECT_B3_IND: - capilib_new_ncci(&cinfo->ncci_head, ApplId, - CAPIMSG_NCCI(skb->data), - hycapi_applications[ApplId - 1].rp.datablkcnt); - break; - case CAPI_DATA_B3_CONF: - capilib_data_b3_conf(&cinfo->ncci_head, ApplId, - CAPIMSG_NCCI(skb->data), - CAPIMSG_MSGID(skb->data)); - break; - default: - break; - } - capi_ctr_handle_message(ctrl, ApplId, skb); -} - -/****************************************************************** -hycapi_tx_capiack - -Internally acknowledge a msg sent. This will remove the msg from the -internal queue. - -*******************************************************************/ - -void hycapi_tx_capiack(hysdn_card *card) -{ - hycapictrl_info *cinfo = card->hyctrlinfo; -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "hycapi_tx_capiack\n"); -#endif - if (!cinfo) { - return; - } - spin_lock_irq(&cinfo->lock); - kfree_skb(cinfo->skbs[cinfo->out_idx]); /* free skb */ - cinfo->skbs[cinfo->out_idx++] = NULL; - if (cinfo->out_idx >= HYSDN_MAX_CAPI_SKB) - cinfo->out_idx = 0; /* wrap around */ - - if (cinfo->sk_count-- == HYSDN_MAX_CAPI_SKB) /* dec usage count */ - capi_ctr_resume_output(&cinfo->capi_ctrl); - spin_unlock_irq(&cinfo->lock); -} - -/*************************************************************** -hycapi_tx_capiget(hysdn_card *card) - -This is called when polling for messages to SEND. - -****************************************************************/ - -struct sk_buff * -hycapi_tx_capiget(hysdn_card *card) -{ - hycapictrl_info *cinfo = card->hyctrlinfo; - if (!cinfo) { - return (struct sk_buff *)NULL; - } - if (!cinfo->sk_count) - return (struct sk_buff *)NULL; /* nothing available */ - - return (cinfo->skbs[cinfo->out_idx]); /* next packet to send */ -} - - -/********************************************************** -int hycapi_init() - -attach the capi-driver to the kernel-capi. - -***********************************************************/ - -int hycapi_init(void) -{ - int i; - for (i = 0; i < CAPI_MAXAPPL; i++) { - memset(&(hycapi_applications[i]), 0, sizeof(hycapi_appl)); - } - return (0); -} - -/************************************************************** -hycapi_cleanup(void) - -detach the capi-driver to the kernel-capi. Actually this should -free some more ressources. Do that later. -**************************************************************/ - -void -hycapi_cleanup(void) -{ -} - -/******************************************************************** -hycapi_capi_create(hysdn_card *card) - -Attach the card with its capi-ctrl. -*********************************************************************/ - -static void hycapi_fill_profile(hysdn_card *card) -{ - hycapictrl_info *cinfo = NULL; - struct capi_ctr *ctrl = NULL; - cinfo = card->hyctrlinfo; - if (!cinfo) return; - ctrl = &cinfo->capi_ctrl; - strcpy(ctrl->manu, "Hypercope"); - ctrl->version.majorversion = 2; - ctrl->version.minorversion = 0; - ctrl->version.majormanuversion = 3; - ctrl->version.minormanuversion = 2; - ctrl->profile.ncontroller = card->myid; - ctrl->profile.nbchannel = card->bchans; - ctrl->profile.goptions = GLOBAL_OPTION_INTERNAL_CONTROLLER | - GLOBAL_OPTION_B_CHANNEL_OPERATION; - ctrl->profile.support1 = B1_PROT_64KBIT_HDLC | - (card->faxchans ? B1_PROT_T30 : 0) | - B1_PROT_64KBIT_TRANSPARENT; - ctrl->profile.support2 = B2_PROT_ISO7776 | - (card->faxchans ? B2_PROT_T30 : 0) | - B2_PROT_TRANSPARENT; - ctrl->profile.support3 = B3_PROT_TRANSPARENT | - B3_PROT_T90NL | - (card->faxchans ? B3_PROT_T30 : 0) | - (card->faxchans ? B3_PROT_T30EXT : 0) | - B3_PROT_ISO8208; -} - -int -hycapi_capi_create(hysdn_card *card) -{ - hycapictrl_info *cinfo = NULL; - struct capi_ctr *ctrl = NULL; - int retval; -#ifdef HYCAPI_PRINTFNAMES - printk(KERN_NOTICE "hycapi_capi_create\n"); -#endif - if ((hycapi_enable & (1 << card->myid)) == 0) { - return 1; - } - if (!card->hyctrlinfo) { - cinfo = kzalloc(sizeof(hycapictrl_info), GFP_ATOMIC); - if (!cinfo) { - printk(KERN_WARNING "HYSDN: no memory for capi-ctrl.\n"); - return -ENOMEM; - } - card->hyctrlinfo = cinfo; - cinfo->card = card; - spin_lock_init(&cinfo->lock); - INIT_LIST_HEAD(&cinfo->ncci_head); - - switch (card->brdtype) { - case BD_PCCARD: strcpy(cinfo->cardname, "HYSDN Hycard"); break; - case BD_ERGO: strcpy(cinfo->cardname, "HYSDN Ergo2"); break; - case BD_METRO: strcpy(cinfo->cardname, "HYSDN Metro4"); break; - case BD_CHAMP2: strcpy(cinfo->cardname, "HYSDN Champ2"); break; - case BD_PLEXUS: strcpy(cinfo->cardname, "HYSDN Plexus30"); break; - default: strcpy(cinfo->cardname, "HYSDN ???"); break; - } - - ctrl = &cinfo->capi_ctrl; - ctrl->driver_name = "hycapi"; - ctrl->driverdata = cinfo; - ctrl->register_appl = hycapi_register_appl; - ctrl->release_appl = hycapi_release_appl; - ctrl->send_message = hycapi_send_message; - ctrl->load_firmware = hycapi_load_firmware; - ctrl->reset_ctr = hycapi_reset_ctr; - ctrl->procinfo = hycapi_procinfo; - ctrl->proc_show = hycapi_proc_show; - strcpy(ctrl->name, cinfo->cardname); - ctrl->owner = THIS_MODULE; - - retval = attach_capi_ctr(ctrl); - if (retval) { - printk(KERN_ERR "hycapi: attach controller failed.\n"); - return -EBUSY; - } - /* fill in the blanks: */ - hycapi_fill_profile(card); - capi_ctr_ready(ctrl); - } else { - /* resume output on stopped ctrl */ - ctrl = &card->hyctrlinfo->capi_ctrl; - hycapi_fill_profile(card); - capi_ctr_ready(ctrl); - hycapi_restart_internal(ctrl); -/* ctrl->resume_output(ctrl); */ - } - return 0; -} diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c deleted file mode 100644 index ba177c3a621b..000000000000 --- a/drivers/isdn/hysdn/hysdn_boot.c +++ /dev/null @@ -1,400 +0,0 @@ -/* $Id: hysdn_boot.c,v 1.4.6.4 2001/09/23 22:24:54 kai Exp $ - * - * Linux driver for HYSDN cards - * specific routines for booting and pof handling - * - * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/vmalloc.h> -#include <linux/slab.h> -#include <linux/uaccess.h> - -#include "hysdn_defs.h" -#include "hysdn_pof.h" - -/********************************/ -/* defines for pof read handler */ -/********************************/ -#define POF_READ_FILE_HEAD 0 -#define POF_READ_TAG_HEAD 1 -#define POF_READ_TAG_DATA 2 - -/************************************************************/ -/* definition of boot specific data area. This data is only */ -/* needed during boot and so allocated dynamically. */ -/************************************************************/ -struct boot_data { - unsigned short Cryptor; /* for use with Decrypt function */ - unsigned short Nrecs; /* records remaining in file */ - unsigned char pof_state;/* actual state of read handler */ - unsigned char is_crypted;/* card data is crypted */ - int BufSize; /* actual number of bytes bufferd */ - int last_error; /* last occurred error */ - unsigned short pof_recid;/* actual pof recid */ - unsigned long pof_reclen;/* total length of pof record data */ - unsigned long pof_recoffset;/* actual offset inside pof record */ - union { - unsigned char BootBuf[BOOT_BUF_SIZE];/* buffer as byte count */ - tPofRecHdr PofRecHdr; /* header for actual record/chunk */ - tPofFileHdr PofFileHdr; /* header from POF file */ - tPofTimeStamp PofTime; /* time information */ - } buf; -}; - -/*****************************************************/ -/* start decryption of successive POF file chuncks. */ -/* */ -/* to be called at start of POF file reading, */ -/* before starting any decryption on any POF record. */ -/*****************************************************/ -static void -StartDecryption(struct boot_data *boot) -{ - boot->Cryptor = CRYPT_STARTTERM; -} /* StartDecryption */ - - -/***************************************************************/ -/* decrypt complete BootBuf */ -/* NOTE: decryption must be applied to all or none boot tags - */ -/* to HI and LO boot loader and (all) seq tags, because */ -/* global Cryptor is started for whole POF. */ -/***************************************************************/ -static void -DecryptBuf(struct boot_data *boot, int cnt) -{ - unsigned char *bufp = boot->buf.BootBuf; - - while (cnt--) { - boot->Cryptor = (boot->Cryptor >> 1) ^ ((boot->Cryptor & 1U) ? CRYPT_FEEDTERM : 0); - *bufp++ ^= (unsigned char)boot->Cryptor; - } -} /* DecryptBuf */ - -/********************************************************************************/ -/* pof_handle_data executes the required actions dependent on the active record */ -/* id. If successful 0 is returned, a negative value shows an error. */ -/********************************************************************************/ -static int -pof_handle_data(hysdn_card *card, int datlen) -{ - struct boot_data *boot = card->boot; /* pointer to boot specific data */ - long l; - unsigned char *imgp; - int img_len; - - /* handle the different record types */ - switch (boot->pof_recid) { - - case TAG_TIMESTMP: - if (card->debug_flags & LOG_POF_RECORD) - hysdn_addlog(card, "POF created %s", boot->buf.PofTime.DateTimeText); - break; - - case TAG_CBOOTDTA: - DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ - /* fall through */ - case TAG_BOOTDTA: - if (card->debug_flags & LOG_POF_RECORD) - hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", - (boot->pof_recid == TAG_CBOOTDTA) ? "CBOOTDATA" : "BOOTDTA", - datlen, boot->pof_recoffset); - - if (boot->pof_reclen != POF_BOOT_LOADER_TOTAL_SIZE) { - boot->last_error = EPOF_BAD_IMG_SIZE; /* invalid length */ - return (boot->last_error); - } - imgp = boot->buf.BootBuf; /* start of buffer */ - img_len = datlen; /* maximum length to transfer */ - - l = POF_BOOT_LOADER_OFF_IN_PAGE - - (boot->pof_recoffset & (POF_BOOT_LOADER_PAGE_SIZE - 1)); - if (l > 0) { - /* buffer needs to be truncated */ - imgp += l; /* advance pointer */ - img_len -= l; /* adjust len */ - } - /* at this point no special handling for data wrapping over buffer */ - /* is necessary, because the boot image always will be adjusted to */ - /* match a page boundary inside the buffer. */ - /* The buffer for the boot image on the card is filled in 2 cycles */ - /* first the 1024 hi-words are put in the buffer, then the low 1024 */ - /* word are handled in the same way with different offset. */ - - if (img_len > 0) { - /* data available for copy */ - if ((boot->last_error = - card->writebootimg(card, imgp, - (boot->pof_recoffset > POF_BOOT_LOADER_PAGE_SIZE) ? 2 : 0)) < 0) - return (boot->last_error); - } - break; /* end of case boot image hi/lo */ - - case TAG_CABSDATA: - DecryptBuf(boot, datlen); /* we need to encrypt the buffer */ - /* fall through */ - case TAG_ABSDATA: - if (card->debug_flags & LOG_POF_RECORD) - hysdn_addlog(card, "POF got %s len=%d offs=0x%lx", - (boot->pof_recid == TAG_CABSDATA) ? "CABSDATA" : "ABSDATA", - datlen, boot->pof_recoffset); - - if ((boot->last_error = card->writebootseq(card, boot->buf.BootBuf, datlen)) < 0) - return (boot->last_error); /* error writing data */ - - if (boot->pof_recoffset + datlen >= boot->pof_reclen) - return (card->waitpofready(card)); /* data completely spooled, wait for ready */ - - break; /* end of case boot seq data */ - - default: - if (card->debug_flags & LOG_POF_RECORD) - hysdn_addlog(card, "POF got data(id=0x%lx) len=%d offs=0x%lx", boot->pof_recid, - datlen, boot->pof_recoffset); - - break; /* simply skip record */ - } /* switch boot->pof_recid */ - - return (0); -} /* pof_handle_data */ - - -/******************************************************************************/ -/* pof_write_buffer is called when the buffer has been filled with the needed */ -/* number of data bytes. The number delivered is additionally supplied for */ -/* verification. The functions handles the data and returns the needed number */ -/* of bytes for the next action. If the returned value is 0 or less an error */ -/* occurred and booting must be aborted. */ -/******************************************************************************/ -int -pof_write_buffer(hysdn_card *card, int datlen) -{ - struct boot_data *boot = card->boot; /* pointer to boot specific data */ - - if (!boot) - return (-EFAULT); /* invalid call */ - if (boot->last_error < 0) - return (boot->last_error); /* repeated error */ - - if (card->debug_flags & LOG_POF_WRITE) - hysdn_addlog(card, "POF write: got %d bytes ", datlen); - - switch (boot->pof_state) { - case POF_READ_FILE_HEAD: - if (card->debug_flags & LOG_POF_WRITE) - hysdn_addlog(card, "POF write: checking file header"); - - if (datlen != sizeof(tPofFileHdr)) { - boot->last_error = -EPOF_INTERNAL; - break; - } - if (boot->buf.PofFileHdr.Magic != TAGFILEMAGIC) { - boot->last_error = -EPOF_BAD_MAGIC; - break; - } - /* Setup the new state and vars */ - boot->Nrecs = (unsigned short)(boot->buf.PofFileHdr.N_PofRecs); /* limited to 65535 */ - boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ - boot->last_error = sizeof(tPofRecHdr); /* new length */ - break; - - case POF_READ_TAG_HEAD: - if (card->debug_flags & LOG_POF_WRITE) - hysdn_addlog(card, "POF write: checking tag header"); - - if (datlen != sizeof(tPofRecHdr)) { - boot->last_error = -EPOF_INTERNAL; - break; - } - boot->pof_recid = boot->buf.PofRecHdr.PofRecId; /* actual pof recid */ - boot->pof_reclen = boot->buf.PofRecHdr.PofRecDataLen; /* total length */ - boot->pof_recoffset = 0; /* no starting offset */ - - if (card->debug_flags & LOG_POF_RECORD) - hysdn_addlog(card, "POF: got record id=0x%lx length=%ld ", - boot->pof_recid, boot->pof_reclen); - - boot->pof_state = POF_READ_TAG_DATA; /* now start with tag data */ - if (boot->pof_reclen < BOOT_BUF_SIZE) - boot->last_error = boot->pof_reclen; /* limit size */ - else - boot->last_error = BOOT_BUF_SIZE; /* maximum */ - - if (!boot->last_error) { /* no data inside record */ - boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ - boot->last_error = sizeof(tPofRecHdr); /* new length */ - } - break; - - case POF_READ_TAG_DATA: - if (card->debug_flags & LOG_POF_WRITE) - hysdn_addlog(card, "POF write: getting tag data"); - - if (datlen != boot->last_error) { - boot->last_error = -EPOF_INTERNAL; - break; - } - if ((boot->last_error = pof_handle_data(card, datlen)) < 0) - return (boot->last_error); /* an error occurred */ - boot->pof_recoffset += datlen; - if (boot->pof_recoffset >= boot->pof_reclen) { - boot->pof_state = POF_READ_TAG_HEAD; /* now start with single tags */ - boot->last_error = sizeof(tPofRecHdr); /* new length */ - } else { - if (boot->pof_reclen - boot->pof_recoffset < BOOT_BUF_SIZE) - boot->last_error = boot->pof_reclen - boot->pof_recoffset; /* limit size */ - else - boot->last_error = BOOT_BUF_SIZE; /* maximum */ - } - break; - - default: - boot->last_error = -EPOF_INTERNAL; /* unknown state */ - break; - } /* switch (boot->pof_state) */ - - return (boot->last_error); -} /* pof_write_buffer */ - - -/*******************************************************************************/ -/* pof_write_open is called when an open for boot on the cardlog device occurs. */ -/* The function returns the needed number of bytes for the next operation. If */ -/* the returned number is less or equal 0 an error specified by this code */ -/* occurred. Additionally the pointer to the buffer data area is set on success */ -/*******************************************************************************/ -int -pof_write_open(hysdn_card *card, unsigned char **bufp) -{ - struct boot_data *boot; /* pointer to boot specific data */ - - if (card->boot) { - if (card->debug_flags & LOG_POF_OPEN) - hysdn_addlog(card, "POF open: already opened for boot"); - return (-ERR_ALREADY_BOOT); /* boot already active */ - } - /* error no mem available */ - if (!(boot = kzalloc(sizeof(struct boot_data), GFP_KERNEL))) { - if (card->debug_flags & LOG_MEM_ERR) - hysdn_addlog(card, "POF open: unable to allocate mem"); - return (-EFAULT); - } - card->boot = boot; - card->state = CARD_STATE_BOOTING; - - card->stopcard(card); /* first stop the card */ - if (card->testram(card)) { - if (card->debug_flags & LOG_POF_OPEN) - hysdn_addlog(card, "POF open: DPRAM test failure"); - boot->last_error = -ERR_BOARD_DPRAM; - card->state = CARD_STATE_BOOTERR; /* show boot error */ - return (boot->last_error); - } - boot->BufSize = 0; /* Buffer is empty */ - boot->pof_state = POF_READ_FILE_HEAD; /* read file header */ - StartDecryption(boot); /* if POF File should be encrypted */ - - if (card->debug_flags & LOG_POF_OPEN) - hysdn_addlog(card, "POF open: success"); - - *bufp = boot->buf.BootBuf; /* point to buffer */ - return (sizeof(tPofFileHdr)); -} /* pof_write_open */ - -/********************************************************************************/ -/* pof_write_close is called when an close of boot on the cardlog device occurs. */ -/* The return value must be 0 if everything has happened as desired. */ -/********************************************************************************/ -int -pof_write_close(hysdn_card *card) -{ - struct boot_data *boot = card->boot; /* pointer to boot specific data */ - - if (!boot) - return (-EFAULT); /* invalid call */ - - card->boot = NULL; /* no boot active */ - kfree(boot); - - if (card->state == CARD_STATE_RUN) - card->set_errlog_state(card, 1); /* activate error log */ - - if (card->debug_flags & LOG_POF_OPEN) - hysdn_addlog(card, "POF close: success"); - - return (0); -} /* pof_write_close */ - -/*********************************************************************************/ -/* EvalSysrTokData checks additional records delivered with the Sysready Message */ -/* when POF has been booted. A return value of 0 is used if no error occurred. */ -/*********************************************************************************/ -int -EvalSysrTokData(hysdn_card *card, unsigned char *cp, int len) -{ - u_char *p; - u_char crc; - - if (card->debug_flags & LOG_POF_RECORD) - hysdn_addlog(card, "SysReady Token data length %d", len); - - if (len < 2) { - hysdn_addlog(card, "SysReady Token Data to short"); - return (1); - } - for (p = cp, crc = 0; p < (cp + len - 2); p++) - if ((crc & 0x80)) - crc = (((u_char) (crc << 1)) + 1) + *p; - else - crc = ((u_char) (crc << 1)) + *p; - crc = ~crc; - if (crc != *(cp + len - 1)) { - hysdn_addlog(card, "SysReady Token Data invalid CRC"); - return (1); - } - len--; /* don't check CRC byte */ - while (len > 0) { - - if (*cp == SYSR_TOK_END) - return (0); /* End of Token stream */ - - if (len < (*(cp + 1) + 2)) { - hysdn_addlog(card, "token 0x%x invalid length %d", *cp, *(cp + 1)); - return (1); - } - switch (*cp) { - case SYSR_TOK_B_CHAN: /* 1 */ - if (*(cp + 1) != 1) - return (1); /* length invalid */ - card->bchans = *(cp + 2); - break; - - case SYSR_TOK_FAX_CHAN: /* 2 */ - if (*(cp + 1) != 1) - return (1); /* length invalid */ - card->faxchans = *(cp + 2); - break; - - case SYSR_TOK_MAC_ADDR: /* 3 */ - if (*(cp + 1) != 6) - return (1); /* length invalid */ - memcpy(card->mac_addr, cp + 2, 6); - break; - - default: - hysdn_addlog(card, "unknown token 0x%02x length %d", *cp, *(cp + 1)); - break; - } - len -= (*(cp + 1) + 2); /* adjust len */ - cp += (*(cp + 1) + 2); /* and pointer */ - } - - hysdn_addlog(card, "no end token found"); - return (1); -} /* EvalSysrTokData */ diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h deleted file mode 100644 index cdac46a21692..000000000000 --- a/drivers/isdn/hysdn/hysdn_defs.h +++ /dev/null @@ -1,282 +0,0 @@ -/* $Id: hysdn_defs.h,v 1.5.6.3 2001/09/23 22:24:54 kai Exp $ - * - * Linux driver for HYSDN cards - * global definitions and exported vars and functions. - * - * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef HYSDN_DEFS_H -#define HYSDN_DEFS_H - -#include <linux/hysdn_if.h> -#include <linux/interrupt.h> -#include <linux/workqueue.h> -#include <linux/skbuff.h> - -#include "ince1pc.h" - -#ifdef CONFIG_HYSDN_CAPI -#include <linux/capi.h> -#include <linux/isdn/capicmd.h> -#include <linux/isdn/capiutil.h> -#include <linux/isdn/capilli.h> - -/***************************/ -/* CAPI-Profile values. */ -/***************************/ - -#define GLOBAL_OPTION_INTERNAL_CONTROLLER 0x0001 -#define GLOBAL_OPTION_EXTERNAL_CONTROLLER 0x0002 -#define GLOBAL_OPTION_HANDSET 0x0004 -#define GLOBAL_OPTION_DTMF 0x0008 -#define GLOBAL_OPTION_SUPPL_SERVICES 0x0010 -#define GLOBAL_OPTION_CHANNEL_ALLOCATION 0x0020 -#define GLOBAL_OPTION_B_CHANNEL_OPERATION 0x0040 - -#define B1_PROT_64KBIT_HDLC 0x0001 -#define B1_PROT_64KBIT_TRANSPARENT 0x0002 -#define B1_PROT_V110_ASYNCH 0x0004 -#define B1_PROT_V110_SYNCH 0x0008 -#define B1_PROT_T30 0x0010 -#define B1_PROT_64KBIT_INV_HDLC 0x0020 -#define B1_PROT_56KBIT_TRANSPARENT 0x0040 - -#define B2_PROT_ISO7776 0x0001 -#define B2_PROT_TRANSPARENT 0x0002 -#define B2_PROT_SDLC 0x0004 -#define B2_PROT_LAPD 0x0008 -#define B2_PROT_T30 0x0010 -#define B2_PROT_PPP 0x0020 -#define B2_PROT_TRANSPARENT_IGNORE_B1_FRAMING_ERRORS 0x0040 - -#define B3_PROT_TRANSPARENT 0x0001 -#define B3_PROT_T90NL 0x0002 -#define B3_PROT_ISO8208 0x0004 -#define B3_PROT_X25_DCE 0x0008 -#define B3_PROT_T30 0x0010 -#define B3_PROT_T30EXT 0x0020 - -#define HYSDN_MAXVERSION 8 - -/* Number of sendbuffers in CAPI-queue */ -#define HYSDN_MAX_CAPI_SKB 20 - -#endif /* CONFIG_HYSDN_CAPI*/ - -/************************************************/ -/* constants and bits for debugging/log outputs */ -/************************************************/ -#define LOG_MAX_LINELEN 120 -#define DEB_OUT_SYSLOG 0x80000000 /* output to syslog instead of proc fs */ -#define LOG_MEM_ERR 0x00000001 /* log memory errors like kmalloc failure */ -#define LOG_POF_OPEN 0x00000010 /* log pof open and close activities */ -#define LOG_POF_RECORD 0x00000020 /* log pof record parser */ -#define LOG_POF_WRITE 0x00000040 /* log detailed pof write operation */ -#define LOG_POF_CARD 0x00000080 /* log pof related card functions */ -#define LOG_CNF_LINE 0x00000100 /* all conf lines are put to procfs */ -#define LOG_CNF_DATA 0x00000200 /* non comment conf lines are shown with channel */ -#define LOG_CNF_MISC 0x00000400 /* additional conf line debug outputs */ -#define LOG_SCHED_ASYN 0x00001000 /* debug schedulers async tx routines */ -#define LOG_PROC_OPEN 0x00100000 /* open and close from procfs are logged */ -#define LOG_PROC_ALL 0x00200000 /* all actions from procfs are logged */ -#define LOG_NET_INIT 0x00010000 /* network init and deinit logging */ - -#define DEF_DEB_FLAGS 0x7fff000f /* everything is logged to procfs */ - -/**********************************/ -/* proc filesystem name constants */ -/**********************************/ -#define PROC_SUBDIR_NAME "hysdn" -#define PROC_CONF_BASENAME "cardconf" -#define PROC_LOG_BASENAME "cardlog" - -/***********************************/ -/* PCI 32 bit parms for IO and MEM */ -/***********************************/ -#define PCI_REG_PLX_MEM_BASE 0 -#define PCI_REG_PLX_IO_BASE 1 -#define PCI_REG_MEMORY_BASE 3 - -/**************/ -/* card types */ -/**************/ -#define BD_NONE 0U -#define BD_PERFORMANCE 1U -#define BD_VALUE 2U -#define BD_PCCARD 3U -#define BD_ERGO 4U -#define BD_METRO 5U -#define BD_CHAMP2 6U -#define BD_PLEXUS 7U - -/******************************************************/ -/* defined states for cards shown by reading cardconf */ -/******************************************************/ -#define CARD_STATE_UNUSED 0 /* never been used or booted */ -#define CARD_STATE_BOOTING 1 /* booting is in progress */ -#define CARD_STATE_BOOTERR 2 /* a previous boot was aborted */ -#define CARD_STATE_RUN 3 /* card is active */ - -/*******************************/ -/* defines for error_log_state */ -/*******************************/ -#define ERRLOG_STATE_OFF 0 /* error log is switched off, nothing to do */ -#define ERRLOG_STATE_ON 1 /* error log is switched on, wait for data */ -#define ERRLOG_STATE_START 2 /* start error logging */ -#define ERRLOG_STATE_STOP 3 /* stop error logging */ - -/*******************************/ -/* data structure for one card */ -/*******************************/ -typedef struct HYSDN_CARD { - - /* general variables for the cards */ - int myid; /* own driver card id */ - unsigned char bus; /* pci bus the card is connected to */ - unsigned char devfn; /* slot+function bit encoded */ - unsigned short subsysid;/* PCI subsystem id */ - unsigned char brdtype; /* type of card */ - unsigned int bchans; /* number of available B-channels */ - unsigned int faxchans; /* number of available fax-channels */ - unsigned char mac_addr[6];/* MAC Address read from card */ - unsigned int irq; /* interrupt number */ - unsigned int iobase; /* IO-port base address */ - unsigned long plxbase; /* PLX memory base */ - unsigned long membase; /* DPRAM memory base */ - unsigned long memend; /* DPRAM memory end */ - void *dpram; /* mapped dpram */ - int state; /* actual state of card -> CARD_STATE_** */ - struct HYSDN_CARD *next; /* pointer to next card */ - - /* data areas for the /proc file system */ - void *proclog; /* pointer to proclog filesystem specific data */ - void *procconf; /* pointer to procconf filesystem specific data */ - - /* debugging and logging */ - unsigned char err_log_state;/* actual error log state of the card */ - unsigned long debug_flags;/* tells what should be debugged and where */ - void (*set_errlog_state) (struct HYSDN_CARD *, int); - - /* interrupt handler + interrupt synchronisation */ - struct work_struct irq_queue; /* interrupt task queue */ - unsigned char volatile irq_enabled;/* interrupt enabled if != 0 */ - unsigned char volatile hw_lock;/* hardware is currently locked -> no access */ - - /* boot process */ - void *boot; /* pointer to boot private data */ - int (*writebootimg) (struct HYSDN_CARD *, unsigned char *, unsigned long); - int (*writebootseq) (struct HYSDN_CARD *, unsigned char *, int); - int (*waitpofready) (struct HYSDN_CARD *); - int (*testram) (struct HYSDN_CARD *); - - /* scheduler for data transfer (only async parts) */ - unsigned char async_data[256];/* async data to be sent (normally for config) */ - unsigned short volatile async_len;/* length of data to sent */ - unsigned short volatile async_channel;/* channel number for async transfer */ - int volatile async_busy; /* flag != 0 sending in progress */ - int volatile net_tx_busy; /* a network packet tx is in progress */ - - /* network interface */ - void *netif; /* pointer to network structure */ - - /* init and deinit stopcard for booting, too */ - void (*stopcard) (struct HYSDN_CARD *); - void (*releasehardware) (struct HYSDN_CARD *); - - spinlock_t hysdn_lock; -#ifdef CONFIG_HYSDN_CAPI - struct hycapictrl_info { - char cardname[32]; - spinlock_t lock; - int versionlen; - char versionbuf[1024]; - char *version[HYSDN_MAXVERSION]; - - char infobuf[128]; /* for function procinfo */ - - struct HYSDN_CARD *card; - struct capi_ctr capi_ctrl; - struct sk_buff *skbs[HYSDN_MAX_CAPI_SKB]; - int in_idx, out_idx; /* indexes to buffer ring */ - int sk_count; /* number of buffers currently in ring */ - struct sk_buff *tx_skb; /* buffer for tx operation */ - - struct list_head ncci_head; - } *hyctrlinfo; -#endif /* CONFIG_HYSDN_CAPI */ -} hysdn_card; - -#ifdef CONFIG_HYSDN_CAPI -typedef struct hycapictrl_info hycapictrl_info; -#endif /* CONFIG_HYSDN_CAPI */ - - -/*****************/ -/* exported vars */ -/*****************/ -extern hysdn_card *card_root; /* pointer to first card */ - - - -/*************************/ -/* im/exported functions */ -/*************************/ - -/* hysdn_procconf.c */ -extern int hysdn_procconf_init(void); /* init proc config filesys */ -extern void hysdn_procconf_release(void); /* deinit proc config filesys */ - -/* hysdn_proclog.c */ -extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */ -extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */ -extern void hysdn_addlog(hysdn_card *, char *, ...); /* output data to log */ -extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */ - -/* boardergo.c */ -extern int ergo_inithardware(hysdn_card *card); /* get hardware -> module init */ - -/* hysdn_boot.c */ -extern int pof_write_close(hysdn_card *); /* close proc file after writing pof */ -extern int pof_write_open(hysdn_card *, unsigned char **); /* open proc file for writing pof */ -extern int pof_write_buffer(hysdn_card *, int); /* write boot data to card */ -extern int EvalSysrTokData(hysdn_card *, unsigned char *, int); /* Check Sysready Token Data */ - -/* hysdn_sched.c */ -extern int hysdn_sched_tx(hysdn_card *, unsigned char *, - unsigned short volatile *, unsigned short volatile *, - unsigned short); -extern int hysdn_sched_rx(hysdn_card *, unsigned char *, unsigned short, - unsigned short); -extern int hysdn_tx_cfgline(hysdn_card *, unsigned char *, - unsigned short); /* send one cfg line */ - -/* hysdn_net.c */ -extern unsigned int hynet_enable; -extern int hysdn_net_create(hysdn_card *); /* create a new net device */ -extern int hysdn_net_release(hysdn_card *); /* delete the device */ -extern char *hysdn_net_getname(hysdn_card *); /* get name of net interface */ -extern void hysdn_tx_netack(hysdn_card *); /* acknowledge a packet tx */ -extern struct sk_buff *hysdn_tx_netget(hysdn_card *); /* get next network packet */ -extern void hysdn_rx_netpkt(hysdn_card *, unsigned char *, - unsigned short); /* rxed packet from network */ - -#ifdef CONFIG_HYSDN_CAPI -extern unsigned int hycapi_enable; -extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */ -extern int hycapi_capi_release(hysdn_card *); /* delete the device */ -extern int hycapi_capi_stop(hysdn_card *card); /* suspend */ -extern void hycapi_rx_capipkt(hysdn_card *card, unsigned char *buf, - unsigned short len); -extern void hycapi_tx_capiack(hysdn_card *card); -extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card); -extern int hycapi_init(void); -extern void hycapi_cleanup(void); -#endif /* CONFIG_HYSDN_CAPI */ - -#endif /* HYSDN_DEFS_H */ diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c deleted file mode 100644 index 0db2f7506250..000000000000 --- a/drivers/isdn/hysdn/hysdn_init.c +++ /dev/null @@ -1,213 +0,0 @@ -/* $Id: hysdn_init.c,v 1.6.6.6 2001/09/23 22:24:54 kai Exp $ - * - * Linux driver for HYSDN cards, init functions. - * - * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/vmalloc.h> -#include <linux/slab.h> -#include <linux/pci.h> - -#include "hysdn_defs.h" - -static struct pci_device_id hysdn_pci_tbl[] = { - { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, - PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO }, - { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, - PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 }, - { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, - PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO }, - { PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, - PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO }, - - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl); -MODULE_DESCRIPTION("ISDN4Linux: Driver for HYSDN cards"); -MODULE_AUTHOR("Werner Cornelius"); -MODULE_LICENSE("GPL"); - -static int cardmax; /* number of found cards */ -hysdn_card *card_root = NULL; /* pointer to first card */ -static hysdn_card *card_last = NULL; /* pointer to first card */ - - -/****************************************************************************/ -/* The module startup and shutdown code. Only compiled when used as module. */ -/* Using the driver as module is always advisable, because the booting */ -/* image becomes smaller and the driver code is only loaded when needed. */ -/* Additionally newer versions may be activated without rebooting. */ -/****************************************************************************/ - -/****************************************************************************/ -/* init_module is called once when the module is loaded to do all necessary */ -/* things like autodetect... */ -/* If the return value of this function is 0 the init has been successful */ -/* and the module is added to the list in /proc/modules, otherwise an error */ -/* is assumed and the module will not be kept in memory. */ -/****************************************************************************/ - -static int hysdn_pci_init_one(struct pci_dev *akt_pcidev, - const struct pci_device_id *ent) -{ - hysdn_card *card; - int rc; - - rc = pci_enable_device(akt_pcidev); - if (rc) - return rc; - - if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) { - printk(KERN_ERR "HYSDN: unable to alloc device mem \n"); - rc = -ENOMEM; - goto err_out; - } - card->myid = cardmax; /* set own id */ - card->bus = akt_pcidev->bus->number; - card->devfn = akt_pcidev->devfn; /* slot + function */ - card->subsysid = akt_pcidev->subsystem_device; - card->irq = akt_pcidev->irq; - card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE); - card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE); - card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE); - card->brdtype = BD_NONE; /* unknown */ - card->debug_flags = DEF_DEB_FLAGS; /* set default debug */ - card->faxchans = 0; /* default no fax channels */ - card->bchans = 2; /* and 2 b-channels */ - card->brdtype = ent->driver_data; - - if (ergo_inithardware(card)) { - printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase); - rc = -EBUSY; - goto err_out_card; - } - - cardmax++; - card->next = NULL; /*end of chain */ - if (card_last) - card_last->next = card; /* pointer to next card */ - else - card_root = card; - card_last = card; /* new chain end */ - - pci_set_drvdata(akt_pcidev, card); - return 0; - -err_out_card: - kfree(card); -err_out: - pci_disable_device(akt_pcidev); - return rc; -} - -static void hysdn_pci_remove_one(struct pci_dev *akt_pcidev) -{ - hysdn_card *card = pci_get_drvdata(akt_pcidev); - - pci_set_drvdata(akt_pcidev, NULL); - - if (card->stopcard) - card->stopcard(card); - -#ifdef CONFIG_HYSDN_CAPI - hycapi_capi_release(card); -#endif - - if (card->releasehardware) - card->releasehardware(card); /* free all hardware resources */ - - if (card == card_root) { - card_root = card_root->next; - if (!card_root) - card_last = NULL; - } else { - hysdn_card *tmp = card_root; - while (tmp) { - if (tmp->next == card) - tmp->next = card->next; - card_last = tmp; - tmp = tmp->next; - } - } - - kfree(card); - pci_disable_device(akt_pcidev); -} - -static struct pci_driver hysdn_pci_driver = { - .name = "hysdn", - .id_table = hysdn_pci_tbl, - .probe = hysdn_pci_init_one, - .remove = hysdn_pci_remove_one, -}; - -static int hysdn_have_procfs; - -static int __init -hysdn_init(void) -{ - int rc; - - printk(KERN_NOTICE "HYSDN: module loaded\n"); - - rc = pci_register_driver(&hysdn_pci_driver); - if (rc) - return rc; - - printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax); - - if (!hysdn_procconf_init()) - hysdn_have_procfs = 1; - -#ifdef CONFIG_HYSDN_CAPI - if (cardmax > 0) { - if (hycapi_init()) { - printk(KERN_ERR "HYCAPI: init failed\n"); - - if (hysdn_have_procfs) - hysdn_procconf_release(); - - pci_unregister_driver(&hysdn_pci_driver); - return -ESPIPE; - } - } -#endif /* CONFIG_HYSDN_CAPI */ - - return 0; /* no error */ -} /* init_module */ - - -/***********************************************************************/ -/* cleanup_module is called when the module is released by the kernel. */ -/* The routine is only called if init_module has been successful and */ -/* the module counter has a value of 0. Otherwise this function will */ -/* not be called. This function must release all resources still allo- */ -/* cated as after the return from this function the module code will */ -/* be removed from memory. */ -/***********************************************************************/ -static void __exit -hysdn_exit(void) -{ - if (hysdn_have_procfs) - hysdn_procconf_release(); - - pci_unregister_driver(&hysdn_pci_driver); - -#ifdef CONFIG_HYSDN_CAPI - hycapi_cleanup(); -#endif /* CONFIG_HYSDN_CAPI */ - - printk(KERN_NOTICE "HYSDN: module unloaded\n"); -} /* cleanup_module */ - -module_init(hysdn_init); -module_exit(hysdn_exit); diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c deleted file mode 100644 index 8e9c34f33d86..000000000000 --- a/drivers/isdn/hysdn/hysdn_net.c +++ /dev/null @@ -1,326 +0,0 @@ -/* $Id: hysdn_net.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $ - * - * Linux driver for HYSDN cards, net (ethernet type) handling routines. - * - * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * This net module has been inspired by the skeleton driver from - * Donald Becker (becker@CESDIS.gsfc.nasa.gov) - * - */ - -#include <linux/module.h> -#include <linux/signal.h> -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/inetdevice.h> - -#include "hysdn_defs.h" - -unsigned int hynet_enable = 0xffffffff; -module_param(hynet_enable, uint, 0); - -#define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */ - -/****************************************************************************/ -/* structure containing the complete network data. The structure is aligned */ -/* in a way that both, the device and statistics are kept inside it. */ -/* for proper access, the device structure MUST be the first var/struct */ -/* inside the definition. */ -/****************************************************************************/ -struct net_local { - /* Tx control lock. This protects the transmit buffer ring - * state along with the "tx full" state of the driver. This - * means all netif_queue flow control actions are protected - * by this lock as well. - */ - struct net_device *dev; - spinlock_t lock; - struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */ - int in_idx, out_idx; /* indexes to buffer ring */ - int sk_count; /* number of buffers currently in ring */ -}; /* net_local */ - - - -/*********************************************************************/ -/* Open/initialize the board. This is called (in the current kernel) */ -/* sometime after booting when the 'ifconfig' program is run. */ -/* This routine should set everything up anew at each open, even */ -/* registers that "should" only need to be set once at boot, so that */ -/* there is non-reboot way to recover if something goes wrong. */ -/*********************************************************************/ -static int -net_open(struct net_device *dev) -{ - struct in_device *in_dev; - hysdn_card *card = dev->ml_priv; - int i; - - netif_start_queue(dev); /* start tx-queueing */ - - /* Fill in the MAC-level header (if not already set) */ - if (!card->mac_addr[0]) { - for (i = 0; i < ETH_ALEN; i++) - dev->dev_addr[i] = 0xfc; - if ((in_dev = dev->ip_ptr) != NULL) { - struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa != NULL) - memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ifa->ifa_local)), &ifa->ifa_local, sizeof(ifa->ifa_local)); - } - } else - memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN); - - return (0); -} /* net_open */ - -/*******************************************/ -/* flush the currently occupied tx-buffers */ -/* must only be called when device closed */ -/*******************************************/ -static void -flush_tx_buffers(struct net_local *nl) -{ - - while (nl->sk_count) { - dev_kfree_skb(nl->skbs[nl->out_idx++]); /* free skb */ - if (nl->out_idx >= MAX_SKB_BUFFERS) - nl->out_idx = 0; /* wrap around */ - nl->sk_count--; - } -} /* flush_tx_buffers */ - - -/*********************************************************************/ -/* close/decativate the device. The device is not removed, but only */ -/* deactivated. */ -/*********************************************************************/ -static int -net_close(struct net_device *dev) -{ - - netif_stop_queue(dev); /* disable queueing */ - - flush_tx_buffers((struct net_local *) dev); - - return (0); /* success */ -} /* net_close */ - -/************************************/ -/* send a packet on this interface. */ -/* new style for kernel >= 2.3.33 */ -/************************************/ -static netdev_tx_t -net_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct net_local *lp = (struct net_local *) dev; - - spin_lock_irq(&lp->lock); - - lp->skbs[lp->in_idx++] = skb; /* add to buffer list */ - if (lp->in_idx >= MAX_SKB_BUFFERS) - lp->in_idx = 0; /* wrap around */ - lp->sk_count++; /* adjust counter */ - netif_trans_update(dev); - - /* If we just used up the very last entry in the - * TX ring on this device, tell the queueing - * layer to send no more. - */ - if (lp->sk_count >= MAX_SKB_BUFFERS) - netif_stop_queue(dev); - - /* When the TX completion hw interrupt arrives, this - * is when the transmit statistics are updated. - */ - - spin_unlock_irq(&lp->lock); - - if (lp->sk_count <= 3) { - schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue); - } - return NETDEV_TX_OK; /* success */ -} /* net_send_packet */ - - - -/***********************************************************************/ -/* acknowlegde a packet send. The network layer will be informed about */ -/* completion */ -/***********************************************************************/ -void -hysdn_tx_netack(hysdn_card *card) -{ - struct net_local *lp = card->netif; - - if (!lp) - return; /* non existing device */ - - - if (!lp->sk_count) - return; /* error condition */ - - lp->dev->stats.tx_packets++; - lp->dev->stats.tx_bytes += lp->skbs[lp->out_idx]->len; - - dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */ - if (lp->out_idx >= MAX_SKB_BUFFERS) - lp->out_idx = 0; /* wrap around */ - - if (lp->sk_count-- == MAX_SKB_BUFFERS) /* dec usage count */ - netif_start_queue((struct net_device *) lp); -} /* hysdn_tx_netack */ - -/*****************************************************/ -/* we got a packet from the network, go and queue it */ -/*****************************************************/ -void -hysdn_rx_netpkt(hysdn_card *card, unsigned char *buf, unsigned short len) -{ - struct net_local *lp = card->netif; - struct net_device *dev; - struct sk_buff *skb; - - if (!lp) - return; /* non existing device */ - - dev = lp->dev; - dev->stats.rx_bytes += len; - - skb = dev_alloc_skb(len); - if (skb == NULL) { - printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", - dev->name); - dev->stats.rx_dropped++; - return; - } - /* copy the data */ - skb_put_data(skb, buf, len); - - /* determine the used protocol */ - skb->protocol = eth_type_trans(skb, dev); - - dev->stats.rx_packets++; /* adjust packet count */ - - netif_rx(skb); -} /* hysdn_rx_netpkt */ - -/*****************************************************/ -/* return the pointer to a network packet to be send */ -/*****************************************************/ -struct sk_buff * -hysdn_tx_netget(hysdn_card *card) -{ - struct net_local *lp = card->netif; - - if (!lp) - return (NULL); /* non existing device */ - - if (!lp->sk_count) - return (NULL); /* nothing available */ - - return (lp->skbs[lp->out_idx]); /* next packet to send */ -} /* hysdn_tx_netget */ - -static const struct net_device_ops hysdn_netdev_ops = { - .ndo_open = net_open, - .ndo_stop = net_close, - .ndo_start_xmit = net_send_packet, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, -}; - - -/*****************************************************************************/ -/* hysdn_net_create creates a new net device for the given card. If a device */ -/* already exists, it will be deleted and created a new one. The return value */ -/* 0 announces success, else a negative error code will be returned. */ -/*****************************************************************************/ -int -hysdn_net_create(hysdn_card *card) -{ - struct net_device *dev; - int i; - struct net_local *lp; - - if (!card) { - printk(KERN_WARNING "No card-pt in hysdn_net_create!\n"); - return (-ENOMEM); - } - hysdn_net_release(card); /* release an existing net device */ - - dev = alloc_etherdev(sizeof(struct net_local)); - if (!dev) { - printk(KERN_WARNING "HYSDN: unable to allocate mem\n"); - return (-ENOMEM); - } - - lp = netdev_priv(dev); - lp->dev = dev; - - dev->netdev_ops = &hysdn_netdev_ops; - spin_lock_init(&((struct net_local *) dev)->lock); - - /* initialise necessary or informing fields */ - dev->base_addr = card->iobase; /* IO address */ - dev->irq = card->irq; /* irq */ - - dev->netdev_ops = &hysdn_netdev_ops; - if ((i = register_netdev(dev))) { - printk(KERN_WARNING "HYSDN: unable to create network device\n"); - free_netdev(dev); - return (i); - } - dev->ml_priv = card; /* remember pointer to own data structure */ - card->netif = dev; /* setup the local pointer */ - - if (card->debug_flags & LOG_NET_INIT) - hysdn_addlog(card, "network device created"); - return (0); /* and return success */ -} /* hysdn_net_create */ - -/***************************************************************************/ -/* hysdn_net_release deletes the net device for the given card. The return */ -/* value 0 announces success, else a negative error code will be returned. */ -/***************************************************************************/ -int -hysdn_net_release(hysdn_card *card) -{ - struct net_device *dev = card->netif; - - if (!dev) - return (0); /* non existing */ - - card->netif = NULL; /* clear out pointer */ - net_close(dev); - - flush_tx_buffers((struct net_local *) dev); /* empty buffers */ - - unregister_netdev(dev); /* release the device */ - free_netdev(dev); /* release the memory allocated */ - if (card->debug_flags & LOG_NET_INIT) - hysdn_addlog(card, "network device deleted"); - - return (0); /* always successful */ -} /* hysdn_net_release */ - -/*****************************************************************************/ -/* hysdn_net_getname returns a pointer to the name of the network interface. */ -/* if the interface is not existing, a "-" is returned. */ -/*****************************************************************************/ -char * -hysdn_net_getname(hysdn_card *card) -{ - struct net_device *dev = card->netif; - - if (!dev) - return ("-"); /* non existing */ - - return (dev->name); -} /* hysdn_net_getname */ diff --git a/drivers/isdn/hysdn/hysdn_pof.h b/drivers/isdn/hysdn/hysdn_pof.h deleted file mode 100644 index f63f5fa59d7e..000000000000 --- a/drivers/isdn/hysdn/hysdn_pof.h +++ /dev/null @@ -1,78 +0,0 @@ -/* $Id: hysdn_pof.h,v 1.2.6.1 2001/09/23 22:24:54 kai Exp $ - * - * Linux driver for HYSDN cards, definitions used for handling pof-files. - * - * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/************************/ -/* POF specific defines */ -/************************/ -#define BOOT_BUF_SIZE 0x1000 /* =4096, maybe moved to other h file */ -#define CRYPT_FEEDTERM 0x8142 -#define CRYPT_STARTTERM 0x81a5 -/* max. timeout time in seconds - * from end of booting to POF is ready - */ -#define POF_READY_TIME_OUT_SEC 10 - -/**********************************/ -/* defines for 1.stage boot image */ -/**********************************/ - -/* the POF file record containing the boot loader image - * has 2 pages a 16KB: - * 1. page contains the high 16-bit part of the 32-bit E1 words - * 2. page contains the low 16-bit part of the 32-bit E1 words - * - * In each 16KB page we assume the start of the boot loader code - * in the highest 2KB part (at offset 0x3800); - * the rest (0x0000..0x37FF) is assumed to contain 0 bytes. - */ - -#define POF_BOOT_LOADER_PAGE_SIZE 0x4000 /* =16384U */ -#define POF_BOOT_LOADER_TOTAL_SIZE (2U * POF_BOOT_LOADER_PAGE_SIZE) - -#define POF_BOOT_LOADER_CODE_SIZE 0x0800 /* =2KB =2048U */ - -/* offset in boot page, where loader code may start */ -/* =0x3800= 14336U */ -#define POF_BOOT_LOADER_OFF_IN_PAGE (POF_BOOT_LOADER_PAGE_SIZE-POF_BOOT_LOADER_CODE_SIZE) - - -/*--------------------------------------POF file record structs------------*/ -typedef struct PofFileHdr_tag { /* Pof file header */ - /*00 */ unsigned long Magic __attribute__((packed)); - /*04 */ unsigned long N_PofRecs __attribute__((packed)); -/*08 */ -} tPofFileHdr; - -typedef struct PofRecHdr_tag { /* Pof record header */ - /*00 */ unsigned short PofRecId __attribute__((packed)); - /*02 */ unsigned long PofRecDataLen __attribute__((packed)); -/*06 */ -} tPofRecHdr; - -typedef struct PofTimeStamp_tag { - /*00 */ unsigned long UnixTime __attribute__((packed)); - /*04 */ unsigned char DateTimeText[0x28]; - /* =40 */ -/*2C */ -} tPofTimeStamp; - -/* tPofFileHdr.Magic value: */ -#define TAGFILEMAGIC 0x464F501AUL -/* tPofRecHdr.PofRecId values: */ -#define TAG_ABSDATA 0x1000 /* abs. data */ -#define TAG_BOOTDTA 0x1001 /* boot data */ -#define TAG_COMMENT 0x0020 -#define TAG_SYSCALL 0x0021 -#define TAG_FLOWCTRL 0x0022 -#define TAG_TIMESTMP 0x0010 /* date/time stamp of version */ -#define TAG_CABSDATA 0x1100 /* crypted abs. data */ -#define TAG_CBOOTDTA 0x1101 /* crypted boot data */ diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c deleted file mode 100644 index 73079213ec94..000000000000 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ /dev/null @@ -1,411 +0,0 @@ -/* $Id: hysdn_procconf.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $ - * - * Linux driver for HYSDN cards, /proc/net filesystem dir and conf functions. - * - * written by Werner Cornelius (werner@titro.de) for Hypercope GmbH - * - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/cred.h> -#include <linux/module.h> -#include <linux/poll.h> -#include <linux/proc_fs.h> -#include <linux/pci.h> -#include <linux/slab.h> -#include <linux/mutex.h> -#include <net/net_namespace.h> - -#include "hysdn_defs.h" - -static DEFINE_MUTEX(hysdn_conf_mutex); - -#define INFO_OUT_LEN 80 /* length of info line including lf */ - -/********************************************************/ -/* defines and data structure for conf write operations */ -/********************************************************/ -#define CONF_STATE_DETECT 0 /* waiting for detect */ -#define CONF_STATE_CONF 1 /* writing config data */ -#define CONF_STATE_POF 2 /* writing pof data */ -#define CONF_LINE_LEN 255 /* 255 chars max */ - -struct conf_writedata { - hysdn_card *card; /* card the device is connected to */ - int buf_size; /* actual number of bytes in the buffer */ - int needed_size; /* needed size when reading pof */ - int state; /* actual interface states from above constants */ - unsigned char conf_line[CONF_LINE_LEN]; /* buffered conf line */ - unsigned short channel; /* active channel number */ - unsigned char *pof_buffer; /* buffer when writing pof */ -}; - -/***********************************************************************/ -/* process_line parses one config line and transfers it to the card if */ -/* necessary. */ -/* if the return value is negative an error occurred. */ -/***********************************************************************/ -static int -process_line(struct conf_writedata *cnf) -{ - unsigned char *cp = cnf->conf_line; - int i; - - if (cnf->card->debug_flags & LOG_CNF_LINE) - hysdn_addlog(cnf->card, "conf line: %s", cp); - - if (*cp == '-') { /* option */ - cp++; /* point to option char */ - - if (*cp++ != 'c') - return (0); /* option unknown or used */ - i = 0; /* start value for channel */ - while ((*cp <= '9') && (*cp >= '0')) - i = i * 10 + *cp++ - '0'; /* get decimal number */ - if (i > 65535) { - if (cnf->card->debug_flags & LOG_CNF_MISC) - hysdn_addlog(cnf->card, "conf channel invalid %d", i); - return (-ERR_INV_CHAN); /* invalid channel */ - } - cnf->channel = i & 0xFFFF; /* set new channel number */ - return (0); /* success */ - } /* option */ - if (*cp == '*') { /* line to send */ - if (cnf->card->debug_flags & LOG_CNF_DATA) - hysdn_addlog(cnf->card, "conf chan=%d %s", cnf->channel, cp); - return (hysdn_tx_cfgline(cnf->card, cnf->conf_line + 1, - cnf->channel)); /* send the line without * */ - } /* line to send */ - return (0); -} /* process_line */ - -/***********************************/ -/* conf file operations and tables */ -/***********************************/ - -/****************************************************/ -/* write conf file -> boot or send cfg line to card */ -/****************************************************/ -static ssize_t -hysdn_conf_write(struct file *file, const char __user *buf, size_t count, loff_t *off) -{ - struct conf_writedata *cnf; - int i; - unsigned char ch, *cp; - - if (!count) - return (0); /* nothing to handle */ - - if (!(cnf = file->private_data)) - return (-EFAULT); /* should never happen */ - - if (cnf->state == CONF_STATE_DETECT) { /* auto detect cnf or pof data */ - if (copy_from_user(&ch, buf, 1)) /* get first char for detect */ - return (-EFAULT); - - if (ch == 0x1A) { - /* we detected a pof file */ - if ((cnf->needed_size = pof_write_open(cnf->card, &cnf->pof_buffer)) <= 0) - return (cnf->needed_size); /* an error occurred -> exit */ - cnf->buf_size = 0; /* buffer is empty */ - cnf->state = CONF_STATE_POF; /* new state */ - } else { - /* conf data has been detected */ - cnf->buf_size = 0; /* buffer is empty */ - cnf->state = CONF_STATE_CONF; /* requested conf data write */ - if (cnf->card->state != CARD_STATE_RUN) - return (-ERR_NOT_BOOTED); - cnf->conf_line[CONF_LINE_LEN - 1] = 0; /* limit string length */ - cnf->channel = 4098; /* default channel for output */ - } - } /* state was auto detect */ - if (cnf->state == CONF_STATE_POF) { /* pof write active */ - i = cnf->needed_size - cnf->buf_size; /* bytes still missing for write */ - if (i <= 0) - return (-EINVAL); /* size error handling pof */ - - if (i < count) - count = i; /* limit requested number of bytes */ - if (copy_from_user(cnf->pof_buffer + cnf->buf_size, buf, count)) - return (-EFAULT); /* error while copying */ - cnf->buf_size += count; - - if (cnf->needed_size == cnf->buf_size) { - cnf->needed_size = pof_write_buffer(cnf->card, cnf->buf_size); /* write data */ - if (cnf->needed_size <= 0) { - cnf->card->state = CARD_STATE_BOOTERR; /* show boot error */ - return (cnf->needed_size); /* an error occurred */ - } - cnf->buf_size = 0; /* buffer is empty again */ - } - } - /* pof write active */ - else { /* conf write active */ - - if (cnf->card->state != CARD_STATE_RUN) { - if (cnf->card->debug_flags & LOG_CNF_MISC) - hysdn_addlog(cnf->card, "cnf write denied -> not booted"); - return (-ERR_NOT_BOOTED); - } - i = (CONF_LINE_LEN - 1) - cnf->buf_size; /* bytes available in buffer */ - if (i > 0) { - /* copy remaining bytes into buffer */ - - if (count > i) - count = i; /* limit transfer */ - if (copy_from_user(cnf->conf_line + cnf->buf_size, buf, count)) - return (-EFAULT); /* error while copying */ - - i = count; /* number of chars in buffer */ - cp = cnf->conf_line + cnf->buf_size; - while (i) { - /* search for end of line */ - if ((*cp < ' ') && (*cp != 9)) - break; /* end of line found */ - cp++; - i--; - } /* search for end of line */ - - if (i) { - /* delimiter found */ - *cp++ = 0; /* string termination */ - count -= (i - 1); /* subtract remaining bytes from count */ - while ((i) && (*cp < ' ') && (*cp != 9)) { - i--; /* discard next char */ - count++; /* mark as read */ - cp++; /* next char */ - } - cnf->buf_size = 0; /* buffer is empty after transfer */ - if ((i = process_line(cnf)) < 0) /* handle the line */ - count = i; /* return the error */ - } - /* delimiter found */ - else { - cnf->buf_size += count; /* add chars to string */ - if (cnf->buf_size >= CONF_LINE_LEN - 1) { - if (cnf->card->debug_flags & LOG_CNF_MISC) - hysdn_addlog(cnf->card, "cnf line too long %d chars pos %d", cnf->buf_size, count); - return (-ERR_CONF_LONG); - } - } /* not delimited */ - - } - /* copy remaining bytes into buffer */ - else { - if (cnf->card->debug_flags & LOG_CNF_MISC) - hysdn_addlog(cnf->card, "cnf line too long"); - return (-ERR_CONF_LONG); - } - } /* conf write active */ - - return (count); -} /* hysdn_conf_write */ - -/*******************************************/ -/* read conf file -> output card info data */ -/*******************************************/ -static ssize_t -hysdn_conf_read(struct file *file, char __user *buf, size_t count, loff_t *off) -{ - char *cp; - - if (!(file->f_mode & FMODE_READ)) - return -EPERM; /* no permission to read */ - - if (!(cp = file->private_data)) - return -EFAULT; /* should never happen */ - - return simple_read_from_buffer(buf, count, off, cp, strlen(cp)); -} /* hysdn_conf_read */ - -/******************/ -/* open conf file */ -/******************/ -static int -hysdn_conf_open(struct inode *ino, struct file *filep) -{ - hysdn_card *card; - struct conf_writedata *cnf; - char *cp, *tmp; - - /* now search the addressed card */ - mutex_lock(&hysdn_conf_mutex); - card = PDE_DATA(ino); - if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) - hysdn_addlog(card, "config open for uid=%d gid=%d mode=0x%x", - filep->f_cred->fsuid, filep->f_cred->fsgid, - filep->f_mode); - - if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { - /* write only access -> write boot file or conf line */ - - if (!(cnf = kmalloc(sizeof(struct conf_writedata), GFP_KERNEL))) { - mutex_unlock(&hysdn_conf_mutex); - return (-EFAULT); - } - cnf->card = card; - cnf->buf_size = 0; /* nothing buffered */ - cnf->state = CONF_STATE_DETECT; /* start auto detect */ - filep->private_data = cnf; - - } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { - /* read access -> output card info data */ - - if (!(tmp = kmalloc(INFO_OUT_LEN * 2 + 2, GFP_KERNEL))) { - mutex_unlock(&hysdn_conf_mutex); - return (-EFAULT); /* out of memory */ - } - filep->private_data = tmp; /* start of string */ - - /* first output a headline */ - sprintf(tmp, "id bus slot type irq iobase dp-mem b-chans fax-chans state device"); - cp = tmp; /* start of string */ - while (*cp) - cp++; - while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) - *cp++ = ' '; - *cp++ = '\n'; - - /* and now the data */ - sprintf(cp, "%d %3d %4d %4d %3d 0x%04x 0x%08lx %7d %9d %3d %s", - card->myid, - card->bus, - PCI_SLOT(card->devfn), - card->brdtype, - card->irq, - card->iobase, - card->membase, - card->bchans, - card->faxchans, - card->state, - hysdn_net_getname(card)); - while (*cp) - cp++; - while (((cp - tmp) % (INFO_OUT_LEN + 1)) != INFO_OUT_LEN) - *cp++ = ' '; - *cp++ = '\n'; - *cp = 0; /* end of string */ - } else { /* simultaneous read/write access forbidden ! */ - mutex_unlock(&hysdn_conf_mutex); - return (-EPERM); /* no permission this time */ - } - mutex_unlock(&hysdn_conf_mutex); - return nonseekable_open(ino, filep); -} /* hysdn_conf_open */ - -/***************************/ -/* close a config file. */ -/***************************/ -static int -hysdn_conf_close(struct inode *ino, struct file *filep) -{ - hysdn_card *card; - struct conf_writedata *cnf; - int retval = 0; - - mutex_lock(&hysdn_conf_mutex); - card = PDE_DATA(ino); - if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) - hysdn_addlog(card, "config close for uid=%d gid=%d mode=0x%x", - filep->f_cred->fsuid, filep->f_cred->fsgid, - filep->f_mode); - - if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { - /* write only access -> write boot file or conf line */ - if (filep->private_data) { - cnf = filep->private_data; - - if (cnf->state == CONF_STATE_POF) - retval = pof_write_close(cnf->card); /* close the pof write */ - kfree(filep->private_data); /* free allocated memory for buffer */ - - } /* handle write private data */ - } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { - /* read access -> output card info data */ - - kfree(filep->private_data); /* release memory */ - } - mutex_unlock(&hysdn_conf_mutex); - return (retval); -} /* hysdn_conf_close */ - -/******************************************************/ -/* table for conf filesystem functions defined above. */ -/******************************************************/ -static const struct file_operations conf_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = hysdn_conf_read, - .write = hysdn_conf_write, - .open = hysdn_conf_open, - .release = hysdn_conf_close, -}; - -/*****************************/ -/* hysdn subdir in /proc/net */ -/*****************************/ -struct proc_dir_entry *hysdn_proc_entry = NULL; - -/*******************************************************************************/ -/* hysdn_procconf_init is called when the module is loaded and after the cards */ -/* have been detected. The needed proc dir and card config files are created. */ -/* The log init is called at last. */ -/*******************************************************************************/ -int -hysdn_procconf_init(void) -{ - hysdn_card *card; - unsigned char conf_name[20]; - - hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, init_net.proc_net); - if (!hysdn_proc_entry) { - printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n"); - return (-1); - } - card = card_root; /* point to first card */ - while (card) { - - sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); - if ((card->procconf = (void *) proc_create_data(conf_name, - S_IFREG | S_IRUGO | S_IWUSR, - hysdn_proc_entry, - &conf_fops, - card)) != NULL) { - hysdn_proclog_init(card); /* init the log file entry */ - } - card = card->next; /* next entry */ - } - - printk(KERN_NOTICE "HYSDN: procfs initialised\n"); - return (0); -} /* hysdn_procconf_init */ - -/*************************************************************************************/ -/* hysdn_procconf_release is called when the module is unloaded and before the cards */ -/* resources are released. The module counter is assumed to be 0 ! */ -/*************************************************************************************/ -void -hysdn_procconf_release(void) -{ - hysdn_card *card; - unsigned char conf_name[20]; - - card = card_root; /* start with first card */ - while (card) { - - sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); - if (card->procconf) - remove_proc_entry(conf_name, hysdn_proc_entry); - - hysdn_proclog_release(card); /* init the log file entry */ - - card = card->next; /* point to next card */ - } - - remove_proc_entry(PROC_SUBDIR_NAME, init_net.proc_net); -} diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c deleted file mode 100644 index 6e898b90e86e..000000000000 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ /dev/null @@ -1,357 +0,0 @@ -/* $Id: hysdn_proclog.c,v 1.9.6.3 2001/09/23 22:24:54 kai Exp $ - * - * Linux driver for HYSDN cards, /proc/net filesystem log functions. - * - * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/poll.h> -#include <linux/proc_fs.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/mutex.h> -#include <linux/kernel.h> - -#include "hysdn_defs.h" - -/* the proc subdir for the interface is defined in the procconf module */ -extern struct proc_dir_entry *hysdn_proc_entry; - -static DEFINE_MUTEX(hysdn_log_mutex); -static void put_log_buffer(hysdn_card *card, char *cp); - -/*************************************************/ -/* structure keeping ascii log for device output */ -/*************************************************/ -struct log_data { - struct log_data *next; - unsigned long usage_cnt;/* number of files still to work */ - void *proc_ctrl; /* pointer to own control procdata structure */ - char log_start[2]; /* log string start (final len aligned by size) */ -}; - -/**********************************************/ -/* structure holding proc entrys for one card */ -/**********************************************/ -struct procdata { - struct proc_dir_entry *log; /* log entry */ - char log_name[15]; /* log filename */ - struct log_data *log_head, *log_tail; /* head and tail for queue */ - int if_used; /* open count for interface */ - unsigned char logtmp[LOG_MAX_LINELEN]; - wait_queue_head_t rd_queue; -}; - - -/**********************************************/ -/* log function for cards error log interface */ -/**********************************************/ -void -hysdn_card_errlog(hysdn_card *card, tErrLogEntry *logp, int maxsize) -{ - char buf[ERRLOG_TEXT_SIZE + 40]; - - sprintf(buf, "LOG 0x%08lX 0x%08lX : %s\n", logp->ulErrType, logp->ulErrSubtype, logp->ucText); - put_log_buffer(card, buf); /* output the string */ -} /* hysdn_card_errlog */ - -/***************************************************/ -/* Log function using format specifiers for output */ -/***************************************************/ -void -hysdn_addlog(hysdn_card *card, char *fmt, ...) -{ - struct procdata *pd = card->proclog; - char *cp; - va_list args; - - if (!pd) - return; /* log structure non existent */ - - cp = pd->logtmp; - cp += sprintf(cp, "HYSDN: card %d ", card->myid); - - va_start(args, fmt); - cp += vsprintf(cp, fmt, args); - va_end(args); - *cp++ = '\n'; - *cp = 0; - - if (card->debug_flags & DEB_OUT_SYSLOG) - printk(KERN_INFO "%s", pd->logtmp); - else - put_log_buffer(card, pd->logtmp); - -} /* hysdn_addlog */ - -/********************************************/ -/* put an log buffer into the log queue. */ -/* This buffer will be kept until all files */ -/* opened for read got the contents. */ -/* Flushes buffers not longer in use. */ -/********************************************/ -static void -put_log_buffer(hysdn_card *card, char *cp) -{ - struct log_data *ib; - struct procdata *pd = card->proclog; - unsigned long flags; - - if (!pd) - return; - if (!cp) - return; - if (!*cp) - return; - if (pd->if_used <= 0) - return; /* no open file for read */ - - if (!(ib = kmalloc(sizeof(struct log_data) + strlen(cp), GFP_ATOMIC))) - return; /* no memory */ - strcpy(ib->log_start, cp); /* set output string */ - ib->next = NULL; - ib->proc_ctrl = pd; /* point to own control structure */ - spin_lock_irqsave(&card->hysdn_lock, flags); - ib->usage_cnt = pd->if_used; - if (!pd->log_head) - pd->log_head = ib; /* new head */ - else - pd->log_tail->next = ib; /* follows existing messages */ - pd->log_tail = ib; /* new tail */ - - /* delete old entrys */ - while (pd->log_head->next) { - if ((pd->log_head->usage_cnt <= 0) && - (pd->log_head->next->usage_cnt <= 0)) { - ib = pd->log_head; - pd->log_head = pd->log_head->next; - kfree(ib); - } else { - break; - } - } /* pd->log_head->next */ - - spin_unlock_irqrestore(&card->hysdn_lock, flags); - - wake_up_interruptible(&(pd->rd_queue)); /* announce new entry */ -} /* put_log_buffer */ - - -/******************************/ -/* file operations and tables */ -/******************************/ - -/****************************************/ -/* write log file -> set log level bits */ -/****************************************/ -static ssize_t -hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t *off) -{ - int rc; - hysdn_card *card = file->private_data; - - rc = kstrtoul_from_user(buf, count, 0, &card->debug_flags); - if (rc < 0) - return rc; - hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags); - return (count); -} /* hysdn_log_write */ - -/******************/ -/* read log file */ -/******************/ -static ssize_t -hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t *off) -{ - struct log_data *inf; - int len; - hysdn_card *card = PDE_DATA(file_inode(file)); - - if (!(inf = *((struct log_data **) file->private_data))) { - struct procdata *pd = card->proclog; - if (file->f_flags & O_NONBLOCK) - return (-EAGAIN); - - wait_event_interruptible(pd->rd_queue, (inf = - *((struct log_data **) file->private_data))); - } - if (!inf) - return (0); - - inf->usage_cnt--; /* new usage count */ - file->private_data = &inf->next; /* next structure */ - if ((len = strlen(inf->log_start)) <= count) { - if (copy_to_user(buf, inf->log_start, len)) - return -EFAULT; - *off += len; - return (len); - } - return (0); -} /* hysdn_log_read */ - -/******************/ -/* open log file */ -/******************/ -static int -hysdn_log_open(struct inode *ino, struct file *filep) -{ - hysdn_card *card = PDE_DATA(ino); - - mutex_lock(&hysdn_log_mutex); - if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { - /* write only access -> write log level only */ - filep->private_data = card; /* remember our own card */ - } else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) { - struct procdata *pd = card->proclog; - unsigned long flags; - - /* read access -> log/debug read */ - spin_lock_irqsave(&card->hysdn_lock, flags); - pd->if_used++; - if (pd->log_head) - filep->private_data = &pd->log_tail->next; - else - filep->private_data = &pd->log_head; - spin_unlock_irqrestore(&card->hysdn_lock, flags); - } else { /* simultaneous read/write access forbidden ! */ - mutex_unlock(&hysdn_log_mutex); - return (-EPERM); /* no permission this time */ - } - mutex_unlock(&hysdn_log_mutex); - return nonseekable_open(ino, filep); -} /* hysdn_log_open */ - -/*******************************************************************************/ -/* close a cardlog file. If the file has been opened for exclusive write it is */ -/* assumed as pof data input and the pof loader is noticed about. */ -/* Otherwise file is handled as log output. In this case the interface usage */ -/* count is decremented and all buffers are noticed of closing. If this file */ -/* was the last one to be closed, all buffers are freed. */ -/*******************************************************************************/ -static int -hysdn_log_close(struct inode *ino, struct file *filep) -{ - struct log_data *inf; - struct procdata *pd; - hysdn_card *card; - int retval = 0; - - mutex_lock(&hysdn_log_mutex); - if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { - /* write only access -> write debug level written */ - retval = 0; /* success */ - } else { - /* read access -> log/debug read, mark one further file as closed */ - - inf = *((struct log_data **) filep->private_data); /* get first log entry */ - if (inf) - pd = (struct procdata *) inf->proc_ctrl; /* still entries there */ - else { - /* no info available -> search card */ - card = PDE_DATA(file_inode(filep)); - pd = card->proclog; /* pointer to procfs log */ - } - if (pd) - pd->if_used--; /* decrement interface usage count by one */ - - while (inf) { - inf->usage_cnt--; /* decrement usage count for buffers */ - inf = inf->next; - } - - if (pd) - if (pd->if_used <= 0) /* delete buffers if last file closed */ - while (pd->log_head) { - inf = pd->log_head; - pd->log_head = pd->log_head->next; - kfree(inf); - } - } /* read access */ - mutex_unlock(&hysdn_log_mutex); - - return (retval); -} /* hysdn_log_close */ - -/*************************************************/ -/* select/poll routine to be able using select() */ -/*************************************************/ -static __poll_t -hysdn_log_poll(struct file *file, poll_table *wait) -{ - __poll_t mask = 0; - hysdn_card *card = PDE_DATA(file_inode(file)); - struct procdata *pd = card->proclog; - - if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) - return (mask); /* no polling for write supported */ - - poll_wait(file, &(pd->rd_queue), wait); - - if (*((struct log_data **) file->private_data)) - mask |= EPOLLIN | EPOLLRDNORM; - - return mask; -} /* hysdn_log_poll */ - -/**************************************************/ -/* table for log filesystem functions defined above. */ -/**************************************************/ -static const struct file_operations log_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = hysdn_log_read, - .write = hysdn_log_write, - .poll = hysdn_log_poll, - .open = hysdn_log_open, - .release = hysdn_log_close, -}; - - -/***********************************************************************************/ -/* hysdn_proclog_init is called when the module is loaded after creating the cards */ -/* conf files. */ -/***********************************************************************************/ -int -hysdn_proclog_init(hysdn_card *card) -{ - struct procdata *pd; - - /* create a cardlog proc entry */ - - if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { - sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); - pd->log = proc_create_data(pd->log_name, - S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry, - &log_fops, card); - - init_waitqueue_head(&(pd->rd_queue)); - - card->proclog = (void *) pd; /* remember procfs structure */ - } - return (0); -} /* hysdn_proclog_init */ - -/************************************************************************************/ -/* hysdn_proclog_release is called when the module is unloaded and before the cards */ -/* conf file is released */ -/* The module counter is assumed to be 0 ! */ -/************************************************************************************/ -void -hysdn_proclog_release(hysdn_card *card) -{ - struct procdata *pd; - - if ((pd = (struct procdata *) card->proclog) != NULL) { - if (pd->log) - remove_proc_entry(pd->log_name, hysdn_proc_entry); - kfree(pd); /* release memory */ - card->proclog = NULL; - } -} /* hysdn_proclog_release */ diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c deleted file mode 100644 index 31d7c1415543..000000000000 --- a/drivers/isdn/hysdn/hysdn_sched.c +++ /dev/null @@ -1,197 +0,0 @@ -/* $Id: hysdn_sched.c,v 1.5.6.4 2001/11/06 21:58:19 kai Exp $ - * - * Linux driver for HYSDN cards - * scheduler routines for handling exchange card <-> pc. - * - * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH - * Copyright 1999 by Werner Cornelius (werner@titro.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/signal.h> -#include <linux/kernel.h> -#include <linux/ioport.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <asm/io.h> - -#include "hysdn_defs.h" - -/*****************************************************************************/ -/* hysdn_sched_rx is called from the cards handler to announce new data is */ -/* available from the card. The routine has to handle the data and return */ -/* with a nonzero code if the data could be worked (or even thrown away), if */ -/* no room to buffer the data is available a zero return tells the card */ -/* to keep the data until later. */ -/*****************************************************************************/ -int -hysdn_sched_rx(hysdn_card *card, unsigned char *buf, unsigned short len, - unsigned short chan) -{ - - switch (chan) { - case CHAN_NDIS_DATA: - if (hynet_enable & (1 << card->myid)) { - /* give packet to network handler */ - hysdn_rx_netpkt(card, buf, len); - } - break; - - case CHAN_ERRLOG: - hysdn_card_errlog(card, (tErrLogEntry *) buf, len); - if (card->err_log_state == ERRLOG_STATE_ON) - card->err_log_state = ERRLOG_STATE_START; /* start new fetch */ - break; -#ifdef CONFIG_HYSDN_CAPI - case CHAN_CAPI: -/* give packet to CAPI handler */ - if (hycapi_enable & (1 << card->myid)) { - hycapi_rx_capipkt(card, buf, len); - } - break; -#endif /* CONFIG_HYSDN_CAPI */ - default: - printk(KERN_INFO "irq message channel %d len %d unhandled \n", chan, len); - break; - - } /* switch rx channel */ - - return (1); /* always handled */ -} /* hysdn_sched_rx */ - -/*****************************************************************************/ -/* hysdn_sched_tx is called from the cards handler to announce that there is */ -/* room in the tx-buffer to the card and data may be sent if needed. */ -/* If the routine wants to send data it must fill buf, len and chan with the */ -/* appropriate data and return a nonzero value. With a zero return no new */ -/* data to send is assumed. maxlen specifies the buffer size available for */ -/* sending. */ -/*****************************************************************************/ -int -hysdn_sched_tx(hysdn_card *card, unsigned char *buf, - unsigned short volatile *len, unsigned short volatile *chan, - unsigned short maxlen) -{ - struct sk_buff *skb; - - if (card->net_tx_busy) { - card->net_tx_busy = 0; /* reset flag */ - hysdn_tx_netack(card); /* acknowledge packet send */ - } /* a network packet has completely been transferred */ - /* first of all async requests are handled */ - if (card->async_busy) { - if (card->async_len <= maxlen) { - memcpy(buf, card->async_data, card->async_len); - *len = card->async_len; - *chan = card->async_channel; - card->async_busy = 0; /* reset request */ - return (1); - } - card->async_busy = 0; /* in case of length error */ - } /* async request */ - if ((card->err_log_state == ERRLOG_STATE_START) && - (maxlen >= ERRLOG_CMD_REQ_SIZE)) { - strcpy(buf, ERRLOG_CMD_REQ); /* copy the command */ - *len = ERRLOG_CMD_REQ_SIZE; /* buffer length */ - *chan = CHAN_ERRLOG; /* and channel */ - card->err_log_state = ERRLOG_STATE_ON; /* new state is on */ - return (1); /* tell that data should be send */ - } /* error log start and able to send */ - if ((card->err_log_state == ERRLOG_STATE_STOP) && - (maxlen >= ERRLOG_CMD_STOP_SIZE)) { - strcpy(buf, ERRLOG_CMD_STOP); /* copy the command */ - *len = ERRLOG_CMD_STOP_SIZE; /* buffer length */ - *chan = CHAN_ERRLOG; /* and channel */ - card->err_log_state = ERRLOG_STATE_OFF; /* new state is off */ - return (1); /* tell that data should be send */ - } /* error log start and able to send */ - /* now handle network interface packets */ - if ((hynet_enable & (1 << card->myid)) && - (skb = hysdn_tx_netget(card)) != NULL) - { - if (skb->len <= maxlen) { - /* copy the packet to the buffer */ - skb_copy_from_linear_data(skb, buf, skb->len); - *len = skb->len; - *chan = CHAN_NDIS_DATA; - card->net_tx_busy = 1; /* we are busy sending network data */ - return (1); /* go and send the data */ - } else - hysdn_tx_netack(card); /* aknowledge packet -> throw away */ - } /* send a network packet if available */ -#ifdef CONFIG_HYSDN_CAPI - if (((hycapi_enable & (1 << card->myid))) && - ((skb = hycapi_tx_capiget(card)) != NULL)) - { - if (skb->len <= maxlen) { - skb_copy_from_linear_data(skb, buf, skb->len); - *len = skb->len; - *chan = CHAN_CAPI; - hycapi_tx_capiack(card); - return (1); /* go and send the data */ - } - } -#endif /* CONFIG_HYSDN_CAPI */ - return (0); /* nothing to send */ -} /* hysdn_sched_tx */ - - -/*****************************************************************************/ -/* send one config line to the card and return 0 if successful, otherwise a */ -/* negative error code. */ -/* The function works with timeouts perhaps not giving the greatest speed */ -/* sending the line, but this should be meaningless because only some lines */ -/* are to be sent and this happens very seldom. */ -/*****************************************************************************/ -int -hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan) -{ - int cnt = 50; /* timeout intervalls */ - unsigned long flags; - - if (card->debug_flags & LOG_SCHED_ASYN) - hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1); - - while (card->async_busy) { - - if (card->debug_flags & LOG_SCHED_ASYN) - hysdn_addlog(card, "async tx-cfg delayed"); - - msleep_interruptible(20); /* Timeout 20ms */ - if (!--cnt) - return (-ERR_ASYNC_TIME); /* timed out */ - } /* wait for buffer to become free */ - - spin_lock_irqsave(&card->hysdn_lock, flags); - strcpy(card->async_data, line); - card->async_len = strlen(line) + 1; - card->async_channel = chan; - card->async_busy = 1; /* request transfer */ - - /* now queue the task */ - schedule_work(&card->irq_queue); - spin_unlock_irqrestore(&card->hysdn_lock, flags); - - if (card->debug_flags & LOG_SCHED_ASYN) - hysdn_addlog(card, "async tx-cfg data queued"); - - cnt++; /* short delay */ - - while (card->async_busy) { - - if (card->debug_flags & LOG_SCHED_ASYN) - hysdn_addlog(card, "async tx-cfg waiting for tx-ready"); - - msleep_interruptible(20); /* Timeout 20ms */ - if (!--cnt) - return (-ERR_ASYNC_TIME); /* timed out */ - } /* wait for buffer to become free again */ - - if (card->debug_flags & LOG_SCHED_ASYN) - hysdn_addlog(card, "async tx-cfg data send"); - - return (0); /* line send correctly */ -} /* hysdn_tx_cfgline */ diff --git a/drivers/isdn/hysdn/ince1pc.h b/drivers/isdn/hysdn/ince1pc.h deleted file mode 100644 index cab68361de65..000000000000 --- a/drivers/isdn/hysdn/ince1pc.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Linux driver for HYSDN cards - * common definitions for both sides of the bus: - * - conventions both spoolers must know - * - channel numbers agreed upon - * - * Author M. Steinkopf - * Copyright 1999 by M. Steinkopf - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef __INCE1PC_H__ -#define __INCE1PC_H__ - -/* basic scalar definitions have same meanning, - * but their declaration location depends on environment - */ - -/*--------------------------------------channel numbers---------------------*/ -#define CHAN_SYSTEM 0x0001 /* system channel (spooler to spooler) */ -#define CHAN_ERRLOG 0x0005 /* error logger */ -#define CHAN_CAPI 0x0064 /* CAPI interface */ -#define CHAN_NDIS_DATA 0x1001 /* NDIS data transfer */ - -/*--------------------------------------POF ready msg-----------------------*/ -/* NOTE: after booting POF sends system ready message to PC: */ -#define RDY_MAGIC 0x52535953UL /* 'SYSR' reversed */ -#define RDY_MAGIC_SIZE 4 /* size in bytes */ - -#define MAX_N_TOK_BYTES 255 - -#define MIN_RDY_MSG_SIZE RDY_MAGIC_SIZE -#define MAX_RDY_MSG_SIZE (RDY_MAGIC_SIZE + MAX_N_TOK_BYTES) - -#define SYSR_TOK_END 0 -#define SYSR_TOK_B_CHAN 1 /* nr. of B-Channels; DataLen=1; def: 2 */ -#define SYSR_TOK_FAX_CHAN 2 /* nr. of FAX Channels; DataLen=1; def: 0 */ -#define SYSR_TOK_MAC_ADDR 3 /* MAC-Address; DataLen=6; def: auto */ -#define SYSR_TOK_ESC 255 /* undefined data size yet */ -/* default values, if not corrected by token: */ -#define SYSR_TOK_B_CHAN_DEF 2 /* assume 2 B-Channels */ -#define SYSR_TOK_FAX_CHAN_DEF 1 /* assume 1 FAX Channel */ - -/* syntax of new SYSR token stream: - * channel: CHAN_SYSTEM - * msgsize: MIN_RDY_MSG_SIZE <= x <= MAX_RDY_MSG_SIZE - * RDY_MAGIC_SIZE <= x <= (RDY_MAGIC_SIZE+MAX_N_TOK_BYTES) - * msg : 0 1 2 3 {4 5 6 ..} - * S Y S R MAX_N_TOK_BYTES bytes of TokenStream - * - * TokenStream := empty - * | {NonEndTokenChunk} EndToken RotlCRC - * NonEndTokenChunk:= NonEndTokenId DataLen [Data] - * NonEndTokenId := 0x01 .. 0xFE 1 BYTE - * DataLen := 0x00 .. 0xFF 1 BYTE - * Data := DataLen bytes - * EndToken := 0x00 - * RotlCRC := special 1 byte CRC over all NonEndTokenChunk bytes - * s. RotlCRC algorithm - * - * RotlCRC algorithm: - * ucSum= 0 1 unsigned char - * for all NonEndTokenChunk bytes: - * ROTL(ucSum,1) rotate left by 1 - * ucSum += Char; add current byte with swap around - * RotlCRC= ~ucSum; invert all bits for result - * - * note: - * - for 16-bit FIFO add padding 0 byte to achieve even token data bytes! - */ - -/*--------------------------------------error logger------------------------*/ -/* note: pof needs final 0 ! */ -#define ERRLOG_CMD_REQ "ERRLOG ON" -#define ERRLOG_CMD_REQ_SIZE 10 /* with final 0 byte ! */ -#define ERRLOG_CMD_STOP "ERRLOG OFF" -#define ERRLOG_CMD_STOP_SIZE 11 /* with final 0 byte ! */ - -#define ERRLOG_ENTRY_SIZE 64 /* sizeof(tErrLogEntry) */ - /* remaining text size = 55 */ -#define ERRLOG_TEXT_SIZE (ERRLOG_ENTRY_SIZE - 2 * 4 - 1) - -typedef struct ErrLogEntry_tag { - - /*00 */ unsigned long ulErrType; - - /*04 */ unsigned long ulErrSubtype; - - /*08 */ unsigned char ucTextSize; - - /*09 */ unsigned char ucText[ERRLOG_TEXT_SIZE]; - /* ASCIIZ of len ucTextSize-1 */ - -/*40 */ -} tErrLogEntry; - - -#if defined(__TURBOC__) -#if sizeof(tErrLogEntry) != ERRLOG_ENTRY_SIZE -#error size of tErrLogEntry != ERRLOG_ENTRY_SIZE -#endif /* */ -#endif /* */ - -/*--------------------------------------DPRAM boot spooler------------------*/ -/* this is the struture used between pc and - * hyperstone to exchange boot data - */ -#define DPRAM_SPOOLER_DATA_SIZE 0x20 -typedef struct DpramBootSpooler_tag { - - /*00 */ unsigned char Len; - - /*01 */ volatile unsigned char RdPtr; - - /*02 */ unsigned char WrPtr; - - /*03 */ unsigned char Data[DPRAM_SPOOLER_DATA_SIZE]; - -/*23 */ -} tDpramBootSpooler; - - -#define DPRAM_SPOOLER_MIN_SIZE 5 /* Len+RdPtr+Wrptr+2*data */ -#define DPRAM_SPOOLER_DEF_SIZE 0x23 /* current default size */ - -/*--------------------------------------HYCARD/ERGO DPRAM SoftUart----------*/ -/* at DPRAM offset 0x1C00: */ -#define SIZE_RSV_SOFT_UART 0x1B0 /* 432 bytes reserved for SoftUart */ - - -#endif /* __INCE1PC_H__ */ diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig deleted file mode 100644 index caa1b52f06f7..000000000000 --- a/drivers/isdn/i4l/Kconfig +++ /dev/null @@ -1,129 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Old ISDN4Linux config -# - -if ISDN_I4L - -config ISDN_PPP - bool "Support synchronous PPP" - depends on INET - select SLHC - help - Over digital connections such as ISDN, there is no need to - synchronize sender and recipient's clocks with start and stop bits - as is done over analog telephone lines. Instead, one can use - "synchronous PPP". Saying Y here will include this protocol. This - protocol is used by Cisco and Sun for example. So you want to say Y - here if the other end of your ISDN connection supports it. You will - need a special version of pppd (called ipppd) for using this - feature. See <file:Documentation/isdn/README.syncppp> and - <file:Documentation/isdn/syncPPP.FAQ> for more information. - -config ISDN_PPP_VJ - bool "Use VJ-compression with synchronous PPP" - depends on ISDN_PPP - help - This enables Van Jacobson header compression for synchronous PPP. - Say Y if the other end of the connection supports it. - -config ISDN_MPP - bool "Support generic MP (RFC 1717)" - depends on ISDN_PPP - help - With synchronous PPP enabled, it is possible to increase throughput - by bundling several ISDN-connections, using this protocol. See - <file:Documentation/isdn/README.syncppp> for more information. - -config IPPP_FILTER - bool "Filtering for synchronous PPP" - depends on ISDN_PPP - help - Say Y here if you want to be able to filter the packets passing over - IPPP interfaces. This allows you to control which packets count as - activity (i.e. which packets will reset the idle timer or bring up - a demand-dialled link) and which packets are to be dropped entirely. - You need to say Y here if you wish to use the pass-filter and - active-filter options to ipppd. - -config ISDN_PPP_BSDCOMP - tristate "Support BSD compression" - depends on ISDN_PPP - help - Support for the BSD-Compress compression method for PPP, which uses - the LZW compression method to compress each PPP packet before it is - sent over the wire. The machine at the other end of the PPP link - (usually your ISP) has to support the BSD-Compress compression - method as well for this to be useful. Even if they don't support it, - it is safe to say Y here. - -config ISDN_AUDIO - bool "Support audio via ISDN" - help - If you say Y here, the modem-emulator will support a subset of the - EIA Class 8 Voice commands. Using a getty with voice-support - (mgetty+sendfax by <gert@greenie.muc.de> with an extension, available - with the ISDN utility package for example), you will be able to use - your Linux box as an ISDN-answering machine. Of course, this must be - supported by the lowlevel driver also. Currently, the HiSax driver - is the only voice-supporting driver. See - <file:Documentation/isdn/README.audio> for more information. - -config ISDN_TTY_FAX - bool "Support AT-Fax Class 1 and 2 commands" - depends on ISDN_AUDIO - help - If you say Y here, the modem-emulator will support a subset of the - Fax Class 1 and 2 commands. Using a getty with fax-support - (mgetty+sendfax, hylafax), you will be able to use your Linux box as - an ISDN-fax-machine. This must be supported by the lowlevel driver - also. See <file:Documentation/isdn/README.fax> for more information. - -config ISDN_X25 - bool "X.25 PLP on top of ISDN" - depends on X25 - help - This feature provides the X.25 protocol over ISDN connections. - See <file:Documentation/isdn/README.x25> for more information - if you are thinking about using this. - - -menu "ISDN feature submodules" - -config ISDN_DRV_LOOP - tristate "isdnloop support" - depends on BROKEN_ON_SMP - help - This driver provides a virtual ISDN card. Its primary purpose is - testing of linklevel features or configuration without getting - charged by your service-provider for lots of phone calls. - You need will need the loopctrl utility from the latest isdn4k-utils - package to set up this driver. - -config ISDN_DIVERSION - tristate "Support isdn diversion services" - help - This option allows you to use some supplementary diversion - services in conjunction with the HiSax driver on an EURO/DSS1 - line. - - Supported options are CD (call deflection), CFU (Call forward - unconditional), CFB (Call forward when busy) and CFNR (call forward - not reachable). Additionally the actual CFU, CFB and CFNR state may - be interrogated. - - The use of CFU, CFB, CFNR and interrogation may be limited to some - countries. The keypad protocol is still not implemented. CD should - work in all countries if the service has been subscribed to. - - Please read the file <file:Documentation/isdn/README.diversion>. - -endmenu - -comment "ISDN4Linux hardware drivers" - -source "drivers/isdn/hisax/Kconfig" - -# end ISDN_I4L -endif - diff --git a/drivers/isdn/i4l/Makefile b/drivers/isdn/i4l/Makefile deleted file mode 100644 index be77500c9e86..000000000000 --- a/drivers/isdn/i4l/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Makefile for the kernel ISDN subsystem and device drivers. - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN_I4L) += isdn.o -obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o -obj-$(CONFIG_ISDN_HDLC) += isdnhdlc.o - -# Multipart objects. - -isdn-y := isdn_net.o isdn_tty.o isdn_v110.o isdn_common.o - -# Optional parts of multipart objects. - -isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o -isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o -isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o -isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o - diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c deleted file mode 100644 index b6bcd1eca128..000000000000 --- a/drivers/isdn/i4l/isdn_audio.c +++ /dev/null @@ -1,711 +0,0 @@ -/* $Id: isdn_audio.c,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $ - * - * Linux ISDN subsystem, audio conversion and compression (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * DTMF code (c) 1996 by Christian Mock (cm@kukuruz.ping.at) - * Silence detection (c) 1998 by Armin Schindler (mac@gismo.telekom.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/isdn.h> -#include <linux/slab.h> -#include "isdn_audio.h" -#include "isdn_common.h" - -char *isdn_audio_revision = "$Revision: 1.1.2.2 $"; - -/* - * Misc. lookup-tables. - */ - -/* ulaw -> signed 16-bit */ -static short isdn_audio_ulaw_to_s16[] = -{ - 0x8284, 0x8684, 0x8a84, 0x8e84, 0x9284, 0x9684, 0x9a84, 0x9e84, - 0xa284, 0xa684, 0xaa84, 0xae84, 0xb284, 0xb684, 0xba84, 0xbe84, - 0xc184, 0xc384, 0xc584, 0xc784, 0xc984, 0xcb84, 0xcd84, 0xcf84, - 0xd184, 0xd384, 0xd584, 0xd784, 0xd984, 0xdb84, 0xdd84, 0xdf84, - 0xe104, 0xe204, 0xe304, 0xe404, 0xe504, 0xe604, 0xe704, 0xe804, - 0xe904, 0xea04, 0xeb04, 0xec04, 0xed04, 0xee04, 0xef04, 0xf004, - 0xf0c4, 0xf144, 0xf1c4, 0xf244, 0xf2c4, 0xf344, 0xf3c4, 0xf444, - 0xf4c4, 0xf544, 0xf5c4, 0xf644, 0xf6c4, 0xf744, 0xf7c4, 0xf844, - 0xf8a4, 0xf8e4, 0xf924, 0xf964, 0xf9a4, 0xf9e4, 0xfa24, 0xfa64, - 0xfaa4, 0xfae4, 0xfb24, 0xfb64, 0xfba4, 0xfbe4, 0xfc24, 0xfc64, - 0xfc94, 0xfcb4, 0xfcd4, 0xfcf4, 0xfd14, 0xfd34, 0xfd54, 0xfd74, - 0xfd94, 0xfdb4, 0xfdd4, 0xfdf4, 0xfe14, 0xfe34, 0xfe54, 0xfe74, - 0xfe8c, 0xfe9c, 0xfeac, 0xfebc, 0xfecc, 0xfedc, 0xfeec, 0xfefc, - 0xff0c, 0xff1c, 0xff2c, 0xff3c, 0xff4c, 0xff5c, 0xff6c, 0xff7c, - 0xff88, 0xff90, 0xff98, 0xffa0, 0xffa8, 0xffb0, 0xffb8, 0xffc0, - 0xffc8, 0xffd0, 0xffd8, 0xffe0, 0xffe8, 0xfff0, 0xfff8, 0x0000, - 0x7d7c, 0x797c, 0x757c, 0x717c, 0x6d7c, 0x697c, 0x657c, 0x617c, - 0x5d7c, 0x597c, 0x557c, 0x517c, 0x4d7c, 0x497c, 0x457c, 0x417c, - 0x3e7c, 0x3c7c, 0x3a7c, 0x387c, 0x367c, 0x347c, 0x327c, 0x307c, - 0x2e7c, 0x2c7c, 0x2a7c, 0x287c, 0x267c, 0x247c, 0x227c, 0x207c, - 0x1efc, 0x1dfc, 0x1cfc, 0x1bfc, 0x1afc, 0x19fc, 0x18fc, 0x17fc, - 0x16fc, 0x15fc, 0x14fc, 0x13fc, 0x12fc, 0x11fc, 0x10fc, 0x0ffc, - 0x0f3c, 0x0ebc, 0x0e3c, 0x0dbc, 0x0d3c, 0x0cbc, 0x0c3c, 0x0bbc, - 0x0b3c, 0x0abc, 0x0a3c, 0x09bc, 0x093c, 0x08bc, 0x083c, 0x07bc, - 0x075c, 0x071c, 0x06dc, 0x069c, 0x065c, 0x061c, 0x05dc, 0x059c, - 0x055c, 0x051c, 0x04dc, 0x049c, 0x045c, 0x041c, 0x03dc, 0x039c, - 0x036c, 0x034c, 0x032c, 0x030c, 0x02ec, 0x02cc, 0x02ac, 0x028c, - 0x026c, 0x024c, 0x022c, 0x020c, 0x01ec, 0x01cc, 0x01ac, 0x018c, - 0x0174, 0x0164, 0x0154, 0x0144, 0x0134, 0x0124, 0x0114, 0x0104, - 0x00f4, 0x00e4, 0x00d4, 0x00c4, 0x00b4, 0x00a4, 0x0094, 0x0084, - 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048, 0x0040, - 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008, 0x0000 -}; - -/* alaw -> signed 16-bit */ -static short isdn_audio_alaw_to_s16[] = -{ - 0x13fc, 0xec04, 0x0144, 0xfebc, 0x517c, 0xae84, 0x051c, 0xfae4, - 0x0a3c, 0xf5c4, 0x0048, 0xffb8, 0x287c, 0xd784, 0x028c, 0xfd74, - 0x1bfc, 0xe404, 0x01cc, 0xfe34, 0x717c, 0x8e84, 0x071c, 0xf8e4, - 0x0e3c, 0xf1c4, 0x00c4, 0xff3c, 0x387c, 0xc784, 0x039c, 0xfc64, - 0x0ffc, 0xf004, 0x0104, 0xfefc, 0x417c, 0xbe84, 0x041c, 0xfbe4, - 0x083c, 0xf7c4, 0x0008, 0xfff8, 0x207c, 0xdf84, 0x020c, 0xfdf4, - 0x17fc, 0xe804, 0x018c, 0xfe74, 0x617c, 0x9e84, 0x061c, 0xf9e4, - 0x0c3c, 0xf3c4, 0x0084, 0xff7c, 0x307c, 0xcf84, 0x030c, 0xfcf4, - 0x15fc, 0xea04, 0x0164, 0xfe9c, 0x597c, 0xa684, 0x059c, 0xfa64, - 0x0b3c, 0xf4c4, 0x0068, 0xff98, 0x2c7c, 0xd384, 0x02cc, 0xfd34, - 0x1dfc, 0xe204, 0x01ec, 0xfe14, 0x797c, 0x8684, 0x07bc, 0xf844, - 0x0f3c, 0xf0c4, 0x00e4, 0xff1c, 0x3c7c, 0xc384, 0x03dc, 0xfc24, - 0x11fc, 0xee04, 0x0124, 0xfedc, 0x497c, 0xb684, 0x049c, 0xfb64, - 0x093c, 0xf6c4, 0x0028, 0xffd8, 0x247c, 0xdb84, 0x024c, 0xfdb4, - 0x19fc, 0xe604, 0x01ac, 0xfe54, 0x697c, 0x9684, 0x069c, 0xf964, - 0x0d3c, 0xf2c4, 0x00a4, 0xff5c, 0x347c, 0xcb84, 0x034c, 0xfcb4, - 0x12fc, 0xed04, 0x0134, 0xfecc, 0x4d7c, 0xb284, 0x04dc, 0xfb24, - 0x09bc, 0xf644, 0x0038, 0xffc8, 0x267c, 0xd984, 0x026c, 0xfd94, - 0x1afc, 0xe504, 0x01ac, 0xfe54, 0x6d7c, 0x9284, 0x06dc, 0xf924, - 0x0dbc, 0xf244, 0x00b4, 0xff4c, 0x367c, 0xc984, 0x036c, 0xfc94, - 0x0f3c, 0xf0c4, 0x00f4, 0xff0c, 0x3e7c, 0xc184, 0x03dc, 0xfc24, - 0x07bc, 0xf844, 0x0008, 0xfff8, 0x1efc, 0xe104, 0x01ec, 0xfe14, - 0x16fc, 0xe904, 0x0174, 0xfe8c, 0x5d7c, 0xa284, 0x05dc, 0xfa24, - 0x0bbc, 0xf444, 0x0078, 0xff88, 0x2e7c, 0xd184, 0x02ec, 0xfd14, - 0x14fc, 0xeb04, 0x0154, 0xfeac, 0x557c, 0xaa84, 0x055c, 0xfaa4, - 0x0abc, 0xf544, 0x0058, 0xffa8, 0x2a7c, 0xd584, 0x02ac, 0xfd54, - 0x1cfc, 0xe304, 0x01cc, 0xfe34, 0x757c, 0x8a84, 0x075c, 0xf8a4, - 0x0ebc, 0xf144, 0x00d4, 0xff2c, 0x3a7c, 0xc584, 0x039c, 0xfc64, - 0x10fc, 0xef04, 0x0114, 0xfeec, 0x457c, 0xba84, 0x045c, 0xfba4, - 0x08bc, 0xf744, 0x0018, 0xffe8, 0x227c, 0xdd84, 0x022c, 0xfdd4, - 0x18fc, 0xe704, 0x018c, 0xfe74, 0x657c, 0x9a84, 0x065c, 0xf9a4, - 0x0cbc, 0xf344, 0x0094, 0xff6c, 0x327c, 0xcd84, 0x032c, 0xfcd4 -}; - -/* alaw -> ulaw */ -static char isdn_audio_alaw_to_ulaw[] = -{ - 0xab, 0x2b, 0xe3, 0x63, 0x8b, 0x0b, 0xc9, 0x49, - 0xba, 0x3a, 0xf6, 0x76, 0x9b, 0x1b, 0xd7, 0x57, - 0xa3, 0x23, 0xdd, 0x5d, 0x83, 0x03, 0xc1, 0x41, - 0xb2, 0x32, 0xeb, 0x6b, 0x93, 0x13, 0xcf, 0x4f, - 0xaf, 0x2f, 0xe7, 0x67, 0x8f, 0x0f, 0xcd, 0x4d, - 0xbe, 0x3e, 0xfe, 0x7e, 0x9f, 0x1f, 0xdb, 0x5b, - 0xa7, 0x27, 0xdf, 0x5f, 0x87, 0x07, 0xc5, 0x45, - 0xb6, 0x36, 0xef, 0x6f, 0x97, 0x17, 0xd3, 0x53, - 0xa9, 0x29, 0xe1, 0x61, 0x89, 0x09, 0xc7, 0x47, - 0xb8, 0x38, 0xf2, 0x72, 0x99, 0x19, 0xd5, 0x55, - 0xa1, 0x21, 0xdc, 0x5c, 0x81, 0x01, 0xbf, 0x3f, - 0xb0, 0x30, 0xe9, 0x69, 0x91, 0x11, 0xce, 0x4e, - 0xad, 0x2d, 0xe5, 0x65, 0x8d, 0x0d, 0xcb, 0x4b, - 0xbc, 0x3c, 0xfa, 0x7a, 0x9d, 0x1d, 0xd9, 0x59, - 0xa5, 0x25, 0xde, 0x5e, 0x85, 0x05, 0xc3, 0x43, - 0xb4, 0x34, 0xed, 0x6d, 0x95, 0x15, 0xd1, 0x51, - 0xac, 0x2c, 0xe4, 0x64, 0x8c, 0x0c, 0xca, 0x4a, - 0xbb, 0x3b, 0xf8, 0x78, 0x9c, 0x1c, 0xd8, 0x58, - 0xa4, 0x24, 0xde, 0x5e, 0x84, 0x04, 0xc2, 0x42, - 0xb3, 0x33, 0xec, 0x6c, 0x94, 0x14, 0xd0, 0x50, - 0xb0, 0x30, 0xe8, 0x68, 0x90, 0x10, 0xce, 0x4e, - 0xbf, 0x3f, 0xfe, 0x7e, 0xa0, 0x20, 0xdc, 0x5c, - 0xa8, 0x28, 0xe0, 0x60, 0x88, 0x08, 0xc6, 0x46, - 0xb7, 0x37, 0xf0, 0x70, 0x98, 0x18, 0xd4, 0x54, - 0xaa, 0x2a, 0xe2, 0x62, 0x8a, 0x0a, 0xc8, 0x48, - 0xb9, 0x39, 0xf4, 0x74, 0x9a, 0x1a, 0xd6, 0x56, - 0xa2, 0x22, 0xdd, 0x5d, 0x82, 0x02, 0xc0, 0x40, - 0xb1, 0x31, 0xea, 0x6a, 0x92, 0x12, 0xcf, 0x4f, - 0xae, 0x2e, 0xe6, 0x66, 0x8e, 0x0e, 0xcc, 0x4c, - 0xbd, 0x3d, 0xfc, 0x7c, 0x9e, 0x1e, 0xda, 0x5a, - 0xa6, 0x26, 0xdf, 0x5f, 0x86, 0x06, 0xc4, 0x44, - 0xb5, 0x35, 0xee, 0x6e, 0x96, 0x16, 0xd2, 0x52 -}; - -/* ulaw -> alaw */ -static char isdn_audio_ulaw_to_alaw[] = -{ - 0xab, 0x55, 0xd5, 0x15, 0x95, 0x75, 0xf5, 0x35, - 0xb5, 0x45, 0xc5, 0x05, 0x85, 0x65, 0xe5, 0x25, - 0xa5, 0x5d, 0xdd, 0x1d, 0x9d, 0x7d, 0xfd, 0x3d, - 0xbd, 0x4d, 0xcd, 0x0d, 0x8d, 0x6d, 0xed, 0x2d, - 0xad, 0x51, 0xd1, 0x11, 0x91, 0x71, 0xf1, 0x31, - 0xb1, 0x41, 0xc1, 0x01, 0x81, 0x61, 0xe1, 0x21, - 0x59, 0xd9, 0x19, 0x99, 0x79, 0xf9, 0x39, 0xb9, - 0x49, 0xc9, 0x09, 0x89, 0x69, 0xe9, 0x29, 0xa9, - 0xd7, 0x17, 0x97, 0x77, 0xf7, 0x37, 0xb7, 0x47, - 0xc7, 0x07, 0x87, 0x67, 0xe7, 0x27, 0xa7, 0xdf, - 0x9f, 0x7f, 0xff, 0x3f, 0xbf, 0x4f, 0xcf, 0x0f, - 0x8f, 0x6f, 0xef, 0x2f, 0x53, 0x13, 0x73, 0x33, - 0xb3, 0x43, 0xc3, 0x03, 0x83, 0x63, 0xe3, 0x23, - 0xa3, 0x5b, 0xdb, 0x1b, 0x9b, 0x7b, 0xfb, 0x3b, - 0xbb, 0xbb, 0x4b, 0x4b, 0xcb, 0xcb, 0x0b, 0x0b, - 0x8b, 0x8b, 0x6b, 0x6b, 0xeb, 0xeb, 0x2b, 0x2b, - 0xab, 0x54, 0xd4, 0x14, 0x94, 0x74, 0xf4, 0x34, - 0xb4, 0x44, 0xc4, 0x04, 0x84, 0x64, 0xe4, 0x24, - 0xa4, 0x5c, 0xdc, 0x1c, 0x9c, 0x7c, 0xfc, 0x3c, - 0xbc, 0x4c, 0xcc, 0x0c, 0x8c, 0x6c, 0xec, 0x2c, - 0xac, 0x50, 0xd0, 0x10, 0x90, 0x70, 0xf0, 0x30, - 0xb0, 0x40, 0xc0, 0x00, 0x80, 0x60, 0xe0, 0x20, - 0x58, 0xd8, 0x18, 0x98, 0x78, 0xf8, 0x38, 0xb8, - 0x48, 0xc8, 0x08, 0x88, 0x68, 0xe8, 0x28, 0xa8, - 0xd6, 0x16, 0x96, 0x76, 0xf6, 0x36, 0xb6, 0x46, - 0xc6, 0x06, 0x86, 0x66, 0xe6, 0x26, 0xa6, 0xde, - 0x9e, 0x7e, 0xfe, 0x3e, 0xbe, 0x4e, 0xce, 0x0e, - 0x8e, 0x6e, 0xee, 0x2e, 0x52, 0x12, 0x72, 0x32, - 0xb2, 0x42, 0xc2, 0x02, 0x82, 0x62, 0xe2, 0x22, - 0xa2, 0x5a, 0xda, 0x1a, 0x9a, 0x7a, 0xfa, 0x3a, - 0xba, 0xba, 0x4a, 0x4a, 0xca, 0xca, 0x0a, 0x0a, - 0x8a, 0x8a, 0x6a, 0x6a, 0xea, 0xea, 0x2a, 0x2a -}; - -#define NCOEFF 8 /* number of frequencies to be analyzed */ -#define DTMF_TRESH 4000 /* above this is dtmf */ -#define SILENCE_TRESH 200 /* below this is silence */ -#define AMP_BITS 9 /* bits per sample, reduced to avoid overflow */ -#define LOGRP 0 -#define HIGRP 1 - -/* For DTMF recognition: - * 2 * cos(2 * PI * k / N) precalculated for all k - */ -static int cos2pik[NCOEFF] = -{ - 55813, 53604, 51193, 48591, 38114, 33057, 25889, 18332 -}; - -static char dtmf_matrix[4][4] = -{ - {'1', '2', '3', 'A'}, - {'4', '5', '6', 'B'}, - {'7', '8', '9', 'C'}, - {'*', '0', '#', 'D'} -}; - -static inline void -isdn_audio_tlookup(const u_char *table, u_char *buff, unsigned long n) -{ -#ifdef __i386__ - unsigned long d0, d1, d2, d3; - __asm__ __volatile__( - "cld\n" - "1:\tlodsb\n\t" - "xlatb\n\t" - "stosb\n\t" - "loop 1b\n\t" - : "=&b"(d0), "=&c"(d1), "=&D"(d2), "=&S"(d3) - : "0"((long) table), "1"(n), "2"((long) buff), "3"((long) buff) - : "memory", "ax"); -#else - while (n--) - *buff = table[*(unsigned char *)buff], buff++; -#endif -} - -void -isdn_audio_ulaw2alaw(unsigned char *buff, unsigned long len) -{ - isdn_audio_tlookup(isdn_audio_ulaw_to_alaw, buff, len); -} - -void -isdn_audio_alaw2ulaw(unsigned char *buff, unsigned long len) -{ - isdn_audio_tlookup(isdn_audio_alaw_to_ulaw, buff, len); -} - -/* - * linear <-> adpcm conversion stuff - * Most parts from the mgetty-package. - * (C) by Gert Doering and Klaus Weidner - * Used by permission of Gert Doering - */ - - -#define ZEROTRAP /* turn on the trap as per the MIL-STD */ -#undef ZEROTRAP -#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ -#define CLIP 32635 - -static unsigned char -isdn_audio_linear2ulaw(int sample) -{ - static int exp_lut[256] = - { - 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - }; - int sign, - exponent, - mantissa; - unsigned char ulawbyte; - - /* Get the sample into sign-magnitude. */ - sign = (sample >> 8) & 0x80; /* set aside the sign */ - if (sign != 0) - sample = -sample; /* get magnitude */ - if (sample > CLIP) - sample = CLIP; /* clip the magnitude */ - - /* Convert from 16 bit linear to ulaw. */ - sample = sample + BIAS; - exponent = exp_lut[(sample >> 7) & 0xFF]; - mantissa = (sample >> (exponent + 3)) & 0x0F; - ulawbyte = ~(sign | (exponent << 4) | mantissa); -#ifdef ZEROTRAP - /* optional CCITT trap */ - if (ulawbyte == 0) - ulawbyte = 0x02; -#endif - return (ulawbyte); -} - - -static int Mx[3][8] = -{ - {0x3800, 0x5600, 0, 0, 0, 0, 0, 0}, - {0x399a, 0x3a9f, 0x4d14, 0x6607, 0, 0, 0, 0}, - {0x3556, 0x3556, 0x399A, 0x3A9F, 0x4200, 0x4D14, 0x6607, 0x6607}, -}; - -static int bitmask[9] = -{ - 0, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff -}; - -static int -isdn_audio_get_bits(adpcm_state *s, unsigned char **in, int *len) -{ - while (s->nleft < s->nbits) { - int d = *((*in)++); - (*len)--; - s->word = (s->word << 8) | d; - s->nleft += 8; - } - s->nleft -= s->nbits; - return (s->word >> s->nleft) & bitmask[s->nbits]; -} - -static void -isdn_audio_put_bits(int data, int nbits, adpcm_state *s, - unsigned char **out, int *len) -{ - s->word = (s->word << nbits) | (data & bitmask[nbits]); - s->nleft += nbits; - while (s->nleft >= 8) { - int d = (s->word >> (s->nleft - 8)); - *(out[0]++) = d & 255; - (*len)++; - s->nleft -= 8; - } -} - -adpcm_state * -isdn_audio_adpcm_init(adpcm_state *s, int nbits) -{ - if (!s) - s = kmalloc(sizeof(adpcm_state), GFP_ATOMIC); - if (s) { - s->a = 0; - s->d = 5; - s->word = 0; - s->nleft = 0; - s->nbits = nbits; - } - return s; -} - -dtmf_state * -isdn_audio_dtmf_init(dtmf_state *s) -{ - if (!s) - s = kmalloc(sizeof(dtmf_state), GFP_ATOMIC); - if (s) { - s->idx = 0; - s->last = ' '; - } - return s; -} - -/* - * Decompression of adpcm data to a/u-law - * - */ - -int -isdn_audio_adpcm2xlaw(adpcm_state *s, int fmt, unsigned char *in, - unsigned char *out, int len) -{ - int a = s->a; - int d = s->d; - int nbits = s->nbits; - int olen = 0; - - while (len) { - int e = isdn_audio_get_bits(s, &in, &len); - int sign; - - if (nbits == 4 && e == 0) - d = 4; - sign = (e >> (nbits - 1)) ? -1 : 1; - e &= bitmask[nbits - 1]; - a += sign * ((e << 1) + 1) * d >> 1; - if (d & 1) - a++; - if (fmt) - *out++ = isdn_audio_ulaw_to_alaw[ - isdn_audio_linear2ulaw(a << 2)]; - else - *out++ = isdn_audio_linear2ulaw(a << 2); - olen++; - d = (d * Mx[nbits - 2][e] + 0x2000) >> 14; - if (d < 5) - d = 5; - } - s->a = a; - s->d = d; - return olen; -} - -int -isdn_audio_xlaw2adpcm(adpcm_state *s, int fmt, unsigned char *in, - unsigned char *out, int len) -{ - int a = s->a; - int d = s->d; - int nbits = s->nbits; - int olen = 0; - - while (len--) { - int e = 0, - nmax = 1 << (nbits - 1); - int sign, - delta; - - if (fmt) - delta = (isdn_audio_alaw_to_s16[*in++] >> 2) - a; - else - delta = (isdn_audio_ulaw_to_s16[*in++] >> 2) - a; - if (delta < 0) { - e = nmax; - delta = -delta; - } - while (--nmax && delta > d) { - delta -= d; - e++; - } - if (nbits == 4 && ((e & 0x0f) == 0)) - e = 8; - isdn_audio_put_bits(e, nbits, s, &out, &olen); - sign = (e >> (nbits - 1)) ? -1 : 1; - e &= bitmask[nbits - 1]; - - a += sign * ((e << 1) + 1) * d >> 1; - if (d & 1) - a++; - d = (d * Mx[nbits - 2][e] + 0x2000) >> 14; - if (d < 5) - d = 5; - } - s->a = a; - s->d = d; - return olen; -} - -/* - * Goertzel algorithm. - * See http://ptolemy.eecs.berkeley.edu/papers/96/dtmf_ict/ - * for more info. - * Result is stored into an sk_buff and queued up for later - * evaluation. - */ -static void -isdn_audio_goertzel(int *sample, modem_info *info) -{ - int sk, - sk1, - sk2; - int k, - n; - struct sk_buff *skb; - int *result; - - skb = dev_alloc_skb(sizeof(int) * NCOEFF); - if (!skb) { - printk(KERN_WARNING - "isdn_audio: Could not alloc DTMF result for ttyI%d\n", - info->line); - return; - } - result = skb_put(skb, sizeof(int) * NCOEFF); - for (k = 0; k < NCOEFF; k++) { - sk = sk1 = sk2 = 0; - for (n = 0; n < DTMF_NPOINTS; n++) { - sk = sample[n] + ((cos2pik[k] * sk1) >> 15) - sk2; - sk2 = sk1; - sk1 = sk; - } - /* Avoid overflows */ - sk >>= 1; - sk2 >>= 1; - /* compute |X(k)|**2 */ - /* report overflows. This should not happen. */ - /* Comment this out if desired */ - if (sk < -32768 || sk > 32767) - printk(KERN_DEBUG - "isdn_audio: dtmf goertzel overflow, sk=%d\n", sk); - if (sk2 < -32768 || sk2 > 32767) - printk(KERN_DEBUG - "isdn_audio: dtmf goertzel overflow, sk2=%d\n", sk2); - result[k] = - ((sk * sk) >> AMP_BITS) - - ((((cos2pik[k] * sk) >> 15) * sk2) >> AMP_BITS) + - ((sk2 * sk2) >> AMP_BITS); - } - skb_queue_tail(&info->dtmf_queue, skb); - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); -} - -void -isdn_audio_eval_dtmf(modem_info *info) -{ - struct sk_buff *skb; - int *result; - dtmf_state *s; - int silence; - int i; - int di; - int ch; - int grp[2]; - char what; - char *p; - int thresh; - - while ((skb = skb_dequeue(&info->dtmf_queue))) { - result = (int *) skb->data; - s = info->dtmf_state; - grp[LOGRP] = grp[HIGRP] = -1; - silence = 0; - thresh = 0; - for (i = 0; i < NCOEFF; i++) { - if (result[i] > DTMF_TRESH) { - if (result[i] > thresh) - thresh = result[i]; - } - else if (result[i] < SILENCE_TRESH) - silence++; - } - if (silence == NCOEFF) - what = ' '; - else { - if (thresh > 0) { - thresh = thresh >> 4; /* touchtones must match within 12 dB */ - for (i = 0; i < NCOEFF; i++) { - if (result[i] < thresh) - continue; /* ignore */ - /* good level found. This is allowed only one time per group */ - if (i < NCOEFF / 2) { - /* lowgroup*/ - if (grp[LOGRP] >= 0) { - // Bad. Another tone found. */ - grp[LOGRP] = -1; - break; - } - else - grp[LOGRP] = i; - } - else { /* higroup */ - if (grp[HIGRP] >= 0) { // Bad. Another tone found. */ - grp[HIGRP] = -1; - break; - } - else - grp[HIGRP] = i - NCOEFF/2; - } - } - if ((grp[LOGRP] >= 0) && (grp[HIGRP] >= 0)) { - what = dtmf_matrix[grp[LOGRP]][grp[HIGRP]]; - if (s->last != ' ' && s->last != '.') - s->last = what; /* min. 1 non-DTMF between DTMF */ - } else - what = '.'; - } - else - what = '.'; - } - if ((what != s->last) && (what != ' ') && (what != '.')) { - printk(KERN_DEBUG "dtmf: tt='%c'\n", what); - p = skb->data; - *p++ = 0x10; - *p = what; - skb_trim(skb, 2); - ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; - ISDN_AUDIO_SKB_LOCK(skb) = 0; - di = info->isdn_driver; - ch = info->isdn_channel; - __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); - dev->drv[di]->rcvcount[ch] += 2; - /* Schedule dequeuing */ - if ((dev->modempoll) && (info->rcvsched)) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); - wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); - } else - kfree_skb(skb); - s->last = what; - } -} - -/* - * Decode DTMF tones, queue result in separate sk_buf for - * later examination. - * Parameters: - * s = pointer to state-struct. - * buf = input audio data - * len = size of audio data. - * fmt = audio data format (0 = ulaw, 1 = alaw) - */ -void -isdn_audio_calc_dtmf(modem_info *info, unsigned char *buf, int len, int fmt) -{ - dtmf_state *s = info->dtmf_state; - int i; - int c; - - while (len) { - c = DTMF_NPOINTS - s->idx; - if (c > len) - c = len; - if (c <= 0) - break; - for (i = 0; i < c; i++) { - if (fmt) - s->buf[s->idx++] = - isdn_audio_alaw_to_s16[*buf++] >> (15 - AMP_BITS); - else - s->buf[s->idx++] = - isdn_audio_ulaw_to_s16[*buf++] >> (15 - AMP_BITS); - } - if (s->idx == DTMF_NPOINTS) { - isdn_audio_goertzel(s->buf, info); - s->idx = 0; - } - len -= c; - } -} - -silence_state * -isdn_audio_silence_init(silence_state *s) -{ - if (!s) - s = kmalloc(sizeof(silence_state), GFP_ATOMIC); - if (s) { - s->idx = 0; - s->state = 0; - } - return s; -} - -void -isdn_audio_calc_silence(modem_info *info, unsigned char *buf, int len, int fmt) -{ - silence_state *s = info->silence_state; - int i; - signed char c; - - if (!info->emu.vpar[1]) return; - - for (i = 0; i < len; i++) { - if (fmt) - c = isdn_audio_alaw_to_ulaw[*buf++]; - else - c = *buf++; - - if (c > 0) c -= 128; - c = abs(c); - - if (c > (info->emu.vpar[1] * 4)) { - s->idx = 0; - s->state = 1; - } else { - if (s->idx < 210000) s->idx++; - } - } -} - -void -isdn_audio_put_dle_code(modem_info *info, u_char code) -{ - struct sk_buff *skb; - int di; - int ch; - char *p; - - skb = dev_alloc_skb(2); - if (!skb) { - printk(KERN_WARNING - "isdn_audio: Could not alloc skb for ttyI%d\n", - info->line); - return; - } - p = skb_put(skb, 2); - p[0] = 0x10; - p[1] = code; - ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; - ISDN_AUDIO_SKB_LOCK(skb) = 0; - di = info->isdn_driver; - ch = info->isdn_channel; - __skb_queue_tail(&dev->drv[di]->rpqueue[ch], skb); - dev->drv[di]->rcvcount[ch] += 2; - /* Schedule dequeuing */ - if ((dev->modempoll) && (info->rcvsched)) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); - wake_up_interruptible(&dev->drv[di]->rcv_waitq[ch]); -} - -void -isdn_audio_eval_silence(modem_info *info) -{ - silence_state *s = info->silence_state; - char what; - - what = ' '; - - if (s->idx > (info->emu.vpar[2] * 800)) { - s->idx = 0; - if (!s->state) { /* silence from beginning of rec */ - what = 's'; - } else { - what = 'q'; - } - } - if ((what == 's') || (what == 'q')) { - printk(KERN_DEBUG "ttyI%d: %s\n", info->line, - (what == 's') ? "silence" : "quiet"); - isdn_audio_put_dle_code(info, what); - } -} diff --git a/drivers/isdn/i4l/isdn_audio.h b/drivers/isdn/i4l/isdn_audio.h deleted file mode 100644 index 013c3582e0d1..000000000000 --- a/drivers/isdn/i4l/isdn_audio.h +++ /dev/null @@ -1,44 +0,0 @@ -/* $Id: isdn_audio.h,v 1.1.2.2 2004/01/12 22:37:18 keil Exp $ - * - * Linux ISDN subsystem, audio conversion and compression (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#define DTMF_NPOINTS 205 /* Number of samples for DTMF recognition */ -typedef struct adpcm_state { - int a; - int d; - int word; - int nleft; - int nbits; -} adpcm_state; - -typedef struct dtmf_state { - char last; - char llast; - int idx; - int buf[DTMF_NPOINTS]; -} dtmf_state; - -typedef struct silence_state { - int state; - unsigned int idx; -} silence_state; - -extern void isdn_audio_ulaw2alaw(unsigned char *, unsigned long); -extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long); -extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int); -extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int); -extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int); -extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int); -extern void isdn_audio_eval_dtmf(modem_info *); -dtmf_state *isdn_audio_dtmf_init(dtmf_state *); -extern void isdn_audio_calc_silence(modem_info *, unsigned char *, int, int); -extern void isdn_audio_eval_silence(modem_info *); -silence_state *isdn_audio_silence_init(silence_state *); -extern void isdn_audio_put_dle_code(modem_info *, u_char); diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c deleted file mode 100644 index 7f28b967ed19..000000000000 --- a/drivers/isdn/i4l/isdn_bsdcomp.c +++ /dev/null @@ -1,930 +0,0 @@ -/* - * BSD compression module - * - * Patched version for ISDN syncPPP written 1997/1998 by Michael Hipp - * The whole module is now SKB based. - * - */ - -/* - * Update: The Berkeley copyright was changed, and the change - * is retroactive to all "true" BSD software (ie everything - * from UCB as opposed to other peoples code that just carried - * the same license). The new copyright doesn't clash with the - * GPL, so the module-only restriction has been removed.. - */ - -/* - * Original copyright notice: - * - * Copyright (c) 1985, 1986 The Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * James A. Woods, derived from original work by Spencer Thomas - * and Joseph Orost. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/interrupt.h> -#include <linux/ptrace.h> -#include <linux/ioport.h> -#include <linux/in.h> -#include <linux/slab.h> -#include <linux/tty.h> -#include <linux/errno.h> -#include <linux/string.h> /* used in new tty drivers */ -#include <linux/signal.h> /* used in new tty drivers */ -#include <linux/bitops.h> - -#include <asm/byteorder.h> -#include <asm/types.h> - -#include <linux/if.h> - -#include <linux/if_ether.h> -#include <linux/netdevice.h> -#include <linux/skbuff.h> -#include <linux/inet.h> -#include <linux/ioctl.h> -#include <linux/vmalloc.h> - -#include <linux/ppp_defs.h> - -#include <linux/isdn.h> -#include <linux/isdn_ppp.h> -#include <linux/ip.h> -#include <linux/tcp.h> -#include <linux/if_arp.h> -#include <linux/ppp-comp.h> - -#include "isdn_ppp.h" - -MODULE_DESCRIPTION("ISDN4Linux: BSD Compression for PPP over ISDN"); -MODULE_LICENSE("Dual BSD/GPL"); - -#define BSD_VERSION(x) ((x) >> 5) -#define BSD_NBITS(x) ((x) & 0x1F) - -#define BSD_CURRENT_VERSION 1 - -#define DEBUG 1 - -/* - * A dictionary for doing BSD compress. - */ - -struct bsd_dict { - u32 fcode; - u16 codem1; /* output of hash table -1 */ - u16 cptr; /* map code to hash table entry */ -}; - -struct bsd_db { - int totlen; /* length of this structure */ - unsigned int hsize; /* size of the hash table */ - unsigned char hshift; /* used in hash function */ - unsigned char n_bits; /* current bits/code */ - unsigned char maxbits; /* maximum bits/code */ - unsigned char debug; /* non-zero if debug desired */ - unsigned char unit; /* ppp unit number */ - u16 seqno; /* sequence # of next packet */ - unsigned int mru; /* size of receive (decompress) bufr */ - unsigned int maxmaxcode; /* largest valid code */ - unsigned int max_ent; /* largest code in use */ - unsigned int in_count; /* uncompressed bytes, aged */ - unsigned int bytes_out; /* compressed bytes, aged */ - unsigned int ratio; /* recent compression ratio */ - unsigned int checkpoint; /* when to next check the ratio */ - unsigned int clear_count; /* times dictionary cleared */ - unsigned int incomp_count; /* incompressible packets */ - unsigned int incomp_bytes; /* incompressible bytes */ - unsigned int uncomp_count; /* uncompressed packets */ - unsigned int uncomp_bytes; /* uncompressed bytes */ - unsigned int comp_count; /* compressed packets */ - unsigned int comp_bytes; /* compressed bytes */ - unsigned short *lens; /* array of lengths of codes */ - struct bsd_dict *dict; /* dictionary */ - int xmit; -}; - -#define BSD_OVHD 2 /* BSD compress overhead/packet */ -#define MIN_BSD_BITS 9 -#define BSD_INIT_BITS MIN_BSD_BITS -#define MAX_BSD_BITS 15 - -/* - * the next two codes should not be changed lightly, as they must not - * lie within the contiguous general code space. - */ -#define CLEAR 256 /* table clear output code */ -#define FIRST 257 /* first free entry */ -#define LAST 255 - -#define MAXCODE(b) ((1 << (b)) - 1) -#define BADCODEM1 MAXCODE(MAX_BSD_BITS) - -#define BSD_HASH(prefix, suffix, hshift) ((((unsigned long)(suffix)) << (hshift)) \ - ^ (unsigned long)(prefix)) -#define BSD_KEY(prefix, suffix) ((((unsigned long)(suffix)) << 16) \ - + (unsigned long)(prefix)) - -#define CHECK_GAP 10000 /* Ratio check interval */ - -#define RATIO_SCALE_LOG 8 -#define RATIO_SCALE (1 << RATIO_SCALE_LOG) -#define RATIO_MAX (0x7fffffff >> RATIO_SCALE_LOG) - -/* - * clear the dictionary - */ - -static void bsd_clear(struct bsd_db *db) -{ - db->clear_count++; - db->max_ent = FIRST - 1; - db->n_bits = BSD_INIT_BITS; - db->bytes_out = 0; - db->in_count = 0; - db->incomp_count = 0; - db->ratio = 0; - db->checkpoint = CHECK_GAP; -} - -/* - * If the dictionary is full, then see if it is time to reset it. - * - * Compute the compression ratio using fixed-point arithmetic - * with 8 fractional bits. - * - * Since we have an infinite stream instead of a single file, - * watch only the local compression ratio. - * - * Since both peers must reset the dictionary at the same time even in - * the absence of CLEAR codes (while packets are incompressible), they - * must compute the same ratio. - */ -static int bsd_check(struct bsd_db *db) /* 1=output CLEAR */ -{ - unsigned int new_ratio; - - if (db->in_count >= db->checkpoint) - { - /* age the ratio by limiting the size of the counts */ - if (db->in_count >= RATIO_MAX || db->bytes_out >= RATIO_MAX) - { - db->in_count -= (db->in_count >> 2); - db->bytes_out -= (db->bytes_out >> 2); - } - - db->checkpoint = db->in_count + CHECK_GAP; - - if (db->max_ent >= db->maxmaxcode) - { - /* Reset the dictionary only if the ratio is worse, - * or if it looks as if it has been poisoned - * by incompressible data. - * - * This does not overflow, because - * db->in_count <= RATIO_MAX. - */ - - new_ratio = db->in_count << RATIO_SCALE_LOG; - if (db->bytes_out != 0) - { - new_ratio /= db->bytes_out; - } - - if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) - { - bsd_clear(db); - return 1; - } - db->ratio = new_ratio; - } - } - return 0; -} - -/* - * Return statistics. - */ - -static void bsd_stats(void *state, struct compstat *stats) -{ - struct bsd_db *db = (struct bsd_db *) state; - - stats->unc_bytes = db->uncomp_bytes; - stats->unc_packets = db->uncomp_count; - stats->comp_bytes = db->comp_bytes; - stats->comp_packets = db->comp_count; - stats->inc_bytes = db->incomp_bytes; - stats->inc_packets = db->incomp_count; - stats->in_count = db->in_count; - stats->bytes_out = db->bytes_out; -} - -/* - * Reset state, as on a CCP ResetReq. - */ -static void bsd_reset(void *state, unsigned char code, unsigned char id, - unsigned char *data, unsigned len, - struct isdn_ppp_resetparams *rsparm) -{ - struct bsd_db *db = (struct bsd_db *) state; - - bsd_clear(db); - db->seqno = 0; - db->clear_count = 0; -} - -/* - * Release the compression structure - */ -static void bsd_free(void *state) -{ - struct bsd_db *db = (struct bsd_db *) state; - - if (db) { - /* - * Release the dictionary - */ - vfree(db->dict); - db->dict = NULL; - - /* - * Release the string buffer - */ - vfree(db->lens); - db->lens = NULL; - - /* - * Finally release the structure itself. - */ - kfree(db); - } -} - - -/* - * Allocate space for a (de) compressor. - */ -static void *bsd_alloc(struct isdn_ppp_comp_data *data) -{ - int bits; - unsigned int hsize, hshift, maxmaxcode; - struct bsd_db *db; - int decomp; - - static unsigned int htab[][2] = { - { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , { 5003 , 4 } , - { 9001 , 5 } , { 18013 , 6 } , { 35023 , 7 } , { 69001 , 8 } - }; - - if (data->optlen != 1 || data->num != CI_BSD_COMPRESS - || BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION) - return NULL; - - bits = BSD_NBITS(data->options[0]); - - if (bits < 9 || bits > 15) - return NULL; - - hsize = htab[bits - 9][0]; - hshift = htab[bits - 9][1]; - - /* - * Allocate the main control structure for this instance. - */ - maxmaxcode = MAXCODE(bits); - db = kzalloc(sizeof(struct bsd_db), GFP_KERNEL); - if (!db) - return NULL; - - db->xmit = data->flags & IPPP_COMP_FLAG_XMIT; - decomp = db->xmit ? 0 : 1; - - /* - * Allocate space for the dictionary. This may be more than one page in - * length. - */ - db->dict = vmalloc(array_size(hsize, sizeof(struct bsd_dict))); - if (!db->dict) { - bsd_free(db); - return NULL; - } - - /* - * If this is the compression buffer then there is no length data. - * For decompression, the length information is needed as well. - */ - if (!decomp) - db->lens = NULL; - else { - db->lens = vmalloc(array_size(sizeof(db->lens[0]), - maxmaxcode + 1)); - if (!db->lens) { - bsd_free(db); - return (NULL); - } - } - - /* - * Initialize the data information for the compression code - */ - db->totlen = sizeof(struct bsd_db) + (sizeof(struct bsd_dict) * hsize); - db->hsize = hsize; - db->hshift = hshift; - db->maxmaxcode = maxmaxcode; - db->maxbits = bits; - - return (void *)db; -} - -/* - * Initialize the database. - */ -static int bsd_init(void *state, struct isdn_ppp_comp_data *data, int unit, int debug) -{ - struct bsd_db *db = state; - int indx; - int decomp; - - if (!state || !data) { - printk(KERN_ERR "isdn_bsd_init: [%d] ERR, state %lx data %lx\n", unit, (long)state, (long)data); - return 0; - } - - decomp = db->xmit ? 0 : 1; - - if (data->optlen != 1 || data->num != CI_BSD_COMPRESS - || (BSD_VERSION(data->options[0]) != BSD_CURRENT_VERSION) - || (BSD_NBITS(data->options[0]) != db->maxbits) - || (decomp && db->lens == NULL)) { - printk(KERN_ERR "isdn_bsd: %d %d %d %d %lx\n", data->optlen, data->num, data->options[0], decomp, (unsigned long)db->lens); - return 0; - } - - if (decomp) - for (indx = LAST; indx >= 0; indx--) - db->lens[indx] = 1; - - indx = db->hsize; - while (indx-- != 0) { - db->dict[indx].codem1 = BADCODEM1; - db->dict[indx].cptr = 0; - } - - db->unit = unit; - db->mru = 0; - - db->debug = 1; - - bsd_reset(db, 0, 0, NULL, 0, NULL); - - return 1; -} - -/* - * Obtain pointers to the various structures in the compression tables - */ - -#define dict_ptrx(p, idx) &(p->dict[idx]) -#define lens_ptrx(p, idx) &(p->lens[idx]) - -#ifdef DEBUG -static unsigned short *lens_ptr(struct bsd_db *db, int idx) -{ - if ((unsigned int) idx > (unsigned int) db->maxmaxcode) { - printk(KERN_DEBUG "<9>ppp: lens_ptr(%d) > max\n", idx); - idx = 0; - } - return lens_ptrx(db, idx); -} - -static struct bsd_dict *dict_ptr(struct bsd_db *db, int idx) -{ - if ((unsigned int) idx >= (unsigned int) db->hsize) { - printk(KERN_DEBUG "<9>ppp: dict_ptr(%d) > max\n", idx); - idx = 0; - } - return dict_ptrx(db, idx); -} - -#else -#define lens_ptr(db, idx) lens_ptrx(db, idx) -#define dict_ptr(db, idx) dict_ptrx(db, idx) -#endif - -/* - * compress a packet - */ -static int bsd_compress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out, int proto) -{ - struct bsd_db *db; - int hshift; - unsigned int max_ent; - unsigned int n_bits; - unsigned int bitno; - unsigned long accm; - int ent; - unsigned long fcode; - struct bsd_dict *dictp; - unsigned char c; - int hval, disp, ilen, mxcode; - unsigned char *rptr = skb_in->data; - int isize = skb_in->len; - -#define OUTPUT(ent) \ - { \ - bitno -= n_bits; \ - accm |= ((ent) << bitno); \ - do { \ - if (skb_out && skb_tailroom(skb_out) > 0) \ - skb_put_u8(skb_out, (u8)(accm >> 24)); \ - accm <<= 8; \ - bitno += 8; \ - } while (bitno <= 24); \ - } - - /* - * If the protocol is not in the range we're interested in, - * just return without compressing the packet. If it is, - * the protocol becomes the first byte to compress. - */ - printk(KERN_DEBUG "bsd_compress called with %x\n", proto); - - ent = proto; - if (proto < 0x21 || proto > 0xf9 || !(proto & 0x1)) - return 0; - - db = (struct bsd_db *) state; - hshift = db->hshift; - max_ent = db->max_ent; - n_bits = db->n_bits; - bitno = 32; - accm = 0; - mxcode = MAXCODE(n_bits); - - /* This is the PPP header information */ - if (skb_out && skb_tailroom(skb_out) >= 2) { - char *v = skb_put(skb_out, 2); - /* we only push our own data on the header, - AC,PC and protos is pushed by caller */ - v[0] = db->seqno >> 8; - v[1] = db->seqno; - } - - ilen = ++isize; /* This is off by one, but that is what is in draft! */ - - while (--ilen > 0) { - c = *rptr++; - fcode = BSD_KEY(ent, c); - hval = BSD_HASH(ent, c, hshift); - dictp = dict_ptr(db, hval); - - /* Validate and then check the entry. */ - if (dictp->codem1 >= max_ent) - goto nomatch; - - if (dictp->fcode == fcode) { - ent = dictp->codem1 + 1; - continue; /* found (prefix,suffix) */ - } - - /* continue probing until a match or invalid entry */ - disp = (hval == 0) ? 1 : hval; - - do { - hval += disp; - if (hval >= db->hsize) - hval -= db->hsize; - dictp = dict_ptr(db, hval); - if (dictp->codem1 >= max_ent) - goto nomatch; - } while (dictp->fcode != fcode); - - ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */ - continue; - - nomatch: - OUTPUT(ent); /* output the prefix */ - - /* code -> hashtable */ - if (max_ent < db->maxmaxcode) { - struct bsd_dict *dictp2; - struct bsd_dict *dictp3; - int indx; - - /* expand code size if needed */ - if (max_ent >= mxcode) { - db->n_bits = ++n_bits; - mxcode = MAXCODE(n_bits); - } - - /* - * Invalidate old hash table entry using - * this code, and then take it over. - */ - dictp2 = dict_ptr(db, max_ent + 1); - indx = dictp2->cptr; - dictp3 = dict_ptr(db, indx); - - if (dictp3->codem1 == max_ent) - dictp3->codem1 = BADCODEM1; - - dictp2->cptr = hval; - dictp->codem1 = max_ent; - dictp->fcode = fcode; - db->max_ent = ++max_ent; - - if (db->lens) { - unsigned short *len1 = lens_ptr(db, max_ent); - unsigned short *len2 = lens_ptr(db, ent); - *len1 = *len2 + 1; - } - } - ent = c; - } - - OUTPUT(ent); /* output the last code */ - - if (skb_out) - db->bytes_out += skb_out->len; /* Do not count bytes from here */ - db->uncomp_bytes += isize; - db->in_count += isize; - ++db->uncomp_count; - ++db->seqno; - - if (bitno < 32) - ++db->bytes_out; /* must be set before calling bsd_check */ - - /* - * Generate the clear command if needed - */ - - if (bsd_check(db)) - OUTPUT(CLEAR); - - /* - * Pad dribble bits of last code with ones. - * Do not emit a completely useless byte of ones. - */ - if (bitno < 32 && skb_out && skb_tailroom(skb_out) > 0) - skb_put_u8(skb_out, - (unsigned char)((accm | (0xff << (bitno - 8))) >> 24)); - - /* - * Increase code size if we would have without the packet - * boundary because the decompressor will do so. - */ - if (max_ent >= mxcode && max_ent < db->maxmaxcode) - db->n_bits++; - - /* If output length is too large then this is an incompressible frame. */ - if (!skb_out || skb_out->len >= skb_in->len) { - ++db->incomp_count; - db->incomp_bytes += isize; - return 0; - } - - /* Count the number of compressed frames */ - ++db->comp_count; - db->comp_bytes += skb_out->len; - return skb_out->len; - -#undef OUTPUT -} - -/* - * Update the "BSD Compress" dictionary on the receiver for - * incompressible data by pretending to compress the incoming data. - */ -static void bsd_incomp(void *state, struct sk_buff *skb_in, int proto) -{ - bsd_compress(state, skb_in, NULL, proto); -} - -/* - * Decompress "BSD Compress". - */ -static int bsd_decompress(void *state, struct sk_buff *skb_in, struct sk_buff *skb_out, - struct isdn_ppp_resetparams *rsparm) -{ - struct bsd_db *db; - unsigned int max_ent; - unsigned long accm; - unsigned int bitno; /* 1st valid bit in accm */ - unsigned int n_bits; - unsigned int tgtbitno; /* bitno when we have a code */ - struct bsd_dict *dictp; - int seq; - unsigned int incode; - unsigned int oldcode; - unsigned int finchar; - unsigned char *p, *ibuf; - int ilen; - int codelen; - int extra; - - db = (struct bsd_db *) state; - max_ent = db->max_ent; - accm = 0; - bitno = 32; /* 1st valid bit in accm */ - n_bits = db->n_bits; - tgtbitno = 32 - n_bits; /* bitno when we have a code */ - - printk(KERN_DEBUG "bsd_decompress called\n"); - - if (!skb_in || !skb_out) { - printk(KERN_ERR "bsd_decompress called with NULL parameter\n"); - return DECOMP_ERROR; - } - - /* - * Get the sequence number. - */ - if ((p = skb_pull(skb_in, 2)) == NULL) { - return DECOMP_ERROR; - } - p -= 2; - seq = (p[0] << 8) + p[1]; - ilen = skb_in->len; - ibuf = skb_in->data; - - /* - * Check the sequence number and give up if it differs from - * the value we're expecting. - */ - if (seq != db->seqno) { - if (db->debug) { - printk(KERN_DEBUG "bsd_decomp%d: bad sequence # %d, expected %d\n", - db->unit, seq, db->seqno - 1); - } - return DECOMP_ERROR; - } - - ++db->seqno; - db->bytes_out += ilen; - - if (skb_tailroom(skb_out) > 0) - skb_put_u8(skb_out, 0); - else - return DECOMP_ERR_NOMEM; - - oldcode = CLEAR; - - /* - * Keep the checkpoint correctly so that incompressible packets - * clear the dictionary at the proper times. - */ - - for (;;) { - if (ilen-- <= 0) { - db->in_count += (skb_out->len - 1); /* don't count the header */ - break; - } - - /* - * Accumulate bytes until we have a complete code. - * Then get the next code, relying on the 32-bit, - * unsigned accm to mask the result. - */ - - bitno -= 8; - accm |= *ibuf++ << bitno; - if (tgtbitno < bitno) - continue; - - incode = accm >> tgtbitno; - accm <<= n_bits; - bitno += n_bits; - - /* - * The dictionary must only be cleared at the end of a packet. - */ - - if (incode == CLEAR) { - if (ilen > 0) { - if (db->debug) - printk(KERN_DEBUG "bsd_decomp%d: bad CLEAR\n", db->unit); - return DECOMP_FATALERROR; /* probably a bug */ - } - bsd_clear(db); - break; - } - - if ((incode > max_ent + 2) || (incode > db->maxmaxcode) - || (incode > max_ent && oldcode == CLEAR)) { - if (db->debug) { - printk(KERN_DEBUG "bsd_decomp%d: bad code 0x%x oldcode=0x%x ", - db->unit, incode, oldcode); - printk(KERN_DEBUG "max_ent=0x%x skb->Len=%d seqno=%d\n", - max_ent, skb_out->len, db->seqno); - } - return DECOMP_FATALERROR; /* probably a bug */ - } - - /* Special case for KwKwK string. */ - if (incode > max_ent) { - finchar = oldcode; - extra = 1; - } else { - finchar = incode; - extra = 0; - } - - codelen = *(lens_ptr(db, finchar)); - if (skb_tailroom(skb_out) < codelen + extra) { - if (db->debug) { - printk(KERN_DEBUG "bsd_decomp%d: ran out of mru\n", db->unit); -#ifdef DEBUG - printk(KERN_DEBUG " len=%d, finchar=0x%x, codelen=%d,skblen=%d\n", - ilen, finchar, codelen, skb_out->len); -#endif - } - return DECOMP_FATALERROR; - } - - /* - * Decode this code and install it in the decompressed buffer. - */ - - p = skb_put(skb_out, codelen); - p += codelen; - while (finchar > LAST) { - struct bsd_dict *dictp2 = dict_ptr(db, finchar); - - dictp = dict_ptr(db, dictp2->cptr); - -#ifdef DEBUG - if (--codelen <= 0 || dictp->codem1 != finchar - 1) { - if (codelen <= 0) { - printk(KERN_ERR "bsd_decomp%d: fell off end of chain ", db->unit); - printk(KERN_ERR "0x%x at 0x%x by 0x%x, max_ent=0x%x\n", incode, finchar, dictp2->cptr, max_ent); - } else { - if (dictp->codem1 != finchar - 1) { - printk(KERN_ERR "bsd_decomp%d: bad code chain 0x%x finchar=0x%x ", db->unit, incode, finchar); - printk(KERN_ERR "oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode, dictp2->cptr, dictp->codem1); - } - } - return DECOMP_FATALERROR; - } -#endif - - { - u32 fcode = dictp->fcode; - *--p = (fcode >> 16) & 0xff; - finchar = fcode & 0xffff; - } - } - *--p = finchar; - -#ifdef DEBUG - if (--codelen != 0) - printk(KERN_ERR "bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n", db->unit, codelen, incode, max_ent); -#endif - - if (extra) /* the KwKwK case again */ - skb_put_u8(skb_out, finchar); - - /* - * If not first code in a packet, and - * if not out of code space, then allocate a new code. - * - * Keep the hash table correct so it can be used - * with uncompressed packets. - */ - if (oldcode != CLEAR && max_ent < db->maxmaxcode) { - struct bsd_dict *dictp2, *dictp3; - u16 *lens1, *lens2; - unsigned long fcode; - int hval, disp, indx; - - fcode = BSD_KEY(oldcode, finchar); - hval = BSD_HASH(oldcode, finchar, db->hshift); - dictp = dict_ptr(db, hval); - - /* look for a free hash table entry */ - if (dictp->codem1 < max_ent) { - disp = (hval == 0) ? 1 : hval; - do { - hval += disp; - if (hval >= db->hsize) - hval -= db->hsize; - dictp = dict_ptr(db, hval); - } while (dictp->codem1 < max_ent); - } - - /* - * Invalidate previous hash table entry - * assigned this code, and then take it over - */ - - dictp2 = dict_ptr(db, max_ent + 1); - indx = dictp2->cptr; - dictp3 = dict_ptr(db, indx); - - if (dictp3->codem1 == max_ent) - dictp3->codem1 = BADCODEM1; - - dictp2->cptr = hval; - dictp->codem1 = max_ent; - dictp->fcode = fcode; - db->max_ent = ++max_ent; - - /* Update the length of this string. */ - lens1 = lens_ptr(db, max_ent); - lens2 = lens_ptr(db, oldcode); - *lens1 = *lens2 + 1; - - /* Expand code size if needed. */ - if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) { - db->n_bits = ++n_bits; - tgtbitno = 32-n_bits; - } - } - oldcode = incode; - } - - ++db->comp_count; - ++db->uncomp_count; - db->comp_bytes += skb_in->len - BSD_OVHD; - db->uncomp_bytes += skb_out->len; - - if (bsd_check(db)) { - if (db->debug) - printk(KERN_DEBUG "bsd_decomp%d: peer should have cleared dictionary on %d\n", - db->unit, db->seqno - 1); - } - return skb_out->len; -} - -/************************************************************* - * Table of addresses for the BSD compression module - *************************************************************/ - -static struct isdn_ppp_compressor ippp_bsd_compress = { - .owner = THIS_MODULE, - .num = CI_BSD_COMPRESS, - .alloc = bsd_alloc, - .free = bsd_free, - .init = bsd_init, - .reset = bsd_reset, - .compress = bsd_compress, - .decompress = bsd_decompress, - .incomp = bsd_incomp, - .stat = bsd_stats, -}; - -/************************************************************* - * Module support routines - *************************************************************/ - -static int __init isdn_bsdcomp_init(void) -{ - int answer = isdn_ppp_register_compressor(&ippp_bsd_compress); - if (answer == 0) - printk(KERN_INFO "PPP BSD Compression module registered\n"); - return answer; -} - -static void __exit isdn_bsdcomp_exit(void) -{ - isdn_ppp_unregister_compressor(&ippp_bsd_compress); -} - -module_init(isdn_bsdcomp_init); -module_exit(isdn_bsdcomp_exit); diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c deleted file mode 100644 index 74ee00f5b310..000000000000 --- a/drivers/isdn/i4l/isdn_common.c +++ /dev/null @@ -1,2368 +0,0 @@ -/* $Id: isdn_common.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $ - * - * Linux ISDN subsystem, common used functions (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/isdn.h> -#include <linux/mutex.h> -#include "isdn_common.h" -#include "isdn_tty.h" -#include "isdn_net.h" -#include "isdn_ppp.h" -#ifdef CONFIG_ISDN_AUDIO -#include "isdn_audio.h" -#endif -#ifdef CONFIG_ISDN_DIVERSION_MODULE -#define CONFIG_ISDN_DIVERSION -#endif -#ifdef CONFIG_ISDN_DIVERSION -#include <linux/isdn_divertif.h> -#endif /* CONFIG_ISDN_DIVERSION */ -#include "isdn_v110.h" - -/* Debugflags */ -#undef ISDN_DEBUG_STATCALLB - -MODULE_DESCRIPTION("ISDN4Linux: link layer"); -MODULE_AUTHOR("Fritz Elfert"); -MODULE_LICENSE("GPL"); - -isdn_dev *dev; - -static DEFINE_MUTEX(isdn_mutex); -static char *isdn_revision = "$Revision: 1.1.2.3 $"; - -extern char *isdn_net_revision; -#ifdef CONFIG_ISDN_PPP -extern char *isdn_ppp_revision; -#else -static char *isdn_ppp_revision = ": none $"; -#endif -#ifdef CONFIG_ISDN_AUDIO -extern char *isdn_audio_revision; -#else -static char *isdn_audio_revision = ": none $"; -#endif -extern char *isdn_v110_revision; - -#ifdef CONFIG_ISDN_DIVERSION -static isdn_divert_if *divert_if; /* = NULL */ -#endif /* CONFIG_ISDN_DIVERSION */ - - -static int isdn_writebuf_stub(int, int, const u_char __user *, int); -static void set_global_features(void); -static int isdn_wildmat(char *s, char *p); -static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding); - -static inline void -isdn_lock_driver(isdn_driver_t *drv) -{ - try_module_get(drv->interface->owner); - drv->locks++; -} - -void -isdn_lock_drivers(void) -{ - int i; - - for (i = 0; i < ISDN_MAX_DRIVERS; i++) { - if (!dev->drv[i]) - continue; - isdn_lock_driver(dev->drv[i]); - } -} - -static inline void -isdn_unlock_driver(isdn_driver_t *drv) -{ - if (drv->locks > 0) { - drv->locks--; - module_put(drv->interface->owner); - } -} - -void -isdn_unlock_drivers(void) -{ - int i; - - for (i = 0; i < ISDN_MAX_DRIVERS; i++) { - if (!dev->drv[i]) - continue; - isdn_unlock_driver(dev->drv[i]); - } -} - -#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) -void -isdn_dumppkt(char *s, u_char *p, int len, int dumplen) -{ - int dumpc; - - printk(KERN_DEBUG "%s(%d) ", s, len); - for (dumpc = 0; (dumpc < dumplen) && (len); len--, dumpc++) - printk(" %02x", *p++); - printk("\n"); -} -#endif - -/* - * I picked the pattern-matching-functions from an old GNU-tar version (1.10) - * It was originally written and put to PD by rs@mirror.TMC.COM (Rich Salz) - */ -static int -isdn_star(char *s, char *p) -{ - while (isdn_wildmat(s, p)) { - if (*++s == '\0') - return (2); - } - return (0); -} - -/* - * Shell-type Pattern-matching for incoming caller-Ids - * This function gets a string in s and checks, if it matches the pattern - * given in p. - * - * Return: - * 0 = match. - * 1 = no match. - * 2 = no match. Would eventually match, if s would be longer. - * - * Possible Patterns: - * - * '?' matches one character - * '*' matches zero or more characters - * [xyz] matches the set of characters in brackets. - * [^xyz] matches any single character not in the set of characters - */ - -static int -isdn_wildmat(char *s, char *p) -{ - register int last; - register int matched; - register int reverse; - register int nostar = 1; - - if (!(*s) && !(*p)) - return (1); - for (; *p; s++, p++) - switch (*p) { - case '\\': - /* Literal match with following character. */ - p++; - /* fall through */ - default: - if (*s != *p) - return (*s == '\0') ? 2 : 1; - continue; - case '?': - /* Match anything. */ - if (*s == '\0') - return (2); - continue; - case '*': - nostar = 0; - /* Trailing star matches everything. */ - return (*++p ? isdn_star(s, p) : 0); - case '[': - /* [^....] means inverse character class. */ - if ((reverse = (p[1] == '^'))) - p++; - for (last = 0, matched = 0; *++p && (*p != ']'); last = *p) - /* This next line requires a good C compiler. */ - if (*p == '-' ? *s <= *++p && *s >= last : *s == *p) - matched = 1; - if (matched == reverse) - return (1); - continue; - } - return (*s == '\0') ? 0 : nostar; -} - -int isdn_msncmp(const char *msn1, const char *msn2) -{ - char TmpMsn1[ISDN_MSNLEN]; - char TmpMsn2[ISDN_MSNLEN]; - char *p; - - for (p = TmpMsn1; *msn1 && *msn1 != ':';) // Strip off a SPID - *p++ = *msn1++; - *p = '\0'; - - for (p = TmpMsn2; *msn2 && *msn2 != ':';) // Strip off a SPID - *p++ = *msn2++; - *p = '\0'; - - return isdn_wildmat(TmpMsn1, TmpMsn2); -} - -int -isdn_dc2minor(int di, int ch) -{ - int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (dev->chanmap[i] == ch && dev->drvmap[i] == di) - return i; - return -1; -} - -static int isdn_timer_cnt1 = 0; -static int isdn_timer_cnt2 = 0; -static int isdn_timer_cnt3 = 0; - -static void -isdn_timer_funct(struct timer_list *unused) -{ - int tf = dev->tflags; - if (tf & ISDN_TIMER_FAST) { - if (tf & ISDN_TIMER_MODEMREAD) - isdn_tty_readmodem(); - if (tf & ISDN_TIMER_MODEMPLUS) - isdn_tty_modem_escape(); - if (tf & ISDN_TIMER_MODEMXMIT) - isdn_tty_modem_xmit(); - } - if (tf & ISDN_TIMER_SLOW) { - if (++isdn_timer_cnt1 >= ISDN_TIMER_02SEC) { - isdn_timer_cnt1 = 0; - if (tf & ISDN_TIMER_NETDIAL) - isdn_net_dial(); - } - if (++isdn_timer_cnt2 >= ISDN_TIMER_1SEC) { - isdn_timer_cnt2 = 0; - if (tf & ISDN_TIMER_NETHANGUP) - isdn_net_autohup(); - if (++isdn_timer_cnt3 >= ISDN_TIMER_RINGING) { - isdn_timer_cnt3 = 0; - if (tf & ISDN_TIMER_MODEMRING) - isdn_tty_modem_ring(); - } - if (tf & ISDN_TIMER_CARRIER) - isdn_tty_carrier_timeout(); - } - } - if (tf) - mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES); -} - -void -isdn_timer_ctrl(int tf, int onoff) -{ - unsigned long flags; - int old_tflags; - - spin_lock_irqsave(&dev->timerlock, flags); - if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) { - /* If the slow-timer wasn't activated until now */ - isdn_timer_cnt1 = 0; - isdn_timer_cnt2 = 0; - } - old_tflags = dev->tflags; - if (onoff) - dev->tflags |= tf; - else - dev->tflags &= ~tf; - if (dev->tflags && !old_tflags) - mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES); - spin_unlock_irqrestore(&dev->timerlock, flags); -} - -/* - * Receive a packet from B-Channel. (Called from low-level-module) - */ -static void -isdn_receive_skb_callback(int di, int channel, struct sk_buff *skb) -{ - int i; - - if ((i = isdn_dc2minor(di, channel)) == -1) { - dev_kfree_skb(skb); - return; - } - /* Update statistics */ - dev->ibytes[i] += skb->len; - - /* First, try to deliver data to network-device */ - if (isdn_net_rcv_skb(i, skb)) - return; - - /* V.110 handling - * makes sense for async streams only, so it is - * called after possible net-device delivery. - */ - if (dev->v110[i]) { - atomic_inc(&dev->v110use[i]); - skb = isdn_v110_decode(dev->v110[i], skb); - atomic_dec(&dev->v110use[i]); - if (!skb) - return; - } - - /* No network-device found, deliver to tty or raw-channel */ - if (skb->len) { - if (isdn_tty_rcv_skb(i, di, channel, skb)) - return; - wake_up_interruptible(&dev->drv[di]->rcv_waitq[channel]); - } else - dev_kfree_skb(skb); -} - -/* - * Intercept command from Linklevel to Lowlevel. - * If layer 2 protocol is V.110 and this is not supported by current - * lowlevel-driver, use driver's transparent mode and handle V.110 in - * linklevel instead. - */ -int -isdn_command(isdn_ctrl *cmd) -{ - if (cmd->driver == -1) { - printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command); - return (1); - } - if (!dev->drv[cmd->driver]) { - printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d] NULL\n", - cmd->command, cmd->driver); - return (1); - } - if (!dev->drv[cmd->driver]->interface) { - printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d]->interface NULL\n", - cmd->command, cmd->driver); - return (1); - } - if (cmd->command == ISDN_CMD_SETL2) { - int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255); - unsigned long l2prot = (cmd->arg >> 8) & 255; - unsigned long features = (dev->drv[cmd->driver]->interface->features - >> ISDN_FEATURE_L2_SHIFT) & - ISDN_FEATURE_L2_MASK; - unsigned long l2_feature = (1 << l2prot); - - switch (l2prot) { - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - /* If V.110 requested, but not supported by - * HL-driver, set emulator-flag and change - * Layer-2 to transparent - */ - if (!(features & l2_feature)) { - dev->v110emu[idx] = l2prot; - cmd->arg = (cmd->arg & 255) | - (ISDN_PROTO_L2_TRANS << 8); - } else - dev->v110emu[idx] = 0; - } - } - return dev->drv[cmd->driver]->interface->command(cmd); -} - -void -isdn_all_eaz(int di, int ch) -{ - isdn_ctrl cmd; - - if (di < 0) - return; - cmd.driver = di; - cmd.arg = ch; - cmd.command = ISDN_CMD_SETEAZ; - cmd.parm.num[0] = '\0'; - isdn_command(&cmd); -} - -/* - * Begin of a CAPI like LL<->HL interface, currently used only for - * supplementary service (CAPI 2.0 part III) - */ -#include <linux/isdn/capicmd.h> - -static int -isdn_capi_rec_hl_msg(capi_msg *cm) -{ - switch (cm->Command) { - case CAPI_FACILITY: - /* in the moment only handled in tty */ - return (isdn_tty_capi_facility(cm)); - default: - return (-1); - } -} - -static int -isdn_status_callback(isdn_ctrl *c) -{ - int di; - u_long flags; - int i; - int r; - int retval = 0; - isdn_ctrl cmd; - isdn_net_dev *p; - - di = c->driver; - i = isdn_dc2minor(di, c->arg); - switch (c->command) { - case ISDN_STAT_BSENT: - if (i < 0) - return -1; - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - if (isdn_net_stat_callback(i, c)) - return 0; - if (isdn_v110_stat_callback(i, c)) - return 0; - if (isdn_tty_stat_callback(i, c)) - return 0; - wake_up_interruptible(&dev->drv[di]->snd_waitq[c->arg]); - break; - case ISDN_STAT_STAVAIL: - dev->drv[di]->stavail += c->arg; - wake_up_interruptible(&dev->drv[di]->st_waitq); - break; - case ISDN_STAT_RUN: - dev->drv[di]->flags |= DRV_FLAG_RUNNING; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (dev->drvmap[i] == di) - isdn_all_eaz(di, dev->chanmap[i]); - set_global_features(); - break; - case ISDN_STAT_STOP: - dev->drv[di]->flags &= ~DRV_FLAG_RUNNING; - break; - case ISDN_STAT_ICALL: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "ICALL (net): %d %ld %s\n", di, c->arg, c->parm.num); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) { - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_HANGUP; - isdn_command(&cmd); - return 0; - } - /* Try to find a network-interface which will accept incoming call */ - r = ((c->command == ISDN_STAT_ICALLW) ? 0 : isdn_net_find_icall(di, c->arg, i, &c->parm.setup)); - switch (r) { - case 0: - /* No network-device replies. - * Try ttyI's. - * These return 0 on no match, 1 on match and - * 3 on eventually match, if CID is longer. - */ - if (c->command == ISDN_STAT_ICALL) - if ((retval = isdn_tty_find_icall(di, c->arg, &c->parm.setup))) return (retval); -#ifdef CONFIG_ISDN_DIVERSION - if (divert_if) - if ((retval = divert_if->stat_callback(c))) - return (retval); /* processed */ -#endif /* CONFIG_ISDN_DIVERSION */ - if ((!retval) && (dev->drv[di]->flags & DRV_FLAG_REJBUS)) { - /* No tty responding */ - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_HANGUP; - isdn_command(&cmd); - retval = 2; - } - break; - case 1: - /* Schedule connection-setup */ - isdn_net_dial(); - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_ACCEPTD; - for (p = dev->netdev; p; p = p->next) - if (p->local->isdn_channel == cmd.arg) - { - strcpy(cmd.parm.setup.eazmsn, p->local->msn); - isdn_command(&cmd); - retval = 1; - break; - } - break; - - case 2: /* For calling back, first reject incoming call ... */ - case 3: /* Interface found, but down, reject call actively */ - retval = 2; - printk(KERN_INFO "isdn: Rejecting Call\n"); - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_HANGUP; - isdn_command(&cmd); - if (r == 3) - break; - /* Fall through */ - case 4: - /* ... then start callback. */ - isdn_net_dial(); - break; - case 5: - /* Number would eventually match, if longer */ - retval = 3; - break; - } -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "ICALL: ret=%d\n", retval); -#endif - return retval; - break; - case ISDN_STAT_CINF: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "CINF: %ld %s\n", c->arg, c->parm.num); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - if (strcmp(c->parm.num, "0")) - isdn_net_stat_callback(i, c); - isdn_tty_stat_callback(i, c); - break; - case ISDN_STAT_CAUSE: -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "CAUSE: %ld %s\n", c->arg, c->parm.num); -#endif - printk(KERN_INFO "isdn: %s,ch%ld cause: %s\n", - dev->drvid[di], c->arg, c->parm.num); - isdn_tty_stat_callback(i, c); -#ifdef CONFIG_ISDN_DIVERSION - if (divert_if) - divert_if->stat_callback(c); -#endif /* CONFIG_ISDN_DIVERSION */ - break; - case ISDN_STAT_DISPLAY: -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "DISPLAY: %ld %s\n", c->arg, c->parm.display); -#endif - isdn_tty_stat_callback(i, c); -#ifdef CONFIG_ISDN_DIVERSION - if (divert_if) - divert_if->stat_callback(c); -#endif /* CONFIG_ISDN_DIVERSION */ - break; - case ISDN_STAT_DCONN: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "DCONN: %ld\n", c->arg); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - /* Find any net-device, waiting for D-channel setup */ - if (isdn_net_stat_callback(i, c)) - break; - isdn_v110_stat_callback(i, c); - /* Find any ttyI, waiting for D-channel setup */ - if (isdn_tty_stat_callback(i, c)) { - cmd.driver = di; - cmd.arg = c->arg; - cmd.command = ISDN_CMD_ACCEPTB; - isdn_command(&cmd); - break; - } - break; - case ISDN_STAT_DHUP: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "DHUP: %ld\n", c->arg); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - dev->drv[di]->online &= ~(1 << (c->arg)); - isdn_info_update(); - /* Signal hangup to network-devices */ - if (isdn_net_stat_callback(i, c)) - break; - isdn_v110_stat_callback(i, c); - if (isdn_tty_stat_callback(i, c)) - break; -#ifdef CONFIG_ISDN_DIVERSION - if (divert_if) - divert_if->stat_callback(c); -#endif /* CONFIG_ISDN_DIVERSION */ - break; - break; - case ISDN_STAT_BCONN: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "BCONN: %ld\n", c->arg); -#endif - /* Signal B-channel-connect to network-devices */ - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - dev->drv[di]->online |= (1 << (c->arg)); - isdn_info_update(); - if (isdn_net_stat_callback(i, c)) - break; - isdn_v110_stat_callback(i, c); - if (isdn_tty_stat_callback(i, c)) - break; - break; - case ISDN_STAT_BHUP: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "BHUP: %ld\n", c->arg); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - dev->drv[di]->online &= ~(1 << (c->arg)); - isdn_info_update(); -#ifdef CONFIG_ISDN_X25 - /* Signal hangup to network-devices */ - if (isdn_net_stat_callback(i, c)) - break; -#endif - isdn_v110_stat_callback(i, c); - if (isdn_tty_stat_callback(i, c)) - break; - break; - case ISDN_STAT_NODCH: - if (i < 0) - return -1; -#ifdef ISDN_DEBUG_STATCALLB - printk(KERN_DEBUG "NODCH: %ld\n", c->arg); -#endif - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - return 0; - if (isdn_net_stat_callback(i, c)) - break; - if (isdn_tty_stat_callback(i, c)) - break; - break; - case ISDN_STAT_ADDCH: - spin_lock_irqsave(&dev->lock, flags); - if (isdn_add_channels(dev->drv[di], di, c->arg, 1)) { - spin_unlock_irqrestore(&dev->lock, flags); - return -1; - } - spin_unlock_irqrestore(&dev->lock, flags); - isdn_info_update(); - break; - case ISDN_STAT_DISCH: - spin_lock_irqsave(&dev->lock, flags); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if ((dev->drvmap[i] == di) && - (dev->chanmap[i] == c->arg)) { - if (c->parm.num[0]) - dev->usage[i] &= ~ISDN_USAGE_DISABLED; - else - if (USG_NONE(dev->usage[i])) { - dev->usage[i] |= ISDN_USAGE_DISABLED; - } - else - retval = -1; - break; - } - spin_unlock_irqrestore(&dev->lock, flags); - isdn_info_update(); - break; - case ISDN_STAT_UNLOAD: - while (dev->drv[di]->locks > 0) { - isdn_unlock_driver(dev->drv[di]); - } - spin_lock_irqsave(&dev->lock, flags); - isdn_tty_stat_callback(i, c); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (dev->drvmap[i] == di) { - dev->drvmap[i] = -1; - dev->chanmap[i] = -1; - dev->usage[i] &= ~ISDN_USAGE_DISABLED; - } - dev->drivers--; - dev->channels -= dev->drv[di]->channels; - kfree(dev->drv[di]->rcverr); - kfree(dev->drv[di]->rcvcount); - for (i = 0; i < dev->drv[di]->channels; i++) - skb_queue_purge(&dev->drv[di]->rpqueue[i]); - kfree(dev->drv[di]->rpqueue); - kfree(dev->drv[di]->rcv_waitq); - kfree(dev->drv[di]); - dev->drv[di] = NULL; - dev->drvid[di][0] = '\0'; - isdn_info_update(); - set_global_features(); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - case ISDN_STAT_L1ERR: - break; - case CAPI_PUT_MESSAGE: - return (isdn_capi_rec_hl_msg(&c->parm.cmsg)); -#ifdef CONFIG_ISDN_TTY_FAX - case ISDN_STAT_FAXIND: - isdn_tty_stat_callback(i, c); - break; -#endif -#ifdef CONFIG_ISDN_AUDIO - case ISDN_STAT_AUDIO: - isdn_tty_stat_callback(i, c); - break; -#endif -#ifdef CONFIG_ISDN_DIVERSION - case ISDN_STAT_PROT: - case ISDN_STAT_REDIR: - if (divert_if) - return (divert_if->stat_callback(c)); -#endif /* CONFIG_ISDN_DIVERSION */ - /* fall through */ - default: - return -1; - } - return 0; -} - -/* - * Get integer from char-pointer, set pointer to end of number - */ -int -isdn_getnum(char **p) -{ - int v = -1; - - while (*p[0] >= '0' && *p[0] <= '9') - v = ((v < 0) ? 0 : (v * 10)) + (int) ((*p[0]++) - '0'); - return v; -} - -#define DLE 0x10 - -/* - * isdn_readbchan() tries to get data from the read-queue. - * It MUST be called with interrupts off. - * - * Be aware that this is not an atomic operation when sleep != 0, even though - * interrupts are turned off! Well, like that we are currently only called - * on behalf of a read system call on raw device files (which are documented - * to be dangerous and for debugging purpose only). The inode semaphore - * takes care that this is not called for the same minor device number while - * we are sleeping, but access is not serialized against simultaneous read() - * from the corresponding ttyI device. Can other ugly events, like changes - * of the mapping (di,ch)<->minor, happen during the sleep? --he - */ -int -isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue_head_t *sleep) -{ - int count; - int count_pull; - int count_put; - int dflag; - struct sk_buff *skb; - u_char *cp; - - if (!dev->drv[di]) - return 0; - if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) { - if (sleep) - wait_event_interruptible(*sleep, - !skb_queue_empty(&dev->drv[di]->rpqueue[channel])); - else - return 0; - } - if (len > dev->drv[di]->rcvcount[channel]) - len = dev->drv[di]->rcvcount[channel]; - cp = buf; - count = 0; - while (len) { - if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel]))) - break; -#ifdef CONFIG_ISDN_AUDIO - if (ISDN_AUDIO_SKB_LOCK(skb)) - break; - ISDN_AUDIO_SKB_LOCK(skb) = 1; - if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) { - char *p = skb->data; - unsigned long DLEmask = (1 << channel); - - dflag = 0; - count_pull = count_put = 0; - while ((count_pull < skb->len) && (len > 0)) { - len--; - if (dev->drv[di]->DLEflag & DLEmask) { - *cp++ = DLE; - dev->drv[di]->DLEflag &= ~DLEmask; - } else { - *cp++ = *p; - if (*p == DLE) { - dev->drv[di]->DLEflag |= DLEmask; - (ISDN_AUDIO_SKB_DLECOUNT(skb))--; - } - p++; - count_pull++; - } - count_put++; - } - if (count_pull >= skb->len) - dflag = 1; - } else { -#endif - /* No DLE's in buff, so simply copy it */ - dflag = 1; - if ((count_pull = skb->len) > len) { - count_pull = len; - dflag = 0; - } - count_put = count_pull; - skb_copy_from_linear_data(skb, cp, count_put); - cp += count_put; - len -= count_put; -#ifdef CONFIG_ISDN_AUDIO - } -#endif - count += count_put; - if (fp) { - memset(fp, 0, count_put); - fp += count_put; - } - if (dflag) { - /* We got all the data in this buff. - * Now we can dequeue it. - */ - if (fp) - *(fp - 1) = 0xff; -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); - dev_kfree_skb(skb); - } else { - /* Not yet emptied this buff, so it - * must stay in the queue, for further calls - * but we pull off the data we got until now. - */ - skb_pull(skb, count_pull); -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - } - dev->drv[di]->rcvcount[channel] -= count_put; - } - return count; -} - -/* - * isdn_readbchan_tty() tries to get data from the read-queue. - * It MUST be called with interrupts off. - * - * Be aware that this is not an atomic operation when sleep != 0, even though - * interrupts are turned off! Well, like that we are currently only called - * on behalf of a read system call on raw device files (which are documented - * to be dangerous and for debugging purpose only). The inode semaphore - * takes care that this is not called for the same minor device number while - * we are sleeping, but access is not serialized against simultaneous read() - * from the corresponding ttyI device. Can other ugly events, like changes - * of the mapping (di,ch)<->minor, happen during the sleep? --he - */ -int -isdn_readbchan_tty(int di, int channel, struct tty_port *port, int cisco_hack) -{ - int count; - int count_pull; - int count_put; - int dflag; - struct sk_buff *skb; - char last = 0; - int len; - - if (!dev->drv[di]) - return 0; - if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) - return 0; - - len = tty_buffer_request_room(port, dev->drv[di]->rcvcount[channel]); - if (len == 0) - return len; - - count = 0; - while (len) { - if (!(skb = skb_peek(&dev->drv[di]->rpqueue[channel]))) - break; -#ifdef CONFIG_ISDN_AUDIO - if (ISDN_AUDIO_SKB_LOCK(skb)) - break; - ISDN_AUDIO_SKB_LOCK(skb) = 1; - if ((ISDN_AUDIO_SKB_DLECOUNT(skb)) || (dev->drv[di]->DLEflag & (1 << channel))) { - char *p = skb->data; - unsigned long DLEmask = (1 << channel); - - dflag = 0; - count_pull = count_put = 0; - while ((count_pull < skb->len) && (len > 0)) { - /* push every character but the last to the tty buffer directly */ - if (count_put) - tty_insert_flip_char(port, last, TTY_NORMAL); - len--; - if (dev->drv[di]->DLEflag & DLEmask) { - last = DLE; - dev->drv[di]->DLEflag &= ~DLEmask; - } else { - last = *p; - if (last == DLE) { - dev->drv[di]->DLEflag |= DLEmask; - (ISDN_AUDIO_SKB_DLECOUNT(skb))--; - } - p++; - count_pull++; - } - count_put++; - } - if (count_pull >= skb->len) - dflag = 1; - } else { -#endif - /* No DLE's in buff, so simply copy it */ - dflag = 1; - if ((count_pull = skb->len) > len) { - count_pull = len; - dflag = 0; - } - count_put = count_pull; - if (count_put > 1) - tty_insert_flip_string(port, skb->data, count_put - 1); - last = skb->data[count_put - 1]; - len -= count_put; -#ifdef CONFIG_ISDN_AUDIO - } -#endif - count += count_put; - if (dflag) { - /* We got all the data in this buff. - * Now we can dequeue it. - */ - if (cisco_hack) - tty_insert_flip_char(port, last, 0xFF); - else - tty_insert_flip_char(port, last, TTY_NORMAL); -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - skb = skb_dequeue(&dev->drv[di]->rpqueue[channel]); - dev_kfree_skb(skb); - } else { - tty_insert_flip_char(port, last, TTY_NORMAL); - /* Not yet emptied this buff, so it - * must stay in the queue, for further calls - * but we pull off the data we got until now. - */ - skb_pull(skb, count_pull); -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - } - dev->drv[di]->rcvcount[channel] -= count_put; - } - return count; -} - - -static inline int -isdn_minor2drv(int minor) -{ - return (dev->drvmap[minor]); -} - -static inline int -isdn_minor2chan(int minor) -{ - return (dev->chanmap[minor]); -} - -static char * -isdn_statstr(void) -{ - static char istatbuf[2048]; - char *p; - int i; - - sprintf(istatbuf, "idmap:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - sprintf(p, "%s ", (dev->drvmap[i] < 0) ? "-" : dev->drvid[dev->drvmap[i]]); - p = istatbuf + strlen(istatbuf); - } - sprintf(p, "\nchmap:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - sprintf(p, "%d ", dev->chanmap[i]); - p = istatbuf + strlen(istatbuf); - } - sprintf(p, "\ndrmap:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - sprintf(p, "%d ", dev->drvmap[i]); - p = istatbuf + strlen(istatbuf); - } - sprintf(p, "\nusage:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - sprintf(p, "%d ", dev->usage[i]); - p = istatbuf + strlen(istatbuf); - } - sprintf(p, "\nflags:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_DRIVERS; i++) { - if (dev->drv[i]) { - sprintf(p, "%ld ", dev->drv[i]->online); - p = istatbuf + strlen(istatbuf); - } else { - sprintf(p, "? "); - p = istatbuf + strlen(istatbuf); - } - } - sprintf(p, "\nphone:\t"); - p = istatbuf + strlen(istatbuf); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - sprintf(p, "%s ", dev->num[i]); - p = istatbuf + strlen(istatbuf); - } - sprintf(p, "\n"); - return istatbuf; -} - -/* Module interface-code */ - -void -isdn_info_update(void) -{ - infostruct *p = dev->infochain; - - while (p) { - *(p->private) = 1; - p = (infostruct *) p->next; - } - wake_up_interruptible(&(dev->info_waitq)); -} - -static ssize_t -isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off) -{ - uint minor = iminor(file_inode(file)); - int len = 0; - int drvidx; - int chidx; - int retval; - char *p; - - mutex_lock(&isdn_mutex); - if (minor == ISDN_MINOR_STATUS) { - if (!file->private_data) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } - wait_event_interruptible(dev->info_waitq, - file->private_data); - } - p = isdn_statstr(); - file->private_data = NULL; - if ((len = strlen(p)) <= count) { - if (copy_to_user(buf, p, len)) { - retval = -EFAULT; - goto out; - } - *off += len; - retval = len; - goto out; - } - retval = 0; - goto out; - } - if (!dev->drivers) { - retval = -ENODEV; - goto out; - } - if (minor <= ISDN_MINOR_BMAX) { - printk(KERN_WARNING "isdn_read minor %d obsolete!\n", minor); - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { - retval = -ENODEV; - goto out; - } - chidx = isdn_minor2chan(minor); - if (!(p = kmalloc(count, GFP_KERNEL))) { - retval = -ENOMEM; - goto out; - } - len = isdn_readbchan(drvidx, chidx, p, NULL, count, - &dev->drv[drvidx]->rcv_waitq[chidx]); - *off += len; - if (copy_to_user(buf, p, len)) - len = -EFAULT; - kfree(p); - retval = len; - goto out; - } - if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - if (!dev->drv[drvidx]->stavail) { - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } - wait_event_interruptible(dev->drv[drvidx]->st_waitq, - dev->drv[drvidx]->stavail); - } - if (dev->drv[drvidx]->interface->readstat) { - if (count > dev->drv[drvidx]->stavail) - count = dev->drv[drvidx]->stavail; - len = dev->drv[drvidx]->interface->readstat(buf, count, - drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL)); - if (len < 0) { - retval = len; - goto out; - } - } else { - len = 0; - } - if (len) - dev->drv[drvidx]->stavail -= len; - else - dev->drv[drvidx]->stavail = 0; - *off += len; - retval = len; - goto out; - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - retval = isdn_ppp_read(minor - ISDN_MINOR_PPP, file, buf, count); - goto out; - } -#endif - retval = -ENODEV; -out: - mutex_unlock(&isdn_mutex); - return retval; -} - -static ssize_t -isdn_write(struct file *file, const char __user *buf, size_t count, loff_t *off) -{ - uint minor = iminor(file_inode(file)); - int drvidx; - int chidx; - int retval; - - if (minor == ISDN_MINOR_STATUS) - return -EPERM; - if (!dev->drivers) - return -ENODEV; - - mutex_lock(&isdn_mutex); - if (minor <= ISDN_MINOR_BMAX) { - printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor); - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) { - retval = -ENODEV; - goto out; - } - chidx = isdn_minor2chan(minor); - wait_event_interruptible(dev->drv[drvidx]->snd_waitq[chidx], - (retval = isdn_writebuf_stub(drvidx, chidx, buf, count))); - goto out; - } - if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) { - retval = -ENODEV; - goto out; - } - /* - * We want to use the isdnctrl device to load the firmware - * - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; - */ - if (dev->drv[drvidx]->interface->writecmd) - retval = dev->drv[drvidx]->interface-> - writecmd(buf, count, drvidx, - isdn_minor2chan(minor - ISDN_MINOR_CTRL)); - else - retval = count; - goto out; - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count); - goto out; - } -#endif - retval = -ENODEV; -out: - mutex_unlock(&isdn_mutex); - return retval; -} - -static __poll_t -isdn_poll(struct file *file, poll_table *wait) -{ - __poll_t mask = 0; - unsigned int minor = iminor(file_inode(file)); - int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - - mutex_lock(&isdn_mutex); - if (minor == ISDN_MINOR_STATUS) { - poll_wait(file, &(dev->info_waitq), wait); - /* mask = EPOLLOUT | EPOLLWRNORM; */ - if (file->private_data) { - mask |= EPOLLIN | EPOLLRDNORM; - } - goto out; - } - if (minor >= ISDN_MINOR_CTRL && minor <= ISDN_MINOR_CTRLMAX) { - if (drvidx < 0) { - /* driver deregistered while file open */ - mask = EPOLLHUP; - goto out; - } - poll_wait(file, &(dev->drv[drvidx]->st_waitq), wait); - mask = EPOLLOUT | EPOLLWRNORM; - if (dev->drv[drvidx]->stavail) { - mask |= EPOLLIN | EPOLLRDNORM; - } - goto out; - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - mask = isdn_ppp_poll(file, wait); - goto out; - } -#endif - mask = EPOLLERR; -out: - mutex_unlock(&isdn_mutex); - return mask; -} - - -static int -isdn_ioctl(struct file *file, uint cmd, ulong arg) -{ - uint minor = iminor(file_inode(file)); - isdn_ctrl c; - int drvidx; - int ret; - int i; - char __user *p; - char *s; - union iocpar { - char name[10]; - char bname[22]; - isdn_ioctl_struct iocts; - isdn_net_ioctl_phone phone; - isdn_net_ioctl_cfg cfg; - } iocpar; - void __user *argp = (void __user *)arg; - -#define name iocpar.name -#define bname iocpar.bname -#define iocts iocpar.iocts -#define phone iocpar.phone -#define cfg iocpar.cfg - - if (minor == ISDN_MINOR_STATUS) { - switch (cmd) { - case IIOCGETDVR: - return (TTY_DV + - (NET_DV << 8) + - (INF_DV << 16)); - case IIOCGETCPS: - if (arg) { - ulong __user *p = argp; - int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - put_user(dev->ibytes[i], p++); - put_user(dev->obytes[i], p++); - } - return 0; - } else - return -EINVAL; - break; - case IIOCNETGPN: - /* Get peer phone number of a connected - * isdn network interface */ - if (arg) { - if (copy_from_user(&phone, argp, sizeof(phone))) - return -EFAULT; - return isdn_net_getpeer(&phone, argp); - } else - return -EINVAL; - default: - return -EINVAL; - } - } - if (!dev->drivers) - return -ENODEV; - if (minor <= ISDN_MINOR_BMAX) { - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - return -ENODEV; - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - return -ENODEV; - return 0; - } - if (minor <= ISDN_MINOR_CTRLMAX) { -/* - * isdn net devices manage lots of configuration variables as linked lists. - * Those lists must only be manipulated from user space. Some of the ioctl's - * service routines access user space and are not atomic. Therefore, ioctl's - * manipulating the lists and ioctl's sleeping while accessing the lists - * are serialized by means of a semaphore. - */ - switch (cmd) { - case IIOCNETDWRSET: - printk(KERN_INFO "INFO: ISDN_DW_ABC_EXTENSION not enabled\n"); - return (-EINVAL); - case IIOCNETLCR: - printk(KERN_INFO "INFO: ISDN_ABC_LCR_SUPPORT not enabled\n"); - return -ENODEV; - case IIOCNETAIF: - /* Add a network-interface */ - if (arg) { - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - s = name; - } else { - s = NULL; - } - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - if ((s = isdn_net_new(s, NULL))) { - if (copy_to_user(argp, s, strlen(s) + 1)) { - ret = -EFAULT; - } else { - ret = 0; - } - } else - ret = -ENODEV; - mutex_unlock(&dev->mtx); - return ret; - case IIOCNETASL: - /* Add a slave to a network-interface */ - if (arg) { - if (copy_from_user(bname, argp, sizeof(bname) - 1)) - return -EFAULT; - bname[sizeof(bname)-1] = 0; - } else - return -EINVAL; - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - if ((s = isdn_net_newslave(bname))) { - if (copy_to_user(argp, s, strlen(s) + 1)) { - ret = -EFAULT; - } else { - ret = 0; - } - } else - ret = -ENODEV; - mutex_unlock(&dev->mtx); - return ret; - case IIOCNETDIF: - /* Delete a network-interface */ - if (arg) { - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - ret = isdn_net_rm(name); - mutex_unlock(&dev->mtx); - return ret; - } else - return -EINVAL; - case IIOCNETSCF: - /* Set configurable parameters of a network-interface */ - if (arg) { - if (copy_from_user(&cfg, argp, sizeof(cfg))) - return -EFAULT; - return isdn_net_setcfg(&cfg); - } else - return -EINVAL; - case IIOCNETGCF: - /* Get configurable parameters of a network-interface */ - if (arg) { - if (copy_from_user(&cfg, argp, sizeof(cfg))) - return -EFAULT; - if (!(ret = isdn_net_getcfg(&cfg))) { - if (copy_to_user(argp, &cfg, sizeof(cfg))) - return -EFAULT; - } - return ret; - } else - return -EINVAL; - case IIOCNETANM: - /* Add a phone-number to a network-interface */ - if (arg) { - if (copy_from_user(&phone, argp, sizeof(phone))) - return -EFAULT; - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - ret = isdn_net_addphone(&phone); - mutex_unlock(&dev->mtx); - return ret; - } else - return -EINVAL; - case IIOCNETGNM: - /* Get list of phone-numbers of a network-interface */ - if (arg) { - if (copy_from_user(&phone, argp, sizeof(phone))) - return -EFAULT; - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - ret = isdn_net_getphones(&phone, argp); - mutex_unlock(&dev->mtx); - return ret; - } else - return -EINVAL; - case IIOCNETDNM: - /* Delete a phone-number of a network-interface */ - if (arg) { - if (copy_from_user(&phone, argp, sizeof(phone))) - return -EFAULT; - ret = mutex_lock_interruptible(&dev->mtx); - if (ret) return ret; - ret = isdn_net_delphone(&phone); - mutex_unlock(&dev->mtx); - return ret; - } else - return -EINVAL; - case IIOCNETDIL: - /* Force dialing of a network-interface */ - if (arg) { - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - return isdn_net_force_dial(name); - } else - return -EINVAL; -#ifdef CONFIG_ISDN_PPP - case IIOCNETALN: - if (!arg) - return -EINVAL; - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - return isdn_ppp_dial_slave(name); - case IIOCNETDLN: - if (!arg) - return -EINVAL; - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - return isdn_ppp_hangup_slave(name); -#endif - case IIOCNETHUP: - /* Force hangup of a network-interface */ - if (!arg) - return -EINVAL; - if (copy_from_user(name, argp, sizeof(name))) - return -EFAULT; - return isdn_net_force_hangup(name); - break; - case IIOCSETVER: - dev->net_verbose = arg; - printk(KERN_INFO "isdn: Verbose-Level is %d\n", dev->net_verbose); - return 0; - case IIOCSETGST: - if (arg) - dev->global_flags |= ISDN_GLOBAL_STOPPED; - else - dev->global_flags &= ~ISDN_GLOBAL_STOPPED; - printk(KERN_INFO "isdn: Global Mode %s\n", - (dev->global_flags & ISDN_GLOBAL_STOPPED) ? "stopped" : "running"); - return 0; - case IIOCSETBRJ: - drvidx = -1; - if (arg) { - int i; - char *p; - if (copy_from_user(&iocts, argp, - sizeof(isdn_ioctl_struct))) - return -EFAULT; - iocts.drvid[sizeof(iocts.drvid) - 1] = 0; - if (strlen(iocts.drvid)) { - if ((p = strchr(iocts.drvid, ','))) - *p = 0; - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } - } - if (drvidx == -1) - return -ENODEV; - if (iocts.arg) - dev->drv[drvidx]->flags |= DRV_FLAG_REJBUS; - else - dev->drv[drvidx]->flags &= ~DRV_FLAG_REJBUS; - return 0; - case IIOCSIGPRF: - dev->profd = current; - return 0; - break; - case IIOCGETPRF: - /* Get all Modem-Profiles */ - if (arg) { - char __user *p = argp; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (copy_to_user(p, dev->mdm.info[i].emu.profile, - ISDN_MODEM_NUMREG)) - return -EFAULT; - p += ISDN_MODEM_NUMREG; - if (copy_to_user(p, dev->mdm.info[i].emu.pmsn, ISDN_MSNLEN)) - return -EFAULT; - p += ISDN_MSNLEN; - if (copy_to_user(p, dev->mdm.info[i].emu.plmsn, ISDN_LMSNLEN)) - return -EFAULT; - p += ISDN_LMSNLEN; - } - return (ISDN_MODEM_NUMREG + ISDN_MSNLEN + ISDN_LMSNLEN) * ISDN_MAX_CHANNELS; - } else - return -EINVAL; - break; - case IIOCSETPRF: - /* Set all Modem-Profiles */ - if (arg) { - char __user *p = argp; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (copy_from_user(dev->mdm.info[i].emu.profile, p, - ISDN_MODEM_NUMREG)) - return -EFAULT; - p += ISDN_MODEM_NUMREG; - if (copy_from_user(dev->mdm.info[i].emu.plmsn, p, ISDN_LMSNLEN)) - return -EFAULT; - p += ISDN_LMSNLEN; - if (copy_from_user(dev->mdm.info[i].emu.pmsn, p, ISDN_MSNLEN)) - return -EFAULT; - p += ISDN_MSNLEN; - } - return 0; - } else - return -EINVAL; - break; - case IIOCSETMAP: - case IIOCGETMAP: - /* Set/Get MSN->EAZ-Mapping for a driver */ - if (arg) { - - if (copy_from_user(&iocts, argp, - sizeof(isdn_ioctl_struct))) - return -EFAULT; - iocts.drvid[sizeof(iocts.drvid) - 1] = 0; - if (strlen(iocts.drvid)) { - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } else - drvidx = 0; - if (drvidx == -1) - return -ENODEV; - if (cmd == IIOCSETMAP) { - int loop = 1; - - p = (char __user *) iocts.arg; - i = 0; - while (loop) { - int j = 0; - - while (1) { - get_user(bname[j], p++); - switch (bname[j]) { - case '\0': - loop = 0; - /* Fall through */ - case ',': - bname[j] = '\0'; - strcpy(dev->drv[drvidx]->msn2eaz[i], bname); - j = ISDN_MSNLEN; - break; - default: - j++; - } - if (j >= ISDN_MSNLEN) - break; - } - if (++i > 9) - break; - } - } else { - p = (char __user *) iocts.arg; - for (i = 0; i < 10; i++) { - snprintf(bname, sizeof(bname), "%s%s", - strlen(dev->drv[drvidx]->msn2eaz[i]) ? - dev->drv[drvidx]->msn2eaz[i] : "_", - (i < 9) ? "," : "\0"); - if (copy_to_user(p, bname, strlen(bname) + 1)) - return -EFAULT; - p += strlen(bname); - } - } - return 0; - } else - return -EINVAL; - case IIOCDBGVAR: - return -EINVAL; - default: - if ((cmd & IIOCDRVCTL) == IIOCDRVCTL) - cmd = ((cmd >> _IOC_NRSHIFT) & _IOC_NRMASK) & ISDN_DRVIOCTL_MASK; - else - return -EINVAL; - if (arg) { - int i; - char *p; - if (copy_from_user(&iocts, argp, sizeof(isdn_ioctl_struct))) - return -EFAULT; - iocts.drvid[sizeof(iocts.drvid) - 1] = 0; - if (strlen(iocts.drvid)) { - if ((p = strchr(iocts.drvid, ','))) - *p = 0; - drvidx = -1; - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (!(strcmp(dev->drvid[i], iocts.drvid))) { - drvidx = i; - break; - } - } else - drvidx = 0; - if (drvidx == -1) - return -ENODEV; - c.driver = drvidx; - c.command = ISDN_CMD_IOCTL; - c.arg = cmd; - memcpy(c.parm.num, &iocts.arg, sizeof(ulong)); - ret = isdn_command(&c); - memcpy(&iocts.arg, c.parm.num, sizeof(ulong)); - if (copy_to_user(argp, &iocts, sizeof(isdn_ioctl_struct))) - return -EFAULT; - return ret; - } else - return -EINVAL; - } - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - return (isdn_ppp_ioctl(minor - ISDN_MINOR_PPP, file, cmd, arg)); -#endif - return -ENODEV; - -#undef name -#undef bname -#undef iocts -#undef phone -#undef cfg -} - -static long -isdn_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&isdn_mutex); - ret = isdn_ioctl(file, cmd, arg); - mutex_unlock(&isdn_mutex); - - return ret; -} - -/* - * Open the device code. - */ -static int -isdn_open(struct inode *ino, struct file *filep) -{ - uint minor = iminor(ino); - int drvidx; - int chidx; - int retval = -ENODEV; - - mutex_lock(&isdn_mutex); - if (minor == ISDN_MINOR_STATUS) { - infostruct *p; - - if ((p = kmalloc(sizeof(infostruct), GFP_KERNEL))) { - p->next = (char *) dev->infochain; - p->private = (char *) &(filep->private_data); - dev->infochain = p; - /* At opening we allow a single update */ - filep->private_data = (char *) 1; - retval = 0; - goto out; - } else { - retval = -ENOMEM; - goto out; - } - } - if (!dev->channels) - goto out; - if (minor <= ISDN_MINOR_BMAX) { - printk(KERN_WARNING "isdn_open minor %d obsolete!\n", minor); - drvidx = isdn_minor2drv(minor); - if (drvidx < 0) - goto out; - chidx = isdn_minor2chan(minor); - if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) - goto out; - if (!(dev->drv[drvidx]->online & (1 << chidx))) - goto out; - isdn_lock_drivers(); - retval = 0; - goto out; - } - if (minor <= ISDN_MINOR_CTRLMAX) { - drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); - if (drvidx < 0) - goto out; - isdn_lock_drivers(); - retval = 0; - goto out; - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) { - retval = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep); - if (retval == 0) - isdn_lock_drivers(); - goto out; - } -#endif -out: - nonseekable_open(ino, filep); - mutex_unlock(&isdn_mutex); - return retval; -} - -static int -isdn_close(struct inode *ino, struct file *filep) -{ - uint minor = iminor(ino); - - mutex_lock(&isdn_mutex); - if (minor == ISDN_MINOR_STATUS) { - infostruct *p = dev->infochain; - infostruct *q = NULL; - - while (p) { - if (p->private == (char *) &(filep->private_data)) { - if (q) - q->next = p->next; - else - dev->infochain = (infostruct *) (p->next); - kfree(p); - goto out; - } - q = p; - p = (infostruct *) (p->next); - } - printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); - goto out; - } - isdn_unlock_drivers(); - if (minor <= ISDN_MINOR_BMAX) - goto out; - if (minor <= ISDN_MINOR_CTRLMAX) { - if (dev->profd == current) - dev->profd = NULL; - goto out; - } -#ifdef CONFIG_ISDN_PPP - if (minor <= ISDN_MINOR_PPPMAX) - isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); -#endif - -out: - mutex_unlock(&isdn_mutex); - return 0; -} - -static const struct file_operations isdn_fops = -{ - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = isdn_read, - .write = isdn_write, - .poll = isdn_poll, - .unlocked_ioctl = isdn_unlocked_ioctl, - .open = isdn_open, - .release = isdn_close, -}; - -char * -isdn_map_eaz2msn(char *msn, int di) -{ - isdn_driver_t *this = dev->drv[di]; - int i; - - if (strlen(msn) == 1) { - i = msn[0] - '0'; - if ((i >= 0) && (i <= 9)) - if (strlen(this->msn2eaz[i])) - return (this->msn2eaz[i]); - } - return (msn); -} - -/* - * Find an unused ISDN-channel, whose feature-flags match the - * given L2- and L3-protocols. - */ -#define L2V (~(ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038)) - -/* - * This function must be called with holding the dev->lock. - */ -int -isdn_get_free_channel(int usage, int l2_proto, int l3_proto, int pre_dev - , int pre_chan, char *msn) -{ - int i; - ulong features; - ulong vfeatures; - - features = ((1 << l2_proto) | (0x10000 << l3_proto)); - vfeatures = (((1 << l2_proto) | (0x10000 << l3_proto)) & - ~(ISDN_FEATURE_L2_V11096 | ISDN_FEATURE_L2_V11019 | ISDN_FEATURE_L2_V11038)); - /* If Layer-2 protocol is V.110, accept drivers with - * transparent feature even if these don't support V.110 - * because we can emulate this in linklevel. - */ - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (USG_NONE(dev->usage[i]) && - (dev->drvmap[i] != -1)) { - int d = dev->drvmap[i]; - if ((dev->usage[i] & ISDN_USAGE_EXCLUSIVE) && - ((pre_dev != d) || (pre_chan != dev->chanmap[i]))) - continue; - if (!strcmp(isdn_map_eaz2msn(msn, d), "-")) - continue; - if (dev->usage[i] & ISDN_USAGE_DISABLED) - continue; /* usage not allowed */ - if (dev->drv[d]->flags & DRV_FLAG_RUNNING) { - if (((dev->drv[d]->interface->features & features) == features) || - (((dev->drv[d]->interface->features & vfeatures) == vfeatures) && - (dev->drv[d]->interface->features & ISDN_FEATURE_L2_TRANS))) { - if ((pre_dev < 0) || (pre_chan < 0)) { - dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[i] |= usage; - isdn_info_update(); - return i; - } else { - if ((pre_dev == d) && (pre_chan == dev->chanmap[i])) { - dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[i] |= usage; - isdn_info_update(); - return i; - } - } - } - } - } - return -1; -} - -/* - * Set state of ISDN-channel to 'unused' - */ -void -isdn_free_channel(int di, int ch, int usage) -{ - int i; - - if ((di < 0) || (ch < 0)) { - printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n", - __func__, di, ch); - return; - } - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) && - (dev->drvmap[i] == di) && - (dev->chanmap[i] == ch)) { - dev->usage[i] &= (ISDN_USAGE_NONE | ISDN_USAGE_EXCLUSIVE); - strcpy(dev->num[i], "???"); - dev->ibytes[i] = 0; - dev->obytes[i] = 0; -// 20.10.99 JIM, try to reinitialize v110 ! - dev->v110emu[i] = 0; - atomic_set(&(dev->v110use[i]), 0); - isdn_v110_close(dev->v110[i]); - dev->v110[i] = NULL; -// 20.10.99 JIM, try to reinitialize v110 ! - isdn_info_update(); - if (dev->drv[di]) - skb_queue_purge(&dev->drv[di]->rpqueue[ch]); - } -} - -/* - * Cancel Exclusive-Flag for ISDN-channel - */ -void -isdn_unexclusive_channel(int di, int ch) -{ - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if ((dev->drvmap[i] == di) && - (dev->chanmap[i] == ch)) { - dev->usage[i] &= ~ISDN_USAGE_EXCLUSIVE; - isdn_info_update(); - return; - } -} - -/* - * writebuf replacement for SKB_ABLE drivers - */ -static int -isdn_writebuf_stub(int drvidx, int chan, const u_char __user *buf, int len) -{ - int ret; - int hl = dev->drv[drvidx]->interface->hl_hdrlen; - struct sk_buff *skb = alloc_skb(hl + len, GFP_ATOMIC); - - if (!skb) - return -ENOMEM; - skb_reserve(skb, hl); - if (copy_from_user(skb_put(skb, len), buf, len)) { - dev_kfree_skb(skb); - return -EFAULT; - } - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, 1, skb); - if (ret <= 0) - dev_kfree_skb(skb); - if (ret > 0) - dev->obytes[isdn_dc2minor(drvidx, chan)] += ret; - return ret; -} - -/* - * Return: length of data on success, -ERRcode on failure. - */ -int -isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb) -{ - int ret; - struct sk_buff *nskb = NULL; - int v110_ret = skb->len; - int idx = isdn_dc2minor(drvidx, chan); - - if (dev->v110[idx]) { - atomic_inc(&dev->v110use[idx]); - nskb = isdn_v110_encode(dev->v110[idx], skb); - atomic_dec(&dev->v110use[idx]); - if (!nskb) - return 0; - v110_ret = *((int *)nskb->data); - skb_pull(nskb, sizeof(int)); - if (!nskb->len) { - dev_kfree_skb(nskb); - return v110_ret; - } - /* V.110 must always be acknowledged */ - ack = 1; - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, nskb); - } else { - int hl = dev->drv[drvidx]->interface->hl_hdrlen; - - if (skb_headroom(skb) < hl) { - /* - * This should only occur when new HL driver with - * increased hl_hdrlen was loaded after netdevice - * was created and connected to the new driver. - * - * The V.110 branch (re-allocates on its own) does - * not need this - */ - struct sk_buff *skb_tmp; - - skb_tmp = skb_realloc_headroom(skb, hl); - printk(KERN_DEBUG "isdn_writebuf_skb_stub: reallocating headroom%s\n", skb_tmp ? "" : " failed"); - if (!skb_tmp) return -ENOMEM; /* 0 better? */ - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb_tmp); - if (ret > 0) { - dev_kfree_skb(skb); - } else { - dev_kfree_skb(skb_tmp); - } - } else { - ret = dev->drv[drvidx]->interface->writebuf_skb(drvidx, chan, ack, skb); - } - } - if (ret > 0) { - dev->obytes[idx] += ret; - if (dev->v110[idx]) { - atomic_inc(&dev->v110use[idx]); - dev->v110[idx]->skbuser++; - atomic_dec(&dev->v110use[idx]); - /* For V.110 return unencoded data length */ - ret = v110_ret; - /* if the complete frame was send we free the skb; - if not upper function will requeue the skb */ - if (ret == skb->len) - dev_kfree_skb(skb); - } - } else - if (dev->v110[idx]) - dev_kfree_skb(nskb); - return ret; -} - -static int -isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding) -{ - int j, k, m; - - init_waitqueue_head(&d->st_waitq); - if (d->flags & DRV_FLAG_RUNNING) - return -1; - if (n < 1) return 0; - - m = (adding) ? d->channels + n : n; - - if (dev->channels + n > ISDN_MAX_CHANNELS) { - printk(KERN_WARNING "register_isdn: Max. %d channels supported\n", - ISDN_MAX_CHANNELS); - return -1; - } - - if ((adding) && (d->rcverr)) - kfree(d->rcverr); - if (!(d->rcverr = kcalloc(m, sizeof(int), GFP_ATOMIC))) { - printk(KERN_WARNING "register_isdn: Could not alloc rcverr\n"); - return -1; - } - - if ((adding) && (d->rcvcount)) - kfree(d->rcvcount); - if (!(d->rcvcount = kcalloc(m, sizeof(int), GFP_ATOMIC))) { - printk(KERN_WARNING "register_isdn: Could not alloc rcvcount\n"); - if (!adding) - kfree(d->rcverr); - return -1; - } - - if ((adding) && (d->rpqueue)) { - for (j = 0; j < d->channels; j++) - skb_queue_purge(&d->rpqueue[j]); - kfree(d->rpqueue); - } - d->rpqueue = kmalloc_array(m, sizeof(struct sk_buff_head), GFP_ATOMIC); - if (!d->rpqueue) { - printk(KERN_WARNING "register_isdn: Could not alloc rpqueue\n"); - if (!adding) { - kfree(d->rcvcount); - kfree(d->rcverr); - } - return -1; - } - for (j = 0; j < m; j++) { - skb_queue_head_init(&d->rpqueue[j]); - } - - if ((adding) && (d->rcv_waitq)) - kfree(d->rcv_waitq); - d->rcv_waitq = kmalloc(array3_size(sizeof(wait_queue_head_t), 2, m), - GFP_ATOMIC); - if (!d->rcv_waitq) { - printk(KERN_WARNING "register_isdn: Could not alloc rcv_waitq\n"); - if (!adding) { - kfree(d->rpqueue); - kfree(d->rcvcount); - kfree(d->rcverr); - } - return -1; - } - d->snd_waitq = d->rcv_waitq + m; - for (j = 0; j < m; j++) { - init_waitqueue_head(&d->rcv_waitq[j]); - init_waitqueue_head(&d->snd_waitq[j]); - } - - dev->channels += n; - for (j = d->channels; j < m; j++) - for (k = 0; k < ISDN_MAX_CHANNELS; k++) - if (dev->chanmap[k] < 0) { - dev->chanmap[k] = j; - dev->drvmap[k] = drvidx; - break; - } - d->channels = m; - return 0; -} - -/* - * Low-level-driver registration - */ - -static void -set_global_features(void) -{ - int drvidx; - - dev->global_features = 0; - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) { - if (!dev->drv[drvidx]) - continue; - if (dev->drv[drvidx]->interface) - dev->global_features |= dev->drv[drvidx]->interface->features; - } -} - -#ifdef CONFIG_ISDN_DIVERSION - -static char *map_drvname(int di) -{ - if ((di < 0) || (di >= ISDN_MAX_DRIVERS)) - return (NULL); - return (dev->drvid[di]); /* driver name */ -} /* map_drvname */ - -static int map_namedrv(char *id) -{ int i; - - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - { if (!strcmp(dev->drvid[i], id)) - return (i); - } - return (-1); -} /* map_namedrv */ - -int DIVERT_REG_NAME(isdn_divert_if *i_div) -{ - if (i_div->if_magic != DIVERT_IF_MAGIC) - return (DIVERT_VER_ERR); - switch (i_div->cmd) - { - case DIVERT_CMD_REL: - if (divert_if != i_div) - return (DIVERT_REL_ERR); - divert_if = NULL; /* free interface */ - return (DIVERT_NO_ERR); - - case DIVERT_CMD_REG: - if (divert_if) - return (DIVERT_REG_ERR); - i_div->ll_cmd = isdn_command; /* set command function */ - i_div->drv_to_name = map_drvname; - i_div->name_to_drv = map_namedrv; - divert_if = i_div; /* remember interface */ - return (DIVERT_NO_ERR); - - default: - return (DIVERT_CMD_ERR); - } -} /* DIVERT_REG_NAME */ - -EXPORT_SYMBOL(DIVERT_REG_NAME); - -#endif /* CONFIG_ISDN_DIVERSION */ - - -EXPORT_SYMBOL(register_isdn); -#ifdef CONFIG_ISDN_PPP -EXPORT_SYMBOL(isdn_ppp_register_compressor); -EXPORT_SYMBOL(isdn_ppp_unregister_compressor); -#endif - -int -register_isdn(isdn_if *i) -{ - isdn_driver_t *d; - int j; - ulong flags; - int drvidx; - - if (dev->drivers >= ISDN_MAX_DRIVERS) { - printk(KERN_WARNING "register_isdn: Max. %d drivers supported\n", - ISDN_MAX_DRIVERS); - return 0; - } - if (!i->writebuf_skb) { - printk(KERN_WARNING "register_isdn: No write routine given.\n"); - return 0; - } - if (!(d = kzalloc(sizeof(isdn_driver_t), GFP_KERNEL))) { - printk(KERN_WARNING "register_isdn: Could not alloc driver-struct\n"); - return 0; - } - - d->maxbufsize = i->maxbufsize; - d->pktcount = 0; - d->stavail = 0; - d->flags = DRV_FLAG_LOADED; - d->online = 0; - d->interface = i; - d->channels = 0; - spin_lock_irqsave(&dev->lock, flags); - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) - if (!dev->drv[drvidx]) - break; - if (isdn_add_channels(d, drvidx, i->channels, 0)) { - spin_unlock_irqrestore(&dev->lock, flags); - kfree(d); - return 0; - } - i->channels = drvidx; - i->rcvcallb_skb = isdn_receive_skb_callback; - i->statcallb = isdn_status_callback; - if (!strlen(i->id)) - sprintf(i->id, "line%d", drvidx); - for (j = 0; j < drvidx; j++) - if (!strcmp(i->id, dev->drvid[j])) - sprintf(i->id, "line%d", drvidx); - dev->drv[drvidx] = d; - strcpy(dev->drvid[drvidx], i->id); - isdn_info_update(); - dev->drivers++; - set_global_features(); - spin_unlock_irqrestore(&dev->lock, flags); - return 1; -} - -/* -***************************************************************************** -* And now the modules code. -***************************************************************************** -*/ - -static char * -isdn_getrev(const char *revision) -{ - char *rev; - char *p; - - if ((p = strchr(revision, ':'))) { - rev = p + 2; - p = strchr(rev, '$'); - *--p = 0; - } else - rev = "???"; - return rev; -} - -/* - * Allocate and initialize all data, register modem-devices - */ -static int __init isdn_init(void) -{ - int i; - char tmprev[50]; - - dev = vzalloc(sizeof(isdn_dev)); - if (!dev) { - printk(KERN_WARNING "isdn: Could not allocate device-struct.\n"); - return -EIO; - } - timer_setup(&dev->timer, isdn_timer_funct, 0); - spin_lock_init(&dev->lock); - spin_lock_init(&dev->timerlock); -#ifdef MODULE - dev->owner = THIS_MODULE; -#endif - mutex_init(&dev->mtx); - init_waitqueue_head(&dev->info_waitq); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - dev->drvmap[i] = -1; - dev->chanmap[i] = -1; - dev->m_idx[i] = -1; - strcpy(dev->num[i], "???"); - } - if (register_chrdev(ISDN_MAJOR, "isdn", &isdn_fops)) { - printk(KERN_WARNING "isdn: Could not register control devices\n"); - vfree(dev); - return -EIO; - } - if ((isdn_tty_modem_init()) < 0) { - printk(KERN_WARNING "isdn: Could not register tty devices\n"); - vfree(dev); - unregister_chrdev(ISDN_MAJOR, "isdn"); - return -EIO; - } -#ifdef CONFIG_ISDN_PPP - if (isdn_ppp_init() < 0) { - printk(KERN_WARNING "isdn: Could not create PPP-device-structs\n"); - isdn_tty_exit(); - unregister_chrdev(ISDN_MAJOR, "isdn"); - vfree(dev); - return -EIO; - } -#endif /* CONFIG_ISDN_PPP */ - - strcpy(tmprev, isdn_revision); - printk(KERN_NOTICE "ISDN subsystem Rev: %s/", isdn_getrev(tmprev)); - strcpy(tmprev, isdn_net_revision); - printk("%s/", isdn_getrev(tmprev)); - strcpy(tmprev, isdn_ppp_revision); - printk("%s/", isdn_getrev(tmprev)); - strcpy(tmprev, isdn_audio_revision); - printk("%s/", isdn_getrev(tmprev)); - strcpy(tmprev, isdn_v110_revision); - printk("%s", isdn_getrev(tmprev)); - -#ifdef MODULE - printk(" loaded\n"); -#else - printk("\n"); -#endif - isdn_info_update(); - return 0; -} - -/* - * Unload module - */ -static void __exit isdn_exit(void) -{ -#ifdef CONFIG_ISDN_PPP - isdn_ppp_cleanup(); -#endif - if (isdn_net_rmall() < 0) { - printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n"); - return; - } - isdn_tty_exit(); - unregister_chrdev(ISDN_MAJOR, "isdn"); - del_timer_sync(&dev->timer); - /* call vfree with interrupts enabled, else it will hang */ - vfree(dev); - printk(KERN_NOTICE "ISDN-subsystem unloaded\n"); -} - -module_init(isdn_init); -module_exit(isdn_exit); diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h deleted file mode 100644 index 2260ef07ab9c..000000000000 --- a/drivers/isdn/i4l/isdn_common.h +++ /dev/null @@ -1,47 +0,0 @@ -/* $Id: isdn_common.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem - * common used functions and debugging-switches (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#undef ISDN_DEBUG_MODEM_OPEN -#undef ISDN_DEBUG_MODEM_IOCTL -#undef ISDN_DEBUG_MODEM_WAITSENT -#undef ISDN_DEBUG_MODEM_HUP -#undef ISDN_DEBUG_MODEM_ICALL -#undef ISDN_DEBUG_MODEM_DUMP -#undef ISDN_DEBUG_MODEM_VOICE -#undef ISDN_DEBUG_AT -#undef ISDN_DEBUG_NET_DUMP -#undef ISDN_DEBUG_NET_DIAL -#undef ISDN_DEBUG_NET_ICALL - -/* Prototypes */ -extern void isdn_lock_drivers(void); -extern void isdn_unlock_drivers(void); -extern void isdn_free_channel(int di, int ch, int usage); -extern void isdn_all_eaz(int di, int ch); -extern int isdn_command(isdn_ctrl *); -extern int isdn_dc2minor(int di, int ch); -extern void isdn_info_update(void); -extern char *isdn_map_eaz2msn(char *msn, int di); -extern void isdn_timer_ctrl(int tf, int onoff); -extern void isdn_unexclusive_channel(int di, int ch); -extern int isdn_getnum(char **); -extern int isdn_readbchan(int, int, u_char *, u_char *, int, wait_queue_head_t *); -extern int isdn_readbchan_tty(int, int, struct tty_port *, int); -extern int isdn_get_free_channel(int, int, int, int, int, char *); -extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *); -extern int register_isdn(isdn_if *i); -extern int isdn_msncmp(const char *, const char *); -#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) -extern void isdn_dumppkt(char *, u_char *, int, int); -#endif diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c deleted file mode 100644 index 336523ec077c..000000000000 --- a/drivers/isdn/i4l/isdn_concap.c +++ /dev/null @@ -1,99 +0,0 @@ -/* $Id: isdn_concap.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, protocol encapsulation - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* Stuff to support the concap_proto by isdn4linux. isdn4linux - specific - * stuff goes here. Stuff that depends only on the concap protocol goes to - * another -- protocol specific -- source file. - * - */ - - -#include <linux/isdn.h> -#include "isdn_x25iface.h" -#include "isdn_net.h" -#include <linux/concap.h> -#include "isdn_concap.h" - - -/* The following set of device service operations are for encapsulation - protocols that require for reliable datalink semantics. That means: - - - before any data is to be submitted the connection must explicitly - be set up. - - after the successful set up of the connection is signalled the - connection is considered to be reliably up. - - Auto-dialing ist not compatible with this requirements. Thus, auto-dialing - is completely bypassed. - - It might be possible to implement a (non standardized) datalink protocol - that provides a reliable data link service while using some auto dialing - mechanism. Such a protocol would need an auxiliary channel (i.e. user-user- - signaling on the D-channel) while the B-channel is down. -*/ - - -static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) -{ - struct net_device *ndev = concap->net_dev; - isdn_net_dev *nd = ((isdn_net_local *) netdev_priv(ndev))->netdev; - isdn_net_local *lp = isdn_net_get_locked_lp(nd); - - IX25DEBUG("isdn_concap_dl_data_req: %s \n", concap->net_dev->name); - if (!lp) { - IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 1); - return 1; - } - lp->huptimer = 0; - isdn_net_writebuf_skb(lp, skb); - spin_unlock_bh(&lp->xmit_lock); - IX25DEBUG("isdn_concap_dl_data_req: %s : isdn_net_send_skb returned %d\n", concap->net_dev->name, 0); - return 0; -} - - -static int isdn_concap_dl_connect_req(struct concap_proto *concap) -{ - struct net_device *ndev = concap->net_dev; - isdn_net_local *lp = netdev_priv(ndev); - int ret; - IX25DEBUG("isdn_concap_dl_connect_req: %s \n", ndev->name); - - /* dial ... */ - ret = isdn_net_dial_req(lp); - if (ret) IX25DEBUG("dialing failed\n"); - return ret; -} - -static int isdn_concap_dl_disconn_req(struct concap_proto *concap) -{ - IX25DEBUG("isdn_concap_dl_disconn_req: %s \n", concap->net_dev->name); - - isdn_net_hangup(concap->net_dev); - return 0; -} - -struct concap_device_ops isdn_concap_reliable_dl_dops = { - .data_req = &isdn_concap_dl_data_req, - .connect_req = &isdn_concap_dl_connect_req, - .disconn_req = &isdn_concap_dl_disconn_req -}; - -/* The following should better go into a dedicated source file such that - this sourcefile does not need to include any protocol specific header - files. For now: -*/ -struct concap_proto *isdn_concap_new(int encap) -{ - switch (encap) { - case ISDN_NET_ENCAP_X25IFACE: - return isdn_x25iface_proto_new(); - } - return NULL; -} diff --git a/drivers/isdn/i4l/isdn_concap.h b/drivers/isdn/i4l/isdn_concap.h deleted file mode 100644 index cd7e3ba74e25..000000000000 --- a/drivers/isdn/i4l/isdn_concap.h +++ /dev/null @@ -1,11 +0,0 @@ -/* $Id: isdn_concap.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, protocol encapsulation - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -extern struct concap_device_ops isdn_concap_reliable_dl_dops; -extern struct concap_proto *isdn_concap_new(int); diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c deleted file mode 100644 index c138f66f2659..000000000000 --- a/drivers/isdn/i4l/isdn_net.c +++ /dev/null @@ -1,3198 +0,0 @@ -/* $Id: isdn_net.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, network interfaces and related functions (linklevel). - * - * Copyright 1994-1998 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02 - * guy@traverse.com.au - * Outgoing calls - looks for a 'V' in first char of dialed number - * Incoming calls - checks first character of eaz as follows: - * Numeric - accept DATA only - original functionality - * 'V' - accept VOICE (DOV) only - * 'B' - accept BOTH DATA and DOV types - * - * Jan 2001: fix CISCO HDLC Bjoern A. Zeeb <i4l@zabbadoz.net> - * for info on the protocol, see - * http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt - */ - -#include <linux/isdn.h> -#include <linux/slab.h> -#include <net/arp.h> -#include <net/dst.h> -#include <net/pkt_sched.h> -#include <linux/inetdevice.h> -#include "isdn_common.h" -#include "isdn_net.h" -#ifdef CONFIG_ISDN_PPP -#include "isdn_ppp.h" -#endif -#ifdef CONFIG_ISDN_X25 -#include <linux/concap.h> -#include "isdn_concap.h" -#endif - - -/* - * Outline of new tbusy handling: - * - * Old method, roughly spoken, consisted of setting tbusy when entering - * isdn_net_start_xmit() and at several other locations and clearing - * it from isdn_net_start_xmit() thread when sending was successful. - * - * With 2.3.x multithreaded network core, to prevent problems, tbusy should - * only be set by the isdn_net_start_xmit() thread and only when a tx-busy - * condition is detected. Other threads (in particular isdn_net_stat_callb()) - * are only allowed to clear tbusy. - * - * -HE - */ - -/* - * About SOFTNET: - * Most of the changes were pretty obvious and basically done by HE already. - * - * One problem of the isdn net device code is that it uses struct net_device - * for masters and slaves. However, only master interface are registered to - * the network layer, and therefore, it only makes sense to call netif_* - * functions on them. - * - * --KG - */ - -/* - * Find out if the netdevice has been ifup-ed yet. - * For slaves, look at the corresponding master. - */ -static __inline__ int isdn_net_device_started(isdn_net_dev *n) -{ - isdn_net_local *lp = n->local; - struct net_device *dev; - - if (lp->master) - dev = lp->master; - else - dev = n->dev; - return netif_running(dev); -} - -/* - * wake up the network -> net_device queue. - * For slaves, wake the corresponding master interface. - */ -static __inline__ void isdn_net_device_wake_queue(isdn_net_local *lp) -{ - if (lp->master) - netif_wake_queue(lp->master); - else - netif_wake_queue(lp->netdev->dev); -} - -/* - * stop the network -> net_device queue. - * For slaves, stop the corresponding master interface. - */ -static __inline__ void isdn_net_device_stop_queue(isdn_net_local *lp) -{ - if (lp->master) - netif_stop_queue(lp->master); - else - netif_stop_queue(lp->netdev->dev); -} - -/* - * find out if the net_device which this lp belongs to (lp can be - * master or slave) is busy. It's busy iff all (master and slave) - * queues are busy - */ -static __inline__ int isdn_net_device_busy(isdn_net_local *lp) -{ - isdn_net_local *nlp; - isdn_net_dev *nd; - unsigned long flags; - - if (!isdn_net_lp_busy(lp)) - return 0; - - if (lp->master) - nd = ISDN_MASTER_PRIV(lp)->netdev; - else - nd = lp->netdev; - - spin_lock_irqsave(&nd->queue_lock, flags); - nlp = lp->next; - while (nlp != lp) { - if (!isdn_net_lp_busy(nlp)) { - spin_unlock_irqrestore(&nd->queue_lock, flags); - return 0; - } - nlp = nlp->next; - } - spin_unlock_irqrestore(&nd->queue_lock, flags); - return 1; -} - -static __inline__ void isdn_net_inc_frame_cnt(isdn_net_local *lp) -{ - atomic_inc(&lp->frame_cnt); - if (isdn_net_device_busy(lp)) - isdn_net_device_stop_queue(lp); -} - -static __inline__ void isdn_net_dec_frame_cnt(isdn_net_local *lp) -{ - atomic_dec(&lp->frame_cnt); - - if (!(isdn_net_device_busy(lp))) { - if (!skb_queue_empty(&lp->super_tx_queue)) { - schedule_work(&lp->tqueue); - } else { - isdn_net_device_wake_queue(lp); - } - } -} - -static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp) -{ - atomic_set(&lp->frame_cnt, 0); -} - -/* For 2.2.x we leave the transmitter busy timeout at 2 secs, just - * to be safe. - * For 2.3.x we push it up to 20 secs, because call establishment - * (in particular callback) may take such a long time, and we - * don't want confusing messages in the log. However, there is a slight - * possibility that this large timeout will break other things like MPPP, - * which might rely on the tx timeout. If so, we'll find out this way... - */ - -#define ISDN_NET_TX_TIMEOUT (20 * HZ) - -/* Prototypes */ - -static int isdn_net_force_dial_lp(isdn_net_local *); -static netdev_tx_t isdn_net_start_xmit(struct sk_buff *, - struct net_device *); - -static void isdn_net_ciscohdlck_connected(isdn_net_local *lp); -static void isdn_net_ciscohdlck_disconnected(isdn_net_local *lp); - -char *isdn_net_revision = "$Revision: 1.1.2.2 $"; - -/* - * Code for raw-networking over ISDN - */ - -static void -isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason) -{ - if (skb) { - - u_short proto = ntohs(skb->protocol); - - printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n", - dev->name, - (reason != NULL) ? reason : "unknown", - (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : ""); - - dst_link_failure(skb); - } - else { /* dial not triggered by rawIP packet */ - printk(KERN_DEBUG "isdn_net: %s: %s\n", - dev->name, - (reason != NULL) ? reason : "reason unknown"); - } -} - -static void -isdn_net_reset(struct net_device *dev) -{ -#ifdef CONFIG_ISDN_X25 - struct concap_device_ops *dops = - ((isdn_net_local *)netdev_priv(dev))->dops; - struct concap_proto *cprot = - ((isdn_net_local *)netdev_priv(dev))->netdev->cprot; -#endif -#ifdef CONFIG_ISDN_X25 - if (cprot && cprot->pops && dops) - cprot->pops->restart(cprot, dev, dops); -#endif -} - -/* Open/initialize the board. */ -static int -isdn_net_open(struct net_device *dev) -{ - int i; - struct net_device *p; - struct in_device *in_dev; - - /* moved here from isdn_net_reset, because only the master has an - interface associated which is supposed to be started. BTW: - we need to call netif_start_queue, not netif_wake_queue here */ - netif_start_queue(dev); - - isdn_net_reset(dev); - /* Fill in the MAC-level header (not needed, but for compatibility... */ - for (i = 0; i < ETH_ALEN - sizeof(u32); i++) - dev->dev_addr[i] = 0xfc; - if ((in_dev = dev->ip_ptr) != NULL) { - /* - * Any address will do - we take the first - */ - struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa != NULL) - memcpy(dev->dev_addr + 2, &ifa->ifa_local, 4); - } - - /* If this interface has slaves, start them also */ - p = MASTER_TO_SLAVE(dev); - if (p) { - while (p) { - isdn_net_reset(p); - p = MASTER_TO_SLAVE(p); - } - } - isdn_lock_drivers(); - return 0; -} - -/* - * Assign an ISDN-channel to a net-interface - */ -static void -isdn_net_bind_channel(isdn_net_local *lp, int idx) -{ - lp->flags |= ISDN_NET_CONNECTED; - lp->isdn_device = dev->drvmap[idx]; - lp->isdn_channel = dev->chanmap[idx]; - dev->rx_netdev[idx] = lp->netdev; - dev->st_netdev[idx] = lp->netdev; -} - -/* - * unbind a net-interface (resets interface after an error) - */ -static void -isdn_net_unbind_channel(isdn_net_local *lp) -{ - skb_queue_purge(&lp->super_tx_queue); - - if (!lp->master) { /* reset only master device */ - /* Moral equivalent of dev_purge_queues(): - BEWARE! This chunk of code cannot be called from hardware - interrupt handler. I hope it is true. --ANK - */ - qdisc_reset_all_tx(lp->netdev->dev); - } - lp->dialstate = 0; - dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; - dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL; - if (lp->isdn_device != -1 && lp->isdn_channel != -1) - isdn_free_channel(lp->isdn_device, lp->isdn_channel, - ISDN_USAGE_NET); - lp->flags &= ~ISDN_NET_CONNECTED; - lp->isdn_device = -1; - lp->isdn_channel = -1; -} - -/* - * Perform auto-hangup and cps-calculation for net-interfaces. - * - * auto-hangup: - * Increment idle-counter (this counter is reset on any incoming or - * outgoing packet), if counter exceeds configured limit either do a - * hangup immediately or - if configured - wait until just before the next - * charge-info. - * - * cps-calculation (needed for dynamic channel-bundling): - * Since this function is called every second, simply reset the - * byte-counter of the interface after copying it to the cps-variable. - */ -static unsigned long last_jiffies = -HZ; - -void -isdn_net_autohup(void) -{ - isdn_net_dev *p = dev->netdev; - int anymore; - - anymore = 0; - while (p) { - isdn_net_local *l = p->local; - if (jiffies == last_jiffies) - l->cps = l->transcount; - else - l->cps = (l->transcount * HZ) / (jiffies - last_jiffies); - l->transcount = 0; - if (dev->net_verbose > 3) - printk(KERN_DEBUG "%s: %d bogocps\n", p->dev->name, l->cps); - if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) { - anymore = 1; - l->huptimer++; - /* - * if there is some dialmode where timeout-hangup - * should _not_ be done, check for that here - */ - if ((l->onhtime) && - (l->huptimer > l->onhtime)) - { - if (l->hupflags & ISDN_MANCHARGE && - l->hupflags & ISDN_CHARGEHUP) { - while (time_after(jiffies, l->chargetime + l->chargeint)) - l->chargetime += l->chargeint; - if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ)) - if (l->outgoing || l->hupflags & ISDN_INHUP) - isdn_net_hangup(p->dev); - } else if (l->outgoing) { - if (l->hupflags & ISDN_CHARGEHUP) { - if (l->hupflags & ISDN_WAITCHARGE) { - printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n", - p->dev->name, l->hupflags); - isdn_net_hangup(p->dev); - } else if (time_after(jiffies, l->chargetime + l->chargeint)) { - printk(KERN_DEBUG - "isdn_net: %s: chtime = %lu, chint = %d\n", - p->dev->name, l->chargetime, l->chargeint); - isdn_net_hangup(p->dev); - } - } else - isdn_net_hangup(p->dev); - } else if (l->hupflags & ISDN_INHUP) - isdn_net_hangup(p->dev); - } - - if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) { - isdn_net_hangup(p->dev); - break; - } - } - p = (isdn_net_dev *) p->next; - } - last_jiffies = jiffies; - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore); -} - -static void isdn_net_lp_disconnected(isdn_net_local *lp) -{ - isdn_net_rm_from_bundle(lp); -} - -/* - * Handle status-messages from ISDN-interfacecard. - * This function is called from within the main-status-dispatcher - * isdn_status_callback, which itself is called from the low-level driver. - * Return: 1 = Event handled, 0 = not for us or unknown Event. - */ -int -isdn_net_stat_callback(int idx, isdn_ctrl *c) -{ - isdn_net_dev *p = dev->st_netdev[idx]; - int cmd = c->command; - - if (p) { - isdn_net_local *lp = p->local; -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = lp->netdev->cprot; - struct concap_proto_ops *pops = cprot ? cprot->pops : NULL; -#endif - switch (cmd) { - case ISDN_STAT_BSENT: - /* A packet has successfully been sent out */ - if ((lp->flags & ISDN_NET_CONNECTED) && - (!lp->dialstate)) { - isdn_net_dec_frame_cnt(lp); - lp->stats.tx_packets++; - lp->stats.tx_bytes += c->parm.length; - } - return 1; - case ISDN_STAT_DCONN: - /* D-Channel is up */ - switch (lp->dialstate) { - case 4: - case 7: - case 8: - lp->dialstate++; - return 1; - case 12: - lp->dialstate = 5; - return 1; - } - break; - case ISDN_STAT_DHUP: - /* Either D-Channel-hangup or error during dialout */ -#ifdef CONFIG_ISDN_X25 - /* If we are not connencted then dialing had - failed. If there are generic encap protocol - receiver routines signal the closure of - the link*/ - - if (!(lp->flags & ISDN_NET_CONNECTED) - && pops && pops->disconn_ind) - pops->disconn_ind(cprot); -#endif /* CONFIG_ISDN_X25 */ - if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { - if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) - isdn_net_ciscohdlck_disconnected(lp); -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - isdn_ppp_free(lp); -#endif - isdn_net_lp_disconnected(lp); - isdn_all_eaz(lp->isdn_device, lp->isdn_channel); - printk(KERN_INFO "%s: remote hangup\n", p->dev->name); - printk(KERN_INFO "%s: Chargesum is %d\n", p->dev->name, - lp->charge); - isdn_net_unbind_channel(lp); - return 1; - } - break; -#ifdef CONFIG_ISDN_X25 - case ISDN_STAT_BHUP: - /* B-Channel-hangup */ - /* try if there are generic encap protocol - receiver routines and signal the closure of - the link */ - if (pops && pops->disconn_ind) { - pops->disconn_ind(cprot); - return 1; - } - break; -#endif /* CONFIG_ISDN_X25 */ - case ISDN_STAT_BCONN: - /* B-Channel is up */ - isdn_net_zero_frame_cnt(lp); - switch (lp->dialstate) { - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 12: - if (lp->dialstate <= 6) { - dev->usage[idx] |= ISDN_USAGE_OUTGOING; - isdn_info_update(); - } else - dev->rx_netdev[idx] = p; - lp->dialstate = 0; - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 1); - if (lp->p_encap == ISDN_NET_ENCAP_CISCOHDLCK) - isdn_net_ciscohdlck_connected(lp); - if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { - if (lp->master) { /* is lp a slave? */ - isdn_net_dev *nd = ISDN_MASTER_PRIV(lp)->netdev; - isdn_net_add_to_bundle(nd, lp); - } - } - printk(KERN_INFO "isdn_net: %s connected\n", p->dev->name); - /* If first Chargeinfo comes before B-Channel connect, - * we correct the timestamp here. - */ - lp->chargetime = jiffies; - - /* reset dial-timeout */ - lp->dialstarted = 0; - lp->dialwait_timer = 0; - -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - isdn_ppp_wakeup_daemon(lp); -#endif -#ifdef CONFIG_ISDN_X25 - /* try if there are generic concap receiver routines */ - if (pops) - if (pops->connect_ind) - pops->connect_ind(cprot); -#endif /* CONFIG_ISDN_X25 */ - /* ppp needs to do negotiations first */ - if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) - isdn_net_device_wake_queue(lp); - return 1; - } - break; - case ISDN_STAT_NODCH: - /* No D-Channel avail. */ - if (lp->dialstate == 4) { - lp->dialstate--; - return 1; - } - break; - case ISDN_STAT_CINF: - /* Charge-info from TelCo. Calculate interval between - * charge-infos and set timestamp for last info for - * usage by isdn_net_autohup() - */ - lp->charge++; - if (lp->hupflags & ISDN_HAVECHARGE) { - lp->hupflags &= ~ISDN_WAITCHARGE; - lp->chargeint = jiffies - lp->chargetime - (2 * HZ); - } - if (lp->hupflags & ISDN_WAITCHARGE) - lp->hupflags |= ISDN_HAVECHARGE; - lp->chargetime = jiffies; - printk(KERN_DEBUG "isdn_net: Got CINF chargetime of %s now %lu\n", - p->dev->name, lp->chargetime); - return 1; - } - } - return 0; -} - -/* - * Perform dialout for net-interfaces and timeout-handling for - * D-Channel-up and B-Channel-up Messages. - * This function is initially called from within isdn_net_start_xmit() or - * or isdn_net_find_icall() after initializing the dialstate for an - * interface. If further calls are needed, the function schedules itself - * for a timer-callback via isdn_timer_function(). - * The dialstate is also affected by incoming status-messages from - * the ISDN-Channel which are handled in isdn_net_stat_callback() above. - */ -void -isdn_net_dial(void) -{ - isdn_net_dev *p = dev->netdev; - int anymore = 0; - int i; - isdn_ctrl cmd; - u_char *phone_number; - - while (p) { - isdn_net_local *lp = p->local; - -#ifdef ISDN_DEBUG_NET_DIAL - if (lp->dialstate) - printk(KERN_DEBUG "%s: dialstate=%d\n", p->dev->name, lp->dialstate); -#endif - switch (lp->dialstate) { - case 0: - /* Nothing to do for this interface */ - break; - case 1: - /* Initiate dialout. Set phone-number-pointer to first number - * of interface. - */ - lp->dial = lp->phone[1]; - if (!lp->dial) { - printk(KERN_WARNING "%s: phone number deleted?\n", - p->dev->name); - isdn_net_hangup(p->dev); - break; - } - anymore = 1; - - if (lp->dialtimeout > 0) - if (lp->dialstarted == 0 || time_after(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) { - lp->dialstarted = jiffies; - lp->dialwait_timer = 0; - } - - lp->dialstate++; - /* Fall through */ - case 2: - /* Prepare dialing. Clear EAZ, then set EAZ. */ - cmd.driver = lp->isdn_device; - cmd.arg = lp->isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - isdn_command(&cmd); - sprintf(cmd.parm.num, "%s", isdn_map_eaz2msn(lp->msn, cmd.driver)); - cmd.command = ISDN_CMD_SETEAZ; - isdn_command(&cmd); - lp->dialretry = 0; - anymore = 1; - lp->dialstate++; - /* Fall through */ - case 3: - /* Setup interface, dial current phone-number, switch to next number. - * If list of phone-numbers is exhausted, increment - * retry-counter. - */ - if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF)) { - char *s; - if (dev->global_flags & ISDN_GLOBAL_STOPPED) - s = "dial suppressed: isdn system stopped"; - else - s = "dial suppressed: dialmode `off'"; - isdn_net_unreachable(p->dev, NULL, s); - isdn_net_hangup(p->dev); - break; - } - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); - isdn_command(&cmd); - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); - isdn_command(&cmd); - cmd.driver = lp->isdn_device; - cmd.arg = lp->isdn_channel; - if (!lp->dial) { - printk(KERN_WARNING "%s: phone number deleted?\n", - p->dev->name); - isdn_net_hangup(p->dev); - break; - } - if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) { - lp->dialstate = 4; - printk(KERN_INFO "%s: Open leased line ...\n", p->dev->name); - } else { - if (lp->dialtimeout > 0) - if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) { - lp->dialwait_timer = jiffies + lp->dialwait; - lp->dialstarted = 0; - isdn_net_unreachable(p->dev, NULL, "dial: timed out"); - isdn_net_hangup(p->dev); - break; - } - - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_DIAL; - cmd.parm.setup.si2 = 0; - - /* check for DOV */ - phone_number = lp->dial->num; - if ((*phone_number == 'v') || - (*phone_number == 'V')) { /* DOV call */ - cmd.parm.setup.si1 = 1; - } else { /* DATA call */ - cmd.parm.setup.si1 = 7; - } - - strcpy(cmd.parm.setup.phone, phone_number); - /* - * Switch to next number or back to start if at end of list. - */ - if (!(lp->dial = (isdn_net_phone *) lp->dial->next)) { - lp->dial = lp->phone[1]; - lp->dialretry++; - - if (lp->dialretry > lp->dialmax) { - if (lp->dialtimeout == 0) { - lp->dialwait_timer = jiffies + lp->dialwait; - lp->dialstarted = 0; - isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times"); - } - isdn_net_hangup(p->dev); - break; - } - } - sprintf(cmd.parm.setup.eazmsn, "%s", - isdn_map_eaz2msn(lp->msn, cmd.driver)); - i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel); - if (i >= 0) { - strcpy(dev->num[i], cmd.parm.setup.phone); - dev->usage[i] |= ISDN_USAGE_OUTGOING; - isdn_info_update(); - } - printk(KERN_INFO "%s: dialing %d %s... %s\n", p->dev->name, - lp->dialretry, cmd.parm.setup.phone, - (cmd.parm.setup.si1 == 1) ? "DOV" : ""); - lp->dtimer = 0; -#ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device, - lp->isdn_channel); -#endif - isdn_command(&cmd); - } - lp->huptimer = 0; - lp->outgoing = 1; - if (lp->chargeint) { - lp->hupflags |= ISDN_HAVECHARGE; - lp->hupflags &= ~ISDN_WAITCHARGE; - } else { - lp->hupflags |= ISDN_WAITCHARGE; - lp->hupflags &= ~ISDN_HAVECHARGE; - } - anymore = 1; - lp->dialstate = - (lp->cbdelay && - (lp->flags & ISDN_NET_CBOUT)) ? 12 : 4; - break; - case 4: - /* Wait for D-Channel-connect. - * If timeout, switch back to state 3. - * Dialmax-handling moved to state 3. - */ - if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) - lp->dialstate = 3; - anymore = 1; - break; - case 5: - /* Got D-Channel-Connect, send B-Channel-request */ - cmd.driver = lp->isdn_device; - cmd.arg = lp->isdn_channel; - cmd.command = ISDN_CMD_ACCEPTB; - anymore = 1; - lp->dtimer = 0; - lp->dialstate++; - isdn_command(&cmd); - break; - case 6: - /* Wait for B- or D-Channel-connect. If timeout, - * switch back to state 3. - */ -#ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dialtimer2: %d\n", lp->dtimer); -#endif - if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) - lp->dialstate = 3; - anymore = 1; - break; - case 7: - /* Got incoming Call, setup L2 and L3 protocols, - * then wait for D-Channel-connect - */ -#ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer); -#endif - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = lp->isdn_channel + (lp->l2_proto << 8); - isdn_command(&cmd); - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = lp->isdn_channel + (lp->l3_proto << 8); - isdn_command(&cmd); - if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15) - isdn_net_hangup(p->dev); - else { - anymore = 1; - lp->dialstate++; - } - break; - case 9: - /* Got incoming D-Channel-Connect, send B-Channel-request */ - cmd.driver = lp->isdn_device; - cmd.arg = lp->isdn_channel; - cmd.command = ISDN_CMD_ACCEPTB; - isdn_command(&cmd); - anymore = 1; - lp->dtimer = 0; - lp->dialstate++; - break; - case 8: - case 10: - /* Wait for B- or D-channel-connect */ -#ifdef ISDN_DEBUG_NET_DIAL - printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer); -#endif - if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10) - isdn_net_hangup(p->dev); - else - anymore = 1; - break; - case 11: - /* Callback Delay */ - if (lp->dtimer++ > lp->cbdelay) - lp->dialstate = 1; - anymore = 1; - break; - case 12: - /* Remote does callback. Hangup after cbdelay, then wait for incoming - * call (in state 4). - */ - if (lp->dtimer++ > lp->cbdelay) - { - printk(KERN_INFO "%s: hangup waiting for callback ...\n", p->dev->name); - lp->dtimer = 0; - lp->dialstate = 4; - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_HANGUP; - cmd.arg = lp->isdn_channel; - isdn_command(&cmd); - isdn_all_eaz(lp->isdn_device, lp->isdn_channel); - } - anymore = 1; - break; - default: - printk(KERN_WARNING "isdn_net: Illegal dialstate %d for device %s\n", - lp->dialstate, p->dev->name); - } - p = (isdn_net_dev *) p->next; - } - isdn_timer_ctrl(ISDN_TIMER_NETDIAL, anymore); -} - -/* - * Perform hangup for a net-interface. - */ -void -isdn_net_hangup(struct net_device *d) -{ - isdn_net_local *lp = netdev_priv(d); - isdn_ctrl cmd; -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = lp->netdev->cprot; - struct concap_proto_ops *pops = cprot ? cprot->pops : NULL; -#endif - - if (lp->flags & ISDN_NET_CONNECTED) { - if (lp->slave != NULL) { - isdn_net_local *slp = ISDN_SLAVE_PRIV(lp); - if (slp->flags & ISDN_NET_CONNECTED) { - printk(KERN_INFO - "isdn_net: hang up slave %s before %s\n", - lp->slave->name, d->name); - isdn_net_hangup(lp->slave); - } - } - printk(KERN_INFO "isdn_net: local hangup %s\n", d->name); -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - isdn_ppp_free(lp); -#endif - isdn_net_lp_disconnected(lp); -#ifdef CONFIG_ISDN_X25 - /* try if there are generic encap protocol - receiver routines and signal the closure of - the link */ - if (pops && pops->disconn_ind) - pops->disconn_ind(cprot); -#endif /* CONFIG_ISDN_X25 */ - - cmd.driver = lp->isdn_device; - cmd.command = ISDN_CMD_HANGUP; - cmd.arg = lp->isdn_channel; - isdn_command(&cmd); - printk(KERN_INFO "%s: Chargesum is %d\n", d->name, lp->charge); - isdn_all_eaz(lp->isdn_device, lp->isdn_channel); - } - isdn_net_unbind_channel(lp); -} - -typedef struct { - __be16 source; - __be16 dest; -} ip_ports; - -static void -isdn_net_log_skb(struct sk_buff *skb, isdn_net_local *lp) -{ - /* hopefully, this was set correctly */ - const u_char *p = skb_network_header(skb); - unsigned short proto = ntohs(skb->protocol); - int data_ofs; - ip_ports *ipp; - char addinfo[100]; - - addinfo[0] = '\0'; - /* This check stolen from 2.1.72 dev_queue_xmit_nit() */ - if (p < skb->data || skb_network_header(skb) >= skb_tail_pointer(skb)) { - /* fall back to old isdn_net_log_packet method() */ - char *buf = skb->data; - - printk(KERN_DEBUG "isdn_net: protocol %04x is buggy, dev %s\n", skb->protocol, lp->netdev->dev->name); - p = buf; - proto = ETH_P_IP; - switch (lp->p_encap) { - case ISDN_NET_ENCAP_IPTYP: - proto = ntohs(*(__be16 *)&buf[0]); - p = &buf[2]; - break; - case ISDN_NET_ENCAP_ETHER: - proto = ntohs(*(__be16 *)&buf[12]); - p = &buf[14]; - break; - case ISDN_NET_ENCAP_CISCOHDLC: - proto = ntohs(*(__be16 *)&buf[2]); - p = &buf[4]; - break; -#ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - proto = ntohs(skb->protocol); - p = &buf[IPPP_MAX_HEADER]; - break; -#endif - } - } - data_ofs = ((p[0] & 15) * 4); - switch (proto) { - case ETH_P_IP: - switch (p[9]) { - case 1: - strcpy(addinfo, " ICMP"); - break; - case 2: - strcpy(addinfo, " IGMP"); - break; - case 4: - strcpy(addinfo, " IPIP"); - break; - case 6: - ipp = (ip_ports *) (&p[data_ofs]); - sprintf(addinfo, " TCP, port: %d -> %d", ntohs(ipp->source), - ntohs(ipp->dest)); - break; - case 8: - strcpy(addinfo, " EGP"); - break; - case 12: - strcpy(addinfo, " PUP"); - break; - case 17: - ipp = (ip_ports *) (&p[data_ofs]); - sprintf(addinfo, " UDP, port: %d -> %d", ntohs(ipp->source), - ntohs(ipp->dest)); - break; - case 22: - strcpy(addinfo, " IDP"); - break; - } - printk(KERN_INFO "OPEN: %pI4 -> %pI4%s\n", - p + 12, p + 16, addinfo); - break; - case ETH_P_ARP: - printk(KERN_INFO "OPEN: ARP %pI4 -> *.*.*.* ?%pI4\n", - p + 14, p + 24); - break; - } -} - -/* - * this function is used to send supervisory data, i.e. data which was - * not received from the network layer, but e.g. frames from ipppd, CCP - * reset frames etc. - */ -void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb) -{ - if (in_irq()) { - // we can't grab the lock from irq context, - // so we just queue the packet - skb_queue_tail(&lp->super_tx_queue, skb); - schedule_work(&lp->tqueue); - return; - } - - spin_lock_bh(&lp->xmit_lock); - if (!isdn_net_lp_busy(lp)) { - isdn_net_writebuf_skb(lp, skb); - } else { - skb_queue_tail(&lp->super_tx_queue, skb); - } - spin_unlock_bh(&lp->xmit_lock); -} - -/* - * called from tq_immediate - */ -static void isdn_net_softint(struct work_struct *work) -{ - isdn_net_local *lp = container_of(work, isdn_net_local, tqueue); - struct sk_buff *skb; - - spin_lock_bh(&lp->xmit_lock); - while (!isdn_net_lp_busy(lp)) { - skb = skb_dequeue(&lp->super_tx_queue); - if (!skb) - break; - isdn_net_writebuf_skb(lp, skb); - } - spin_unlock_bh(&lp->xmit_lock); -} - -/* - * all frames sent from the (net) LL to a HL driver should go via this function - * it's serialized by the caller holding the lp->xmit_lock spinlock - */ -void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb) -{ - int ret; - int len = skb->len; /* save len */ - - /* before obtaining the lock the caller should have checked that - the lp isn't busy */ - if (isdn_net_lp_busy(lp)) { - printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); - goto error; - } - - if (!(lp->flags & ISDN_NET_CONNECTED)) { - printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); - goto error; - } - ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb); - if (ret != len) { - /* we should never get here */ - printk(KERN_WARNING "%s: HL driver queue full\n", lp->netdev->dev->name); - goto error; - } - - lp->transcount += len; - isdn_net_inc_frame_cnt(lp); - return; - -error: - dev_kfree_skb(skb); - lp->stats.tx_errors++; - -} - - -/* - * Helper function for isdn_net_start_xmit. - * When called, the connection is already established. - * Based on cps-calculation, check if device is overloaded. - * If so, and if a slave exists, trigger dialing for it. - * If any slave is online, deliver packets using a simple round robin - * scheme. - * - * Return: 0 on success, !0 on failure. - */ - -static int -isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) -{ - isdn_net_dev *nd; - isdn_net_local *slp; - isdn_net_local *lp = netdev_priv(ndev); - int retv = NETDEV_TX_OK; - - if (((isdn_net_local *) netdev_priv(ndev))->master) { - printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - - /* For the other encaps the header has already been built */ -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { - return isdn_ppp_xmit(skb, ndev); - } -#endif - nd = ((isdn_net_local *) netdev_priv(ndev))->netdev; - lp = isdn_net_get_locked_lp(nd); - if (!lp) { - printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); - return NETDEV_TX_BUSY; - } - /* we have our lp locked from now on */ - - /* Reset hangup-timeout */ - lp->huptimer = 0; // FIXME? - isdn_net_writebuf_skb(lp, skb); - spin_unlock_bh(&lp->xmit_lock); - - /* the following stuff is here for backwards compatibility. - * in future, start-up and hangup of slaves (based on current load) - * should move to userspace and get based on an overall cps - * calculation - */ - if (lp->cps > lp->triggercps) { - if (lp->slave) { - if (!lp->sqfull) { - /* First time overload: set timestamp only */ - lp->sqfull = 1; - lp->sqfull_stamp = jiffies; - } else { - /* subsequent overload: if slavedelay exceeded, start dialing */ - if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) { - slp = ISDN_SLAVE_PRIV(lp); - if (!(slp->flags & ISDN_NET_CONNECTED)) { - isdn_net_force_dial_lp(ISDN_SLAVE_PRIV(lp)); - } - } - } - } - } else { - if (lp->sqfull && time_after(jiffies, lp->sqfull_stamp + lp->slavedelay + (10 * HZ))) { - lp->sqfull = 0; - } - /* this is a hack to allow auto-hangup for slaves on moderate loads */ - nd->queue = nd->local; - } - - return retv; - -} - -static void -isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev) -{ - isdn_net_local *lp = netdev_priv(dev); - if (!skb) - return; - if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { - const int pullsize = skb_network_offset(skb) - ETH_HLEN; - if (pullsize > 0) { - printk(KERN_DEBUG "isdn_net: Pull junk %d\n", pullsize); - skb_pull(skb, pullsize); - } - } -} - - -static void isdn_net_tx_timeout(struct net_device *ndev) -{ - isdn_net_local *lp = netdev_priv(ndev); - - printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate); - if (!lp->dialstate) { - lp->stats.tx_errors++; - /* - * There is a certain probability that this currently - * works at all because if we always wake up the interface, - * then upper layer will try to send the next packet - * immediately. And then, the old clean_up logic in the - * driver will hopefully continue to work as it used to do. - * - * This is rather primitive right know, we better should - * clean internal queues here, in particular for multilink and - * ppp, and reset HL driver's channel, too. --HE - * - * actually, this may not matter at all, because ISDN hardware - * should not see transmitter hangs at all IMO - * changed KERN_DEBUG to KERN_WARNING to find out if this is - * ever called --KG - */ - } - netif_trans_update(ndev); - netif_wake_queue(ndev); -} - -/* - * Try sending a packet. - * If this interface isn't connected to a ISDN-Channel, find a free channel, - * and start dialing. - */ -static netdev_tx_t -isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) -{ - isdn_net_local *lp = netdev_priv(ndev); -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = lp->netdev->cprot; -/* At this point hard_start_xmit() passes control to the encapsulation - protocol (if present). - For X.25 auto-dialing is completly bypassed because: - - It does not conform with the semantics of a reliable datalink - service as needed by X.25 PLP. - - I don't want that the interface starts dialing when the network layer - sends a message which requests to disconnect the lapb link (or if it - sends any other message not resulting in data transmission). - Instead, dialing will be initiated by the encapsulation protocol entity - when a dl_establish request is received from the upper layer. -*/ - if (cprot && cprot->pops) { - int ret = cprot->pops->encap_and_xmit(cprot, skb); - - if (ret) - netif_stop_queue(ndev); - return ret; - } else -#endif - /* auto-dialing xmit function */ - { -#ifdef ISDN_DEBUG_NET_DUMP - u_char *buf; -#endif - isdn_net_adjust_hdr(skb, ndev); -#ifdef ISDN_DEBUG_NET_DUMP - buf = skb->data; - isdn_dumppkt("S:", buf, skb->len, 40); -#endif - - if (!(lp->flags & ISDN_NET_CONNECTED)) { - int chi; - /* only do autodial if allowed by config */ - if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) { - isdn_net_unreachable(ndev, skb, "dial rejected: interface not in dialmode `auto'"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - if (lp->phone[1]) { - ulong flags; - - if (lp->dialwait_timer <= 0) - if (lp->dialstarted > 0 && lp->dialtimeout > 0 && time_before(jiffies, lp->dialstarted + lp->dialtimeout + lp->dialwait)) - lp->dialwait_timer = lp->dialstarted + lp->dialtimeout + lp->dialwait; - - if (lp->dialwait_timer > 0) { - if (time_before(jiffies, lp->dialwait_timer)) { - isdn_net_unreachable(ndev, skb, "dial rejected: retry-time not reached"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } else - lp->dialwait_timer = 0; - } - /* Grab a free ISDN-Channel */ - spin_lock_irqsave(&dev->lock, flags); - if (((chi = - isdn_get_free_channel( - ISDN_USAGE_NET, - lp->l2_proto, - lp->l3_proto, - lp->pre_device, - lp->pre_channel, - lp->msn) - ) < 0) && - ((chi = - isdn_get_free_channel( - ISDN_USAGE_NET, - lp->l2_proto, - lp->l3_proto, - lp->pre_device, - lp->pre_channel^1, - lp->msn) - ) < 0)) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_unreachable(ndev, skb, - "No channel"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - /* Log packet, which triggered dialing */ - if (dev->net_verbose) - isdn_net_log_skb(skb, lp); - lp->dialstate = 1; - /* Connect interface with channel */ - isdn_net_bind_channel(lp, chi); -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { - /* no 'first_skb' handling for syncPPP */ - if (isdn_ppp_bind(lp) < 0) { - dev_kfree_skb(skb); - isdn_net_unbind_channel(lp); - spin_unlock_irqrestore(&dev->lock, flags); - return NETDEV_TX_OK; /* STN (skb to nirvana) ;) */ - } -#ifdef CONFIG_IPPP_FILTER - if (isdn_ppp_autodial_filter(skb, lp)) { - isdn_ppp_free(lp); - isdn_net_unbind_channel(lp); - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_unreachable(ndev, skb, "dial rejected: packet filtered"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } -#endif - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_dial(); /* Initiate dialing */ - netif_stop_queue(ndev); - return NETDEV_TX_BUSY; /* let upper layer requeue skb packet */ - } -#endif - /* Initiate dialing */ - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_dial(); - isdn_net_device_stop_queue(lp); - return NETDEV_TX_BUSY; - } else { - isdn_net_unreachable(ndev, skb, - "No phone number"); - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - } else { - /* Device is connected to an ISDN channel */ - netif_trans_update(ndev); - if (!lp->dialstate) { - /* ISDN connection is established, try sending */ - int ret; - ret = (isdn_net_xmit(ndev, skb)); - if (ret) netif_stop_queue(ndev); - return ret; - } else - netif_stop_queue(ndev); - } - } - return NETDEV_TX_BUSY; -} - -/* - * Shutdown a net-interface. - */ -static int -isdn_net_close(struct net_device *dev) -{ - struct net_device *p; -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = - ((isdn_net_local *)netdev_priv(dev))->netdev->cprot; - /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name); */ -#endif - -#ifdef CONFIG_ISDN_X25 - if (cprot && cprot->pops) cprot->pops->close(cprot); -#endif - netif_stop_queue(dev); - p = MASTER_TO_SLAVE(dev); - if (p) { - /* If this interface has slaves, stop them also */ - while (p) { -#ifdef CONFIG_ISDN_X25 - cprot = ((isdn_net_local *)netdev_priv(p)) - ->netdev->cprot; - if (cprot && cprot->pops) - cprot->pops->close(cprot); -#endif - isdn_net_hangup(p); - p = MASTER_TO_SLAVE(p); - } - } - isdn_net_hangup(dev); - isdn_unlock_drivers(); - return 0; -} - -/* - * Get statistics - */ -static struct net_device_stats * -isdn_net_get_stats(struct net_device *dev) -{ - isdn_net_local *lp = netdev_priv(dev); - return &lp->stats; -} - -/* This is simply a copy from std. eth.c EXCEPT we pull ETH_HLEN - * instead of dev->hard_header_len off. This is done because the - * lowlevel-driver has already pulled off its stuff when we get - * here and this routine only gets called with p_encap == ETHER. - * Determine the packet's protocol ID. The rule here is that we - * assume 802.3 if the type field is short enough to be a length. - * This is normal practice and works for any 'now in use' protocol. - */ - -static __be16 -isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - struct ethhdr *eth; - unsigned char *rawp; - - skb_reset_mac_header(skb); - skb_pull(skb, ETH_HLEN); - eth = eth_hdr(skb); - - if (*eth->h_dest & 1) { - if (ether_addr_equal(eth->h_dest, dev->broadcast)) - skb->pkt_type = PACKET_BROADCAST; - else - skb->pkt_type = PACKET_MULTICAST; - } - /* - * This ALLMULTI check should be redundant by 1.4 - * so don't forget to remove it. - */ - - else if (dev->flags & (IFF_PROMISC /*| IFF_ALLMULTI*/)) { - if (!ether_addr_equal(eth->h_dest, dev->dev_addr)) - skb->pkt_type = PACKET_OTHERHOST; - } - if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN) - return eth->h_proto; - - rawp = skb->data; - - /* - * This is a magic hack to spot IPX packets. Older Novell breaks - * the protocol design and runs IPX over 802.3 without an 802.2 LLC - * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This - * won't work for fault tolerant netware but does for the rest. - */ - if (*(unsigned short *) rawp == 0xFFFF) - return htons(ETH_P_802_3); - /* - * Real 802.2 LLC - */ - return htons(ETH_P_802_2); -} - - -/* - * CISCO HDLC keepalive specific stuff - */ -static struct sk_buff* -isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len) -{ - unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; - struct sk_buff *skb; - - skb = alloc_skb(hl + len, GFP_ATOMIC); - if (skb) - skb_reserve(skb, hl); - else - printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__); - return skb; -} - -/* cisco hdlck device private ioctls */ -static int -isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - isdn_net_local *lp = netdev_priv(dev); - unsigned long len = 0; - unsigned long expires = 0; - int tmp = 0; - int period = lp->cisco_keepalive_period; - s8 debserint = lp->cisco_debserint; - int rc = 0; - - if (lp->p_encap != ISDN_NET_ENCAP_CISCOHDLCK) - return -EINVAL; - - switch (cmd) { - /* get/set keepalive period */ - case SIOCGKEEPPERIOD: - len = (unsigned long)sizeof(lp->cisco_keepalive_period); - if (copy_to_user(ifr->ifr_data, - &lp->cisco_keepalive_period, len)) - rc = -EFAULT; - break; - case SIOCSKEEPPERIOD: - tmp = lp->cisco_keepalive_period; - len = (unsigned long)sizeof(lp->cisco_keepalive_period); - if (copy_from_user(&period, ifr->ifr_data, len)) - rc = -EFAULT; - if ((period > 0) && (period <= 32767)) - lp->cisco_keepalive_period = period; - else - rc = -EINVAL; - if (!rc && (tmp != lp->cisco_keepalive_period)) { - expires = (unsigned long)(jiffies + - lp->cisco_keepalive_period * HZ); - mod_timer(&lp->cisco_timer, expires); - printk(KERN_INFO "%s: Keepalive period set " - "to %d seconds.\n", - dev->name, lp->cisco_keepalive_period); - } - break; - - /* get/set debugging */ - case SIOCGDEBSERINT: - len = (unsigned long)sizeof(lp->cisco_debserint); - if (copy_to_user(ifr->ifr_data, - &lp->cisco_debserint, len)) - rc = -EFAULT; - break; - case SIOCSDEBSERINT: - len = (unsigned long)sizeof(lp->cisco_debserint); - if (copy_from_user(&debserint, - ifr->ifr_data, len)) - rc = -EFAULT; - if ((debserint >= 0) && (debserint <= 64)) - lp->cisco_debserint = debserint; - else - rc = -EINVAL; - break; - - default: - rc = -EINVAL; - break; - } - return (rc); -} - - -static int isdn_net_ioctl(struct net_device *dev, - struct ifreq *ifr, int cmd) -{ - isdn_net_local *lp = netdev_priv(dev); - - switch (lp->p_encap) { -#ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - return isdn_ppp_dev_ioctl(dev, ifr, cmd); -#endif - case ISDN_NET_ENCAP_CISCOHDLCK: - return isdn_ciscohdlck_dev_ioctl(dev, ifr, cmd); - default: - return -EINVAL; - } -} - -/* called via cisco_timer.function */ -static void -isdn_net_ciscohdlck_slarp_send_keepalive(struct timer_list *t) -{ - isdn_net_local *lp = from_timer(lp, t, cisco_timer); - struct sk_buff *skb; - unsigned char *p; - unsigned long last_cisco_myseq = lp->cisco_myseq; - int myseq_diff = 0; - - if (!(lp->flags & ISDN_NET_CONNECTED) || lp->dialstate) { - printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); - return; - } - lp->cisco_myseq++; - - myseq_diff = (lp->cisco_myseq - lp->cisco_mineseen); - if ((lp->cisco_line_state) && ((myseq_diff >= 3) || (myseq_diff <= -3))) { - /* line up -> down */ - lp->cisco_line_state = 0; - printk(KERN_WARNING - "UPDOWN: Line protocol on Interface %s," - " changed state to down\n", lp->netdev->dev->name); - /* should stop routing higher-level data across */ - } else if ((!lp->cisco_line_state) && - (myseq_diff >= 0) && (myseq_diff <= 2)) { - /* line down -> up */ - lp->cisco_line_state = 1; - printk(KERN_WARNING - "UPDOWN: Line protocol on Interface %s," - " changed state to up\n", lp->netdev->dev->name); - /* restart routing higher-level data across */ - } - - if (lp->cisco_debserint) - printk(KERN_DEBUG "%s: HDLC " - "myseq %lu, mineseen %lu%c, yourseen %lu, %s\n", - lp->netdev->dev->name, last_cisco_myseq, lp->cisco_mineseen, - ((last_cisco_myseq == lp->cisco_mineseen) ? '*' : 040), - lp->cisco_yourseq, - ((lp->cisco_line_state) ? "line up" : "line down")); - - skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); - if (!skb) - return; - - p = skb_put(skb, 4 + 14); - - /* cisco header */ - *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; - *(u8 *)(p + 1) = CISCO_CTRL; - *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); - - /* slarp keepalive */ - *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_KEEPALIVE); - *(__be32 *)(p + 8) = cpu_to_be32(lp->cisco_myseq); - *(__be32 *)(p + 12) = cpu_to_be32(lp->cisco_yourseq); - *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliability, always 0xffff - p += 18; - - isdn_net_write_super(lp, skb); - - lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ; - - add_timer(&lp->cisco_timer); -} - -static void -isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp) -{ - struct sk_buff *skb; - unsigned char *p; - - skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); - if (!skb) - return; - - p = skb_put(skb, 4 + 14); - - /* cisco header */ - *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; - *(u8 *)(p + 1) = CISCO_CTRL; - *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); - - /* slarp request */ - *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REQUEST); - *(__be32 *)(p + 8) = cpu_to_be32(0); // address - *(__be32 *)(p + 12) = cpu_to_be32(0); // netmask - *(__be16 *)(p + 16) = cpu_to_be16(0); // unused - p += 18; - - isdn_net_write_super(lp, skb); -} - -static void -isdn_net_ciscohdlck_connected(isdn_net_local *lp) -{ - lp->cisco_myseq = 0; - lp->cisco_mineseen = 0; - lp->cisco_yourseq = 0; - lp->cisco_keepalive_period = ISDN_TIMER_KEEPINT; - lp->cisco_last_slarp_in = 0; - lp->cisco_line_state = 0; - lp->cisco_debserint = 0; - - /* send slarp request because interface/seq.no.s reset */ - isdn_net_ciscohdlck_slarp_send_request(lp); - - timer_setup(&lp->cisco_timer, - isdn_net_ciscohdlck_slarp_send_keepalive, 0); - lp->cisco_timer.expires = jiffies + lp->cisco_keepalive_period * HZ; - add_timer(&lp->cisco_timer); -} - -static void -isdn_net_ciscohdlck_disconnected(isdn_net_local *lp) -{ - del_timer(&lp->cisco_timer); -} - -static void -isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp) -{ - struct sk_buff *skb; - unsigned char *p; - struct in_device *in_dev = NULL; - __be32 addr = 0; /* local ipv4 address */ - __be32 mask = 0; /* local netmask */ - - if ((in_dev = lp->netdev->dev->ip_ptr) != NULL) { - /* take primary(first) address of interface */ - struct in_ifaddr *ifa = in_dev->ifa_list; - if (ifa != NULL) { - addr = ifa->ifa_local; - mask = ifa->ifa_mask; - } - } - - skb = isdn_net_ciscohdlck_alloc_skb(lp, 4 + 14); - if (!skb) - return; - - p = skb_put(skb, 4 + 14); - - /* cisco header */ - *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; - *(u8 *)(p + 1) = CISCO_CTRL; - *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); - - /* slarp reply, send own ip/netmask; if values are nonsense remote - * should think we are unable to provide it with an address via SLARP */ - *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REPLY); - *(__be32 *)(p + 8) = addr; // address - *(__be32 *)(p + 12) = mask; // netmask - *(__be16 *)(p + 16) = cpu_to_be16(0); // unused - p += 18; - - isdn_net_write_super(lp, skb); -} - -static void -isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) -{ - unsigned char *p; - int period; - u32 code; - u32 my_seq; - u32 your_seq; - __be32 local; - __be32 *addr, *mask; - - if (skb->len < 14) - return; - - p = skb->data; - code = be32_to_cpup((__be32 *)p); - p += 4; - - switch (code) { - case CISCO_SLARP_REQUEST: - lp->cisco_yourseq = 0; - isdn_net_ciscohdlck_slarp_send_reply(lp); - break; - case CISCO_SLARP_REPLY: - addr = (__be32 *)p; - mask = (__be32 *)(p + 4); - if (*mask != cpu_to_be32(0xfffffffc)) - goto slarp_reply_out; - if ((*addr & cpu_to_be32(3)) == cpu_to_be32(0) || - (*addr & cpu_to_be32(3)) == cpu_to_be32(3)) - goto slarp_reply_out; - local = *addr ^ cpu_to_be32(3); - printk(KERN_INFO "%s: got slarp reply: remote ip: %pI4, local ip: %pI4 mask: %pI4\n", - lp->netdev->dev->name, addr, &local, mask); - break; - slarp_reply_out: - printk(KERN_INFO "%s: got invalid slarp reply (%pI4/%pI4) - ignored\n", - lp->netdev->dev->name, addr, mask); - break; - case CISCO_SLARP_KEEPALIVE: - period = (int)((jiffies - lp->cisco_last_slarp_in - + HZ / 2 - 1) / HZ); - if (lp->cisco_debserint && - (period != lp->cisco_keepalive_period) && - lp->cisco_last_slarp_in) { - printk(KERN_DEBUG "%s: Keepalive period mismatch - " - "is %d but should be %d.\n", - lp->netdev->dev->name, period, - lp->cisco_keepalive_period); - } - lp->cisco_last_slarp_in = jiffies; - my_seq = be32_to_cpup((__be32 *)(p + 0)); - your_seq = be32_to_cpup((__be32 *)(p + 4)); - p += 10; - lp->cisco_yourseq = my_seq; - lp->cisco_mineseen = your_seq; - break; - } -} - -static void -isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb) -{ - unsigned char *p; - u8 addr; - u8 ctrl; - u16 type; - - if (skb->len < 4) - goto out_free; - - p = skb->data; - addr = *(u8 *)(p + 0); - ctrl = *(u8 *)(p + 1); - type = be16_to_cpup((__be16 *)(p + 2)); - p += 4; - skb_pull(skb, 4); - - if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) { - printk(KERN_WARNING "%s: Unknown Cisco addr 0x%02x\n", - lp->netdev->dev->name, addr); - goto out_free; - } - if (ctrl != CISCO_CTRL) { - printk(KERN_WARNING "%s: Unknown Cisco ctrl 0x%02x\n", - lp->netdev->dev->name, ctrl); - goto out_free; - } - - switch (type) { - case CISCO_TYPE_SLARP: - isdn_net_ciscohdlck_slarp_in(lp, skb); - goto out_free; - case CISCO_TYPE_CDP: - if (lp->cisco_debserint) - printk(KERN_DEBUG "%s: Received CDP packet. use " - "\"no cdp enable\" on cisco.\n", - lp->netdev->dev->name); - goto out_free; - default: - /* no special cisco protocol */ - skb->protocol = htons(type); - netif_rx(skb); - return; - } - -out_free: - kfree_skb(skb); -} - -/* - * Got a packet from ISDN-Channel. - */ -static void -isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) -{ - isdn_net_local *lp = netdev_priv(ndev); - isdn_net_local *olp = lp; /* original 'lp' */ -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = lp->netdev->cprot; -#endif - lp->transcount += skb->len; - - lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; - if (lp->master) { - /* Bundling: If device is a slave-device, deliver to master, also - * handle master's statistics and hangup-timeout - */ - ndev = lp->master; - lp = netdev_priv(ndev); - lp->stats.rx_packets++; - lp->stats.rx_bytes += skb->len; - } - skb->dev = ndev; - skb->pkt_type = PACKET_HOST; - skb_reset_mac_header(skb); -#ifdef ISDN_DEBUG_NET_DUMP - isdn_dumppkt("R:", skb->data, skb->len, 40); -#endif - switch (lp->p_encap) { - case ISDN_NET_ENCAP_ETHER: - /* Ethernet over ISDN */ - olp->huptimer = 0; - lp->huptimer = 0; - skb->protocol = isdn_net_type_trans(skb, ndev); - break; - case ISDN_NET_ENCAP_UIHDLC: - /* HDLC with UI-frame (for ispa with -h1 option) */ - olp->huptimer = 0; - lp->huptimer = 0; - skb_pull(skb, 2); - /* Fall through */ - case ISDN_NET_ENCAP_RAWIP: - /* RAW-IP without MAC-Header */ - olp->huptimer = 0; - lp->huptimer = 0; - skb->protocol = htons(ETH_P_IP); - break; - case ISDN_NET_ENCAP_CISCOHDLCK: - isdn_net_ciscohdlck_receive(lp, skb); - return; - case ISDN_NET_ENCAP_CISCOHDLC: - /* CISCO-HDLC IP with type field and fake I-frame-header */ - skb_pull(skb, 2); - /* Fall through */ - case ISDN_NET_ENCAP_IPTYP: - /* IP with type field */ - olp->huptimer = 0; - lp->huptimer = 0; - skb->protocol = *(__be16 *)&(skb->data[0]); - skb_pull(skb, 2); - if (*(unsigned short *) skb->data == 0xFFFF) - skb->protocol = htons(ETH_P_802_3); - break; -#ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - /* huptimer is done in isdn_ppp_push_higher */ - isdn_ppp_receive(lp->netdev, olp, skb); - return; -#endif - - default: -#ifdef CONFIG_ISDN_X25 - /* try if there are generic sync_device receiver routines */ - if (cprot) if (cprot->pops) - if (cprot->pops->data_ind) { - cprot->pops->data_ind(cprot, skb); - return; - }; -#endif /* CONFIG_ISDN_X25 */ - printk(KERN_WARNING "%s: unknown encapsulation, dropping\n", - lp->netdev->dev->name); - kfree_skb(skb); - return; - } - - netif_rx(skb); - return; -} - -/* - * A packet arrived via ISDN. Search interface-chain for a corresponding - * interface. If found, deliver packet to receiver-function and return 1, - * else return 0. - */ -int -isdn_net_rcv_skb(int idx, struct sk_buff *skb) -{ - isdn_net_dev *p = dev->rx_netdev[idx]; - - if (p) { - isdn_net_local *lp = p->local; - if ((lp->flags & ISDN_NET_CONNECTED) && - (!lp->dialstate)) { - isdn_net_receive(p->dev, skb); - return 1; - } - } - return 0; -} - -/* - * build an header - * depends on encaps that is being used. - */ - -static int isdn_net_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - const void *daddr, const void *saddr, unsigned plen) -{ - isdn_net_local *lp = netdev_priv(dev); - unsigned char *p; - int len = 0; - - switch (lp->p_encap) { - case ISDN_NET_ENCAP_ETHER: - len = eth_header(skb, dev, type, daddr, saddr, plen); - break; -#ifdef CONFIG_ISDN_PPP - case ISDN_NET_ENCAP_SYNCPPP: - /* stick on a fake header to keep fragmentation code happy. */ - len = IPPP_MAX_HEADER; - skb_push(skb, len); - break; -#endif - case ISDN_NET_ENCAP_RAWIP: - printk(KERN_WARNING "isdn_net_header called with RAW_IP!\n"); - len = 0; - break; - case ISDN_NET_ENCAP_IPTYP: - /* ethernet type field */ - *((__be16 *)skb_push(skb, 2)) = htons(type); - len = 2; - break; - case ISDN_NET_ENCAP_UIHDLC: - /* HDLC with UI-Frames (for ispa with -h1 option) */ - *((__be16 *)skb_push(skb, 2)) = htons(0x0103); - len = 2; - break; - case ISDN_NET_ENCAP_CISCOHDLC: - case ISDN_NET_ENCAP_CISCOHDLCK: - p = skb_push(skb, 4); - *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; - *(u8 *)(p + 1) = CISCO_CTRL; - *(__be16 *)(p + 2) = cpu_to_be16(type); - p += 4; - len = 4; - break; -#ifdef CONFIG_ISDN_X25 - default: - /* try if there are generic concap protocol routines */ - if (lp->netdev->cprot) { - printk(KERN_WARNING "isdn_net_header called with concap_proto!\n"); - len = 0; - break; - } - break; -#endif /* CONFIG_ISDN_X25 */ - } - return len; -} - -static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh, - __be16 type) -{ - const struct net_device *dev = neigh->dev; - isdn_net_local *lp = netdev_priv(dev); - - if (lp->p_encap == ISDN_NET_ENCAP_ETHER) - return eth_header_cache(neigh, hh, type); - return -1; -} - -static void isdn_header_cache_update(struct hh_cache *hh, - const struct net_device *dev, - const unsigned char *haddr) -{ - isdn_net_local *lp = netdev_priv(dev); - if (lp->p_encap == ISDN_NET_ENCAP_ETHER) - eth_header_cache_update(hh, dev, haddr); -} - -static const struct header_ops isdn_header_ops = { - .create = isdn_net_header, - .cache = isdn_header_cache, - .cache_update = isdn_header_cache_update, -}; - -/* - * Interface-setup. (just after registering a new interface) - */ -static int -isdn_net_init(struct net_device *ndev) -{ - ushort max_hlhdr_len = 0; - int drvidx; - - /* - * up till binding we ask the protocol layer to reserve as much - * as we might need for HL layer - */ - - for (drvidx = 0; drvidx < ISDN_MAX_DRIVERS; drvidx++) - if (dev->drv[drvidx]) - if (max_hlhdr_len < dev->drv[drvidx]->interface->hl_hdrlen) - max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen; - - ndev->hard_header_len = ETH_HLEN + max_hlhdr_len; - return 0; -} - -static void -isdn_net_swapbind(int drvidx) -{ - isdn_net_dev *p; - -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: swapping ch of %d\n", drvidx); -#endif - p = dev->netdev; - while (p) { - if (p->local->pre_device == drvidx) - switch (p->local->pre_channel) { - case 0: - p->local->pre_channel = 1; - break; - case 1: - p->local->pre_channel = 0; - break; - } - p = (isdn_net_dev *) p->next; - } -} - -static void -isdn_net_swap_usage(int i1, int i2) -{ - int u1 = dev->usage[i1] & ISDN_USAGE_EXCLUSIVE; - int u2 = dev->usage[i2] & ISDN_USAGE_EXCLUSIVE; - -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: usage of %d and %d\n", i1, i2); -#endif - dev->usage[i1] &= ~ISDN_USAGE_EXCLUSIVE; - dev->usage[i1] |= u2; - dev->usage[i2] &= ~ISDN_USAGE_EXCLUSIVE; - dev->usage[i2] |= u1; - isdn_info_update(); -} - -/* - * An incoming call-request has arrived. - * Search the interface-chain for an appropriate interface. - * If found, connect the interface to the ISDN-channel and initiate - * D- and B-Channel-setup. If secure-flag is set, accept only - * configured phone-numbers. If callback-flag is set, initiate - * callback-dialing. - * - * Return-Value: 0 = No appropriate interface for this call. - * 1 = Call accepted - * 2 = Reject call, wait cbdelay, then call back - * 3 = Reject call - * 4 = Wait cbdelay, then call back - * 5 = No appropriate interface for this call, - * would eventually match if CID was longer. - */ - -int -isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) -{ - char *eaz; - int si1; - int si2; - int ematch; - int wret; - int swapped; - int sidx = 0; - u_long flags; - isdn_net_dev *p; - isdn_net_phone *n; - char nr[ISDN_MSNLEN]; - char *my_eaz; - - /* Search name in netdev-chain */ - if (!setup->phone[0]) { - nr[0] = '0'; - nr[1] = '\0'; - printk(KERN_INFO "isdn_net: Incoming call without OAD, assuming '0'\n"); - } else - strlcpy(nr, setup->phone, ISDN_MSNLEN); - si1 = (int) setup->si1; - si2 = (int) setup->si2; - if (!setup->eazmsn[0]) { - printk(KERN_WARNING "isdn_net: Incoming call without CPN, assuming '0'\n"); - eaz = "0"; - } else - eaz = setup->eazmsn; - if (dev->net_verbose > 1) - printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz); - /* Accept DATA and VOICE calls at this stage - * local eaz is checked later for allowed call types - */ - if ((si1 != 7) && (si1 != 1)) { - if (dev->net_verbose > 1) - printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n"); - return 0; - } - n = (isdn_net_phone *) 0; - p = dev->netdev; - ematch = wret = swapped = 0; -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx, - dev->usage[idx]); -#endif - while (p) { - int matchret; - isdn_net_local *lp = p->local; - - /* If last check has triggered as binding-swap, revert it */ - switch (swapped) { - case 2: - isdn_net_swap_usage(idx, sidx); - /* fall through */ - case 1: - isdn_net_swapbind(di); - break; - } - swapped = 0; - /* check acceptable call types for DOV */ - my_eaz = isdn_map_eaz2msn(lp->msn, di); - if (si1 == 1) { /* it's a DOV call, check if we allow it */ - if (*my_eaz == 'v' || *my_eaz == 'V' || - *my_eaz == 'b' || *my_eaz == 'B') - my_eaz++; /* skip to allow a match */ - else - my_eaz = NULL; /* force non match */ - } else { /* it's a DATA call, check if we allow it */ - if (*my_eaz == 'b' || *my_eaz == 'B') - my_eaz++; /* skip to allow a match */ - } - if (my_eaz) - matchret = isdn_msncmp(eaz, my_eaz); - else - matchret = 1; - if (!matchret) - ematch = 1; - - /* Remember if more numbers eventually can match */ - if (matchret > wret) - wret = matchret; -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: if='%s', l.msn=%s, l.flags=%d, l.dstate=%d\n", - p->dev->name, lp->msn, lp->flags, lp->dialstate); -#endif - if ((!matchret) && /* EAZ is matching */ - (((!(lp->flags & ISDN_NET_CONNECTED)) && /* but not connected */ - (USG_NONE(dev->usage[idx]))) || /* and ch. unused or */ - ((((lp->dialstate == 4) || (lp->dialstate == 12)) && /* if dialing */ - (!(lp->flags & ISDN_NET_CALLBACK))) /* but no callback */ - ))) - { -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: match1, pdev=%d pch=%d\n", - lp->pre_device, lp->pre_channel); -#endif - if (dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) { - if ((lp->pre_channel != ch) || - (lp->pre_device != di)) { - /* Here we got a problem: - * If using an ICN-Card, an incoming call is always signaled on - * on the first channel of the card, if both channels are - * down. However this channel may be bound exclusive. If the - * second channel is free, this call should be accepted. - * The solution is horribly but it runs, so what: - * We exchange the exclusive bindings of the two channels, the - * corresponding variables in the interface-structs. - */ - if (ch == 0) { - sidx = isdn_dc2minor(di, 1); -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: ch is 0\n"); -#endif - if (USG_NONE(dev->usage[sidx])) { - /* Second Channel is free, now see if it is bound - * exclusive too. */ - if (dev->usage[sidx] & ISDN_USAGE_EXCLUSIVE) { -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: 2nd channel is down and bound\n"); -#endif - /* Yes, swap bindings only, if the original - * binding is bound to channel 1 of this driver */ - if ((lp->pre_device == di) && - (lp->pre_channel == 1)) { - isdn_net_swapbind(di); - swapped = 1; - } else { - /* ... else iterate next device */ - p = (isdn_net_dev *) p->next; - continue; - } - } else { -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: 2nd channel is down and unbound\n"); -#endif - /* No, swap always and swap excl-usage also */ - isdn_net_swap_usage(idx, sidx); - isdn_net_swapbind(di); - swapped = 2; - } - /* Now check for exclusive binding again */ -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: final check\n"); -#endif - if ((dev->usage[idx] & ISDN_USAGE_EXCLUSIVE) && - ((lp->pre_channel != ch) || - (lp->pre_device != di))) { -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: final check failed\n"); -#endif - p = (isdn_net_dev *) p->next; - continue; - } - } - } else { - /* We are already on the second channel, so nothing to do */ -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: already on 2nd channel\n"); -#endif - } - } - } -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: match2\n"); -#endif - n = lp->phone[0]; - if (lp->flags & ISDN_NET_SECURE) { - while (n) { - if (!isdn_msncmp(nr, n->num)) - break; - n = (isdn_net_phone *) n->next; - } - } - if (n || (!(lp->flags & ISDN_NET_SECURE))) { -#ifdef ISDN_DEBUG_NET_ICALL - printk(KERN_DEBUG "n_fi: match3\n"); -#endif - /* matching interface found */ - - /* - * Is the state STOPPED? - * If so, no dialin is allowed, - * so reject actively. - * */ - if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { - printk(KERN_INFO "incoming call, interface %s `stopped' -> rejected\n", - p->dev->name); - return 3; - } - /* - * Is the interface up? - * If not, reject the call actively. - */ - if (!isdn_net_device_started(p)) { - printk(KERN_INFO "%s: incoming call, interface down -> rejected\n", - p->dev->name); - return 3; - } - /* Interface is up, now see if it's a slave. If so, see if - * it's master and parent slave is online. If not, reject the call. - */ - if (lp->master) { - isdn_net_local *mlp = ISDN_MASTER_PRIV(lp); - printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name); - printk(KERN_DEBUG "master=%s\n", lp->master->name); - if (mlp->flags & ISDN_NET_CONNECTED) { - printk(KERN_DEBUG "master online\n"); - /* Master is online, find parent-slave (master if first slave) */ - while (mlp->slave) { - if (ISDN_SLAVE_PRIV(mlp) == lp) - break; - mlp = ISDN_SLAVE_PRIV(mlp); - } - } else - printk(KERN_DEBUG "master offline\n"); - /* Found parent, if it's offline iterate next device */ - printk(KERN_DEBUG "mlpf: %d\n", mlp->flags & ISDN_NET_CONNECTED); - if (!(mlp->flags & ISDN_NET_CONNECTED)) { - p = (isdn_net_dev *) p->next; - continue; - } - } - if (lp->flags & ISDN_NET_CALLBACK) { - int chi; - /* - * Is the state MANUAL? - * If so, no callback can be made, - * so reject actively. - * */ - if (ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_OFF) { - printk(KERN_INFO "incoming call for callback, interface %s `off' -> rejected\n", - p->dev->name); - return 3; - } - printk(KERN_DEBUG "%s: call from %s -> %s, start callback\n", - p->dev->name, nr, eaz); - if (lp->phone[1]) { - /* Grab a free ISDN-Channel */ - spin_lock_irqsave(&dev->lock, flags); - if ((chi = - isdn_get_free_channel( - ISDN_USAGE_NET, - lp->l2_proto, - lp->l3_proto, - lp->pre_device, - lp->pre_channel, - lp->msn) - ) < 0) { - - printk(KERN_WARNING "isdn_net_find_icall: No channel for %s\n", - p->dev->name); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - /* Setup dialstate. */ - lp->dtimer = 0; - lp->dialstate = 11; - /* Connect interface with channel */ - isdn_net_bind_channel(lp, chi); -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - if (isdn_ppp_bind(lp) < 0) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_unbind_channel(lp); - return 0; - } -#endif - spin_unlock_irqrestore(&dev->lock, flags); - /* Initiate dialing by returning 2 or 4 */ - return (lp->flags & ISDN_NET_CBHUP) ? 2 : 4; - } else - printk(KERN_WARNING "isdn_net: %s: No phone number\n", - p->dev->name); - return 0; - } else { - printk(KERN_DEBUG "%s: call from %s -> %s accepted\n", - p->dev->name, nr, eaz); - /* if this interface is dialing, it does it probably on a different - device, so free this device */ - if ((lp->dialstate == 4) || (lp->dialstate == 12)) { -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - isdn_ppp_free(lp); -#endif - isdn_net_lp_disconnected(lp); - isdn_free_channel(lp->isdn_device, lp->isdn_channel, - ISDN_USAGE_NET); - } - spin_lock_irqsave(&dev->lock, flags); - dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[idx] |= ISDN_USAGE_NET; - strcpy(dev->num[idx], nr); - isdn_info_update(); - dev->st_netdev[idx] = lp->netdev; - lp->isdn_device = di; - lp->isdn_channel = ch; - lp->ppp_slot = -1; - lp->flags |= ISDN_NET_CONNECTED; - lp->dialstate = 7; - lp->dtimer = 0; - lp->outgoing = 0; - lp->huptimer = 0; - lp->hupflags |= ISDN_WAITCHARGE; - lp->hupflags &= ~ISDN_HAVECHARGE; -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { - if (isdn_ppp_bind(lp) < 0) { - isdn_net_unbind_channel(lp); - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - } -#endif - spin_unlock_irqrestore(&dev->lock, flags); - return 1; - } - } - } - p = (isdn_net_dev *) p->next; - } - /* If none of configured EAZ/MSN matched and not verbose, be silent */ - if (!ematch || dev->net_verbose) - printk(KERN_INFO "isdn_net: call from %s -> %d %s ignored\n", nr, di, eaz); - return (wret == 2) ? 5 : 0; -} - -/* - * Search list of net-interfaces for an interface with given name. - */ -isdn_net_dev * -isdn_net_findif(char *name) -{ - isdn_net_dev *p = dev->netdev; - - while (p) { - if (!strcmp(p->dev->name, name)) - return p; - p = (isdn_net_dev *) p->next; - } - return (isdn_net_dev *) NULL; -} - -/* - * Force a net-interface to dial out. - * This is called from the userlevel-routine below or - * from isdn_net_start_xmit(). - */ -static int -isdn_net_force_dial_lp(isdn_net_local *lp) -{ - if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) { - int chi; - if (lp->phone[1]) { - ulong flags; - - /* Grab a free ISDN-Channel */ - spin_lock_irqsave(&dev->lock, flags); - if ((chi = isdn_get_free_channel( - ISDN_USAGE_NET, - lp->l2_proto, - lp->l3_proto, - lp->pre_device, - lp->pre_channel, - lp->msn)) < 0) { - printk(KERN_WARNING "isdn_net_force_dial: No channel for %s\n", - lp->netdev->dev->name); - spin_unlock_irqrestore(&dev->lock, flags); - return -EAGAIN; - } - lp->dialstate = 1; - /* Connect interface with channel */ - isdn_net_bind_channel(lp, chi); -#ifdef CONFIG_ISDN_PPP - if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) - if (isdn_ppp_bind(lp) < 0) { - isdn_net_unbind_channel(lp); - spin_unlock_irqrestore(&dev->lock, flags); - return -EAGAIN; - } -#endif - /* Initiate dialing */ - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_dial(); - return 0; - } else - return -EINVAL; - } else - return -EBUSY; -} - -/* - * This is called from certain upper protocol layers (multilink ppp - * and x25iface encapsulation module) that want to initiate dialing - * themselves. - */ -int -isdn_net_dial_req(isdn_net_local *lp) -{ - /* is there a better error code? */ - if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY; - - return isdn_net_force_dial_lp(lp); -} - -/* - * Force a net-interface to dial out. - * This is always called from within userspace (ISDN_IOCTL_NET_DIAL). - */ -int -isdn_net_force_dial(char *name) -{ - isdn_net_dev *p = isdn_net_findif(name); - - if (!p) - return -ENODEV; - return (isdn_net_force_dial_lp(p->local)); -} - -/* The ISDN-specific entries in the device structure. */ -static const struct net_device_ops isdn_netdev_ops = { - .ndo_init = isdn_net_init, - .ndo_open = isdn_net_open, - .ndo_stop = isdn_net_close, - .ndo_do_ioctl = isdn_net_ioctl, - - .ndo_start_xmit = isdn_net_start_xmit, - .ndo_get_stats = isdn_net_get_stats, - .ndo_tx_timeout = isdn_net_tx_timeout, -}; - -/* - * Helper for alloc_netdev() - */ -static void _isdn_setup(struct net_device *dev) -{ - isdn_net_local *lp = netdev_priv(dev); - - ether_setup(dev); - - /* Setup the generic properties */ - dev->flags = IFF_NOARP | IFF_POINTOPOINT; - - /* isdn prepends a header in the tx path, can't share skbs */ - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - dev->header_ops = NULL; - dev->netdev_ops = &isdn_netdev_ops; - - /* for clients with MPPP maybe higher values better */ - dev->tx_queue_len = 30; - - lp->p_encap = ISDN_NET_ENCAP_RAWIP; - lp->magic = ISDN_NET_MAGIC; - lp->last = lp; - lp->next = lp; - lp->isdn_device = -1; - lp->isdn_channel = -1; - lp->pre_device = -1; - lp->pre_channel = -1; - lp->exclusive = -1; - lp->ppp_slot = -1; - lp->pppbind = -1; - skb_queue_head_init(&lp->super_tx_queue); - lp->l2_proto = ISDN_PROTO_L2_X75I; - lp->l3_proto = ISDN_PROTO_L3_TRANS; - lp->triggercps = 6000; - lp->slavedelay = 10 * HZ; - lp->hupflags = ISDN_INHUP; /* Do hangup even on incoming calls */ - lp->onhtime = 10; /* Default hangup-time for saving costs */ - lp->dialmax = 1; - /* Hangup before Callback, manual dial */ - lp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL; - lp->cbdelay = 25; /* Wait 5 secs before Callback */ - lp->dialtimeout = -1; /* Infinite Dial-Timeout */ - lp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */ - lp->dialstarted = 0; /* Jiffies of last dial-start */ - lp->dialwait_timer = 0; /* Jiffies of earliest next dial-start */ -} - -/* - * Allocate a new network-interface and initialize its data structures. - */ -char * -isdn_net_new(char *name, struct net_device *master) -{ - isdn_net_dev *netdev; - - /* Avoid creating an existing interface */ - if (isdn_net_findif(name)) { - printk(KERN_WARNING "isdn_net: interface %s already exists\n", name); - return NULL; - } - if (name == NULL) - return NULL; - if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) { - printk(KERN_WARNING "isdn_net: Could not allocate net-device\n"); - return NULL; - } - netdev->dev = alloc_netdev(sizeof(isdn_net_local), name, - NET_NAME_UNKNOWN, _isdn_setup); - if (!netdev->dev) { - printk(KERN_WARNING "isdn_net: Could not allocate network device\n"); - kfree(netdev); - return NULL; - } - netdev->local = netdev_priv(netdev->dev); - - if (master) { - /* Device shall be a slave */ - struct net_device *p = MASTER_TO_SLAVE(master); - struct net_device *q = master; - - netdev->local->master = master; - /* Put device at end of slave-chain */ - while (p) { - q = p; - p = MASTER_TO_SLAVE(p); - } - MASTER_TO_SLAVE(q) = netdev->dev; - } else { - /* Device shall be a master */ - /* - * Watchdog timer (currently) for master only. - */ - netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT; - if (register_netdev(netdev->dev) != 0) { - printk(KERN_WARNING "isdn_net: Could not register net-device\n"); - free_netdev(netdev->dev); - kfree(netdev); - return NULL; - } - } - netdev->queue = netdev->local; - spin_lock_init(&netdev->queue_lock); - - netdev->local->netdev = netdev; - - INIT_WORK(&netdev->local->tqueue, isdn_net_softint); - spin_lock_init(&netdev->local->xmit_lock); - - /* Put into to netdev-chain */ - netdev->next = (void *) dev->netdev; - dev->netdev = netdev; - return netdev->dev->name; -} - -char * -isdn_net_newslave(char *parm) -{ - char *p = strchr(parm, ','); - isdn_net_dev *n; - char newname[10]; - - if (p) { - /* Slave-Name MUST not be empty or overflow 'newname' */ - if (strscpy(newname, p + 1, sizeof(newname)) <= 0) - return NULL; - *p = 0; - /* Master must already exist */ - if (!(n = isdn_net_findif(parm))) - return NULL; - /* Master must be a real interface, not a slave */ - if (n->local->master) - return NULL; - /* Master must not be started yet */ - if (isdn_net_device_started(n)) - return NULL; - return (isdn_net_new(newname, n->dev)); - } - return NULL; -} - -/* - * Set interface-parameters. - * Always set all parameters, so the user-level application is responsible - * for not overwriting existing setups. It has to get the current - * setup first, if only selected parameters are to be changed. - */ -int -isdn_net_setcfg(isdn_net_ioctl_cfg *cfg) -{ - isdn_net_dev *p = isdn_net_findif(cfg->name); - ulong features; - int i; - int drvidx; - int chidx; - char drvid[25]; - - if (p) { - isdn_net_local *lp = p->local; - - /* See if any registered driver supports the features we want */ - features = ((1 << cfg->l2_proto) << ISDN_FEATURE_L2_SHIFT) | - ((1 << cfg->l3_proto) << ISDN_FEATURE_L3_SHIFT); - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - if (dev->drv[i]) - if ((dev->drv[i]->interface->features & features) == features) - break; - if (i == ISDN_MAX_DRIVERS) { - printk(KERN_WARNING "isdn_net: No driver with selected features\n"); - return -ENODEV; - } - if (lp->p_encap != cfg->p_encap) { -#ifdef CONFIG_ISDN_X25 - struct concap_proto *cprot = p->cprot; -#endif - if (isdn_net_device_started(p)) { - printk(KERN_WARNING "%s: cannot change encap when if is up\n", - p->dev->name); - return -EBUSY; - } -#ifdef CONFIG_ISDN_X25 - if (cprot && cprot->pops) - cprot->pops->proto_del(cprot); - p->cprot = NULL; - lp->dops = NULL; - /* ... , prepare for configuration of new one ... */ - switch (cfg->p_encap) { - case ISDN_NET_ENCAP_X25IFACE: - lp->dops = &isdn_concap_reliable_dl_dops; - } - /* ... and allocate new one ... */ - p->cprot = isdn_concap_new(cfg->p_encap); - /* p -> cprot == NULL now if p_encap is not supported - by means of the concap_proto mechanism */ - /* the protocol is not configured yet; this will - happen later when isdn_net_reset() is called */ -#endif - } - switch (cfg->p_encap) { - case ISDN_NET_ENCAP_SYNCPPP: -#ifndef CONFIG_ISDN_PPP - printk(KERN_WARNING "%s: SyncPPP support not configured\n", - p->dev->name); - return -EINVAL; -#else - p->dev->type = ARPHRD_PPP; /* change ARP type */ - p->dev->addr_len = 0; -#endif - break; - case ISDN_NET_ENCAP_X25IFACE: -#ifndef CONFIG_ISDN_X25 - printk(KERN_WARNING "%s: isdn-x25 support not configured\n", - p->dev->name); - return -EINVAL; -#else - p->dev->type = ARPHRD_X25; /* change ARP type */ - p->dev->addr_len = 0; -#endif - break; - case ISDN_NET_ENCAP_CISCOHDLCK: - break; - default: - if (cfg->p_encap >= 0 && - cfg->p_encap <= ISDN_NET_ENCAP_MAX_ENCAP) - break; - printk(KERN_WARNING - "%s: encapsulation protocol %d not supported\n", - p->dev->name, cfg->p_encap); - return -EINVAL; - } - if (strlen(cfg->drvid)) { - /* A bind has been requested ... */ - char *c, - *e; - - if (strnlen(cfg->drvid, sizeof(cfg->drvid)) == - sizeof(cfg->drvid)) - return -EINVAL; - drvidx = -1; - chidx = -1; - strcpy(drvid, cfg->drvid); - if ((c = strchr(drvid, ','))) { - /* The channel-number is appended to the driver-Id with a comma */ - chidx = (int) simple_strtoul(c + 1, &e, 10); - if (e == c) - chidx = -1; - *c = '\0'; - } - for (i = 0; i < ISDN_MAX_DRIVERS; i++) - /* Lookup driver-Id in array */ - if (!(strcmp(dev->drvid[i], drvid))) { - drvidx = i; - break; - } - if ((drvidx == -1) || (chidx == -1)) - /* Either driver-Id or channel-number invalid */ - return -ENODEV; - } else { - /* Parameters are valid, so get them */ - drvidx = lp->pre_device; - chidx = lp->pre_channel; - } - if (cfg->exclusive > 0) { - unsigned long flags; - - /* If binding is exclusive, try to grab the channel */ - spin_lock_irqsave(&dev->lock, flags); - if ((i = isdn_get_free_channel(ISDN_USAGE_NET, - lp->l2_proto, lp->l3_proto, drvidx, - chidx, lp->msn)) < 0) { - /* Grab failed, because desired channel is in use */ - lp->exclusive = -1; - spin_unlock_irqrestore(&dev->lock, flags); - return -EBUSY; - } - /* All went ok, so update isdninfo */ - dev->usage[i] = ISDN_USAGE_EXCLUSIVE; - isdn_info_update(); - spin_unlock_irqrestore(&dev->lock, flags); - lp->exclusive = i; - } else { - /* Non-exclusive binding or unbind. */ - lp->exclusive = -1; - if ((lp->pre_device != -1) && (cfg->exclusive == -1)) { - isdn_unexclusive_channel(lp->pre_device, lp->pre_channel); - isdn_free_channel(lp->pre_device, lp->pre_channel, ISDN_USAGE_NET); - drvidx = -1; - chidx = -1; - } - } - strlcpy(lp->msn, cfg->eaz, sizeof(lp->msn)); - lp->pre_device = drvidx; - lp->pre_channel = chidx; - lp->onhtime = cfg->onhtime; - lp->charge = cfg->charge; - lp->l2_proto = cfg->l2_proto; - lp->l3_proto = cfg->l3_proto; - lp->cbdelay = cfg->cbdelay; - lp->dialmax = cfg->dialmax; - lp->triggercps = cfg->triggercps; - lp->slavedelay = cfg->slavedelay * HZ; - lp->pppbind = cfg->pppbind; - lp->dialtimeout = cfg->dialtimeout >= 0 ? cfg->dialtimeout * HZ : -1; - lp->dialwait = cfg->dialwait * HZ; - if (cfg->secure) - lp->flags |= ISDN_NET_SECURE; - else - lp->flags &= ~ISDN_NET_SECURE; - if (cfg->cbhup) - lp->flags |= ISDN_NET_CBHUP; - else - lp->flags &= ~ISDN_NET_CBHUP; - switch (cfg->callback) { - case 0: - lp->flags &= ~(ISDN_NET_CALLBACK | ISDN_NET_CBOUT); - break; - case 1: - lp->flags |= ISDN_NET_CALLBACK; - lp->flags &= ~ISDN_NET_CBOUT; - break; - case 2: - lp->flags |= ISDN_NET_CBOUT; - lp->flags &= ~ISDN_NET_CALLBACK; - break; - } - lp->flags &= ~ISDN_NET_DIALMODE_MASK; /* first all bits off */ - if (cfg->dialmode && !(cfg->dialmode & ISDN_NET_DIALMODE_MASK)) { - /* old isdnctrl version, where only 0 or 1 is given */ - printk(KERN_WARNING - "Old isdnctrl version detected! Please update.\n"); - lp->flags |= ISDN_NET_DM_OFF; /* turn on `off' bit */ - } - else { - lp->flags |= cfg->dialmode; /* turn on selected bits */ - } - if (cfg->chargehup) - lp->hupflags |= ISDN_CHARGEHUP; - else - lp->hupflags &= ~ISDN_CHARGEHUP; - if (cfg->ihup) - lp->hupflags |= ISDN_INHUP; - else - lp->hupflags &= ~ISDN_INHUP; - if (cfg->chargeint > 10) { - lp->hupflags |= ISDN_CHARGEHUP | ISDN_HAVECHARGE | ISDN_MANCHARGE; - lp->chargeint = cfg->chargeint * HZ; - } - if (cfg->p_encap != lp->p_encap) { - if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) { - p->dev->header_ops = NULL; - p->dev->flags = IFF_NOARP | IFF_POINTOPOINT; - } else { - p->dev->header_ops = &isdn_header_ops; - if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) - p->dev->flags = IFF_BROADCAST | IFF_MULTICAST; - else - p->dev->flags = IFF_NOARP | IFF_POINTOPOINT; - } - } - lp->p_encap = cfg->p_encap; - return 0; - } - return -ENODEV; -} - -/* - * Perform get-interface-parameters.ioctl - */ -int -isdn_net_getcfg(isdn_net_ioctl_cfg *cfg) -{ - isdn_net_dev *p = isdn_net_findif(cfg->name); - - if (p) { - isdn_net_local *lp = p->local; - - strcpy(cfg->eaz, lp->msn); - cfg->exclusive = lp->exclusive; - if (lp->pre_device >= 0) { - sprintf(cfg->drvid, "%s,%d", dev->drvid[lp->pre_device], - lp->pre_channel); - } else - cfg->drvid[0] = '\0'; - cfg->onhtime = lp->onhtime; - cfg->charge = lp->charge; - cfg->l2_proto = lp->l2_proto; - cfg->l3_proto = lp->l3_proto; - cfg->p_encap = lp->p_encap; - cfg->secure = (lp->flags & ISDN_NET_SECURE) ? 1 : 0; - cfg->callback = 0; - if (lp->flags & ISDN_NET_CALLBACK) - cfg->callback = 1; - if (lp->flags & ISDN_NET_CBOUT) - cfg->callback = 2; - cfg->cbhup = (lp->flags & ISDN_NET_CBHUP) ? 1 : 0; - cfg->dialmode = lp->flags & ISDN_NET_DIALMODE_MASK; - cfg->chargehup = (lp->hupflags & ISDN_CHARGEHUP) ? 1 : 0; - cfg->ihup = (lp->hupflags & ISDN_INHUP) ? 1 : 0; - cfg->cbdelay = lp->cbdelay; - cfg->dialmax = lp->dialmax; - cfg->triggercps = lp->triggercps; - cfg->slavedelay = lp->slavedelay / HZ; - cfg->chargeint = (lp->hupflags & ISDN_CHARGEHUP) ? - (lp->chargeint / HZ) : 0; - cfg->pppbind = lp->pppbind; - cfg->dialtimeout = lp->dialtimeout >= 0 ? lp->dialtimeout / HZ : -1; - cfg->dialwait = lp->dialwait / HZ; - if (lp->slave) { - if (strlen(lp->slave->name) >= 10) - strcpy(cfg->slave, "too-long"); - else - strcpy(cfg->slave, lp->slave->name); - } else - cfg->slave[0] = '\0'; - if (lp->master) { - if (strlen(lp->master->name) >= 10) - strcpy(cfg->master, "too-long"); - else - strcpy(cfg->master, lp->master->name); - } else - cfg->master[0] = '\0'; - return 0; - } - return -ENODEV; -} - -/* - * Add a phone-number to an interface. - */ -int -isdn_net_addphone(isdn_net_ioctl_phone *phone) -{ - isdn_net_dev *p = isdn_net_findif(phone->name); - isdn_net_phone *n; - - if (p) { - if (!(n = kmalloc(sizeof(isdn_net_phone), GFP_KERNEL))) - return -ENOMEM; - strlcpy(n->num, phone->phone, sizeof(n->num)); - n->next = p->local->phone[phone->outgoing & 1]; - p->local->phone[phone->outgoing & 1] = n; - return 0; - } - return -ENODEV; -} - -/* - * Copy a string of all phone-numbers of an interface to user space. - * This might sleep and must be called with the isdn semaphore down. - */ -int -isdn_net_getphones(isdn_net_ioctl_phone *phone, char __user *phones) -{ - isdn_net_dev *p = isdn_net_findif(phone->name); - int inout = phone->outgoing & 1; - int more = 0; - int count = 0; - isdn_net_phone *n; - - if (!p) - return -ENODEV; - inout &= 1; - for (n = p->local->phone[inout]; n; n = n->next) { - if (more) { - put_user(' ', phones++); - count++; - } - if (copy_to_user(phones, n->num, strlen(n->num) + 1)) { - return -EFAULT; - } - phones += strlen(n->num); - count += strlen(n->num); - more = 1; - } - put_user(0, phones); - count++; - return count; -} - -/* - * Copy a string containing the peer's phone number of a connected interface - * to user space. - */ -int -isdn_net_getpeer(isdn_net_ioctl_phone *phone, isdn_net_ioctl_phone __user *peer) -{ - isdn_net_dev *p = isdn_net_findif(phone->name); - int ch, dv, idx; - - if (!p) - return -ENODEV; - /* - * Theoretical race: while this executes, the remote number might - * become invalid (hang up) or change (new connection), resulting - * in (partially) wrong number copied to user. This race - * currently ignored. - */ - ch = p->local->isdn_channel; - dv = p->local->isdn_device; - if (ch < 0 && dv < 0) - return -ENOTCONN; - idx = isdn_dc2minor(dv, ch); - if (idx < 0) - return -ENODEV; - /* for pre-bound channels, we need this extra check */ - if (strncmp(dev->num[idx], "???", 3) == 0) - return -ENOTCONN; - strncpy(phone->phone, dev->num[idx], ISDN_MSNLEN); - phone->outgoing = USG_OUTGOING(dev->usage[idx]); - if (copy_to_user(peer, phone, sizeof(*peer))) - return -EFAULT; - return 0; -} -/* - * Delete a phone-number from an interface. - */ -int -isdn_net_delphone(isdn_net_ioctl_phone *phone) -{ - isdn_net_dev *p = isdn_net_findif(phone->name); - int inout = phone->outgoing & 1; - isdn_net_phone *n; - isdn_net_phone *m; - - if (p) { - n = p->local->phone[inout]; - m = NULL; - while (n) { - if (!strcmp(n->num, phone->phone)) { - if (p->local->dial == n) - p->local->dial = n->next; - if (m) - m->next = n->next; - else - p->local->phone[inout] = n->next; - kfree(n); - return 0; - } - m = n; - n = (isdn_net_phone *) n->next; - } - return -EINVAL; - } - return -ENODEV; -} - -/* - * Delete all phone-numbers of an interface. - */ -static int -isdn_net_rmallphone(isdn_net_dev *p) -{ - isdn_net_phone *n; - isdn_net_phone *m; - int i; - - for (i = 0; i < 2; i++) { - n = p->local->phone[i]; - while (n) { - m = n->next; - kfree(n); - n = m; - } - p->local->phone[i] = NULL; - } - p->local->dial = NULL; - return 0; -} - -/* - * Force a hangup of a network-interface. - */ -int -isdn_net_force_hangup(char *name) -{ - isdn_net_dev *p = isdn_net_findif(name); - struct net_device *q; - - if (p) { - if (p->local->isdn_device < 0) - return 1; - q = p->local->slave; - /* If this interface has slaves, do a hangup for them also. */ - while (q) { - isdn_net_hangup(q); - q = MASTER_TO_SLAVE(q); - } - isdn_net_hangup(p->dev); - return 0; - } - return -ENODEV; -} - -/* - * Helper-function for isdn_net_rm: Do the real work. - */ -static int -isdn_net_realrm(isdn_net_dev *p, isdn_net_dev *q) -{ - u_long flags; - - if (isdn_net_device_started(p)) { - return -EBUSY; - } -#ifdef CONFIG_ISDN_X25 - if (p->cprot && p->cprot->pops) - p->cprot->pops->proto_del(p->cprot); -#endif - /* Free all phone-entries */ - isdn_net_rmallphone(p); - /* If interface is bound exclusive, free channel-usage */ - if (p->local->exclusive != -1) - isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel); - if (p->local->master) { - /* It's a slave-device, so update master's slave-pointer if necessary */ - if (((isdn_net_local *) ISDN_MASTER_PRIV(p->local))->slave == - p->dev) - ((isdn_net_local *)ISDN_MASTER_PRIV(p->local))->slave = - p->local->slave; - } else { - /* Unregister only if it's a master-device */ - unregister_netdev(p->dev); - } - /* Unlink device from chain */ - spin_lock_irqsave(&dev->lock, flags); - if (q) - q->next = p->next; - else - dev->netdev = p->next; - if (p->local->slave) { - /* If this interface has a slave, remove it also */ - char *slavename = p->local->slave->name; - isdn_net_dev *n = dev->netdev; - q = NULL; - while (n) { - if (!strcmp(n->dev->name, slavename)) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_net_realrm(n, q); - spin_lock_irqsave(&dev->lock, flags); - break; - } - q = n; - n = (isdn_net_dev *)n->next; - } - } - spin_unlock_irqrestore(&dev->lock, flags); - /* If no more net-devices remain, disable auto-hangup timer */ - if (dev->netdev == NULL) - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0); - free_netdev(p->dev); - kfree(p); - - return 0; -} - -/* - * Remove a single network-interface. - */ -int -isdn_net_rm(char *name) -{ - u_long flags; - isdn_net_dev *p; - isdn_net_dev *q; - - /* Search name in netdev-chain */ - spin_lock_irqsave(&dev->lock, flags); - p = dev->netdev; - q = NULL; - while (p) { - if (!strcmp(p->dev->name, name)) { - spin_unlock_irqrestore(&dev->lock, flags); - return (isdn_net_realrm(p, q)); - } - q = p; - p = (isdn_net_dev *) p->next; - } - spin_unlock_irqrestore(&dev->lock, flags); - /* If no more net-devices remain, disable auto-hangup timer */ - if (dev->netdev == NULL) - isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0); - return -ENODEV; -} - -/* - * Remove all network-interfaces - */ -int -isdn_net_rmall(void) -{ - u_long flags; - int ret; - - /* Walk through netdev-chain */ - spin_lock_irqsave(&dev->lock, flags); - while (dev->netdev) { - if (!dev->netdev->local->master) { - /* Remove master-devices only, slaves get removed with their master */ - spin_unlock_irqrestore(&dev->lock, flags); - if ((ret = isdn_net_realrm(dev->netdev, NULL))) { - return ret; - } - spin_lock_irqsave(&dev->lock, flags); - } - } - dev->netdev = NULL; - spin_unlock_irqrestore(&dev->lock, flags); - return 0; -} diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h deleted file mode 100644 index cca6d68da171..000000000000 --- a/drivers/isdn/i4l/isdn_net.h +++ /dev/null @@ -1,151 +0,0 @@ -/* $Id: isdn_net.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem, network related functions (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -/* Definitions for hupflags: */ -#define ISDN_WAITCHARGE 1 /* did not get a charge info yet */ -#define ISDN_HAVECHARGE 2 /* We know a charge info */ -#define ISDN_CHARGEHUP 4 /* We want to use the charge mechanism */ -#define ISDN_INHUP 8 /* Even if incoming, close after huptimeout */ -#define ISDN_MANCHARGE 16 /* Charge Interval manually set */ - -/* - * Definitions for Cisco-HDLC header. - */ - -#define CISCO_ADDR_UNICAST 0x0f -#define CISCO_ADDR_BROADCAST 0x8f -#define CISCO_CTRL 0x00 -#define CISCO_TYPE_CDP 0x2000 -#define CISCO_TYPE_SLARP 0x8035 -#define CISCO_SLARP_REQUEST 0 -#define CISCO_SLARP_REPLY 1 -#define CISCO_SLARP_KEEPALIVE 2 - -extern char *isdn_net_new(char *, struct net_device *); -extern char *isdn_net_newslave(char *); -extern int isdn_net_rm(char *); -extern int isdn_net_rmall(void); -extern int isdn_net_stat_callback(int, isdn_ctrl *); -extern int isdn_net_setcfg(isdn_net_ioctl_cfg *); -extern int isdn_net_getcfg(isdn_net_ioctl_cfg *); -extern int isdn_net_addphone(isdn_net_ioctl_phone *); -extern int isdn_net_getphones(isdn_net_ioctl_phone *, char __user *); -extern int isdn_net_getpeer(isdn_net_ioctl_phone *, isdn_net_ioctl_phone __user *); -extern int isdn_net_delphone(isdn_net_ioctl_phone *); -extern int isdn_net_find_icall(int, int, int, setup_parm *); -extern void isdn_net_hangup(struct net_device *); -extern void isdn_net_dial(void); -extern void isdn_net_autohup(void); -extern int isdn_net_force_hangup(char *); -extern int isdn_net_force_dial(char *); -extern isdn_net_dev *isdn_net_findif(char *); -extern int isdn_net_rcv_skb(int, struct sk_buff *); -extern int isdn_net_dial_req(isdn_net_local *); -extern void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb); -extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb); - -#define ISDN_NET_MAX_QUEUE_LENGTH 2 - -#define ISDN_MASTER_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->master)) -#define ISDN_SLAVE_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->slave)) -#define MASTER_TO_SLAVE(master) \ - (((isdn_net_local *) netdev_priv(master))->slave) - -/* - * is this particular channel busy? - */ -static __inline__ int isdn_net_lp_busy(isdn_net_local *lp) -{ - if (atomic_read(&lp->frame_cnt) < ISDN_NET_MAX_QUEUE_LENGTH) - return 0; - else - return 1; -} - -/* - * For the given net device, this will get a non-busy channel out of the - * corresponding bundle. The returned channel is locked. - */ -static __inline__ isdn_net_local *isdn_net_get_locked_lp(isdn_net_dev *nd) -{ - unsigned long flags; - isdn_net_local *lp; - - spin_lock_irqsave(&nd->queue_lock, flags); - lp = nd->queue; /* get lp on top of queue */ - while (isdn_net_lp_busy(nd->queue)) { - nd->queue = nd->queue->next; - if (nd->queue == lp) { /* not found -- should never happen */ - lp = NULL; - goto errout; - } - } - lp = nd->queue; - nd->queue = nd->queue->next; - spin_unlock_irqrestore(&nd->queue_lock, flags); - spin_lock(&lp->xmit_lock); - local_bh_disable(); - return lp; -errout: - spin_unlock_irqrestore(&nd->queue_lock, flags); - return lp; -} - -/* - * add a channel to a bundle - */ -static __inline__ void isdn_net_add_to_bundle(isdn_net_dev *nd, isdn_net_local *nlp) -{ - isdn_net_local *lp; - unsigned long flags; - - spin_lock_irqsave(&nd->queue_lock, flags); - - lp = nd->queue; -// printk(KERN_DEBUG "%s: lp:%s(%p) nlp:%s(%p) last(%p)\n", -// __func__, lp->name, lp, nlp->name, nlp, lp->last); - nlp->last = lp->last; - lp->last->next = nlp; - lp->last = nlp; - nlp->next = lp; - nd->queue = nlp; - - spin_unlock_irqrestore(&nd->queue_lock, flags); -} -/* - * remove a channel from the bundle it belongs to - */ -static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) -{ - isdn_net_local *master_lp = lp; - unsigned long flags; - - if (lp->master) - master_lp = ISDN_MASTER_PRIV(lp); - -// printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n", -// __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); - spin_lock_irqsave(&master_lp->netdev->queue_lock, flags); - lp->last->next = lp->next; - lp->next->last = lp->last; - if (master_lp->netdev->queue == lp) { - master_lp->netdev->queue = lp->next; - if (lp->next == lp) { /* last in queue */ - master_lp->netdev->queue = master_lp->netdev->local; - } - } - lp->next = lp->last = lp; /* (re)set own pointers */ -// printk(KERN_DEBUG "%s: mndq(%p)\n", -// __func__, master_lp->netdev->queue); - spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); -} diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c deleted file mode 100644 index 7e0f419c14f8..000000000000 --- a/drivers/isdn/i4l/isdn_ppp.c +++ /dev/null @@ -1,3046 +0,0 @@ -/* $Id: isdn_ppp.c,v 1.1.2.3 2004/02/10 01:07:13 keil Exp $ - * - * Linux ISDN subsystem, functions for synchronous PPP (linklevel). - * - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/isdn.h> -#include <linux/poll.h> -#include <linux/ppp-comp.h> -#include <linux/slab.h> -#ifdef CONFIG_IPPP_FILTER -#include <linux/filter.h> -#endif - -#include "isdn_common.h" -#include "isdn_ppp.h" -#include "isdn_net.h" - -#ifndef PPP_IPX -#define PPP_IPX 0x002b -#endif - -/* Prototypes */ -static int isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot); -static int isdn_ppp_closewait(int slot); -static void isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb, int proto); -static int isdn_ppp_if_get_unit(char *namebuf); -static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *); -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *, - struct ippp_struct *, struct ippp_struct *, int *proto); -static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb, int proto); -static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto, - struct ippp_struct *is, struct ippp_struct *master, int type); -static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb); - -/* New CCP stuff */ -static void isdn_ppp_ccp_kickup(struct ippp_struct *is); -static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, - unsigned char code, unsigned char id, - unsigned char *data, int len); -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is); -static void isdn_ppp_ccp_reset_free(struct ippp_struct *is); -static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, - unsigned char id); -static void isdn_ppp_ccp_timer_callback(struct timer_list *t); -static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, - unsigned char id); -static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, - struct isdn_ppp_resetparams *rp); -static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, - unsigned char id); - - - -#ifdef CONFIG_ISDN_MPP -static ippp_bundle *isdn_ppp_bundle_arr = NULL; - -static int isdn_ppp_mp_bundle_array_init(void); -static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to); -static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb); -static void isdn_ppp_mp_cleanup(isdn_net_local *lp); - -static int isdn_ppp_bundle(struct ippp_struct *, int unit); -#endif /* CONFIG_ISDN_MPP */ - -char *isdn_ppp_revision = "$Revision: 1.1.2.3 $"; - -static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; - -static struct isdn_ppp_compressor *ipc_head = NULL; - -/* - * frame log (debug) - */ -static void -isdn_ppp_frame_log(char *info, char *data, int len, int maxlen, int unit, int slot) -{ - int cnt, - j, - i; - char buf[80]; - - if (len < maxlen) - maxlen = len; - - for (i = 0, cnt = 0; cnt < maxlen; i++) { - for (j = 0; j < 16 && cnt < maxlen; j++, cnt++) - sprintf(buf + j * 3, "%02x ", (unsigned char)data[cnt]); - printk(KERN_DEBUG "[%d/%d].%s[%d]: %s\n", unit, slot, info, i, buf); - } -} - -/* - * unbind isdn_net_local <=> ippp-device - * note: it can happen, that we hangup/free the master before the slaves - * in this case we bind another lp to the master device - */ -int -isdn_ppp_free(isdn_net_local *lp) -{ - struct ippp_struct *is; - - if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __func__, lp->ppp_slot); - return 0; - } - -#ifdef CONFIG_ISDN_MPP - spin_lock(&lp->netdev->pb->lock); -#endif - isdn_net_rm_from_bundle(lp); -#ifdef CONFIG_ISDN_MPP - if (lp->netdev->pb->ref_ct == 1) /* last link in queue? */ - isdn_ppp_mp_cleanup(lp); - - lp->netdev->pb->ref_ct--; - spin_unlock(&lp->netdev->pb->lock); -#endif /* CONFIG_ISDN_MPP */ - if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) now invalid\n", - __func__, lp->ppp_slot); - return 0; - } - is = ippp_table[lp->ppp_slot]; - if ((is->state & IPPP_CONNECT)) - isdn_ppp_closewait(lp->ppp_slot); /* force wakeup on ippp device */ - else if (is->state & IPPP_ASSIGNED) - is->state = IPPP_OPEN; /* fallback to 'OPEN but not ASSIGNED' state */ - - if (is->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_free %d %lx %lx\n", lp->ppp_slot, (long) lp, (long) is->lp); - - is->lp = NULL; /* link is down .. set lp to NULL */ - lp->ppp_slot = -1; /* is this OK ?? */ - - return 0; -} - -/* - * bind isdn_net_local <=> ippp-device - * - * This function is allways called with holding dev->lock so - * no additional lock is needed - */ -int -isdn_ppp_bind(isdn_net_local *lp) -{ - int i; - int unit = 0; - struct ippp_struct *is; - int retval; - - if (lp->pppbind < 0) { /* device bounded to ippp device ? */ - isdn_net_dev *net_dev = dev->netdev; - char exclusive[ISDN_MAX_CHANNELS]; /* exclusive flags */ - memset(exclusive, 0, ISDN_MAX_CHANNELS); - while (net_dev) { /* step through net devices to find exclusive minors */ - isdn_net_local *lp = net_dev->local; - if (lp->pppbind >= 0) - exclusive[lp->pppbind] = 1; - net_dev = net_dev->next; - } - /* - * search a free device / slot - */ - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i]->state == IPPP_OPEN && !exclusive[ippp_table[i]->minor]) { /* OPEN, but not connected! */ - break; - } - } - } else { - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (ippp_table[i]->minor == lp->pppbind && - (ippp_table[i]->state & IPPP_OPEN) == IPPP_OPEN) - break; - } - } - - if (i >= ISDN_MAX_CHANNELS) { - printk(KERN_WARNING "isdn_ppp_bind: Can't find a (free) connection to the ipppd daemon.\n"); - retval = -1; - goto out; - } - /* get unit number from interface name .. ugly! */ - unit = isdn_ppp_if_get_unit(lp->netdev->dev->name); - if (unit < 0) { - printk(KERN_ERR "isdn_ppp_bind: illegal interface name %s.\n", - lp->netdev->dev->name); - retval = -1; - goto out; - } - - lp->ppp_slot = i; - is = ippp_table[i]; - is->lp = lp; - is->unit = unit; - is->state = IPPP_OPEN | IPPP_ASSIGNED; /* assigned to a netdevice but not connected */ -#ifdef CONFIG_ISDN_MPP - retval = isdn_ppp_mp_init(lp, NULL); - if (retval < 0) - goto out; -#endif /* CONFIG_ISDN_MPP */ - - retval = lp->ppp_slot; - -out: - return retval; -} - -/* - * kick the ipppd on the device - * (wakes up daemon after B-channel connect) - */ - -void -isdn_ppp_wakeup_daemon(isdn_net_local *lp) -{ - if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: ppp_slot(%d) out of range\n", - __func__, lp->ppp_slot); - return; - } - ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK; - wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq); -} - -/* - * there was a hangup on the netdevice - * force wakeup of the ippp device - * go into 'device waits for release' state - */ -static int -isdn_ppp_closewait(int slot) -{ - struct ippp_struct *is; - - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: slot(%d) out of range\n", - __func__, slot); - return 0; - } - is = ippp_table[slot]; - if (is->state) - wake_up_interruptible(&is->wq); - is->state = IPPP_CLOSEWAIT; - return 1; -} - -/* - * isdn_ppp_find_slot / isdn_ppp_free_slot - */ - -static int -isdn_ppp_get_slot(void) -{ - int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (!ippp_table[i]->state) - return i; - } - return -1; -} - -/* - * isdn_ppp_open - */ - -int -isdn_ppp_open(int min, struct file *file) -{ - int slot; - struct ippp_struct *is; - - if (min < 0 || min >= ISDN_MAX_CHANNELS) - return -ENODEV; - - slot = isdn_ppp_get_slot(); - if (slot < 0) { - return -EBUSY; - } - is = file->private_data = ippp_table[slot]; - - printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", - slot, min, is->state); - - /* compression stuff */ - is->link_compressor = is->compressor = NULL; - is->link_decompressor = is->decompressor = NULL; - is->link_comp_stat = is->comp_stat = NULL; - is->link_decomp_stat = is->decomp_stat = NULL; - is->compflags = 0; - - is->reset = isdn_ppp_ccp_reset_alloc(is); - if (!is->reset) - return -ENOMEM; - - is->lp = NULL; - is->mp_seqno = 0; /* MP sequence number */ - is->pppcfg = 0; /* ppp configuration */ - is->mpppcfg = 0; /* mppp configuration */ - is->last_link_seqno = -1; /* MP: maybe set to Bundle-MIN, when joining a bundle ?? */ - is->unit = -1; /* set, when we have our interface */ - is->mru = 1524; /* MRU, default 1524 */ - is->maxcid = 16; /* VJ: maxcid */ - is->tk = current; - init_waitqueue_head(&is->wq); - is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ - is->last = is->rq; - is->minor = min; -#ifdef CONFIG_ISDN_PPP_VJ - /* - * VJ header compression init - */ - is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ - if (IS_ERR(is->slcomp)) { - isdn_ppp_ccp_reset_free(is); - return PTR_ERR(is->slcomp); - } -#endif -#ifdef CONFIG_IPPP_FILTER - is->pass_filter = NULL; - is->active_filter = NULL; -#endif - is->state = IPPP_OPEN; - - return 0; -} - -/* - * release ippp device - */ -void -isdn_ppp_release(int min, struct file *file) -{ - int i; - struct ippp_struct *is; - - if (min < 0 || min >= ISDN_MAX_CHANNELS) - return; - is = file->private_data; - - if (!is) { - printk(KERN_ERR "%s: no file->private_data\n", __func__); - return; - } - if (is->debug & 0x1) - printk(KERN_DEBUG "ippp: release, minor: %d %lx\n", min, (long) is->lp); - - if (is->lp) { /* a lp address says: this link is still up */ - isdn_net_dev *p = is->lp->netdev; - - if (!p) { - printk(KERN_ERR "%s: no lp->netdev\n", __func__); - return; - } - is->state &= ~IPPP_CONNECT; /* -> effect: no call of wakeup */ - /* - * isdn_net_hangup() calls isdn_ppp_free() - * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1 - * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon() - */ - isdn_net_hangup(p->dev); - } - for (i = 0; i < NUM_RCV_BUFFS; i++) { - kfree(is->rq[i].buf); - is->rq[i].buf = NULL; - } - is->first = is->rq + NUM_RCV_BUFFS - 1; /* receive queue */ - is->last = is->rq; - -#ifdef CONFIG_ISDN_PPP_VJ -/* TODO: if this was the previous master: link the slcomp to the new master */ - slhc_free(is->slcomp); - is->slcomp = NULL; -#endif -#ifdef CONFIG_IPPP_FILTER - if (is->pass_filter) { - bpf_prog_destroy(is->pass_filter); - is->pass_filter = NULL; - } - - if (is->active_filter) { - bpf_prog_destroy(is->active_filter); - is->active_filter = NULL; - } -#endif - -/* TODO: if this was the previous master: link the stuff to the new master */ - if (is->comp_stat) - is->compressor->free(is->comp_stat); - if (is->link_comp_stat) - is->link_compressor->free(is->link_comp_stat); - if (is->link_decomp_stat) - is->link_decompressor->free(is->link_decomp_stat); - if (is->decomp_stat) - is->decompressor->free(is->decomp_stat); - is->compressor = is->link_compressor = NULL; - is->decompressor = is->link_decompressor = NULL; - is->comp_stat = is->link_comp_stat = NULL; - is->decomp_stat = is->link_decomp_stat = NULL; - - /* Clean up if necessary */ - if (is->reset) - isdn_ppp_ccp_reset_free(is); - - /* this slot is ready for new connections */ - is->state = 0; -} - -/* - * get_arg .. ioctl helper - */ -static int -get_arg(void __user *b, void *val, int len) -{ - if (len <= 0) - len = sizeof(void *); - if (copy_from_user(val, b, len)) - return -EFAULT; - return 0; -} - -/* - * set arg .. ioctl helper - */ -static int -set_arg(void __user *b, void *val, int len) -{ - if (len <= 0) - len = sizeof(void *); - if (copy_to_user(b, val, len)) - return -EFAULT; - return 0; -} - -#ifdef CONFIG_IPPP_FILTER -static int get_filter(void __user *arg, struct sock_filter **p) -{ - struct sock_fprog uprog; - struct sock_filter *code = NULL; - int len; - - if (copy_from_user(&uprog, arg, sizeof(uprog))) - return -EFAULT; - - if (!uprog.len) { - *p = NULL; - return 0; - } - - /* uprog.len is unsigned short, so no overflow here */ - len = uprog.len * sizeof(struct sock_filter); - code = memdup_user(uprog.filter, len); - if (IS_ERR(code)) - return PTR_ERR(code); - - *p = code; - return uprog.len; -} -#endif /* CONFIG_IPPP_FILTER */ - -/* - * ippp device ioctl - */ -int -isdn_ppp_ioctl(int min, struct file *file, unsigned int cmd, unsigned long arg) -{ - unsigned long val; - int r, i, j; - struct ippp_struct *is; - isdn_net_local *lp; - struct isdn_ppp_comp_data data; - void __user *argp = (void __user *)arg; - - is = file->private_data; - lp = is->lp; - - if (is->debug & 0x1) - printk(KERN_DEBUG "isdn_ppp_ioctl: minor: %d cmd: %x state: %x\n", min, cmd, is->state); - - if (!(is->state & IPPP_OPEN)) - return -EINVAL; - - switch (cmd) { - case PPPIOCBUNDLE: -#ifdef CONFIG_ISDN_MPP - if (!(is->state & IPPP_CONNECT)) - return -EINVAL; - if ((r = get_arg(argp, &val, sizeof(val)))) - return r; - printk(KERN_DEBUG "iPPP-bundle: minor: %d, slave unit: %d, master unit: %d\n", - (int) min, (int) is->unit, (int) val); - return isdn_ppp_bundle(is, val); -#else - return -1; -#endif - break; - case PPPIOCGUNIT: /* get ppp/isdn unit number */ - if ((r = set_arg(argp, &is->unit, sizeof(is->unit)))) - return r; - break; - case PPPIOCGIFNAME: - if (!lp) - return -EINVAL; - if ((r = set_arg(argp, lp->netdev->dev->name, - strlen(lp->netdev->dev->name)))) - return r; - break; - case PPPIOCGMPFLAGS: /* get configuration flags */ - if ((r = set_arg(argp, &is->mpppcfg, sizeof(is->mpppcfg)))) - return r; - break; - case PPPIOCSMPFLAGS: /* set configuration flags */ - if ((r = get_arg(argp, &val, sizeof(val)))) - return r; - is->mpppcfg = val; - break; - case PPPIOCGFLAGS: /* get configuration flags */ - if ((r = set_arg(argp, &is->pppcfg, sizeof(is->pppcfg)))) - return r; - break; - case PPPIOCSFLAGS: /* set configuration flags */ - if ((r = get_arg(argp, &val, sizeof(val)))) { - return r; - } - if (val & SC_ENABLE_IP && !(is->pppcfg & SC_ENABLE_IP) && (is->state & IPPP_CONNECT)) { - if (lp) { - /* OK .. we are ready to send buffers */ - is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */ - netif_wake_queue(lp->netdev->dev); - break; - } - } - is->pppcfg = val; - break; - case PPPIOCGIDLE: /* get idle time information */ - if (lp) { - struct ppp_idle pidle; - pidle.xmit_idle = pidle.recv_idle = lp->huptimer; - if ((r = set_arg(argp, &pidle, sizeof(struct ppp_idle)))) - return r; - } - break; - case PPPIOCSMRU: /* set receive unit size for PPP */ - if ((r = get_arg(argp, &val, sizeof(val)))) - return r; - is->mru = val; - break; - case PPPIOCSMPMRU: - break; - case PPPIOCSMPMTU: - break; - case PPPIOCSMAXCID: /* set the maximum compression slot id */ - if ((r = get_arg(argp, &val, sizeof(val)))) - return r; - val++; - if (is->maxcid != val) { -#ifdef CONFIG_ISDN_PPP_VJ - struct slcompress *sltmp; -#endif - if (is->debug & 0x1) - printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n", val); - is->maxcid = val; -#ifdef CONFIG_ISDN_PPP_VJ - sltmp = slhc_init(16, val); - if (IS_ERR(sltmp)) - return PTR_ERR(sltmp); - if (is->slcomp) - slhc_free(is->slcomp); - is->slcomp = sltmp; -#endif - } - break; - case PPPIOCGDEBUG: - if ((r = set_arg(argp, &is->debug, sizeof(is->debug)))) - return r; - break; - case PPPIOCSDEBUG: - if ((r = get_arg(argp, &val, sizeof(val)))) - return r; - is->debug = val; - break; - case PPPIOCGCOMPRESSORS: - { - unsigned long protos[8] = {0,}; - struct isdn_ppp_compressor *ipc = ipc_head; - while (ipc) { - j = ipc->num / (sizeof(long) * 8); - i = ipc->num % (sizeof(long) * 8); - if (j < 8) - protos[j] |= (1UL << i); - ipc = ipc->next; - } - if ((r = set_arg(argp, protos, 8 * sizeof(long)))) - return r; - } - break; - case PPPIOCSCOMPRESSOR: - if ((r = get_arg(argp, &data, sizeof(struct isdn_ppp_comp_data)))) - return r; - return isdn_ppp_set_compressor(is, &data); - case PPPIOCGCALLINFO: - { - struct pppcallinfo pci; - memset((char *)&pci, 0, sizeof(struct pppcallinfo)); - if (lp) - { - strncpy(pci.local_num, lp->msn, 63); - if (lp->dial) { - strncpy(pci.remote_num, lp->dial->num, 63); - } - pci.charge_units = lp->charge; - if (lp->outgoing) - pci.calltype = CALLTYPE_OUTGOING; - else - pci.calltype = CALLTYPE_INCOMING; - if (lp->flags & ISDN_NET_CALLBACK) - pci.calltype |= CALLTYPE_CALLBACK; - } - return set_arg(argp, &pci, sizeof(struct pppcallinfo)); - } -#ifdef CONFIG_IPPP_FILTER - case PPPIOCSPASS: - { - struct sock_fprog_kern fprog; - struct sock_filter *code; - int err, len = get_filter(argp, &code); - - if (len < 0) - return len; - - fprog.len = len; - fprog.filter = code; - - if (is->pass_filter) { - bpf_prog_destroy(is->pass_filter); - is->pass_filter = NULL; - } - if (fprog.filter != NULL) - err = bpf_prog_create(&is->pass_filter, &fprog); - else - err = 0; - kfree(code); - - return err; - } - case PPPIOCSACTIVE: - { - struct sock_fprog_kern fprog; - struct sock_filter *code; - int err, len = get_filter(argp, &code); - - if (len < 0) - return len; - - fprog.len = len; - fprog.filter = code; - - if (is->active_filter) { - bpf_prog_destroy(is->active_filter); - is->active_filter = NULL; - } - if (fprog.filter != NULL) - err = bpf_prog_create(&is->active_filter, &fprog); - else - err = 0; - kfree(code); - - return err; - } -#endif /* CONFIG_IPPP_FILTER */ - default: - break; - } - return 0; -} - -__poll_t -isdn_ppp_poll(struct file *file, poll_table *wait) -{ - __poll_t mask; - struct ippp_buf_queue *bf, *bl; - u_long flags; - struct ippp_struct *is; - - is = file->private_data; - - if (is->debug & 0x2) - printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n", - iminor(file_inode(file))); - - /* just registers wait_queue hook. This doesn't really wait. */ - poll_wait(file, &is->wq, wait); - - if (!(is->state & IPPP_OPEN)) { - if (is->state == IPPP_CLOSEWAIT) - return EPOLLHUP; - printk(KERN_DEBUG "isdn_ppp: device not open\n"); - return EPOLLERR; - } - /* we're always ready to send .. */ - mask = EPOLLOUT | EPOLLWRNORM; - - spin_lock_irqsave(&is->buflock, flags); - bl = is->last; - bf = is->first; - /* - * if IPPP_NOBLOCK is set we return even if we have nothing to read - */ - if (bf->next != bl || (is->state & IPPP_NOBLOCK)) { - is->state &= ~IPPP_NOBLOCK; - mask |= EPOLLIN | EPOLLRDNORM; - } - spin_unlock_irqrestore(&is->buflock, flags); - return mask; -} - -/* - * fill up isdn_ppp_read() queue .. - */ - -static int -isdn_ppp_fill_rq(unsigned char *buf, int len, int proto, int slot) -{ - struct ippp_buf_queue *bf, *bl; - u_long flags; - u_char *nbuf; - struct ippp_struct *is; - - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot); - return 0; - } - is = ippp_table[slot]; - - if (!(is->state & IPPP_CONNECT)) { - printk(KERN_DEBUG "ippp: device not activated.\n"); - return 0; - } - nbuf = kmalloc(len + 4, GFP_ATOMIC); - if (!nbuf) { - printk(KERN_WARNING "ippp: Can't alloc buf\n"); - return 0; - } - nbuf[0] = PPP_ALLSTATIONS; - nbuf[1] = PPP_UI; - nbuf[2] = proto >> 8; - nbuf[3] = proto & 0xff; - memcpy(nbuf + 4, buf, len); - - spin_lock_irqsave(&is->buflock, flags); - bf = is->first; - bl = is->last; - - if (bf == bl) { - printk(KERN_WARNING "ippp: Queue is full; discarding first buffer\n"); - bf = bf->next; - kfree(bf->buf); - is->first = bf; - } - bl->buf = (char *) nbuf; - bl->len = len + 4; - - is->last = bl->next; - spin_unlock_irqrestore(&is->buflock, flags); - wake_up_interruptible(&is->wq); - return len; -} - -/* - * read() .. non-blocking: ipppd calls it only after select() - * reports, that there is data - */ - -int -isdn_ppp_read(int min, struct file *file, char __user *buf, int count) -{ - struct ippp_struct *is; - struct ippp_buf_queue *b; - u_long flags; - u_char *save_buf; - - is = file->private_data; - - if (!(is->state & IPPP_OPEN)) - return 0; - - spin_lock_irqsave(&is->buflock, flags); - b = is->first->next; - save_buf = b->buf; - if (!save_buf) { - spin_unlock_irqrestore(&is->buflock, flags); - return -EAGAIN; - } - if (b->len < count) - count = b->len; - b->buf = NULL; - is->first = b; - - spin_unlock_irqrestore(&is->buflock, flags); - if (copy_to_user(buf, save_buf, count)) - count = -EFAULT; - kfree(save_buf); - - return count; -} - -/* - * ipppd wanna write a packet to the card .. non-blocking - */ - -int -isdn_ppp_write(int min, struct file *file, const char __user *buf, int count) -{ - isdn_net_local *lp; - struct ippp_struct *is; - int proto; - - is = file->private_data; - - if (!(is->state & IPPP_CONNECT)) - return 0; - - lp = is->lp; - - /* -> push it directly to the lowlevel interface */ - - if (!lp) - printk(KERN_DEBUG "isdn_ppp_write: lp == NULL\n"); - else { - if (lp->isdn_device < 0 || lp->isdn_channel < 0) { - unsigned char protobuf[4]; - /* - * Don't reset huptimer for - * LCP packets. (Echo requests). - */ - if (copy_from_user(protobuf, buf, 4)) - return -EFAULT; - - proto = PPP_PROTOCOL(protobuf); - if (proto != PPP_LCP) - lp->huptimer = 0; - - return 0; - } - - if ((dev->drv[lp->isdn_device]->flags & DRV_FLAG_RUNNING) && - lp->dialstate == 0 && - (lp->flags & ISDN_NET_CONNECTED)) { - unsigned short hl; - struct sk_buff *skb; - unsigned char *cpy_buf; - /* - * we need to reserve enough space in front of - * sk_buff. old call to dev_alloc_skb only reserved - * 16 bytes, now we are looking what the driver want - */ - hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; - skb = alloc_skb(hl + count, GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING "isdn_ppp_write: out of memory!\n"); - return count; - } - skb_reserve(skb, hl); - cpy_buf = skb_put(skb, count); - if (copy_from_user(cpy_buf, buf, count)) - { - kfree_skb(skb); - return -EFAULT; - } - - /* - * Don't reset huptimer for - * LCP packets. (Echo requests). - */ - proto = PPP_PROTOCOL(cpy_buf); - if (proto != PPP_LCP) - lp->huptimer = 0; - - if (is->debug & 0x40) { - printk(KERN_DEBUG "ppp xmit: len %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - } - - isdn_ppp_send_ccp(lp->netdev, lp, skb); /* keeps CCP/compression states in sync */ - - isdn_net_write_super(lp, skb); - } - } - return count; -} - -/* - * init memory, structures etc. - */ - -int -isdn_ppp_init(void) -{ - int i, - j; - -#ifdef CONFIG_ISDN_MPP - if (isdn_ppp_mp_bundle_array_init() < 0) - return -ENOMEM; -#endif /* CONFIG_ISDN_MPP */ - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - if (!(ippp_table[i] = kzalloc(sizeof(struct ippp_struct), GFP_KERNEL))) { - printk(KERN_WARNING "isdn_ppp_init: Could not alloc ippp_table\n"); - for (j = 0; j < i; j++) - kfree(ippp_table[j]); - return -1; - } - spin_lock_init(&ippp_table[i]->buflock); - ippp_table[i]->state = 0; - ippp_table[i]->first = ippp_table[i]->rq + NUM_RCV_BUFFS - 1; - ippp_table[i]->last = ippp_table[i]->rq; - - for (j = 0; j < NUM_RCV_BUFFS; j++) { - ippp_table[i]->rq[j].buf = NULL; - ippp_table[i]->rq[j].last = ippp_table[i]->rq + - (NUM_RCV_BUFFS + j - 1) % NUM_RCV_BUFFS; - ippp_table[i]->rq[j].next = ippp_table[i]->rq + (j + 1) % NUM_RCV_BUFFS; - } - } - return 0; -} - -void -isdn_ppp_cleanup(void) -{ - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - kfree(ippp_table[i]); - -#ifdef CONFIG_ISDN_MPP - kfree(isdn_ppp_bundle_arr); -#endif /* CONFIG_ISDN_MPP */ - -} - -/* - * check for address/control field and skip if allowed - * retval != 0 -> discard packet silently - */ -static int isdn_ppp_skip_ac(struct ippp_struct *is, struct sk_buff *skb) -{ - if (skb->len < 1) - return -1; - - if (skb->data[0] == 0xff) { - if (skb->len < 2) - return -1; - - if (skb->data[1] != 0x03) - return -1; - - // skip address/control (AC) field - skb_pull(skb, 2); - } else { - if (is->pppcfg & SC_REJ_COMP_AC) - // if AC compression was not negotiated, but used, discard packet - return -1; - } - return 0; -} - -/* - * get the PPP protocol header and pull skb - * retval < 0 -> discard packet silently - */ -static int isdn_ppp_strip_proto(struct sk_buff *skb) -{ - int proto; - - if (skb->len < 1) - return -1; - - if (skb->data[0] & 0x1) { - // protocol field is compressed - proto = skb->data[0]; - skb_pull(skb, 1); - } else { - if (skb->len < 2) - return -1; - proto = ((int) skb->data[0] << 8) + skb->data[1]; - skb_pull(skb, 2); - } - return proto; -} - - -/* - * handler for incoming packets on a syncPPP interface - */ -void isdn_ppp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) -{ - struct ippp_struct *is; - int slot; - int proto; - - BUG_ON(net_dev->local->master); // we're called with the master device always - - slot = lp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n", - lp->ppp_slot); - kfree_skb(skb); - return; - } - is = ippp_table[slot]; - - if (is->debug & 0x4) { - printk(KERN_DEBUG "ippp_receive: is:%08lx lp:%08lx slot:%d unit:%d len:%d\n", - (long)is, (long)lp, lp->ppp_slot, is->unit, (int)skb->len); - isdn_ppp_frame_log("receive", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - } - - if (isdn_ppp_skip_ac(is, skb) < 0) { - kfree_skb(skb); - return; - } - proto = isdn_ppp_strip_proto(skb); - if (proto < 0) { - kfree_skb(skb); - return; - } - -#ifdef CONFIG_ISDN_MPP - if (is->compflags & SC_LINK_DECOMP_ON) { - skb = isdn_ppp_decompress(skb, is, NULL, &proto); - if (!skb) // decompression error - return; - } - - if (!(is->mpppcfg & SC_REJ_MP_PROT)) { // we agreed to receive MPPP - if (proto == PPP_MP) { - isdn_ppp_mp_receive(net_dev, lp, skb); - return; - } - } -#endif - isdn_ppp_push_higher(net_dev, lp, skb, proto); -} - -/* - * we receive a reassembled frame, MPPP has been taken care of before. - * address/control and protocol have been stripped from the skb - * note: net_dev has to be master net_dev - */ -static void -isdn_ppp_push_higher(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb, int proto) -{ - struct net_device *dev = net_dev->dev; - struct ippp_struct *is, *mis; - isdn_net_local *mlp = NULL; - int slot; - - slot = lp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n", - lp->ppp_slot); - goto drop_packet; - } - is = ippp_table[slot]; - - if (lp->master) { // FIXME? - mlp = ISDN_MASTER_PRIV(lp); - slot = mlp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n", - lp->ppp_slot); - goto drop_packet; - } - } - mis = ippp_table[slot]; - - if (is->debug & 0x10) { - printk(KERN_DEBUG "push, skb %d %04x\n", (int) skb->len, proto); - isdn_ppp_frame_log("rpush", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - } - if (mis->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_decompress(skb, is, mis, &proto); - if (!skb) // decompression error - return; - } - switch (proto) { - case PPP_IPX: /* untested */ - if (is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: IPX\n"); - skb->protocol = htons(ETH_P_IPX); - break; - case PPP_IP: - if (is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: IP\n"); - skb->protocol = htons(ETH_P_IP); - break; - case PPP_COMP: - case PPP_COMPFRAG: - printk(KERN_INFO "isdn_ppp: unexpected compressed frame dropped\n"); - goto drop_packet; -#ifdef CONFIG_ISDN_PPP_VJ - case PPP_VJC_UNCOMP: - if (is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); - if (net_dev->local->ppp_slot < 0) { - printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", - __func__, net_dev->local->ppp_slot); - goto drop_packet; - } - if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) { - printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); - goto drop_packet; - } - skb->protocol = htons(ETH_P_IP); - break; - case PPP_VJC_COMP: - if (is->debug & 0x20) - printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n"); - { - struct sk_buff *skb_old = skb; - int pkt_len; - skb = dev_alloc_skb(skb_old->len + 128); - - if (!skb) { - printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); - skb = skb_old; - goto drop_packet; - } - skb_put(skb, skb_old->len + 128); - skb_copy_from_linear_data(skb_old, skb->data, - skb_old->len); - if (net_dev->local->ppp_slot < 0) { - printk(KERN_ERR "%s: net_dev->local->ppp_slot(%d) out of range\n", - __func__, net_dev->local->ppp_slot); - goto drop_packet; - } - pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp, - skb->data, skb_old->len); - kfree_skb(skb_old); - if (pkt_len < 0) - goto drop_packet; - - skb_trim(skb, pkt_len); - skb->protocol = htons(ETH_P_IP); - } - break; -#endif - case PPP_CCP: - case PPP_CCPFRAG: - isdn_ppp_receive_ccp(net_dev, lp, skb, proto); - /* Dont pop up ResetReq/Ack stuff to the daemon any - longer - the job is done already */ - if (skb->data[0] == CCP_RESETREQ || - skb->data[0] == CCP_RESETACK) - break; - /* fall through */ - default: - isdn_ppp_fill_rq(skb->data, skb->len, proto, lp->ppp_slot); /* push data to pppd device */ - kfree_skb(skb); - return; - } - -#ifdef CONFIG_IPPP_FILTER - /* check if the packet passes the pass and active filters - * the filter instructions are constructed assuming - * a four-byte PPP header on each packet (which is still present) */ - skb_push(skb, 4); - - { - u_int16_t *p = (u_int16_t *) skb->data; - - *p = 0; /* indicate inbound */ - } - - if (is->pass_filter - && BPF_PROG_RUN(is->pass_filter, skb) == 0) { - if (is->debug & 0x2) - printk(KERN_DEBUG "IPPP: inbound frame filtered.\n"); - kfree_skb(skb); - return; - } - if (!(is->active_filter - && BPF_PROG_RUN(is->active_filter, skb) == 0)) { - if (is->debug & 0x2) - printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n"); - lp->huptimer = 0; - if (mlp) - mlp->huptimer = 0; - } - skb_pull(skb, 4); -#else /* CONFIG_IPPP_FILTER */ - lp->huptimer = 0; - if (mlp) - mlp->huptimer = 0; -#endif /* CONFIG_IPPP_FILTER */ - skb->dev = dev; - skb_reset_mac_header(skb); - netif_rx(skb); - /* net_dev->local->stats.rx_packets++; done in isdn_net.c */ - return; - -drop_packet: - net_dev->local->stats.rx_dropped++; - kfree_skb(skb); -} - -/* - * isdn_ppp_skb_push .. - * checks whether we have enough space at the beginning of the skb - * and allocs a new SKB if necessary - */ -static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p, int len) -{ - struct sk_buff *skb = *skb_p; - - if (skb_headroom(skb) < len) { - struct sk_buff *nskb = skb_realloc_headroom(skb, len); - - if (!nskb) { - printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n"); - dev_kfree_skb(skb); - return NULL; - } - printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n", skb_headroom(skb), len); - dev_kfree_skb(skb); - *skb_p = nskb; - return skb_push(nskb, len); - } - return skb_push(skb, len); -} - -/* - * send ppp frame .. we expect a PIDCOMPressable proto -- - * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP) - * - * VJ compression may change skb pointer!!! .. requeue with old - * skb isn't allowed!! - */ - -int -isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) -{ - isdn_net_local *lp, *mlp; - isdn_net_dev *nd; - unsigned int proto = PPP_IP; /* 0x21 */ - struct ippp_struct *ipt, *ipts; - int slot, retval = NETDEV_TX_OK; - - mlp = netdev_priv(netdev); - nd = mlp->netdev; /* get master lp */ - - slot = mlp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", - mlp->ppp_slot); - kfree_skb(skb); - goto out; - } - ipts = ippp_table[slot]; - - if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - if (ipts->debug & 0x1) - printk(KERN_INFO "%s: IP frame delayed.\n", netdev->name); - retval = NETDEV_TX_BUSY; - goto out; - } - - switch (ntohs(skb->protocol)) { - case ETH_P_IP: - proto = PPP_IP; - break; - case ETH_P_IPX: - proto = PPP_IPX; /* untested */ - break; - default: - printk(KERN_ERR "isdn_ppp: skipped unsupported protocol: %#x.\n", - skb->protocol); - dev_kfree_skb(skb); - goto out; - } - - lp = isdn_net_get_locked_lp(nd); - if (!lp) { - printk(KERN_WARNING "%s: all channels busy - requeuing!\n", netdev->name); - retval = NETDEV_TX_BUSY; - goto out; - } - /* we have our lp locked from now on */ - - slot = lp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n", - lp->ppp_slot); - kfree_skb(skb); - goto unlock; - } - ipt = ippp_table[slot]; - - /* - * after this line .. requeueing in the device queue is no longer allowed!!! - */ - - /* Pull off the fake header we stuck on earlier to keep - * the fragmentation code happy. - */ - skb_pull(skb, IPPP_MAX_HEADER); - -#ifdef CONFIG_IPPP_FILTER - /* check if we should pass this packet - * the filter instructions are constructed assuming - * a four-byte PPP header on each packet */ - *(u8 *)skb_push(skb, 4) = 1; /* indicate outbound */ - - { - __be16 *p = (__be16 *)skb->data; - - p++; - *p = htons(proto); - } - - if (ipt->pass_filter - && BPF_PROG_RUN(ipt->pass_filter, skb) == 0) { - if (ipt->debug & 0x4) - printk(KERN_DEBUG "IPPP: outbound frame filtered.\n"); - kfree_skb(skb); - goto unlock; - } - if (!(ipt->active_filter - && BPF_PROG_RUN(ipt->active_filter, skb) == 0)) { - if (ipt->debug & 0x4) - printk(KERN_DEBUG "IPPP: link-active filter: resetting huptimer.\n"); - lp->huptimer = 0; - } - skb_pull(skb, 4); -#else /* CONFIG_IPPP_FILTER */ - lp->huptimer = 0; -#endif /* CONFIG_IPPP_FILTER */ - - if (ipt->debug & 0x4) - printk(KERN_DEBUG "xmit skb, len %d\n", (int) skb->len); - if (ipts->debug & 0x40) - isdn_ppp_frame_log("xmit0", skb->data, skb->len, 32, ipts->unit, lp->ppp_slot); - -#ifdef CONFIG_ISDN_PPP_VJ - if (proto == PPP_IP && ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes, but check this again */ - struct sk_buff *new_skb; - unsigned short hl; - /* - * we need to reserve enough space in front of - * sk_buff. old call to dev_alloc_skb only reserved - * 16 bytes, now we are looking what the driver want. - */ - hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen + IPPP_MAX_HEADER; - /* - * Note: hl might still be insufficient because the method - * above does not account for a possibible MPPP slave channel - * which had larger HL header space requirements than the - * master. - */ - new_skb = alloc_skb(hl + skb->len, GFP_ATOMIC); - if (new_skb) { - u_char *buf; - int pktlen; - - skb_reserve(new_skb, hl); - new_skb->dev = skb->dev; - skb_put(new_skb, skb->len); - buf = skb->data; - - pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data, - &buf, !(ipts->pppcfg & SC_NO_TCP_CCID)); - - if (buf != skb->data) { - if (new_skb->data != buf) - printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n"); - dev_kfree_skb(skb); - skb = new_skb; - } else { - dev_kfree_skb(new_skb); - } - - skb_trim(skb, pktlen); - if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */ - proto = PPP_VJC_COMP; - skb->data[0] ^= SL_TYPE_COMPRESSED_TCP; - } else { - if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP) - proto = PPP_VJC_UNCOMP; - skb->data[0] = (skb->data[0] & 0x0f) | 0x40; - } - } - } -#endif - - /* - * normal (single link) or bundle compression - */ - if (ipts->compflags & SC_COMP_ON) { - /* We send compressed only if both down- und upstream - compression is negotiated, that means, CCP is up */ - if (ipts->compflags & SC_DECOMP_ON) { - skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 0); - } else { - printk(KERN_DEBUG "isdn_ppp: CCP not yet up - sending as-is\n"); - } - } - - if (ipt->debug & 0x24) - printk(KERN_DEBUG "xmit2 skb, len %d, proto %04x\n", (int) skb->len, proto); - -#ifdef CONFIG_ISDN_MPP - if (ipt->mpppcfg & SC_MP_PROT) { - /* we get mp_seqno from static isdn_net_local */ - long mp_seqno = ipts->mp_seqno; - ipts->mp_seqno++; - if (ipt->mpppcfg & SC_OUT_SHORT_SEQ) { - unsigned char *data = isdn_ppp_skb_push(&skb, 3); - if (!data) - goto unlock; - mp_seqno &= 0xfff; - data[0] = MP_BEGIN_FRAG | MP_END_FRAG | ((mp_seqno >> 8) & 0xf); /* (B)egin & (E)ndbit .. */ - data[1] = mp_seqno & 0xff; - data[2] = proto; /* PID compression */ - } else { - unsigned char *data = isdn_ppp_skb_push(&skb, 5); - if (!data) - goto unlock; - data[0] = MP_BEGIN_FRAG | MP_END_FRAG; /* (B)egin & (E)ndbit .. */ - data[1] = (mp_seqno >> 16) & 0xff; /* sequence number: 24bit */ - data[2] = (mp_seqno >> 8) & 0xff; - data[3] = (mp_seqno >> 0) & 0xff; - data[4] = proto; /* PID compression */ - } - proto = PPP_MP; /* MP Protocol, 0x003d */ - } -#endif - - /* - * 'link in bundle' compression ... - */ - if (ipt->compflags & SC_LINK_COMP_ON) - skb = isdn_ppp_compress(skb, &proto, ipt, ipts, 1); - - if ((ipt->pppcfg & SC_COMP_PROT) && (proto <= 0xff)) { - unsigned char *data = isdn_ppp_skb_push(&skb, 1); - if (!data) - goto unlock; - data[0] = proto & 0xff; - } - else { - unsigned char *data = isdn_ppp_skb_push(&skb, 2); - if (!data) - goto unlock; - data[0] = (proto >> 8) & 0xff; - data[1] = proto & 0xff; - } - if (!(ipt->pppcfg & SC_COMP_AC)) { - unsigned char *data = isdn_ppp_skb_push(&skb, 2); - if (!data) - goto unlock; - data[0] = 0xff; /* All Stations */ - data[1] = 0x03; /* Unnumbered information */ - } - - /* tx-stats are now updated via BSENT-callback */ - - if (ipts->debug & 0x40) { - printk(KERN_DEBUG "skb xmit: len: %d\n", (int) skb->len); - isdn_ppp_frame_log("xmit", skb->data, skb->len, 32, ipt->unit, lp->ppp_slot); - } - - isdn_net_writebuf_skb(lp, skb); - -unlock: - spin_unlock_bh(&lp->xmit_lock); -out: - return retval; -} - -#ifdef CONFIG_IPPP_FILTER -/* - * check if this packet may trigger auto-dial. - */ - -int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp) -{ - struct ippp_struct *is = ippp_table[lp->ppp_slot]; - u_int16_t proto; - int drop = 0; - - switch (ntohs(skb->protocol)) { - case ETH_P_IP: - proto = PPP_IP; - break; - case ETH_P_IPX: - proto = PPP_IPX; - break; - default: - printk(KERN_ERR "isdn_ppp_autodial_filter: unsupported protocol 0x%x.\n", - skb->protocol); - return 1; - } - - /* the filter instructions are constructed assuming - * a four-byte PPP header on each packet. we have to - * temporarily remove part of the fake header stuck on - * earlier. - */ - *(u8 *)skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */ - - { - __be16 *p = (__be16 *)skb->data; - - p++; - *p = htons(proto); - } - - drop |= is->pass_filter - && BPF_PROG_RUN(is->pass_filter, skb) == 0; - drop |= is->active_filter - && BPF_PROG_RUN(is->active_filter, skb) == 0; - - skb_push(skb, IPPP_MAX_HEADER - 4); - return drop; -} -#endif -#ifdef CONFIG_ISDN_MPP - -/* this is _not_ rfc1990 header, but something we convert both short and long - * headers to for convinience's sake: - * byte 0 is flags as in rfc1990 - * bytes 1...4 is 24-bit seqence number converted to host byte order - */ -#define MP_HEADER_LEN 5 - -#define MP_LONGSEQ_MASK 0x00ffffff -#define MP_SHORTSEQ_MASK 0x00000fff -#define MP_LONGSEQ_MAX MP_LONGSEQ_MASK -#define MP_SHORTSEQ_MAX MP_SHORTSEQ_MASK -#define MP_LONGSEQ_MAXBIT ((MP_LONGSEQ_MASK + 1) >> 1) -#define MP_SHORTSEQ_MAXBIT ((MP_SHORTSEQ_MASK + 1) >> 1) - -/* sequence-wrap safe comparisons (for long sequence)*/ -#define MP_LT(a, b) ((a - b) & MP_LONGSEQ_MAXBIT) -#define MP_LE(a, b) !((b - a) & MP_LONGSEQ_MAXBIT) -#define MP_GT(a, b) ((b - a) & MP_LONGSEQ_MAXBIT) -#define MP_GE(a, b) !((a - b) & MP_LONGSEQ_MAXBIT) - -#define MP_SEQ(f) ((*(u32 *)(f->data + 1))) -#define MP_FLAGS(f) (f->data[0]) - -static int isdn_ppp_mp_bundle_array_init(void) -{ - int i; - int sz = ISDN_MAX_CHANNELS * sizeof(ippp_bundle); - if ((isdn_ppp_bundle_arr = kzalloc(sz, GFP_KERNEL)) == NULL) - return -ENOMEM; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - spin_lock_init(&isdn_ppp_bundle_arr[i].lock); - return 0; -} - -static ippp_bundle *isdn_ppp_mp_bundle_alloc(void) -{ - int i; - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (isdn_ppp_bundle_arr[i].ref_ct <= 0) - return (isdn_ppp_bundle_arr + i); - return NULL; -} - -static int isdn_ppp_mp_init(isdn_net_local *lp, ippp_bundle *add_to) -{ - struct ippp_struct *is; - - if (lp->ppp_slot < 0) { - printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __func__, lp->ppp_slot); - return (-EINVAL); - } - - is = ippp_table[lp->ppp_slot]; - if (add_to) { - if (lp->netdev->pb) - lp->netdev->pb->ref_ct--; - lp->netdev->pb = add_to; - } else { /* first link in a bundle */ - is->mp_seqno = 0; - if ((lp->netdev->pb = isdn_ppp_mp_bundle_alloc()) == NULL) - return -ENOMEM; - lp->next = lp->last = lp; /* nobody else in a queue */ - lp->netdev->pb->frags = NULL; - lp->netdev->pb->frames = 0; - lp->netdev->pb->seq = UINT_MAX; - } - lp->netdev->pb->ref_ct++; - - is->last_link_seqno = 0; - return 0; -} - -static u32 isdn_ppp_mp_get_seq(int short_seq, - struct sk_buff *skb, u32 last_seq); -static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp, - struct sk_buff *from, struct sk_buff *to); -static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *from, struct sk_buff *to); -static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb); -static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb); - -static void isdn_ppp_mp_receive(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb) -{ - struct ippp_struct *is; - isdn_net_local *lpq; - ippp_bundle *mp; - isdn_mppp_stats *stats; - struct sk_buff *newfrag, *frag, *start, *nextf; - u32 newseq, minseq, thisseq; - unsigned long flags; - int slot; - - spin_lock_irqsave(&net_dev->pb->lock, flags); - mp = net_dev->pb; - stats = &mp->stats; - slot = lp->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lp->ppp_slot(%d)\n", - __func__, lp->ppp_slot); - stats->frame_drops++; - dev_kfree_skb(skb); - spin_unlock_irqrestore(&mp->lock, flags); - return; - } - is = ippp_table[slot]; - if (++mp->frames > stats->max_queue_len) - stats->max_queue_len = mp->frames; - - if (is->debug & 0x8) - isdn_ppp_mp_print_recv_pkt(lp->ppp_slot, skb); - - newseq = isdn_ppp_mp_get_seq(is->mpppcfg & SC_IN_SHORT_SEQ, - skb, is->last_link_seqno); - - - /* if this packet seq # is less than last already processed one, - * toss it right away, but check for sequence start case first - */ - if (mp->seq > MP_LONGSEQ_MAX && (newseq & MP_LONGSEQ_MAXBIT)) { - mp->seq = newseq; /* the first packet: required for - * rfc1990 non-compliant clients -- - * prevents constant packet toss */ - } else if (MP_LT(newseq, mp->seq)) { - stats->frame_drops++; - isdn_ppp_mp_free_skb(mp, skb); - spin_unlock_irqrestore(&mp->lock, flags); - return; - } - - /* find the minimum received sequence number over all links */ - is->last_link_seqno = minseq = newseq; - for (lpq = net_dev->queue;;) { - slot = lpq->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lpq->ppp_slot(%d)\n", - __func__, lpq->ppp_slot); - } else { - u32 lls = ippp_table[slot]->last_link_seqno; - if (MP_LT(lls, minseq)) - minseq = lls; - } - if ((lpq = lpq->next) == net_dev->queue) - break; - } - if (MP_LT(minseq, mp->seq)) - minseq = mp->seq; /* can't go beyond already processed - * packets */ - newfrag = skb; - - /* if this new fragment is before the first one, then enqueue it now. */ - if ((frag = mp->frags) == NULL || MP_LT(newseq, MP_SEQ(frag))) { - newfrag->next = frag; - mp->frags = frag = newfrag; - newfrag = NULL; - } - - start = MP_FLAGS(frag) & MP_BEGIN_FRAG && - MP_SEQ(frag) == mp->seq ? frag : NULL; - - /* - * main fragment traversing loop - * - * try to accomplish several tasks: - * - insert new fragment into the proper sequence slot (once that's done - * newfrag will be set to NULL) - * - reassemble any complete fragment sequence (non-null 'start' - * indicates there is a contiguous sequence present) - * - discard any incomplete sequences that are below minseq -- due - * to the fact that sender always increment sequence number, if there - * is an incomplete sequence below minseq, no new fragments would - * come to complete such sequence and it should be discarded - * - * loop completes when we accomplished the following tasks: - * - new fragment is inserted in the proper sequence ('newfrag' is - * set to NULL) - * - we hit a gap in the sequence, so no reassembly/processing is - * possible ('start' would be set to NULL) - * - * algorithm for this code is derived from code in the book - * 'PPP Design And Debugging' by James Carlson (Addison-Wesley) - */ - while (start != NULL || newfrag != NULL) { - - thisseq = MP_SEQ(frag); - nextf = frag->next; - - /* drop any duplicate fragments */ - if (newfrag != NULL && thisseq == newseq) { - isdn_ppp_mp_free_skb(mp, newfrag); - newfrag = NULL; - } - - /* insert new fragment before next element if possible. */ - if (newfrag != NULL && (nextf == NULL || - MP_LT(newseq, MP_SEQ(nextf)))) { - newfrag->next = nextf; - frag->next = nextf = newfrag; - newfrag = NULL; - } - - if (start != NULL) { - /* check for misplaced start */ - if (start != frag && (MP_FLAGS(frag) & MP_BEGIN_FRAG)) { - printk(KERN_WARNING"isdn_mppp(seq %d): new " - "BEGIN flag with no prior END", thisseq); - stats->seqerrs++; - stats->frame_drops++; - start = isdn_ppp_mp_discard(mp, start, frag); - nextf = frag->next; - } - } else if (MP_LE(thisseq, minseq)) { - if (MP_FLAGS(frag) & MP_BEGIN_FRAG) - start = frag; - else { - if (MP_FLAGS(frag) & MP_END_FRAG) - stats->frame_drops++; - if (mp->frags == frag) - mp->frags = nextf; - isdn_ppp_mp_free_skb(mp, frag); - frag = nextf; - continue; - } - } - - /* if start is non-null and we have end fragment, then - * we have full reassembly sequence -- reassemble - * and process packet now - */ - if (start != NULL && (MP_FLAGS(frag) & MP_END_FRAG)) { - minseq = mp->seq = (thisseq + 1) & MP_LONGSEQ_MASK; - /* Reassemble the packet then dispatch it */ - isdn_ppp_mp_reassembly(net_dev, lp, start, nextf); - - start = NULL; - frag = NULL; - - mp->frags = nextf; - } - - /* check if need to update start pointer: if we just - * reassembled the packet and sequence is contiguous - * then next fragment should be the start of new reassembly - * if sequence is contiguous, but we haven't reassembled yet, - * keep going. - * if sequence is not contiguous, either clear everything - * below low watermark and set start to the next frag or - * clear start ptr. - */ - if (nextf != NULL && - ((thisseq + 1) & MP_LONGSEQ_MASK) == MP_SEQ(nextf)) { - /* if we just reassembled and the next one is here, - * then start another reassembly. */ - - if (frag == NULL) { - if (MP_FLAGS(nextf) & MP_BEGIN_FRAG) - start = nextf; - else - { - printk(KERN_WARNING"isdn_mppp(seq %d):" - " END flag with no following " - "BEGIN", thisseq); - stats->seqerrs++; - } - } - - } else { - if (nextf != NULL && frag != NULL && - MP_LT(thisseq, minseq)) { - /* we've got a break in the sequence - * and we not at the end yet - * and we did not just reassembled - *(if we did, there wouldn't be anything before) - * and we below the low watermark - * discard all the frames below low watermark - * and start over */ - stats->frame_drops++; - mp->frags = isdn_ppp_mp_discard(mp, start, nextf); - } - /* break in the sequence, no reassembly */ - start = NULL; - } - - frag = nextf; - } /* while -- main loop */ - - if (mp->frags == NULL) - mp->frags = frag; - - /* rather straighforward way to deal with (not very) possible - * queue overflow */ - if (mp->frames > MP_MAX_QUEUE_LEN) { - stats->overflows++; - while (mp->frames > MP_MAX_QUEUE_LEN) { - frag = mp->frags->next; - isdn_ppp_mp_free_skb(mp, mp->frags); - mp->frags = frag; - } - } - spin_unlock_irqrestore(&mp->lock, flags); -} - -static void isdn_ppp_mp_cleanup(isdn_net_local *lp) -{ - struct sk_buff *frag = lp->netdev->pb->frags; - struct sk_buff *nextfrag; - while (frag) { - nextfrag = frag->next; - isdn_ppp_mp_free_skb(lp->netdev->pb, frag); - frag = nextfrag; - } - lp->netdev->pb->frags = NULL; -} - -static u32 isdn_ppp_mp_get_seq(int short_seq, - struct sk_buff *skb, u32 last_seq) -{ - u32 seq; - int flags = skb->data[0] & (MP_BEGIN_FRAG | MP_END_FRAG); - - if (!short_seq) - { - seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK; - skb_push(skb, 1); - } - else - { - /* convert 12-bit short seq number to 24-bit long one - */ - seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK; - - /* check for seqence wrap */ - if (!(seq & MP_SHORTSEQ_MAXBIT) && - (last_seq & MP_SHORTSEQ_MAXBIT) && - (unsigned long)last_seq <= MP_LONGSEQ_MAX) - seq |= (last_seq + MP_SHORTSEQ_MAX + 1) & - (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK); - else - seq |= last_seq & (~MP_SHORTSEQ_MASK & MP_LONGSEQ_MASK); - - skb_push(skb, 3); /* put converted seqence back in skb */ - } - *(u32 *)(skb->data + 1) = seq; /* put seqence back in _host_ byte - * order */ - skb->data[0] = flags; /* restore flags */ - return seq; -} - -static struct sk_buff *isdn_ppp_mp_discard(ippp_bundle *mp, - struct sk_buff *from, - struct sk_buff *to) -{ - if (from) - while (from != to) { - struct sk_buff *next = from->next; - isdn_ppp_mp_free_skb(mp, from); - from = next; - } - return from; -} - -static void isdn_ppp_mp_reassembly(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *from, struct sk_buff *to) -{ - ippp_bundle *mp = net_dev->pb; - int proto; - struct sk_buff *skb; - unsigned int tot_len; - - if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __func__, lp->ppp_slot); - return; - } - if (MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG)) { - if (ippp_table[lp->ppp_slot]->debug & 0x40) - printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, " - "len %d\n", MP_SEQ(from), from->len); - skb = from; - skb_pull(skb, MP_HEADER_LEN); - mp->frames--; - } else { - struct sk_buff *frag; - int n; - - for (tot_len = n = 0, frag = from; frag != to; frag = frag->next, n++) - tot_len += frag->len - MP_HEADER_LEN; - - if (ippp_table[lp->ppp_slot]->debug & 0x40) - printk(KERN_DEBUG"isdn_mppp: reassembling frames %d " - "to %d, len %d\n", MP_SEQ(from), - (MP_SEQ(from) + n - 1) & MP_LONGSEQ_MASK, tot_len); - if ((skb = dev_alloc_skb(tot_len)) == NULL) { - printk(KERN_ERR "isdn_mppp: cannot allocate sk buff " - "of size %d\n", tot_len); - isdn_ppp_mp_discard(mp, from, to); - return; - } - - while (from != to) { - unsigned int len = from->len - MP_HEADER_LEN; - - skb_copy_from_linear_data_offset(from, MP_HEADER_LEN, - skb_put(skb, len), - len); - frag = from->next; - isdn_ppp_mp_free_skb(mp, from); - from = frag; - } - } - proto = isdn_ppp_strip_proto(skb); - isdn_ppp_push_higher(net_dev, lp, skb, proto); -} - -static void isdn_ppp_mp_free_skb(ippp_bundle *mp, struct sk_buff *skb) -{ - dev_kfree_skb(skb); - mp->frames--; -} - -static void isdn_ppp_mp_print_recv_pkt(int slot, struct sk_buff *skb) -{ - printk(KERN_DEBUG "mp_recv: %d/%d -> %02x %02x %02x %02x %02x %02x\n", - slot, (int) skb->len, - (int) skb->data[0], (int) skb->data[1], (int) skb->data[2], - (int) skb->data[3], (int) skb->data[4], (int) skb->data[5]); -} - -static int -isdn_ppp_bundle(struct ippp_struct *is, int unit) -{ - char ifn[IFNAMSIZ + 1]; - isdn_net_dev *p; - isdn_net_local *lp, *nlp; - int rc; - unsigned long flags; - - sprintf(ifn, "ippp%d", unit); - p = isdn_net_findif(ifn); - if (!p) { - printk(KERN_ERR "ippp_bundle: cannot find %s\n", ifn); - return -EINVAL; - } - - spin_lock_irqsave(&p->pb->lock, flags); - - nlp = is->lp; - lp = p->queue; - if (nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS || - lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "ippp_bundle: binding to invalid slot %d\n", - nlp->ppp_slot < 0 || nlp->ppp_slot >= ISDN_MAX_CHANNELS ? - nlp->ppp_slot : lp->ppp_slot); - rc = -EINVAL; - goto out; - } - - isdn_net_add_to_bundle(p, nlp); - - ippp_table[nlp->ppp_slot]->unit = ippp_table[lp->ppp_slot]->unit; - - /* maybe also SC_CCP stuff */ - ippp_table[nlp->ppp_slot]->pppcfg |= ippp_table[lp->ppp_slot]->pppcfg & - (SC_ENABLE_IP | SC_NO_TCP_CCID | SC_REJ_COMP_TCP); - ippp_table[nlp->ppp_slot]->mpppcfg |= ippp_table[lp->ppp_slot]->mpppcfg & - (SC_MP_PROT | SC_REJ_MP_PROT | SC_OUT_SHORT_SEQ | SC_IN_SHORT_SEQ); - rc = isdn_ppp_mp_init(nlp, p->pb); -out: - spin_unlock_irqrestore(&p->pb->lock, flags); - return rc; -} - -#endif /* CONFIG_ISDN_MPP */ - -/* - * network device ioctl handlers - */ - -static int -isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) -{ - struct ppp_stats __user *res = ifr->ifr_data; - struct ppp_stats t; - isdn_net_local *lp = netdev_priv(dev); - - /* build a temporary stat struct and copy it to user space */ - - memset(&t, 0, sizeof(struct ppp_stats)); - if (dev->flags & IFF_UP) { - t.p.ppp_ipackets = lp->stats.rx_packets; - t.p.ppp_ibytes = lp->stats.rx_bytes; - t.p.ppp_ierrors = lp->stats.rx_errors; - t.p.ppp_opackets = lp->stats.tx_packets; - t.p.ppp_obytes = lp->stats.tx_bytes; - t.p.ppp_oerrors = lp->stats.tx_errors; -#ifdef CONFIG_ISDN_PPP_VJ - if (slot >= 0 && ippp_table[slot]->slcomp) { - struct slcompress *slcomp = ippp_table[slot]->slcomp; - t.vj.vjs_packets = slcomp->sls_o_compressed + slcomp->sls_o_uncompressed; - t.vj.vjs_compressed = slcomp->sls_o_compressed; - t.vj.vjs_searches = slcomp->sls_o_searches; - t.vj.vjs_misses = slcomp->sls_o_misses; - t.vj.vjs_errorin = slcomp->sls_i_error; - t.vj.vjs_tossed = slcomp->sls_i_tossed; - t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed; - t.vj.vjs_compressedin = slcomp->sls_i_compressed; - } -#endif - } - if (copy_to_user(res, &t, sizeof(struct ppp_stats))) - return -EFAULT; - return 0; -} - -int -isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - int error = 0; - int len; - isdn_net_local *lp = netdev_priv(dev); - - - if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) - return -EINVAL; - - switch (cmd) { -#define PPP_VERSION "2.3.7" - case SIOCGPPPVER: - len = strlen(PPP_VERSION) + 1; - if (copy_to_user(ifr->ifr_data, PPP_VERSION, len)) - error = -EFAULT; - break; - - case SIOCGPPPSTATS: - error = isdn_ppp_dev_ioctl_stats(lp->ppp_slot, ifr, dev); - break; - default: - error = -EINVAL; - break; - } - return error; -} - -static int -isdn_ppp_if_get_unit(char *name) -{ - int len, - i, - unit = 0, - deci; - - len = strlen(name); - - if (strncmp("ippp", name, 4) || len > 8) - return -1; - - for (i = 0, deci = 1; i < len; i++, deci *= 10) { - char a = name[len - i - 1]; - if (a >= '0' && a <= '9') - unit += (a - '0') * deci; - else - break; - } - if (!i || len - i != 4) - unit = -1; - - return unit; -} - - -int -isdn_ppp_dial_slave(char *name) -{ -#ifdef CONFIG_ISDN_MPP - isdn_net_dev *ndev; - isdn_net_local *lp; - struct net_device *sdev; - - if (!(ndev = isdn_net_findif(name))) - return 1; - lp = ndev->local; - if (!(lp->flags & ISDN_NET_CONNECTED)) - return 5; - - sdev = lp->slave; - while (sdev) { - isdn_net_local *mlp = netdev_priv(sdev); - if (!(mlp->flags & ISDN_NET_CONNECTED)) - break; - sdev = mlp->slave; - } - if (!sdev) - return 2; - - isdn_net_dial_req(netdev_priv(sdev)); - return 0; -#else - return -1; -#endif -} - -int -isdn_ppp_hangup_slave(char *name) -{ -#ifdef CONFIG_ISDN_MPP - isdn_net_dev *ndev; - isdn_net_local *lp; - struct net_device *sdev; - - if (!(ndev = isdn_net_findif(name))) - return 1; - lp = ndev->local; - if (!(lp->flags & ISDN_NET_CONNECTED)) - return 5; - - sdev = lp->slave; - while (sdev) { - isdn_net_local *mlp = netdev_priv(sdev); - - if (mlp->slave) { /* find last connected link in chain */ - isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp); - - if (!(nlp->flags & ISDN_NET_CONNECTED)) - break; - } else if (mlp->flags & ISDN_NET_CONNECTED) - break; - - sdev = mlp->slave; - } - if (!sdev) - return 2; - - isdn_net_hangup(sdev); - return 0; -#else - return -1; -#endif -} - -/* - * PPP compression stuff - */ - - -/* Push an empty CCP Data Frame up to the daemon to wake it up and let it - generate a CCP Reset-Request or tear down CCP altogether */ - -static void isdn_ppp_ccp_kickup(struct ippp_struct *is) -{ - isdn_ppp_fill_rq(NULL, 0, PPP_COMP, is->lp->ppp_slot); -} - -/* In-kernel handling of CCP Reset-Request and Reset-Ack is necessary, - but absolutely nontrivial. The most abstruse problem we are facing is - that the generation, reception and all the handling of timeouts and - resends including proper request id management should be entirely left - to the (de)compressor, but indeed is not covered by the current API to - the (de)compressor. The API is a prototype version from PPP where only - some (de)compressors have yet been implemented and all of them are - rather simple in their reset handling. Especially, their is only one - outstanding ResetAck at a time with all of them and ResetReq/-Acks do - not have parameters. For this very special case it was sufficient to - just return an error code from the decompressor and have a single - reset() entry to communicate all the necessary information between - the framework and the (de)compressor. Bad enough, LZS is different - (and any other compressor may be different, too). It has multiple - histories (eventually) and needs to Reset each of them independently - and thus uses multiple outstanding Acks and history numbers as an - additional parameter to Reqs/Acks. - All that makes it harder to port the reset state engine into the - kernel because it is not just the same simple one as in (i)pppd but - it must be able to pass additional parameters and have multiple out- - standing Acks. We are trying to achieve the impossible by handling - reset transactions independent by their id. The id MUST change when - the data portion changes, thus any (de)compressor who uses more than - one resettable state must provide and recognize individual ids for - each individual reset transaction. The framework itself does _only_ - differentiate them by id, because it has no other semantics like the - (de)compressor might. - This looks like a major redesign of the interface would be nice, - but I don't have an idea how to do it better. */ - -/* Send a CCP Reset-Request or Reset-Ack directly from the kernel. This is - getting that lengthy because there is no simple "send-this-frame-out" - function above but every wrapper does a bit different. Hope I guess - correct in this hack... */ - -static void isdn_ppp_ccp_xmit_reset(struct ippp_struct *is, int proto, - unsigned char code, unsigned char id, - unsigned char *data, int len) -{ - struct sk_buff *skb; - unsigned char *p; - int hl; - int cnt = 0; - isdn_net_local *lp = is->lp; - - /* Alloc large enough skb */ - hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen; - skb = alloc_skb(len + hl + 16, GFP_ATOMIC); - if (!skb) { - printk(KERN_WARNING - "ippp: CCP cannot send reset - out of memory\n"); - return; - } - skb_reserve(skb, hl); - - /* We may need to stuff an address and control field first */ - if (!(is->pppcfg & SC_COMP_AC)) { - p = skb_put(skb, 2); - *p++ = 0xff; - *p++ = 0x03; - } - - /* Stuff proto, code, id and length */ - p = skb_put(skb, 6); - *p++ = (proto >> 8); - *p++ = (proto & 0xff); - *p++ = code; - *p++ = id; - cnt = 4 + len; - *p++ = (cnt >> 8); - *p++ = (cnt & 0xff); - - /* Now stuff remaining bytes */ - if (len) { - skb_put_data(skb, data, len); - } - - /* skb is now ready for xmit */ - printk(KERN_DEBUG "Sending CCP Frame:\n"); - isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - - isdn_net_write_super(lp, skb); -} - -/* Allocate the reset state vector */ -static struct ippp_ccp_reset *isdn_ppp_ccp_reset_alloc(struct ippp_struct *is) -{ - struct ippp_ccp_reset *r; - r = kzalloc(sizeof(struct ippp_ccp_reset), GFP_KERNEL); - if (!r) { - printk(KERN_ERR "ippp_ccp: failed to allocate reset data" - " structure - no mem\n"); - return NULL; - } - printk(KERN_DEBUG "ippp_ccp: allocated reset data structure %p\n", r); - is->reset = r; - return r; -} - -/* Destroy the reset state vector. Kill all pending timers first. */ -static void isdn_ppp_ccp_reset_free(struct ippp_struct *is) -{ - unsigned int id; - - printk(KERN_DEBUG "ippp_ccp: freeing reset data structure %p\n", - is->reset); - for (id = 0; id < 256; id++) { - if (is->reset->rs[id]) { - isdn_ppp_ccp_reset_free_state(is, (unsigned char)id); - } - } - kfree(is->reset); - is->reset = NULL; -} - -/* Free a given state and clear everything up for later reallocation */ -static void isdn_ppp_ccp_reset_free_state(struct ippp_struct *is, - unsigned char id) -{ - struct ippp_ccp_reset_state *rs; - - if (is->reset->rs[id]) { - printk(KERN_DEBUG "ippp_ccp: freeing state for id %d\n", id); - rs = is->reset->rs[id]; - /* Make sure the kernel will not call back later */ - if (rs->ta) - del_timer(&rs->timer); - is->reset->rs[id] = NULL; - kfree(rs); - } else { - printk(KERN_WARNING "ippp_ccp: id %d is not allocated\n", id); - } -} - -/* The timer callback function which is called when a ResetReq has timed out, - aka has never been answered by a ResetAck */ -static void isdn_ppp_ccp_timer_callback(struct timer_list *t) -{ - struct ippp_ccp_reset_state *rs = - from_timer(rs, t, timer); - - if (!rs) { - printk(KERN_ERR "ippp_ccp: timer cb with zero closure.\n"); - return; - } - if (rs->ta && rs->state == CCPResetSentReq) { - /* We are correct here */ - if (!rs->expra) { - /* Hmm, there is no Ack really expected. We can clean - up the state now, it will be reallocated if the - decompressor insists on another reset */ - rs->ta = 0; - isdn_ppp_ccp_reset_free_state(rs->is, rs->id); - return; - } - printk(KERN_DEBUG "ippp_ccp: CCP Reset timed out for id %d\n", - rs->id); - /* Push it again */ - isdn_ppp_ccp_xmit_reset(rs->is, PPP_CCP, CCP_RESETREQ, rs->id, - rs->data, rs->dlen); - /* Restart timer */ - rs->timer.expires = jiffies + HZ * 5; - add_timer(&rs->timer); - } else { - printk(KERN_WARNING "ippp_ccp: timer cb in wrong state %d\n", - rs->state); - } -} - -/* Allocate a new reset transaction state */ -static struct ippp_ccp_reset_state *isdn_ppp_ccp_reset_alloc_state(struct ippp_struct *is, - unsigned char id) -{ - struct ippp_ccp_reset_state *rs; - if (is->reset->rs[id]) { - printk(KERN_WARNING "ippp_ccp: old state exists for id %d\n", - id); - return NULL; - } else { - rs = kzalloc(sizeof(struct ippp_ccp_reset_state), GFP_ATOMIC); - if (!rs) - return NULL; - rs->state = CCPResetIdle; - rs->is = is; - rs->id = id; - timer_setup(&rs->timer, isdn_ppp_ccp_timer_callback, 0); - is->reset->rs[id] = rs; - } - return rs; -} - - -/* A decompressor wants a reset with a set of parameters - do what is - necessary to fulfill it */ -static void isdn_ppp_ccp_reset_trans(struct ippp_struct *is, - struct isdn_ppp_resetparams *rp) -{ - struct ippp_ccp_reset_state *rs; - - if (rp->valid) { - /* The decompressor defines parameters by itself */ - if (rp->rsend) { - /* And he wants us to send a request */ - if (!(rp->idval)) { - printk(KERN_ERR "ippp_ccp: decompressor must" - " specify reset id\n"); - return; - } - if (is->reset->rs[rp->id]) { - /* There is already a transaction in existence - for this id. May be still waiting for a - Ack or may be wrong. */ - rs = is->reset->rs[rp->id]; - if (rs->state == CCPResetSentReq && rs->ta) { - printk(KERN_DEBUG "ippp_ccp: reset" - " trans still in progress" - " for id %d\n", rp->id); - } else { - printk(KERN_WARNING "ippp_ccp: reset" - " trans in wrong state %d for" - " id %d\n", rs->state, rp->id); - } - } else { - /* Ok, this is a new transaction */ - printk(KERN_DEBUG "ippp_ccp: new trans for id" - " %d to be started\n", rp->id); - rs = isdn_ppp_ccp_reset_alloc_state(is, rp->id); - if (!rs) { - printk(KERN_ERR "ippp_ccp: out of mem" - " allocing ccp trans\n"); - return; - } - rs->state = CCPResetSentReq; - rs->expra = rp->expra; - if (rp->dtval) { - rs->dlen = rp->dlen; - memcpy(rs->data, rp->data, rp->dlen); - } - /* HACK TODO - add link comp here */ - isdn_ppp_ccp_xmit_reset(is, PPP_CCP, - CCP_RESETREQ, rs->id, - rs->data, rs->dlen); - /* Start the timer */ - rs->timer.expires = jiffies + 5 * HZ; - add_timer(&rs->timer); - rs->ta = 1; - } - } else { - printk(KERN_DEBUG "ippp_ccp: no reset sent\n"); - } - } else { - /* The reset params are invalid. The decompressor does not - care about them, so we just send the minimal requests - and increase ids only when an Ack is received for a - given id */ - if (is->reset->rs[is->reset->lastid]) { - /* There is already a transaction in existence - for this id. May be still waiting for a - Ack or may be wrong. */ - rs = is->reset->rs[is->reset->lastid]; - if (rs->state == CCPResetSentReq && rs->ta) { - printk(KERN_DEBUG "ippp_ccp: reset" - " trans still in progress" - " for id %d\n", rp->id); - } else { - printk(KERN_WARNING "ippp_ccp: reset" - " trans in wrong state %d for" - " id %d\n", rs->state, rp->id); - } - } else { - printk(KERN_DEBUG "ippp_ccp: new trans for id" - " %d to be started\n", is->reset->lastid); - rs = isdn_ppp_ccp_reset_alloc_state(is, - is->reset->lastid); - if (!rs) { - printk(KERN_ERR "ippp_ccp: out of mem" - " allocing ccp trans\n"); - return; - } - rs->state = CCPResetSentReq; - /* We always expect an Ack if the decompressor doesn't - know better */ - rs->expra = 1; - rs->dlen = 0; - /* HACK TODO - add link comp here */ - isdn_ppp_ccp_xmit_reset(is, PPP_CCP, CCP_RESETREQ, - rs->id, NULL, 0); - /* Start the timer */ - rs->timer.expires = jiffies + 5 * HZ; - add_timer(&rs->timer); - rs->ta = 1; - } - } -} - -/* An Ack was received for this id. This means we stop the timer and clean - up the state prior to calling the decompressors reset routine. */ -static void isdn_ppp_ccp_reset_ack_rcvd(struct ippp_struct *is, - unsigned char id) -{ - struct ippp_ccp_reset_state *rs = is->reset->rs[id]; - - if (rs) { - if (rs->ta && rs->state == CCPResetSentReq) { - /* Great, we are correct */ - if (!rs->expra) - printk(KERN_DEBUG "ippp_ccp: ResetAck received" - " for id %d but not expected\n", id); - } else { - printk(KERN_INFO "ippp_ccp: ResetAck received out of" - "sync for id %d\n", id); - } - if (rs->ta) { - rs->ta = 0; - del_timer(&rs->timer); - } - isdn_ppp_ccp_reset_free_state(is, id); - } else { - printk(KERN_INFO "ippp_ccp: ResetAck received for unknown id" - " %d\n", id); - } - /* Make sure the simple reset stuff uses a new id next time */ - is->reset->lastid++; -} - -/* - * decompress packet - * - * if master = 0, we're trying to uncompress an per-link compressed packet, - * as opposed to an compressed reconstructed-from-MPPP packet. - * proto is updated to protocol field of uncompressed packet. - * - * retval: decompressed packet, - * same packet if uncompressed, - * NULL if decompression error - */ - -static struct sk_buff *isdn_ppp_decompress(struct sk_buff *skb, struct ippp_struct *is, struct ippp_struct *master, - int *proto) -{ - void *stat = NULL; - struct isdn_ppp_compressor *ipc = NULL; - struct sk_buff *skb_out; - int len; - struct ippp_struct *ri; - struct isdn_ppp_resetparams rsparm; - unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - - if (!master) { - // per-link decompression - stat = is->link_decomp_stat; - ipc = is->link_decompressor; - ri = is; - } else { - stat = master->decomp_stat; - ipc = master->decompressor; - ri = master; - } - - if (!ipc) { - // no decompressor -> we can't decompress. - printk(KERN_DEBUG "ippp: no decompressor defined!\n"); - return skb; - } - BUG_ON(!stat); // if we have a compressor, stat has been set as well - - if ((master && *proto == PPP_COMP) || (!master && *proto == PPP_COMPFRAG)) { - // compressed packets are compressed by their protocol type - - // Set up reset params for the decompressor - memset(&rsparm, 0, sizeof(rsparm)); - rsparm.data = rsdata; - rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; - - skb_out = dev_alloc_skb(is->mru + PPP_HDRLEN); - if (!skb_out) { - kfree_skb(skb); - printk(KERN_ERR "ippp: decomp memory allocation failure\n"); - return NULL; - } - len = ipc->decompress(stat, skb, skb_out, &rsparm); - kfree_skb(skb); - if (len <= 0) { - switch (len) { - case DECOMP_ERROR: - printk(KERN_INFO "ippp: decomp wants reset %s params\n", - rsparm.valid ? "with" : "without"); - - isdn_ppp_ccp_reset_trans(ri, &rsparm); - break; - case DECOMP_FATALERROR: - ri->pppcfg |= SC_DC_FERROR; - /* Kick ipppd to recognize the error */ - isdn_ppp_ccp_kickup(ri); - break; - } - kfree_skb(skb_out); - return NULL; - } - *proto = isdn_ppp_strip_proto(skb_out); - if (*proto < 0) { - kfree_skb(skb_out); - return NULL; - } - return skb_out; - } else { - // uncompressed packets are fed through the decompressor to - // update the decompressor state - ipc->incomp(stat, skb, *proto); - return skb; - } -} - -/* - * compress a frame - * type=0: normal/bundle compression - * =1: link compression - * returns original skb if we haven't compressed the frame - * and a new skb pointer if we've done it - */ -static struct sk_buff *isdn_ppp_compress(struct sk_buff *skb_in, int *proto, - struct ippp_struct *is, struct ippp_struct *master, int type) -{ - int ret; - int new_proto; - struct isdn_ppp_compressor *compressor; - void *stat; - struct sk_buff *skb_out; - - /* we do not compress control protocols */ - if (*proto < 0 || *proto > 0x3fff) { - return skb_in; - } - - if (type) { /* type=1 => Link compression */ - return skb_in; - } - else { - if (!master) { - compressor = is->compressor; - stat = is->comp_stat; - } - else { - compressor = master->compressor; - stat = master->comp_stat; - } - new_proto = PPP_COMP; - } - - if (!compressor) { - printk(KERN_ERR "isdn_ppp: No compressor set!\n"); - return skb_in; - } - if (!stat) { - printk(KERN_ERR "isdn_ppp: Compressor not initialized?\n"); - return skb_in; - } - - /* Allow for at least 150 % expansion (for now) */ - skb_out = alloc_skb(skb_in->len + skb_in->len / 2 + 32 + - skb_headroom(skb_in), GFP_ATOMIC); - if (!skb_out) - return skb_in; - skb_reserve(skb_out, skb_headroom(skb_in)); - - ret = (compressor->compress)(stat, skb_in, skb_out, *proto); - if (!ret) { - dev_kfree_skb(skb_out); - return skb_in; - } - - dev_kfree_skb(skb_in); - *proto = new_proto; - return skb_out; -} - -/* - * we received a CCP frame .. - * not a clean solution, but we MUST handle a few cases in the kernel - */ -static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, - struct sk_buff *skb, int proto) -{ - struct ippp_struct *is; - struct ippp_struct *mis; - int len; - struct isdn_ppp_resetparams rsparm; - unsigned char rsdata[IPPP_RESET_MAXDATABYTES]; - - printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n", - lp->ppp_slot); - if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __func__, lp->ppp_slot); - return; - } - is = ippp_table[lp->ppp_slot]; - isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - - if (lp->master) { - int slot = ISDN_MASTER_PRIV(lp)->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: slot(%d) out of range\n", - __func__, slot); - return; - } - mis = ippp_table[slot]; - } else - mis = is; - - switch (skb->data[0]) { - case CCP_CONFREQ: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable compression here!\n"); - if (proto == PPP_CCP) - mis->compflags &= ~SC_COMP_ON; - else - is->compflags &= ~SC_LINK_COMP_ON; - break; - case CCP_TERMREQ: - case CCP_TERMACK: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable (de)compression here!\n"); - if (proto == PPP_CCP) - mis->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON); - else - is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON); - break; - case CCP_CONFACK: - /* if we RECEIVE an ackowledge we enable the decompressor */ - if (is->debug & 0x10) - printk(KERN_DEBUG "Enable decompression here!\n"); - if (proto == PPP_CCP) { - if (!mis->decompressor) - break; - mis->compflags |= SC_DECOMP_ON; - } else { - if (!is->decompressor) - break; - is->compflags |= SC_LINK_DECOMP_ON; - } - break; - - case CCP_RESETACK: - printk(KERN_DEBUG "Received ResetAck from peer\n"); - len = (skb->data[2] << 8) | skb->data[3]; - len -= 4; - - if (proto == PPP_CCP) { - /* If a reset Ack was outstanding for this id, then - clean up the state engine */ - isdn_ppp_ccp_reset_ack_rcvd(mis, skb->data[1]); - if (mis->decompressor && mis->decomp_stat) - mis->decompressor-> - reset(mis->decomp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, NULL); - /* TODO: This is not easy to decide here */ - mis->compflags &= ~SC_DECOMP_DISCARD; - } - else { - isdn_ppp_ccp_reset_ack_rcvd(is, skb->data[1]); - if (is->link_decompressor && is->link_decomp_stat) - is->link_decompressor-> - reset(is->link_decomp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, NULL); - /* TODO: neither here */ - is->compflags &= ~SC_LINK_DECOMP_DISCARD; - } - break; - - case CCP_RESETREQ: - printk(KERN_DEBUG "Received ResetReq from peer\n"); - /* Receiving a ResetReq means we must reset our compressor */ - /* Set up reset params for the reset entry */ - memset(&rsparm, 0, sizeof(rsparm)); - rsparm.data = rsdata; - rsparm.maxdlen = IPPP_RESET_MAXDATABYTES; - /* Isolate data length */ - len = (skb->data[2] << 8) | skb->data[3]; - len -= 4; - if (proto == PPP_CCP) { - if (mis->compressor && mis->comp_stat) - mis->compressor-> - reset(mis->comp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, &rsparm); - } - else { - if (is->link_compressor && is->link_comp_stat) - is->link_compressor-> - reset(is->link_comp_stat, - skb->data[0], - skb->data[1], - len ? &skb->data[4] : NULL, - len, &rsparm); - } - /* Ack the Req as specified by rsparm */ - if (rsparm.valid) { - /* Compressor reset handler decided how to answer */ - if (rsparm.rsend) { - /* We should send a Frame */ - isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, - rsparm.idval ? rsparm.id - : skb->data[1], - rsparm.dtval ? - rsparm.data : NULL, - rsparm.dtval ? - rsparm.dlen : 0); - } else { - printk(KERN_DEBUG "ResetAck suppressed\n"); - } - } else { - /* We answer with a straight reflected Ack */ - isdn_ppp_ccp_xmit_reset(is, proto, CCP_RESETACK, - skb->data[1], - len ? &skb->data[4] : NULL, - len); - } - break; - } -} - - -/* - * Daemon sends a CCP frame ... - */ - -/* TODO: Clean this up with new Reset semantics */ - -/* I believe the CCP handling as-is is done wrong. Compressed frames - * should only be sent/received after CCP reaches UP state, which means - * both sides have sent CONF_ACK. Currently, we handle both directions - * independently, which means we may accept compressed frames too early - * (supposedly not a problem), but may also mean we send compressed frames - * too early, which may turn out to be a problem. - * This part of state machine should actually be handled by (i)pppd, but - * that's too big of a change now. --kai - */ - -/* Actually, we might turn this into an advantage: deal with the RFC in - * the old tradition of beeing generous on what we accept, but beeing - * strict on what we send. Thus we should just - * - accept compressed frames as soon as decompression is negotiated - * - send compressed frames only when decomp *and* comp are negotiated - * - drop rx compressed frames if we cannot decomp (instead of pushing them - * up to ipppd) - * and I tried to modify this file according to that. --abp - */ - -static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb) -{ - struct ippp_struct *mis, *is; - int proto, slot = lp->ppp_slot; - unsigned char *data; - - if (!skb || skb->len < 3) - return; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: lp->ppp_slot(%d) out of range\n", - __func__, slot); - return; - } - is = ippp_table[slot]; - /* Daemon may send with or without address and control field comp */ - data = skb->data; - if (!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) { - data += 2; - if (skb->len < 5) - return; - } - - proto = ((int)data[0]<<8) + data[1]; - if (proto != PPP_CCP && proto != PPP_CCPFRAG) - return; - - printk(KERN_DEBUG "Received CCP frame from daemon:\n"); - isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit, lp->ppp_slot); - - if (lp->master) { - slot = ISDN_MASTER_PRIV(lp)->ppp_slot; - if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { - printk(KERN_ERR "%s: slot(%d) out of range\n", - __func__, slot); - return; - } - mis = ippp_table[slot]; - } else - mis = is; - if (mis != is) - printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n"); - - switch (data[2]) { - case CCP_CONFREQ: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable decompression here!\n"); - if (proto == PPP_CCP) - is->compflags &= ~SC_DECOMP_ON; - else - is->compflags &= ~SC_LINK_DECOMP_ON; - break; - case CCP_TERMREQ: - case CCP_TERMACK: - if (is->debug & 0x10) - printk(KERN_DEBUG "Disable (de)compression here!\n"); - if (proto == PPP_CCP) - is->compflags &= ~(SC_DECOMP_ON | SC_COMP_ON); - else - is->compflags &= ~(SC_LINK_DECOMP_ON | SC_LINK_COMP_ON); - break; - case CCP_CONFACK: - /* if we SEND an ackowledge we can/must enable the compressor */ - if (is->debug & 0x10) - printk(KERN_DEBUG "Enable compression here!\n"); - if (proto == PPP_CCP) { - if (!is->compressor) - break; - is->compflags |= SC_COMP_ON; - } else { - if (!is->compressor) - break; - is->compflags |= SC_LINK_COMP_ON; - } - break; - case CCP_RESETACK: - /* If we send a ACK we should reset our compressor */ - if (is->debug & 0x10) - printk(KERN_DEBUG "Reset decompression state here!\n"); - printk(KERN_DEBUG "ResetAck from daemon passed by\n"); - if (proto == PPP_CCP) { - /* link to master? */ - if (is->compressor && is->comp_stat) - is->compressor->reset(is->comp_stat, 0, 0, - NULL, 0, NULL); - is->compflags &= ~SC_COMP_DISCARD; - } - else { - if (is->link_compressor && is->link_comp_stat) - is->link_compressor->reset(is->link_comp_stat, - 0, 0, NULL, 0, NULL); - is->compflags &= ~SC_LINK_COMP_DISCARD; - } - break; - case CCP_RESETREQ: - /* Just let it pass by */ - printk(KERN_DEBUG "ResetReq from daemon passed by\n"); - break; - } -} - -int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc) -{ - ipc->next = ipc_head; - ipc->prev = NULL; - if (ipc_head) { - ipc_head->prev = ipc; - } - ipc_head = ipc; - return 0; -} - -int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc) -{ - if (ipc->prev) - ipc->prev->next = ipc->next; - else - ipc_head = ipc->next; - if (ipc->next) - ipc->next->prev = ipc->prev; - ipc->prev = ipc->next = NULL; - return 0; -} - -static int isdn_ppp_set_compressor(struct ippp_struct *is, struct isdn_ppp_comp_data *data) -{ - struct isdn_ppp_compressor *ipc = ipc_head; - int ret; - void *stat; - int num = data->num; - - if (is->debug & 0x10) - printk(KERN_DEBUG "[%d] Set %s type %d\n", is->unit, - (data->flags & IPPP_COMP_FLAG_XMIT) ? "compressor" : "decompressor", num); - - /* If is has no valid reset state vector, we cannot allocate a - decompressor. The decompressor would cause reset transactions - sooner or later, and they need that vector. */ - - if (!(data->flags & IPPP_COMP_FLAG_XMIT) && !is->reset) { - printk(KERN_ERR "ippp_ccp: no reset data structure - can't" - " allow decompression.\n"); - return -ENOMEM; - } - - while (ipc) { - if (ipc->num == num) { - stat = ipc->alloc(data); - if (stat) { - ret = ipc->init(stat, data, is->unit, 0); - if (!ret) { - printk(KERN_ERR "Can't init (de)compression!\n"); - ipc->free(stat); - stat = NULL; - break; - } - } - else { - printk(KERN_ERR "Can't alloc (de)compression!\n"); - break; - } - - if (data->flags & IPPP_COMP_FLAG_XMIT) { - if (data->flags & IPPP_COMP_FLAG_LINK) { - if (is->link_comp_stat) - is->link_compressor->free(is->link_comp_stat); - is->link_comp_stat = stat; - is->link_compressor = ipc; - } - else { - if (is->comp_stat) - is->compressor->free(is->comp_stat); - is->comp_stat = stat; - is->compressor = ipc; - } - } - else { - if (data->flags & IPPP_COMP_FLAG_LINK) { - if (is->link_decomp_stat) - is->link_decompressor->free(is->link_decomp_stat); - is->link_decomp_stat = stat; - is->link_decompressor = ipc; - } - else { - if (is->decomp_stat) - is->decompressor->free(is->decomp_stat); - is->decomp_stat = stat; - is->decompressor = ipc; - } - } - return 0; - } - ipc = ipc->next; - } - return -EINVAL; -} diff --git a/drivers/isdn/i4l/isdn_ppp.h b/drivers/isdn/i4l/isdn_ppp.h deleted file mode 100644 index 34b8a2ce84f3..000000000000 --- a/drivers/isdn/i4l/isdn_ppp.h +++ /dev/null @@ -1,41 +0,0 @@ -/* $Id: isdn_ppp.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). - * - * Copyright 1995,96 by Michael Hipp (Michael.Hipp@student.uni-tuebingen.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/ppp_defs.h> /* for PPP_PROTOCOL */ -#include <linux/isdn_ppp.h> /* for isdn_ppp info */ - -extern int isdn_ppp_read(int, struct file *, char __user *, int); -extern int isdn_ppp_write(int, struct file *, const char __user *, int); -extern int isdn_ppp_open(int, struct file *); -extern int isdn_ppp_init(void); -extern void isdn_ppp_cleanup(void); -extern int isdn_ppp_free(isdn_net_local *); -extern int isdn_ppp_bind(isdn_net_local *); -extern int isdn_ppp_autodial_filter(struct sk_buff *, isdn_net_local *); -extern int isdn_ppp_xmit(struct sk_buff *, struct net_device *); -extern void isdn_ppp_receive(isdn_net_dev *, isdn_net_local *, struct sk_buff *); -extern int isdn_ppp_dev_ioctl(struct net_device *, struct ifreq *, int); -extern __poll_t isdn_ppp_poll(struct file *, struct poll_table_struct *); -extern int isdn_ppp_ioctl(int, struct file *, unsigned int, unsigned long); -extern void isdn_ppp_release(int, struct file *); -extern int isdn_ppp_dial_slave(char *); -extern void isdn_ppp_wakeup_daemon(isdn_net_local *); - -extern int isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc); -extern int isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc); - -#define IPPP_OPEN 0x01 -#define IPPP_CONNECT 0x02 -#define IPPP_CLOSEWAIT 0x04 -#define IPPP_NOBLOCK 0x08 -#define IPPP_ASSIGNED 0x10 - -#define IPPP_MAX_HEADER 10 diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c deleted file mode 100644 index 43700fc19a31..000000000000 --- a/drivers/isdn/i4l/isdn_tty.c +++ /dev/null @@ -1,3756 +0,0 @@ -/* - * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ -#undef ISDN_TTY_STAT_DEBUG - -#include <linux/isdn.h> -#include <linux/serial.h> /* ASYNC_* flags */ -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/mutex.h> -#include <linux/sched/signal.h> -#include "isdn_common.h" -#include "isdn_tty.h" -#ifdef CONFIG_ISDN_AUDIO -#include "isdn_audio.h" -#define VBUF 0x3e0 -#define VBUFX (VBUF/16) -#endif - -#define FIX_FILE_TRANSFER -#define DUMMY_HAYES_AT - -/* Prototypes */ - -static DEFINE_MUTEX(modem_info_mutex); -static int isdn_tty_edit_at(const char *, int, modem_info *); -static void isdn_tty_check_esc(const u_char *, u_char, int, int *, u_long *); -static void isdn_tty_modem_reset_regs(modem_info *, int); -static void isdn_tty_cmd_ATA(modem_info *); -static void isdn_tty_flush_buffer(struct tty_struct *); -static void isdn_tty_modem_result(int, modem_info *); -#ifdef CONFIG_ISDN_AUDIO -static int isdn_tty_countDLE(unsigned char *, int); -#endif - -/* Leave this unchanged unless you know what you do! */ -#define MODEM_PARANOIA_CHECK -#define MODEM_DO_RESTART - -static int bit2si[8] = -{1, 5, 7, 7, 7, 7, 7, 7}; -static int si2bit[8] = -{4, 1, 4, 4, 4, 4, 4, 4}; - -/* isdn_tty_try_read() is called from within isdn_tty_rcv_skb() - * to stuff incoming data directly into a tty's flip-buffer. This - * is done to speed up tty-receiving if the receive-queue is empty. - * This routine MUST be called with interrupts off. - * Return: - * 1 = Success - * 0 = Failure, data has to be buffered and later processed by - * isdn_tty_readmodem(). - */ -static int -isdn_tty_try_read(modem_info *info, struct sk_buff *skb) -{ - struct tty_port *port = &info->port; - int c; - int len; - char last; - - if (!info->online) - return 0; - - if (!(info->mcr & UART_MCR_RTS)) - return 0; - - len = skb->len -#ifdef CONFIG_ISDN_AUDIO - + ISDN_AUDIO_SKB_DLECOUNT(skb) -#endif - ; - - c = tty_buffer_request_room(port, len); - if (c < len) - return 0; - -#ifdef CONFIG_ISDN_AUDIO - if (ISDN_AUDIO_SKB_DLECOUNT(skb)) { - int l = skb->len; - unsigned char *dp = skb->data; - while (--l) { - if (*dp == DLE) - tty_insert_flip_char(port, DLE, 0); - tty_insert_flip_char(port, *dp++, 0); - } - if (*dp == DLE) - tty_insert_flip_char(port, DLE, 0); - last = *dp; - } else { -#endif - if (len > 1) - tty_insert_flip_string(port, skb->data, len - 1); - last = skb->data[len - 1]; -#ifdef CONFIG_ISDN_AUDIO - } -#endif - if (info->emu.mdmreg[REG_CPPP] & BIT_CPPP) - tty_insert_flip_char(port, last, 0xFF); - else - tty_insert_flip_char(port, last, TTY_NORMAL); - tty_flip_buffer_push(port); - kfree_skb(skb); - - return 1; -} - -/* isdn_tty_readmodem() is called periodically from within timer-interrupt. - * It tries getting received data from the receive queue an stuff it into - * the tty's flip-buffer. - */ -void -isdn_tty_readmodem(void) -{ - int resched = 0; - int midx; - int i; - int r; - modem_info *info; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - midx = dev->m_idx[i]; - if (midx < 0) - continue; - - info = &dev->mdm.info[midx]; - if (!info->online) - continue; - - r = 0; -#ifdef CONFIG_ISDN_AUDIO - isdn_audio_eval_dtmf(info); - if ((info->vonline & 1) && (info->emu.vpar[1])) - isdn_audio_eval_silence(info); -#endif - if (info->mcr & UART_MCR_RTS) { - /* CISCO AsyncPPP Hack */ - if (!(info->emu.mdmreg[REG_CPPP] & BIT_CPPP)) - r = isdn_readbchan_tty(info->isdn_driver, - info->isdn_channel, - &info->port, 0); - else - r = isdn_readbchan_tty(info->isdn_driver, - info->isdn_channel, - &info->port, 1); - if (r) - tty_flip_buffer_push(&info->port); - } else - r = 1; - - if (r) { - info->rcvsched = 0; - resched = 1; - } else - info->rcvsched = 1; - } - if (!resched) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 0); -} - -int -isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb) -{ - ulong flags; - int midx; -#ifdef CONFIG_ISDN_AUDIO - int ifmt; -#endif - modem_info *info; - - if ((midx = dev->m_idx[i]) < 0) { - /* if midx is invalid, packet is not for tty */ - return 0; - } - info = &dev->mdm.info[midx]; -#ifdef CONFIG_ISDN_AUDIO - ifmt = 1; - - if ((info->vonline) && (!info->emu.vpar[4])) - isdn_audio_calc_dtmf(info, skb->data, skb->len, ifmt); - if ((info->vonline & 1) && (info->emu.vpar[1])) - isdn_audio_calc_silence(info, skb->data, skb->len, ifmt); -#endif - if ((info->online < 2) -#ifdef CONFIG_ISDN_AUDIO - && (!(info->vonline & 1)) -#endif - ) { - /* If Modem not listening, drop data */ - kfree_skb(skb); - return 1; - } - if (info->emu.mdmreg[REG_T70] & BIT_T70) { - if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) { - /* T.70 decoding: throw away the T.70 header (2 or 4 bytes) */ - if (skb->data[0] == 3) /* pure data packet -> 4 byte headers */ - skb_pull(skb, 4); - else - if (skb->data[0] == 1) /* keepalive packet -> 2 byte hdr */ - skb_pull(skb, 2); - } else - /* T.70 decoding: Simply throw away the T.70 header (4 bytes) */ - if ((skb->data[0] == 1) && ((skb->data[1] == 0) || (skb->data[1] == 1))) - skb_pull(skb, 4); - } -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; - ISDN_AUDIO_SKB_LOCK(skb) = 0; - if (info->vonline & 1) { - /* voice conversion/compression */ - switch (info->emu.vpar[3]) { - case 2: - case 3: - case 4: - /* adpcm - * Since compressed data takes less - * space, we can overwrite the buffer. - */ - skb_trim(skb, isdn_audio_xlaw2adpcm(info->adpcmr, - ifmt, - skb->data, - skb->data, - skb->len)); - break; - case 5: - /* a-law */ - if (!ifmt) - isdn_audio_ulaw2alaw(skb->data, skb->len); - break; - case 6: - /* u-law */ - if (ifmt) - isdn_audio_alaw2ulaw(skb->data, skb->len); - break; - } - ISDN_AUDIO_SKB_DLECOUNT(skb) = - isdn_tty_countDLE(skb->data, skb->len); - } -#ifdef CONFIG_ISDN_TTY_FAX - else { - if (info->faxonline & 2) { - isdn_tty_fax_bitorder(info, skb); - ISDN_AUDIO_SKB_DLECOUNT(skb) = - isdn_tty_countDLE(skb->data, skb->len); - } - } -#endif -#endif - /* Try to deliver directly via tty-buf if queue is empty */ - spin_lock_irqsave(&info->readlock, flags); - if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) - if (isdn_tty_try_read(info, skb)) { - spin_unlock_irqrestore(&info->readlock, flags); - return 1; - } - /* Direct deliver failed or queue wasn't empty. - * Queue up for later dequeueing via timer-irq. - */ - __skb_queue_tail(&dev->drv[di]->rpqueue[channel], skb); - dev->drv[di]->rcvcount[channel] += - (skb->len -#ifdef CONFIG_ISDN_AUDIO - + ISDN_AUDIO_SKB_DLECOUNT(skb) -#endif - ); - spin_unlock_irqrestore(&info->readlock, flags); - /* Schedule dequeuing */ - if ((dev->modempoll) && (info->rcvsched)) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); - return 1; -} - -static void -isdn_tty_cleanup_xmit(modem_info *info) -{ - skb_queue_purge(&info->xmit_queue); -#ifdef CONFIG_ISDN_AUDIO - skb_queue_purge(&info->dtmf_queue); -#endif -} - -static void -isdn_tty_tint(modem_info *info) -{ - struct sk_buff *skb = skb_dequeue(&info->xmit_queue); - int len, slen; - - if (!skb) - return; - len = skb->len; - if ((slen = isdn_writebuf_skb_stub(info->isdn_driver, - info->isdn_channel, 1, skb)) == len) { - struct tty_struct *tty = info->port.tty; - info->send_outstanding++; - info->msr &= ~UART_MSR_CTS; - info->lsr &= ~UART_LSR_TEMT; - tty_wakeup(tty); - return; - } - if (slen < 0) { - /* Error: no channel, already shutdown, or wrong parameter */ - dev_kfree_skb(skb); - return; - } - skb_queue_head(&info->xmit_queue, skb); -} - -#ifdef CONFIG_ISDN_AUDIO -static int -isdn_tty_countDLE(unsigned char *buf, int len) -{ - int count = 0; - - while (len--) - if (*buf++ == DLE) - count++; - return count; -} - -/* This routine is called from within isdn_tty_write() to perform - * DLE-decoding when sending audio-data. - */ -static int -isdn_tty_handleDLEdown(modem_info *info, atemu *m, int len) -{ - unsigned char *p = &info->port.xmit_buf[info->xmit_count]; - int count = 0; - - while (len > 0) { - if (m->lastDLE) { - m->lastDLE = 0; - switch (*p) { - case DLE: - /* Escape code */ - if (len > 1) - memmove(p, p + 1, len - 1); - p--; - count++; - break; - case ETX: - /* End of data */ - info->vonline |= 4; - return count; - case DC4: - /* Abort RX */ - info->vonline &= ~1; -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG - "DLEdown: got DLE-DC4, send DLE-ETX on ttyI%d\n", - info->line); -#endif - isdn_tty_at_cout("\020\003", info); - if (!info->vonline) { -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG - "DLEdown: send VCON on ttyI%d\n", - info->line); -#endif - isdn_tty_at_cout("\r\nVCON\r\n", info); - } - /* Fall through */ - case 'q': - case 's': - /* Silence */ - if (len > 1) - memmove(p, p + 1, len - 1); - p--; - break; - } - } else { - if (*p == DLE) - m->lastDLE = 1; - else - count++; - } - p++; - len--; - } - if (len < 0) { - printk(KERN_WARNING "isdn_tty: len<0 in DLEdown\n"); - return 0; - } - return count; -} - -/* This routine is called from within isdn_tty_write() when receiving - * audio-data. It interrupts receiving, if an character other than - * ^S or ^Q is sent. - */ -static int -isdn_tty_end_vrx(const char *buf, int c) -{ - char ch; - - while (c--) { - ch = *buf; - if ((ch != 0x11) && (ch != 0x13)) - return 1; - buf++; - } - return 0; -} - -static int voice_cf[7] = -{0, 0, 4, 3, 2, 0, 0}; - -#endif /* CONFIG_ISDN_AUDIO */ - -/* isdn_tty_senddown() is called either directly from within isdn_tty_write() - * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls - * outgoing data from the tty's xmit-buffer, handles voice-decompression or - * T.70 if necessary, and finally queues it up for sending via isdn_tty_tint. - */ -static void -isdn_tty_senddown(modem_info *info) -{ - int buflen; - int skb_res; -#ifdef CONFIG_ISDN_AUDIO - int audio_len; -#endif - struct sk_buff *skb; - -#ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 4) { - info->vonline &= ~6; - if (!info->vonline) { -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG - "senddown: send VCON on ttyI%d\n", - info->line); -#endif - isdn_tty_at_cout("\r\nVCON\r\n", info); - } - } -#endif - if (!(buflen = info->xmit_count)) - return; - if ((info->emu.mdmreg[REG_CTS] & BIT_CTS) != 0) - info->msr &= ~UART_MSR_CTS; - info->lsr &= ~UART_LSR_TEMT; - /* info->xmit_count is modified here and in isdn_tty_write(). - * So we return here if isdn_tty_write() is in the - * critical section. - */ - atomic_inc(&info->xmit_lock); - if (!(atomic_dec_and_test(&info->xmit_lock))) - return; - if (info->isdn_driver < 0) { - info->xmit_count = 0; - return; - } - skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4; -#ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 2) - audio_len = buflen * voice_cf[info->emu.vpar[3]]; - else - audio_len = 0; - skb = dev_alloc_skb(skb_res + buflen + audio_len); -#else - skb = dev_alloc_skb(skb_res + buflen); -#endif - if (!skb) { - printk(KERN_WARNING - "isdn_tty: Out of memory in ttyI%d senddown\n", - info->line); - return; - } - skb_reserve(skb, skb_res); - skb_put_data(skb, info->port.xmit_buf, buflen); - info->xmit_count = 0; -#ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 2) { - /* For now, ifmt is fixed to 1 (alaw), since this - * is used with ISDN everywhere in the world, except - * US, Canada and Japan. - * Later, when US-ISDN protocols are implemented, - * this setting will depend on the D-channel protocol. - */ - int ifmt = 1; - - /* voice conversion/decompression */ - switch (info->emu.vpar[3]) { - case 2: - case 3: - case 4: - /* adpcm, compatible to ZyXel 1496 modem - * with ROM revision 6.01 - */ - audio_len = isdn_audio_adpcm2xlaw(info->adpcms, - ifmt, - skb->data, - skb_put(skb, audio_len), - buflen); - skb_pull(skb, buflen); - skb_trim(skb, audio_len); - break; - case 5: - /* a-law */ - if (!ifmt) - isdn_audio_alaw2ulaw(skb->data, - buflen); - break; - case 6: - /* u-law */ - if (ifmt) - isdn_audio_ulaw2alaw(skb->data, - buflen); - break; - } - } -#endif /* CONFIG_ISDN_AUDIO */ - if (info->emu.mdmreg[REG_T70] & BIT_T70) { - /* Add T.70 simplified header */ - if (info->emu.mdmreg[REG_T70] & BIT_T70_EXT) - memcpy(skb_push(skb, 2), "\1\0", 2); - else - memcpy(skb_push(skb, 4), "\1\0\1\0", 4); - } - skb_queue_tail(&info->xmit_queue, skb); -} - -/************************************************************ - * - * Modem-functions - * - * mostly "stolen" from original Linux-serial.c and friends. - * - ************************************************************/ - -/* The next routine is called once from within timer-interrupt - * triggered within isdn_tty_modem_ncarrier(). It calls - * isdn_tty_modem_result() to stuff a "NO CARRIER" Message - * into the tty's buffer. - */ -static void -isdn_tty_modem_do_ncarrier(struct timer_list *t) -{ - modem_info *info = from_timer(info, t, nc_timer); - isdn_tty_modem_result(RESULT_NO_CARRIER, info); -} - -/* Next routine is called, whenever the DTR-signal is raised. - * It checks the ncarrier-flag, and triggers the above routine - * when necessary. The ncarrier-flag is set, whenever DTR goes - * low. - */ -static void -isdn_tty_modem_ncarrier(modem_info *info) -{ - if (info->ncarrier) { - info->nc_timer.expires = jiffies + HZ; - add_timer(&info->nc_timer); - } -} - -/* - * return the usage calculated by si and layer 2 protocol - */ -static int -isdn_calc_usage(int si, int l2) -{ - int usg = ISDN_USAGE_MODEM; - -#ifdef CONFIG_ISDN_AUDIO - if (si == 1) { - switch (l2) { - case ISDN_PROTO_L2_MODEM: - usg = ISDN_USAGE_MODEM; - break; -#ifdef CONFIG_ISDN_TTY_FAX - case ISDN_PROTO_L2_FAX: - usg = ISDN_USAGE_FAX; - break; -#endif - case ISDN_PROTO_L2_TRANS: - default: - usg = ISDN_USAGE_VOICE; - break; - } - } -#endif - return (usg); -} - -/* isdn_tty_dial() performs dialing of a tty an the necessary - * setup of the lower levels before that. - */ -static void -isdn_tty_dial(char *n, modem_info *info, atemu *m) -{ - int usg = ISDN_USAGE_MODEM; - int si = 7; - int l2 = m->mdmreg[REG_L2PROT]; - u_long flags; - isdn_ctrl cmd; - int i; - int j; - - for (j = 7; j >= 0; j--) - if (m->mdmreg[REG_SI1] & (1 << j)) { - si = bit2si[j]; - break; - } - usg = isdn_calc_usage(si, l2); -#ifdef CONFIG_ISDN_AUDIO - if ((si == 1) && - (l2 != ISDN_PROTO_L2_MODEM) -#ifdef CONFIG_ISDN_TTY_FAX - && (l2 != ISDN_PROTO_L2_FAX) -#endif - ) { - l2 = ISDN_PROTO_L2_TRANS; - usg = ISDN_USAGE_VOICE; - } -#endif - m->mdmreg[REG_SI1I] = si2bit[si]; - spin_lock_irqsave(&dev->lock, flags); - i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); - if (i < 0) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_tty_modem_result(RESULT_NO_DIALTONE, info); - } else { - info->isdn_driver = dev->drvmap[i]; - info->isdn_channel = dev->chanmap[i]; - info->drv_index = i; - dev->m_idx[i] = info->line; - dev->usage[i] |= ISDN_USAGE_OUTGOING; - info->last_dir = 1; - strcpy(info->last_num, n); - isdn_info_update(); - spin_unlock_irqrestore(&dev->lock, flags); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - isdn_command(&cmd); - strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETEAZ; - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - info->last_l2 = l2; - cmd.arg = info->isdn_channel + (l2 << 8); - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); -#ifdef CONFIG_ISDN_TTY_FAX - if (l2 == ISDN_PROTO_L2_FAX) { - cmd.parm.fax = info->fax; - info->fax->direction = ISDN_TTY_FAX_CONN_OUT; - } -#endif - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - sprintf(cmd.parm.setup.phone, "%s", n); - sprintf(cmd.parm.setup.eazmsn, "%s", - isdn_map_eaz2msn(m->msn, info->isdn_driver)); - cmd.parm.setup.si1 = si; - cmd.parm.setup.si2 = m->mdmreg[REG_SI2]; - cmd.command = ISDN_CMD_DIAL; - info->dialing = 1; - info->emu.carrierwait = 0; - strcpy(dev->num[i], n); - isdn_info_update(); - isdn_command(&cmd); - isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); - } -} - -/* isdn_tty_hangup() disassociates a tty from the real - * ISDN-line (hangup). The usage-status is cleared - * and some cleanup is done also. - */ -void -isdn_tty_modem_hup(modem_info *info, int local) -{ - isdn_ctrl cmd; - int di, ch; - - if (!info) - return; - - di = info->isdn_driver; - ch = info->isdn_channel; - if (di < 0 || ch < 0) - return; - - info->isdn_driver = -1; - info->isdn_channel = -1; - -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup ttyI%d\n", info->line); -#endif - info->rcvsched = 0; - isdn_tty_flush_buffer(info->port.tty); - if (info->online) { - info->last_lhup = local; - info->online = 0; - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - } -#ifdef CONFIG_ISDN_AUDIO - info->vonline = 0; -#ifdef CONFIG_ISDN_TTY_FAX - info->faxonline = 0; - info->fax->phase = ISDN_FAX_PHASE_IDLE; -#endif - info->emu.vpar[4] = 0; - info->emu.vpar[5] = 8; - kfree(info->dtmf_state); - info->dtmf_state = NULL; - kfree(info->silence_state); - info->silence_state = NULL; - kfree(info->adpcms); - info->adpcms = NULL; - kfree(info->adpcmr); - info->adpcmr = NULL; -#endif - if ((info->msr & UART_MSR_RI) && - (info->emu.mdmreg[REG_RUNG] & BIT_RUNG)) - isdn_tty_modem_result(RESULT_RUNG, info); - info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); - info->lsr |= UART_LSR_TEMT; - - if (local) { - cmd.driver = di; - cmd.command = ISDN_CMD_HANGUP; - cmd.arg = ch; - isdn_command(&cmd); - } - - isdn_all_eaz(di, ch); - info->emu.mdmreg[REG_RINGCNT] = 0; - isdn_free_channel(di, ch, 0); - - if (info->drv_index >= 0) { - dev->m_idx[info->drv_index] = -1; - info->drv_index = -1; - } -} - -/* - * Begin of a CAPI like interface, currently used only for - * supplementary service (CAPI 2.0 part III) - */ -#include <linux/isdn/capicmd.h> -#include <linux/module.h> - -int -isdn_tty_capi_facility(capi_msg *cm) { - return (-1); /* dummy */ -} - -/* isdn_tty_suspend() tries to suspend the current tty connection - */ -static void -isdn_tty_suspend(char *id, modem_info *info, atemu *m) -{ - isdn_ctrl cmd; - - int l; - - if (!info) - return; - -#ifdef ISDN_DEBUG_MODEM_SERVICES - printk(KERN_DEBUG "Msusp ttyI%d\n", info->line); -#endif - l = strlen(id); - if ((info->isdn_driver >= 0)) { - cmd.parm.cmsg.Length = l + 18; - cmd.parm.cmsg.Command = CAPI_FACILITY; - cmd.parm.cmsg.Subcommand = CAPI_REQ; - cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; - cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */ - cmd.parm.cmsg.para[1] = 0; - cmd.parm.cmsg.para[2] = l + 3; - cmd.parm.cmsg.para[3] = 4; /* 16 bit 0x0004 Suspend */ - cmd.parm.cmsg.para[4] = 0; - cmd.parm.cmsg.para[5] = l; - memcpy(&cmd.parm.cmsg.para[6], id, l); - cmd.command = CAPI_PUT_MESSAGE; - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - isdn_command(&cmd); - } -} - -/* isdn_tty_resume() tries to resume a suspended call - * setup of the lower levels before that. unfortunately here is no - * checking for compatibility of used protocols implemented by Q931 - * It does the same things like isdn_tty_dial, the last command - * is different, may be we can merge it. - */ - -static void -isdn_tty_resume(char *id, modem_info *info, atemu *m) -{ - int usg = ISDN_USAGE_MODEM; - int si = 7; - int l2 = m->mdmreg[REG_L2PROT]; - isdn_ctrl cmd; - ulong flags; - int i; - int j; - int l; - - l = strlen(id); - for (j = 7; j >= 0; j--) - if (m->mdmreg[REG_SI1] & (1 << j)) { - si = bit2si[j]; - break; - } - usg = isdn_calc_usage(si, l2); -#ifdef CONFIG_ISDN_AUDIO - if ((si == 1) && - (l2 != ISDN_PROTO_L2_MODEM) -#ifdef CONFIG_ISDN_TTY_FAX - && (l2 != ISDN_PROTO_L2_FAX) -#endif - ) { - l2 = ISDN_PROTO_L2_TRANS; - usg = ISDN_USAGE_VOICE; - } -#endif - m->mdmreg[REG_SI1I] = si2bit[si]; - spin_lock_irqsave(&dev->lock, flags); - i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); - if (i < 0) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_tty_modem_result(RESULT_NO_DIALTONE, info); - } else { - info->isdn_driver = dev->drvmap[i]; - info->isdn_channel = dev->chanmap[i]; - info->drv_index = i; - dev->m_idx[i] = info->line; - dev->usage[i] |= ISDN_USAGE_OUTGOING; - info->last_dir = 1; -// strcpy(info->last_num, n); - isdn_info_update(); - spin_unlock_irqrestore(&dev->lock, flags); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - isdn_command(&cmd); - strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETEAZ; - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - info->last_l2 = l2; - cmd.arg = info->isdn_channel + (l2 << 8); - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.parm.cmsg.Length = l + 18; - cmd.parm.cmsg.Command = CAPI_FACILITY; - cmd.parm.cmsg.Subcommand = CAPI_REQ; - cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; - cmd.parm.cmsg.para[0] = 3; /* 16 bit 0x0003 suplementary service */ - cmd.parm.cmsg.para[1] = 0; - cmd.parm.cmsg.para[2] = l + 3; - cmd.parm.cmsg.para[3] = 5; /* 16 bit 0x0005 Resume */ - cmd.parm.cmsg.para[4] = 0; - cmd.parm.cmsg.para[5] = l; - memcpy(&cmd.parm.cmsg.para[6], id, l); - cmd.command = CAPI_PUT_MESSAGE; - info->dialing = 1; -// strcpy(dev->num[i], n); - isdn_info_update(); - isdn_command(&cmd); - isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); - } -} - -/* isdn_tty_send_msg() sends a message to a HL driver - * This is used for hybrid modem cards to send AT commands to it - */ - -static void -isdn_tty_send_msg(modem_info *info, atemu *m, char *msg) -{ - int usg = ISDN_USAGE_MODEM; - int si = 7; - int l2 = m->mdmreg[REG_L2PROT]; - isdn_ctrl cmd; - ulong flags; - int i; - int j; - int l; - - l = min(strlen(msg), sizeof(cmd.parm) - sizeof(cmd.parm.cmsg) - + sizeof(cmd.parm.cmsg.para) - 2); - - if (!l) { - isdn_tty_modem_result(RESULT_ERROR, info); - return; - } - for (j = 7; j >= 0; j--) - if (m->mdmreg[REG_SI1] & (1 << j)) { - si = bit2si[j]; - break; - } - usg = isdn_calc_usage(si, l2); -#ifdef CONFIG_ISDN_AUDIO - if ((si == 1) && - (l2 != ISDN_PROTO_L2_MODEM) -#ifdef CONFIG_ISDN_TTY_FAX - && (l2 != ISDN_PROTO_L2_FAX) -#endif - ) { - l2 = ISDN_PROTO_L2_TRANS; - usg = ISDN_USAGE_VOICE; - } -#endif - m->mdmreg[REG_SI1I] = si2bit[si]; - spin_lock_irqsave(&dev->lock, flags); - i = isdn_get_free_channel(usg, l2, m->mdmreg[REG_L3PROT], -1, -1, m->msn); - if (i < 0) { - spin_unlock_irqrestore(&dev->lock, flags); - isdn_tty_modem_result(RESULT_NO_DIALTONE, info); - } else { - info->isdn_driver = dev->drvmap[i]; - info->isdn_channel = dev->chanmap[i]; - info->drv_index = i; - dev->m_idx[i] = info->line; - dev->usage[i] |= ISDN_USAGE_OUTGOING; - info->last_dir = 1; - isdn_info_update(); - spin_unlock_irqrestore(&dev->lock, flags); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_CLREAZ; - isdn_command(&cmd); - strcpy(cmd.parm.num, isdn_map_eaz2msn(m->msn, info->isdn_driver)); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETEAZ; - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - info->last_l2 = l2; - cmd.arg = info->isdn_channel + (l2 << 8); - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.parm.cmsg.Length = l + 14; - cmd.parm.cmsg.Command = CAPI_MANUFACTURER; - cmd.parm.cmsg.Subcommand = CAPI_REQ; - cmd.parm.cmsg.adr.Controller = info->isdn_driver + 1; - cmd.parm.cmsg.para[0] = l + 1; - strncpy(&cmd.parm.cmsg.para[1], msg, l); - cmd.parm.cmsg.para[l + 1] = 0xd; - cmd.command = CAPI_PUT_MESSAGE; -/* info->dialing = 1; - strcpy(dev->num[i], n); - isdn_info_update(); -*/ - isdn_command(&cmd); - } -} - -static inline int -isdn_tty_paranoia_check(modem_info *info, char *name, const char *routine) -{ -#ifdef MODEM_PARANOIA_CHECK - if (!info) { - printk(KERN_WARNING "isdn_tty: null info_struct for %s in %s\n", - name, routine); - return 1; - } - if (info->magic != ISDN_ASYNC_MAGIC) { - printk(KERN_WARNING "isdn_tty: bad magic for modem struct %s in %s\n", - name, routine); - return 1; - } -#endif - return 0; -} - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void -isdn_tty_change_speed(modem_info *info) -{ - struct tty_port *port = &info->port; - uint cflag, - cval, - quot; - int i; - - if (!port->tty) - return; - cflag = port->tty->termios.c_cflag; - - quot = i = cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; - if (i < 1 || i > 2) - port->tty->termios.c_cflag &= ~CBAUDEX; - else - i += 15; - } - if (quot) { - info->mcr |= UART_MCR_DTR; - isdn_tty_modem_ncarrier(info); - } else { - info->mcr &= ~UART_MCR_DTR; - if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in changespeed\n"); -#endif - if (info->online) - info->ncarrier = 1; - isdn_tty_modem_reset_regs(info, 0); - isdn_tty_modem_hup(info, 1); - } - return; - } - /* byte size and parity */ - cval = cflag & (CSIZE | CSTOPB); - cval >>= 4; - if (cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(cflag & PARODD)) - cval |= UART_LCR_EPAR; - - tty_port_set_check_carrier(port, ~cflag & CLOCAL); -} - -static int -isdn_tty_startup(modem_info *info) -{ - if (tty_port_initialized(&info->port)) - return 0; - isdn_lock_drivers(); -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "starting up ttyi%d ...\n", info->line); -#endif - /* - * Now, initialize the UART - */ - info->mcr = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); - /* - * and set the speed of the serial port - */ - isdn_tty_change_speed(info); - - tty_port_set_initialized(&info->port, 1); - info->msr |= (UART_MSR_DSR | UART_MSR_CTS); - info->send_outstanding = 0; - return 0; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void -isdn_tty_shutdown(modem_info *info) -{ - if (!tty_port_initialized(&info->port)) - return; -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "Shutting down isdnmodem port %d ....\n", info->line); -#endif - isdn_unlock_drivers(); - info->msr &= ~UART_MSR_RI; - if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) { - info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS); - if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { - isdn_tty_modem_reset_regs(info, 0); -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_shutdown\n"); -#endif - isdn_tty_modem_hup(info, 1); - } - } - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); - - tty_port_set_initialized(&info->port, 0); -} - -/* isdn_tty_write() is the main send-routine. It is called from the upper - * levels within the kernel to perform sending data. Depending on the - * online-flag it either directs output to the at-command-interpreter or - * to the lower level. Additional tasks done here: - * - If online, check for escape-sequence (+++) - * - If sending audio-data, call isdn_tty_DLEdown() to parse DLE-codes. - * - If receiving audio-data, call isdn_tty_end_vrx() to abort if needed. - * - If dialing, abort dial. - */ -static int -isdn_tty_write(struct tty_struct *tty, const u_char *buf, int count) -{ - int c; - int total = 0; - modem_info *info = (modem_info *) tty->driver_data; - atemu *m = &info->emu; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write")) - return 0; - /* See isdn_tty_senddown() */ - atomic_inc(&info->xmit_lock); - while (1) { - c = count; - if (c > info->xmit_size - info->xmit_count) - c = info->xmit_size - info->xmit_count; - if (info->isdn_driver >= 0 && c > dev->drv[info->isdn_driver]->maxbufsize) - c = dev->drv[info->isdn_driver]->maxbufsize; - if (c <= 0) - break; - if ((info->online > 1) -#ifdef CONFIG_ISDN_AUDIO - || (info->vonline & 3) -#endif - ) { -#ifdef CONFIG_ISDN_AUDIO - if (!info->vonline) -#endif - isdn_tty_check_esc(buf, m->mdmreg[REG_ESC], c, - &(m->pluscount), - &(m->lastplus)); - memcpy(&info->port.xmit_buf[info->xmit_count], buf, c); -#ifdef CONFIG_ISDN_AUDIO - if (info->vonline) { - int cc = isdn_tty_handleDLEdown(info, m, c); - if (info->vonline & 2) { - if (!cc) { - /* If DLE decoding results in zero-transmit, but - * c originally was non-zero, do a wakeup. - */ - tty_wakeup(tty); - info->msr |= UART_MSR_CTS; - info->lsr |= UART_LSR_TEMT; - } - info->xmit_count += cc; - } - if ((info->vonline & 3) == 1) { - /* Do NOT handle Ctrl-Q or Ctrl-S - * when in full-duplex audio mode. - */ - if (isdn_tty_end_vrx(buf, c)) { - info->vonline &= ~1; -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG - "got !^Q/^S, send DLE-ETX,VCON on ttyI%d\n", - info->line); -#endif - isdn_tty_at_cout("\020\003\r\nVCON\r\n", info); - } - } - } else - if (TTY_IS_FCLASS1(info)) { - int cc = isdn_tty_handleDLEdown(info, m, c); - - if (info->vonline & 4) { /* ETX seen */ - isdn_ctrl c; - - c.command = ISDN_CMD_FAXCMD; - c.driver = info->isdn_driver; - c.arg = info->isdn_channel; - c.parm.aux.cmd = ISDN_FAX_CLASS1_CTRL; - c.parm.aux.subcmd = ETX; - isdn_command(&c); - } - info->vonline = 0; -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG "fax dle cc/c %d/%d\n", cc, c); -#endif - info->xmit_count += cc; - } else -#endif - info->xmit_count += c; - } else { - info->msr |= UART_MSR_CTS; - info->lsr |= UART_LSR_TEMT; - if (info->dialing) { - info->dialing = 0; -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_write\n"); -#endif - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - isdn_tty_modem_hup(info, 1); - } else - c = isdn_tty_edit_at(buf, c, info); - } - buf += c; - count -= c; - total += c; - } - atomic_dec(&info->xmit_lock); - if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) { - if (m->mdmreg[REG_DXMT] & BIT_DXMT) { - isdn_tty_senddown(info); - isdn_tty_tint(info); - } - isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); - } - return total; -} - -static int -isdn_tty_write_room(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - int ret; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_write_room")) - return 0; - if (!info->online) - return info->xmit_size; - ret = info->xmit_size - info->xmit_count; - return (ret < 0) ? 0 : ret; -} - -static int -isdn_tty_chars_in_buffer(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_chars_in_buffer")) - return 0; - if (!info->online) - return 0; - return (info->xmit_count); -} - -static void -isdn_tty_flush_buffer(struct tty_struct *tty) -{ - modem_info *info; - - if (!tty) { - return; - } - info = (modem_info *) tty->driver_data; - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_buffer")) { - return; - } - isdn_tty_cleanup_xmit(info); - info->xmit_count = 0; - tty_wakeup(tty); -} - -static void -isdn_tty_flush_chars(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars")) - return; - if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) - isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1); -} - -/* - * ------------------------------------------------------------ - * isdn_tty_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void -isdn_tty_throttle(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_throttle")) - return; - if (I_IXOFF(tty)) - info->x_char = STOP_CHAR(tty); - info->mcr &= ~UART_MCR_RTS; -} - -static void -isdn_tty_unthrottle(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_unthrottle")) - return; - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - info->x_char = START_CHAR(tty); - } - info->mcr |= UART_MCR_RTS; -} - -/* - * ------------------------------------------------------------ - * isdn_tty_ioctl() and friends - * ------------------------------------------------------------ - */ - -/* - * isdn_tty_get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows RS485 driver to be written in user space. - */ -static int -isdn_tty_get_lsr_info(modem_info *info, uint __user *value) -{ - u_char status; - uint result; - - status = info->lsr; - result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result, value); -} - - -static int -isdn_tty_tiocmget(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - u_char control, status; - - if (isdn_tty_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - if (tty_io_error(tty)) - return -EIO; - - mutex_lock(&modem_info_mutex); -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line); -#endif - - control = info->mcr; - status = info->msr; - mutex_unlock(&modem_info_mutex); - return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) - | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) - | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) - | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) - | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) - | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); -} - -static int -isdn_tty_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - if (tty_io_error(tty)) - return -EIO; - -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear); -#endif - - mutex_lock(&modem_info_mutex); - if (set & TIOCM_RTS) - info->mcr |= UART_MCR_RTS; - if (set & TIOCM_DTR) { - info->mcr |= UART_MCR_DTR; - isdn_tty_modem_ncarrier(info); - } - - if (clear & TIOCM_RTS) - info->mcr &= ~UART_MCR_RTS; - if (clear & TIOCM_DTR) { - info->mcr &= ~UART_MCR_DTR; - if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) { - isdn_tty_modem_reset_regs(info, 0); -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in TIOCMSET\n"); -#endif - if (info->online) - info->ncarrier = 1; - isdn_tty_modem_hup(info, 1); - } - } - mutex_unlock(&modem_info_mutex); - return 0; -} - -static int -isdn_tty_ioctl(struct tty_struct *tty, uint cmd, ulong arg) -{ - modem_info *info = (modem_info *) tty->driver_data; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_ioctl")) - return -ENODEV; - if (tty_io_error(tty)) - return -EIO; - switch (cmd) { - case TIOCSERGETLSR: /* Get line status register */ -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line); -#endif - return isdn_tty_get_lsr_info(info, (uint __user *) arg); - default: -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on ttyi%d\n", cmd, info->line); -#endif - return -ENOIOCTLCMD; - } - return 0; -} - -static void -isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - modem_info *info = (modem_info *) tty->driver_data; - - mutex_lock(&modem_info_mutex); - if (!old_termios) - isdn_tty_change_speed(info); - else { - if (tty->termios.c_cflag == old_termios->c_cflag && - tty->termios.c_ispeed == old_termios->c_ispeed && - tty->termios.c_ospeed == old_termios->c_ospeed) { - mutex_unlock(&modem_info_mutex); - return; - } - isdn_tty_change_speed(info); - } - mutex_unlock(&modem_info_mutex); -} - -/* - * ------------------------------------------------------------ - * isdn_tty_open() and friends - * ------------------------------------------------------------ - */ - -static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty) -{ - modem_info *info = &dev->mdm.info[tty->index]; - - if (isdn_tty_paranoia_check(info, tty->name, __func__)) - return -ENODEV; - - tty->driver_data = info; - - return tty_port_install(&info->port, driver, tty); -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -static int -isdn_tty_open(struct tty_struct *tty, struct file *filp) -{ - modem_info *info = tty->driver_data; - struct tty_port *port = &info->port; - int retval; - -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name, - port->count); -#endif - port->count++; - port->tty = tty; - /* - * Start up serial port - */ - retval = isdn_tty_startup(info); - if (retval) { -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open return after startup\n"); -#endif - return retval; - } - retval = tty_port_block_til_ready(port, tty, filp); - if (retval) { -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open return after isdn_tty_block_til_ready \n"); -#endif - return retval; - } -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line); -#endif - dev->modempoll++; -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_open normal exit\n"); -#endif - return 0; -} - -static void -isdn_tty_close(struct tty_struct *tty, struct file *filp) -{ - modem_info *info = (modem_info *) tty->driver_data; - struct tty_port *port = &info->port; - ulong timeout; - - if (!info || isdn_tty_paranoia_check(info, tty->name, "isdn_tty_close")) - return; - if (tty_hung_up_p(filp)) { -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_close return after tty_hung_up_p\n"); -#endif - return; - } - if ((tty->count == 1) && (port->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk(KERN_ERR "isdn_tty_close: bad port count; tty->count is 1, " - "info->count is %d\n", port->count); - port->count = 1; - } - if (--port->count < 0) { - printk(KERN_ERR "isdn_tty_close: bad port count for ttyi%d: %d\n", - info->line, port->count); - port->count = 0; - } - if (port->count) { -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_close after info->count != 0\n"); -#endif - return; - } - info->closing = 1; - - tty->closing = 1; - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - if (tty_port_initialized(port)) { - tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - timeout = jiffies + HZ; - while (!(info->lsr & UART_LSR_TEMT)) { - schedule_timeout_interruptible(20); - if (time_after(jiffies, timeout)) - break; - } - } - dev->modempoll--; - isdn_tty_shutdown(info); - isdn_tty_flush_buffer(tty); - tty_ldisc_flush(tty); - port->tty = NULL; - info->ncarrier = 0; - - tty_port_close_end(port, tty); - info->closing = 0; -#ifdef ISDN_DEBUG_MODEM_OPEN - printk(KERN_DEBUG "isdn_tty_close normal exit\n"); -#endif -} - -/* - * isdn_tty_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void -isdn_tty_hangup(struct tty_struct *tty) -{ - modem_info *info = (modem_info *) tty->driver_data; - struct tty_port *port = &info->port; - - if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_hangup")) - return; - isdn_tty_shutdown(info); - port->count = 0; - tty_port_set_active(port, 0); - port->tty = NULL; - wake_up_interruptible(&port->open_wait); -} - -/* This routine initializes all emulator-data. - */ -static void -isdn_tty_reset_profile(atemu *m) -{ - m->profile[0] = 0; - m->profile[1] = 0; - m->profile[2] = 43; - m->profile[3] = 13; - m->profile[4] = 10; - m->profile[5] = 8; - m->profile[6] = 3; - m->profile[7] = 60; - m->profile[8] = 2; - m->profile[9] = 6; - m->profile[10] = 7; - m->profile[11] = 70; - m->profile[12] = 0x45; - m->profile[13] = 4; - m->profile[14] = ISDN_PROTO_L2_X75I; - m->profile[15] = ISDN_PROTO_L3_TRANS; - m->profile[16] = ISDN_SERIAL_XMIT_SIZE / 16; - m->profile[17] = ISDN_MODEM_WINSIZE; - m->profile[18] = 4; - m->profile[19] = 0; - m->profile[20] = 0; - m->profile[23] = 0; - m->pmsn[0] = '\0'; - m->plmsn[0] = '\0'; -} - -#ifdef CONFIG_ISDN_AUDIO -static void -isdn_tty_modem_reset_vpar(atemu *m) -{ - m->vpar[0] = 2; /* Voice-device (2 = phone line) */ - m->vpar[1] = 0; /* Silence detection level (0 = none ) */ - m->vpar[2] = 70; /* Silence interval (7 sec. ) */ - m->vpar[3] = 2; /* Compression type (1 = ADPCM-2 ) */ - m->vpar[4] = 0; /* DTMF detection level (0 = softcode ) */ - m->vpar[5] = 8; /* DTMF interval (8 * 5 ms. ) */ -} -#endif - -#ifdef CONFIG_ISDN_TTY_FAX -static void -isdn_tty_modem_reset_faxpar(modem_info *info) -{ - T30_s *f = info->fax; - - f->code = 0; - f->phase = ISDN_FAX_PHASE_IDLE; - f->direction = 0; - f->resolution = 1; /* fine */ - f->rate = 5; /* 14400 bit/s */ - f->width = 0; - f->length = 0; - f->compression = 0; - f->ecm = 0; - f->binary = 0; - f->scantime = 0; - memset(&f->id[0], 32, FAXIDLEN - 1); - f->id[FAXIDLEN - 1] = 0; - f->badlin = 0; - f->badmul = 0; - f->bor = 0; - f->nbc = 0; - f->cq = 0; - f->cr = 0; - f->ctcrty = 0; - f->minsp = 0; - f->phcto = 30; - f->rel = 0; - memset(&f->pollid[0], 32, FAXIDLEN - 1); - f->pollid[FAXIDLEN - 1] = 0; -} -#endif - -static void -isdn_tty_modem_reset_regs(modem_info *info, int force) -{ - atemu *m = &info->emu; - if ((m->mdmreg[REG_DTRR] & BIT_DTRR) || force) { - memcpy(m->mdmreg, m->profile, ISDN_MODEM_NUMREG); - memcpy(m->msn, m->pmsn, ISDN_MSNLEN); - memcpy(m->lmsn, m->plmsn, ISDN_LMSNLEN); - info->xmit_size = m->mdmreg[REG_PSIZE] * 16; - } -#ifdef CONFIG_ISDN_AUDIO - isdn_tty_modem_reset_vpar(m); -#endif -#ifdef CONFIG_ISDN_TTY_FAX - isdn_tty_modem_reset_faxpar(info); -#endif - m->mdmcmdl = 0; -} - -static void -modem_write_profile(atemu *m) -{ - memcpy(m->profile, m->mdmreg, ISDN_MODEM_NUMREG); - memcpy(m->pmsn, m->msn, ISDN_MSNLEN); - memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN); - if (dev->profd) - send_sig(SIGIO, dev->profd, 1); -} - -static const struct tty_operations modem_ops = { - .install = isdn_tty_install, - .open = isdn_tty_open, - .close = isdn_tty_close, - .write = isdn_tty_write, - .flush_chars = isdn_tty_flush_chars, - .write_room = isdn_tty_write_room, - .chars_in_buffer = isdn_tty_chars_in_buffer, - .flush_buffer = isdn_tty_flush_buffer, - .ioctl = isdn_tty_ioctl, - .throttle = isdn_tty_throttle, - .unthrottle = isdn_tty_unthrottle, - .set_termios = isdn_tty_set_termios, - .hangup = isdn_tty_hangup, - .tiocmget = isdn_tty_tiocmget, - .tiocmset = isdn_tty_tiocmset, -}; - -static int isdn_tty_carrier_raised(struct tty_port *port) -{ - modem_info *info = container_of(port, modem_info, port); - return info->msr & UART_MSR_DCD; -} - -static const struct tty_port_operations isdn_tty_port_ops = { - .carrier_raised = isdn_tty_carrier_raised, -}; - -int -isdn_tty_modem_init(void) -{ - isdn_modem_t *m; - int i, retval; - modem_info *info; - - m = &dev->mdm; - m->tty_modem = alloc_tty_driver(ISDN_MAX_CHANNELS); - if (!m->tty_modem) - return -ENOMEM; - m->tty_modem->name = "ttyI"; - m->tty_modem->major = ISDN_TTY_MAJOR; - m->tty_modem->minor_start = 0; - m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL; - m->tty_modem->subtype = SERIAL_TYPE_NORMAL; - m->tty_modem->init_termios = tty_std_termios; - m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - m->tty_modem->flags = TTY_DRIVER_REAL_RAW; - m->tty_modem->driver_name = "isdn_tty"; - tty_set_operations(m->tty_modem, &modem_ops); - retval = tty_register_driver(m->tty_modem); - if (retval) { - printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n"); - goto err; - } - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - info = &m->info[i]; -#ifdef CONFIG_ISDN_TTY_FAX - if (!(info->fax = kmalloc(sizeof(T30_s), GFP_KERNEL))) { - printk(KERN_ERR "Could not allocate fax t30-buffer\n"); - retval = -ENOMEM; - goto err_unregister; - } -#endif - tty_port_init(&info->port); - info->port.ops = &isdn_tty_port_ops; - spin_lock_init(&info->readlock); - sprintf(info->last_cause, "0000"); - sprintf(info->last_num, "none"); - info->last_dir = 0; - info->last_lhup = 1; - info->last_l2 = -1; - info->last_si = 0; - isdn_tty_reset_profile(&info->emu); - isdn_tty_modem_reset_regs(info, 1); - info->magic = ISDN_ASYNC_MAGIC; - info->line = i; - info->x_char = 0; - info->isdn_driver = -1; - info->isdn_channel = -1; - info->drv_index = -1; - info->xmit_size = ISDN_SERIAL_XMIT_SIZE; - timer_setup(&info->nc_timer, isdn_tty_modem_do_ncarrier, 0); - skb_queue_head_init(&info->xmit_queue); -#ifdef CONFIG_ISDN_AUDIO - skb_queue_head_init(&info->dtmf_queue); -#endif - info->port.xmit_buf = kmalloc(ISDN_SERIAL_XMIT_MAX + 5, - GFP_KERNEL); - if (!info->port.xmit_buf) { - printk(KERN_ERR "Could not allocate modem xmit-buffer\n"); - retval = -ENOMEM; - goto err_unregister; - } - /* Make room for T.70 header */ - info->port.xmit_buf += 4; - } - return 0; -err_unregister: - for (i--; i >= 0; i--) { - info = &m->info[i]; -#ifdef CONFIG_ISDN_TTY_FAX - kfree(info->fax); -#endif - kfree(info->port.xmit_buf - 4); - info->port.xmit_buf = NULL; - tty_port_destroy(&info->port); - } - tty_unregister_driver(m->tty_modem); -err: - put_tty_driver(m->tty_modem); - m->tty_modem = NULL; - return retval; -} - -void -isdn_tty_exit(void) -{ - modem_info *info; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - info = &dev->mdm.info[i]; - isdn_tty_cleanup_xmit(info); -#ifdef CONFIG_ISDN_TTY_FAX - kfree(info->fax); -#endif - kfree(info->port.xmit_buf - 4); - info->port.xmit_buf = NULL; - tty_port_destroy(&info->port); - } - tty_unregister_driver(dev->mdm.tty_modem); - put_tty_driver(dev->mdm.tty_modem); - dev->mdm.tty_modem = NULL; -} - - -/* - * isdn_tty_match_icall(char *MSN, atemu *tty_emulator, int dev_idx) - * match the MSN against the MSNs (glob patterns) defined for tty_emulator, - * and return 0 for match, 1 for no match, 2 if MSN could match if longer. - */ - -static int -isdn_tty_match_icall(char *cid, atemu *emu, int di) -{ -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: msn=%s lmsn=%s mmsn=%s mreg[SI1]=%d mreg[SI2]=%d\n", - emu->msn, emu->lmsn, isdn_map_eaz2msn(emu->msn, di), - emu->mdmreg[REG_SI1], emu->mdmreg[REG_SI2]); -#endif - if (strlen(emu->lmsn)) { - char *p = emu->lmsn; - char *q; - int tmp; - int ret = 0; - - while (1) { - if ((q = strchr(p, ';'))) - *q = '\0'; - if ((tmp = isdn_msncmp(cid, isdn_map_eaz2msn(p, di))) > ret) - ret = tmp; -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: lmsnX=%s mmsn=%s -> tmp=%d\n", - p, isdn_map_eaz2msn(emu->msn, di), tmp); -#endif - if (q) { - *q = ';'; - p = q; - p++; - } - if (!tmp) - return 0; - if (!q) - break; - } - return ret; - } else { - int tmp; - tmp = isdn_msncmp(cid, isdn_map_eaz2msn(emu->msn, di)); -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: mmsn=%s -> tmp=%d\n", - isdn_map_eaz2msn(emu->msn, di), tmp); -#endif - return tmp; - } -} - -/* - * An incoming call-request has arrived. - * Search the tty-devices for an appropriate device and bind - * it to the ISDN-Channel. - * Return: - * - * 0 = No matching device found. - * 1 = A matching device found. - * 3 = No match found, but eventually would match, if - * CID is longer. - */ -int -isdn_tty_find_icall(int di, int ch, setup_parm *setup) -{ - char *eaz; - int i; - int wret; - int idx; - int si1; - int si2; - char *nr; - ulong flags; - - if (!setup->phone[0]) { - nr = "0"; - printk(KERN_INFO "isdn_tty: Incoming call without OAD, assuming '0'\n"); - } else - nr = setup->phone; - si1 = (int) setup->si1; - si2 = (int) setup->si2; - if (!setup->eazmsn[0]) { - printk(KERN_WARNING "isdn_tty: Incoming call without CPN, assuming '0'\n"); - eaz = "0"; - } else - eaz = setup->eazmsn; -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: eaz=%s si1=%d si2=%d\n", eaz, si1, si2); -#endif - wret = 0; - spin_lock_irqsave(&dev->lock, flags); - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - - if (info->port.count == 0) - continue; - if ((info->emu.mdmreg[REG_SI1] & si2bit[si1]) && /* SI1 is matching */ - (info->emu.mdmreg[REG_SI2] == si2)) { /* SI2 is matching */ - idx = isdn_dc2minor(di, ch); -#ifdef ISDN_DEBUG_MODEM_ICALL - printk(KERN_DEBUG "m_fi: match1 wret=%d\n", wret); - printk(KERN_DEBUG "m_fi: idx=%d flags=%08lx drv=%d ch=%d usg=%d\n", idx, - info->port.flags, info->isdn_driver, - info->isdn_channel, dev->usage[idx]); -#endif - if ( -#ifndef FIX_FILE_TRANSFER - tty_port_active(&info->port) && -#endif - (info->isdn_driver == -1) && - (info->isdn_channel == -1) && - (USG_NONE(dev->usage[idx]))) { - int matchret; - - if ((matchret = isdn_tty_match_icall(eaz, &info->emu, di)) > wret) - wret = matchret; - if (!matchret) { /* EAZ is matching */ - info->isdn_driver = di; - info->isdn_channel = ch; - info->drv_index = idx; - dev->m_idx[idx] = info->line; - dev->usage[idx] &= ISDN_USAGE_EXCLUSIVE; - dev->usage[idx] |= isdn_calc_usage(si1, info->emu.mdmreg[REG_L2PROT]); - strcpy(dev->num[idx], nr); - strcpy(info->emu.cpn, eaz); - info->emu.mdmreg[REG_SI1I] = si2bit[si1]; - info->emu.mdmreg[REG_PLAN] = setup->plan; - info->emu.mdmreg[REG_SCREEN] = setup->screen; - isdn_info_update(); - spin_unlock_irqrestore(&dev->lock, flags); - printk(KERN_INFO "isdn_tty: call from %s, -> RING on ttyI%d\n", nr, - info->line); - info->msr |= UART_MSR_RI; - isdn_tty_modem_result(RESULT_RING, info); - isdn_timer_ctrl(ISDN_TIMER_MODEMRING, 1); - return 1; - } - } - } - } - spin_unlock_irqrestore(&dev->lock, flags); - printk(KERN_INFO "isdn_tty: call from %s -> %s %s\n", nr, eaz, - ((dev->drv[di]->flags & DRV_FLAG_REJBUS) && (wret != 2)) ? "rejected" : "ignored"); - return (wret == 2) ? 3 : 0; -} - -int -isdn_tty_stat_callback(int i, isdn_ctrl *c) -{ - int mi; - modem_info *info; - char *e; - - if (i < 0) - return 0; - if ((mi = dev->m_idx[i]) >= 0) { - info = &dev->mdm.info[mi]; - switch (c->command) { - case ISDN_STAT_CINF: - printk(KERN_DEBUG "CHARGEINFO on ttyI%d: %ld %s\n", info->line, c->arg, c->parm.num); - info->emu.charge = (unsigned) simple_strtoul(c->parm.num, &e, 10); - if (e == (char *)c->parm.num) - info->emu.charge = 0; - - break; - case ISDN_STAT_BSENT: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_BSENT ttyI%d\n", info->line); -#endif - if ((info->isdn_driver == c->driver) && - (info->isdn_channel == c->arg)) { - info->msr |= UART_MSR_CTS; - if (info->send_outstanding) - if (!(--info->send_outstanding)) - info->lsr |= UART_LSR_TEMT; - isdn_tty_tint(info); - return 1; - } - break; - case ISDN_STAT_CAUSE: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_CAUSE ttyI%d\n", info->line); -#endif - /* Signal cause to tty-device */ - strncpy(info->last_cause, c->parm.num, 5); - return 1; - case ISDN_STAT_DISPLAY: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_DISPLAY ttyI%d\n", info->line); -#endif - /* Signal display to tty-device */ - if ((info->emu.mdmreg[REG_DISPLAY] & BIT_DISPLAY) && - !(info->emu.mdmreg[REG_RESPNUM] & BIT_RESPNUM)) { - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout("DISPLAY: ", info); - isdn_tty_at_cout(c->parm.display, info); - isdn_tty_at_cout("\r\n", info); - } - return 1; - case ISDN_STAT_DCONN: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_DCONN ttyI%d\n", info->line); -#endif - if (tty_port_active(&info->port)) { - if (info->dialing == 1) { - info->dialing = 2; - return 1; - } - } - break; - case ISDN_STAT_DHUP: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_DHUP ttyI%d\n", info->line); -#endif - if (tty_port_active(&info->port)) { - if (info->dialing == 1) - isdn_tty_modem_result(RESULT_BUSY, info); - if (info->dialing > 1) - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - info->dialing = 0; -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in ISDN_STAT_DHUP\n"); -#endif - isdn_tty_modem_hup(info, 0); - return 1; - } - break; - case ISDN_STAT_BCONN: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_BCONN ttyI%d\n", info->line); -#endif - /* Wake up any processes waiting - * for incoming call of this device when - * DCD follow the state of incoming carrier - */ - if (info->port.blocked_open && - (info->emu.mdmreg[REG_DCD] & BIT_DCD)) { - wake_up_interruptible(&info->port.open_wait); - } - - /* Schedule CONNECT-Message to any tty - * waiting for it and - * set DCD-bit of its modem-status. - */ - if (tty_port_active(&info->port) || - (info->port.blocked_open && - (info->emu.mdmreg[REG_DCD] & BIT_DCD))) { - info->msr |= UART_MSR_DCD; - info->emu.charge = 0; - if (info->dialing & 0xf) - info->last_dir = 1; - else - info->last_dir = 0; - info->dialing = 0; - info->rcvsched = 1; - if (USG_MODEM(dev->usage[i])) { - if (info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) { - strcpy(info->emu.connmsg, c->parm.num); - isdn_tty_modem_result(RESULT_CONNECT, info); - } else - isdn_tty_modem_result(RESULT_CONNECT64000, info); - } - if (USG_VOICE(dev->usage[i])) - isdn_tty_modem_result(RESULT_VCON, info); - return 1; - } - break; - case ISDN_STAT_BHUP: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_BHUP ttyI%d\n", info->line); -#endif - if (tty_port_active(&info->port)) { -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n"); -#endif - isdn_tty_modem_hup(info, 0); - return 1; - } - break; - case ISDN_STAT_NODCH: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_NODCH ttyI%d\n", info->line); -#endif - if (tty_port_active(&info->port)) { - if (info->dialing) { - info->dialing = 0; - info->last_l2 = -1; - info->last_si = 0; - sprintf(info->last_cause, "0000"); - isdn_tty_modem_result(RESULT_NO_DIALTONE, info); - } - isdn_tty_modem_hup(info, 0); - return 1; - } - break; - case ISDN_STAT_UNLOAD: -#ifdef ISDN_TTY_STAT_DEBUG - printk(KERN_DEBUG "tty_STAT_UNLOAD ttyI%d\n", info->line); -#endif - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - info = &dev->mdm.info[i]; - if (info->isdn_driver == c->driver) { - if (info->online) - isdn_tty_modem_hup(info, 1); - } - } - return 1; -#ifdef CONFIG_ISDN_TTY_FAX - case ISDN_STAT_FAXIND: - if (tty_port_active(&info->port)) { - isdn_tty_fax_command(info, c); - } - break; -#endif -#ifdef CONFIG_ISDN_AUDIO - case ISDN_STAT_AUDIO: - if (tty_port_active(&info->port)) { - switch (c->parm.num[0]) { - case ISDN_AUDIO_DTMF: - if (info->vonline) { - isdn_audio_put_dle_code(info, - c->parm.num[1]); - } - break; - } - } - break; -#endif - } - } - return 0; -} - -/********************************************************************* - Modem-Emulator-Routines -*********************************************************************/ - -#define cmdchar(c) ((c >= ' ') && (c <= 0x7f)) - -/* - * Put a message from the AT-emulator into receive-buffer of tty, - * convert CR, LF, and BS to values in modem-registers 3, 4 and 5. - */ -void -isdn_tty_at_cout(char *msg, modem_info *info) -{ - struct tty_port *port = &info->port; - atemu *m = &info->emu; - char *p; - char c; - u_long flags; - struct sk_buff *skb = NULL; - char *sp = NULL; - int l; - - if (!msg) { - printk(KERN_WARNING "isdn_tty: Null-Message in isdn_tty_at_cout\n"); - return; - } - - l = strlen(msg); - - spin_lock_irqsave(&info->readlock, flags); - if (info->closing) { - spin_unlock_irqrestore(&info->readlock, flags); - return; - } - - /* use queue instead of direct, if online and */ - /* data is in queue or buffer is full */ - if (info->online && ((tty_buffer_request_room(port, l) < l) || - !skb_queue_empty(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel]))) { - skb = alloc_skb(l, GFP_ATOMIC); - if (!skb) { - spin_unlock_irqrestore(&info->readlock, flags); - return; - } - sp = skb_put(skb, l); -#ifdef CONFIG_ISDN_AUDIO - ISDN_AUDIO_SKB_DLECOUNT(skb) = 0; - ISDN_AUDIO_SKB_LOCK(skb) = 0; -#endif - } - - for (p = msg; *p; p++) { - switch (*p) { - case '\r': - c = m->mdmreg[REG_CR]; - break; - case '\n': - c = m->mdmreg[REG_LF]; - break; - case '\b': - c = m->mdmreg[REG_BS]; - break; - default: - c = *p; - } - if (skb) { - *sp++ = c; - } else { - if (tty_insert_flip_char(port, c, TTY_NORMAL) == 0) - break; - } - } - if (skb) { - __skb_queue_tail(&dev->drv[info->isdn_driver]->rpqueue[info->isdn_channel], skb); - dev->drv[info->isdn_driver]->rcvcount[info->isdn_channel] += skb->len; - spin_unlock_irqrestore(&info->readlock, flags); - /* Schedule dequeuing */ - if (dev->modempoll && info->rcvsched) - isdn_timer_ctrl(ISDN_TIMER_MODEMREAD, 1); - - } else { - spin_unlock_irqrestore(&info->readlock, flags); - tty_flip_buffer_push(port); - } -} - -/* - * Perform ATH Hangup - */ -static void -isdn_tty_on_hook(modem_info *info) -{ - if (info->isdn_channel >= 0) { -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "Mhup in isdn_tty_on_hook\n"); -#endif - isdn_tty_modem_hup(info, 1); - } -} - -static void -isdn_tty_off_hook(void) -{ - printk(KERN_DEBUG "isdn_tty_off_hook\n"); -} - -#define PLUSWAIT1 (HZ / 2) /* 0.5 sec. */ -#define PLUSWAIT2 (HZ * 3 / 2) /* 1.5 sec */ - -/* - * Check Buffer for Modem-escape-sequence, activate timer-callback to - * isdn_tty_modem_escape() if sequence found. - * - * Parameters: - * p pointer to databuffer - * plus escape-character - * count length of buffer - * pluscount count of valid escape-characters so far - * lastplus timestamp of last character - */ -static void -isdn_tty_check_esc(const u_char *p, u_char plus, int count, int *pluscount, - u_long *lastplus) -{ - if (plus > 127) - return; - if (count > 3) { - p += count - 3; - count = 3; - *pluscount = 0; - } - while (count > 0) { - if (*(p++) == plus) { - if ((*pluscount)++) { - /* Time since last '+' > 0.5 sec. ? */ - if (time_after(jiffies, *lastplus + PLUSWAIT1)) - *pluscount = 1; - } else { - /* Time since last non-'+' < 1.5 sec. ? */ - if (time_before(jiffies, *lastplus + PLUSWAIT2)) - *pluscount = 0; - } - if ((*pluscount == 3) && (count == 1)) - isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, 1); - if (*pluscount > 3) - *pluscount = 1; - } else - *pluscount = 0; - *lastplus = jiffies; - count--; - } -} - -/* - * Return result of AT-emulator to tty-receive-buffer, depending on - * modem-register 12, bit 0 and 1. - * For CONNECT-messages also switch to online-mode. - * For RING-message handle auto-ATA if register 0 != 0 - */ - -static void -isdn_tty_modem_result(int code, modem_info *info) -{ - atemu *m = &info->emu; - static char *msg[] = - {"OK", "CONNECT", "RING", "NO CARRIER", "ERROR", - "CONNECT 64000", "NO DIALTONE", "BUSY", "NO ANSWER", - "RINGING", "NO MSN/EAZ", "VCON", "RUNG"}; - char s[ISDN_MSNLEN + 10]; - - switch (code) { - case RESULT_RING: - m->mdmreg[REG_RINGCNT]++; - if (m->mdmreg[REG_RINGCNT] == m->mdmreg[REG_RINGATA]) - /* Automatically accept incoming call */ - isdn_tty_cmd_ATA(info); - break; - case RESULT_NO_CARRIER: -#ifdef ISDN_DEBUG_MODEM_HUP - printk(KERN_DEBUG "modem_result: NO CARRIER %d %d\n", - info->closing, !info->port.tty); -#endif - m->mdmreg[REG_RINGCNT] = 0; - del_timer(&info->nc_timer); - info->ncarrier = 0; - if (info->closing || !info->port.tty) - return; - -#ifdef CONFIG_ISDN_AUDIO - if (info->vonline & 1) { -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG "res3: send DLE-ETX on ttyI%d\n", - info->line); -#endif - /* voice-recording, add DLE-ETX */ - isdn_tty_at_cout("\020\003", info); - } - if (info->vonline & 2) { -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG "res3: send DLE-DC4 on ttyI%d\n", - info->line); -#endif - /* voice-playing, add DLE-DC4 */ - isdn_tty_at_cout("\020\024", info); - } -#endif - break; - case RESULT_CONNECT: - case RESULT_CONNECT64000: - sprintf(info->last_cause, "0000"); - if (!info->online) - info->online = 2; - break; - case RESULT_VCON: -#ifdef ISDN_DEBUG_MODEM_VOICE - printk(KERN_DEBUG "res3: send VCON on ttyI%d\n", - info->line); -#endif - sprintf(info->last_cause, "0000"); - if (!info->online) - info->online = 1; - break; - } /* switch (code) */ - - if (m->mdmreg[REG_RESP] & BIT_RESP) { - /* Show results */ - if (m->mdmreg[REG_RESPNUM] & BIT_RESPNUM) { - /* Show numeric results only */ - sprintf(s, "\r\n%d\r\n", code); - isdn_tty_at_cout(s, info); - } else { - if (code == RESULT_RING) { - /* return if "show RUNG" and ringcounter>1 */ - if ((m->mdmreg[REG_RUNG] & BIT_RUNG) && - (m->mdmreg[REG_RINGCNT] > 1)) - return; - /* print CID, _before_ _every_ ring */ - if (!(m->mdmreg[REG_CIDONCE] & BIT_CIDONCE)) { - isdn_tty_at_cout("\r\nCALLER NUMBER: ", info); - isdn_tty_at_cout(dev->num[info->drv_index], info); - if (m->mdmreg[REG_CDN] & BIT_CDN) { - isdn_tty_at_cout("\r\nCALLED NUMBER: ", info); - isdn_tty_at_cout(info->emu.cpn, info); - } - } - } - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout(msg[code], info); - switch (code) { - case RESULT_CONNECT: - switch (m->mdmreg[REG_L2PROT]) { - case ISDN_PROTO_L2_MODEM: - isdn_tty_at_cout(" ", info); - isdn_tty_at_cout(m->connmsg, info); - break; - } - break; - case RESULT_RING: - /* Append CPN, if enabled */ - if ((m->mdmreg[REG_CPN] & BIT_CPN)) { - sprintf(s, "/%s", m->cpn); - isdn_tty_at_cout(s, info); - } - /* Print CID only once, _after_ 1st RING */ - if ((m->mdmreg[REG_CIDONCE] & BIT_CIDONCE) && - (m->mdmreg[REG_RINGCNT] == 1)) { - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout("CALLER NUMBER: ", info); - isdn_tty_at_cout(dev->num[info->drv_index], info); - if (m->mdmreg[REG_CDN] & BIT_CDN) { - isdn_tty_at_cout("\r\nCALLED NUMBER: ", info); - isdn_tty_at_cout(info->emu.cpn, info); - } - } - break; - case RESULT_NO_CARRIER: - case RESULT_NO_DIALTONE: - case RESULT_BUSY: - case RESULT_NO_ANSWER: - m->mdmreg[REG_RINGCNT] = 0; - /* Append Cause-Message if enabled */ - if (m->mdmreg[REG_RESPXT] & BIT_RESPXT) { - sprintf(s, "/%s", info->last_cause); - isdn_tty_at_cout(s, info); - } - break; - case RESULT_CONNECT64000: - /* Append Protocol to CONNECT message */ - switch (m->mdmreg[REG_L2PROT]) { - case ISDN_PROTO_L2_X75I: - case ISDN_PROTO_L2_X75UI: - case ISDN_PROTO_L2_X75BUI: - isdn_tty_at_cout("/X.75", info); - break; - case ISDN_PROTO_L2_HDLC: - isdn_tty_at_cout("/HDLC", info); - break; - case ISDN_PROTO_L2_V11096: - isdn_tty_at_cout("/V110/9600", info); - break; - case ISDN_PROTO_L2_V11019: - isdn_tty_at_cout("/V110/19200", info); - break; - case ISDN_PROTO_L2_V11038: - isdn_tty_at_cout("/V110/38400", info); - break; - } - if (m->mdmreg[REG_T70] & BIT_T70) { - isdn_tty_at_cout("/T.70", info); - if (m->mdmreg[REG_T70] & BIT_T70_EXT) - isdn_tty_at_cout("+", info); - } - break; - } - isdn_tty_at_cout("\r\n", info); - } - } - if (code == RESULT_NO_CARRIER) { - if (info->closing || (!info->port.tty)) - return; - - if (tty_port_check_carrier(&info->port)) - tty_hangup(info->port.tty); - } -} - - -/* - * Display a modem-register-value. - */ -static void -isdn_tty_show_profile(int ridx, modem_info *info) -{ - char v[6]; - - sprintf(v, "\r\n%d", info->emu.mdmreg[ridx]); - isdn_tty_at_cout(v, info); -} - -/* - * Get MSN-string from char-pointer, set pointer to end of number - */ -static void -isdn_tty_get_msnstr(char *n, char **p) -{ - int limit = ISDN_MSNLEN - 1; - - while (((*p[0] >= '0' && *p[0] <= '9') || - /* Why a comma ??? */ - (*p[0] == ',') || (*p[0] == ':')) && - (limit--)) - *n++ = *p[0]++; - *n = '\0'; -} - -/* - * Get phone-number from modem-commandbuffer - */ -static void -isdn_tty_getdial(char *p, char *q, int cnt) -{ - int first = 1; - int limit = ISDN_MSNLEN - 1; /* MUST match the size of interface var to avoid - buffer overflow */ - - while (strchr(" 0123456789,#.*WPTSR-", *p) && *p && --cnt > 0) { - if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first) || - ((*p == 'R') && first) || - (*p == '*') || (*p == '#')) { - *q++ = *p; - limit--; - } - if (!limit) - break; - p++; - first = 0; - } - *q = 0; -} - -#define PARSE_ERROR { isdn_tty_modem_result(RESULT_ERROR, info); return; } -#define PARSE_ERROR1 { isdn_tty_modem_result(RESULT_ERROR, info); return 1; } - -static void -isdn_tty_report(modem_info *info) -{ - atemu *m = &info->emu; - char s[80]; - - isdn_tty_at_cout("\r\nStatistics of last connection:\r\n\r\n", info); - sprintf(s, " Remote Number: %s\r\n", info->last_num); - isdn_tty_at_cout(s, info); - sprintf(s, " Direction: %s\r\n", info->last_dir ? "outgoing" : "incoming"); - isdn_tty_at_cout(s, info); - isdn_tty_at_cout(" Layer-2 Protocol: ", info); - switch (info->last_l2) { - case ISDN_PROTO_L2_X75I: - isdn_tty_at_cout("X.75i", info); - break; - case ISDN_PROTO_L2_X75UI: - isdn_tty_at_cout("X.75ui", info); - break; - case ISDN_PROTO_L2_X75BUI: - isdn_tty_at_cout("X.75bui", info); - break; - case ISDN_PROTO_L2_HDLC: - isdn_tty_at_cout("HDLC", info); - break; - case ISDN_PROTO_L2_V11096: - isdn_tty_at_cout("V.110 9600 Baud", info); - break; - case ISDN_PROTO_L2_V11019: - isdn_tty_at_cout("V.110 19200 Baud", info); - break; - case ISDN_PROTO_L2_V11038: - isdn_tty_at_cout("V.110 38400 Baud", info); - break; - case ISDN_PROTO_L2_TRANS: - isdn_tty_at_cout("transparent", info); - break; - case ISDN_PROTO_L2_MODEM: - isdn_tty_at_cout("modem", info); - break; - case ISDN_PROTO_L2_FAX: - isdn_tty_at_cout("fax", info); - break; - default: - isdn_tty_at_cout("unknown", info); - break; - } - if (m->mdmreg[REG_T70] & BIT_T70) { - isdn_tty_at_cout("/T.70", info); - if (m->mdmreg[REG_T70] & BIT_T70_EXT) - isdn_tty_at_cout("+", info); - } - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout(" Service: ", info); - switch (info->last_si) { - case 1: - isdn_tty_at_cout("audio\r\n", info); - break; - case 5: - isdn_tty_at_cout("btx\r\n", info); - break; - case 7: - isdn_tty_at_cout("data\r\n", info); - break; - default: - sprintf(s, "%d\r\n", info->last_si); - isdn_tty_at_cout(s, info); - break; - } - sprintf(s, " Hangup location: %s\r\n", info->last_lhup ? "local" : "remote"); - isdn_tty_at_cout(s, info); - sprintf(s, " Last cause: %s\r\n", info->last_cause); - isdn_tty_at_cout(s, info); -} - -/* - * Parse AT&.. commands. - */ -static int -isdn_tty_cmd_ATand(char **p, modem_info *info) -{ - atemu *m = &info->emu; - int i; - char rb[100]; - -#define MAXRB (sizeof(rb) - 1) - - switch (*p[0]) { - case 'B': - /* &B - Set Buffersize */ - p[0]++; - i = isdn_getnum(p); - if ((i < 0) || (i > ISDN_SERIAL_XMIT_MAX)) - PARSE_ERROR1; -#ifdef CONFIG_ISDN_AUDIO - if ((m->mdmreg[REG_SI1] & 1) && (i > VBUF)) - PARSE_ERROR1; -#endif - m->mdmreg[REG_PSIZE] = i / 16; - info->xmit_size = m->mdmreg[REG_PSIZE] * 16; - switch (m->mdmreg[REG_L2PROT]) { - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - info->xmit_size /= 10; - } - break; - case 'C': - /* &C - DCD Status */ - p[0]++; - switch (isdn_getnum(p)) { - case 0: - m->mdmreg[REG_DCD] &= ~BIT_DCD; - break; - case 1: - m->mdmreg[REG_DCD] |= BIT_DCD; - break; - default: - PARSE_ERROR1 - } - break; - case 'D': - /* &D - Set DTR-Low-behavior */ - p[0]++; - switch (isdn_getnum(p)) { - case 0: - m->mdmreg[REG_DTRHUP] &= ~BIT_DTRHUP; - m->mdmreg[REG_DTRR] &= ~BIT_DTRR; - break; - case 2: - m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP; - m->mdmreg[REG_DTRR] &= ~BIT_DTRR; - break; - case 3: - m->mdmreg[REG_DTRHUP] |= BIT_DTRHUP; - m->mdmreg[REG_DTRR] |= BIT_DTRR; - break; - default: - PARSE_ERROR1 - } - break; - case 'E': - /* &E -Set EAZ/MSN */ - p[0]++; - isdn_tty_get_msnstr(m->msn, p); - break; - case 'F': - /* &F -Set Factory-Defaults */ - p[0]++; - if (info->msr & UART_MSR_DCD) - PARSE_ERROR1; - isdn_tty_reset_profile(m); - isdn_tty_modem_reset_regs(info, 1); - break; -#ifdef DUMMY_HAYES_AT - case 'K': - /* only for be compilant with common scripts */ - /* &K Flowcontrol - no function */ - p[0]++; - isdn_getnum(p); - break; -#endif - case 'L': - /* &L -Set Numbers to listen on */ - p[0]++; - i = 0; - while (*p[0] && (strchr("0123456789,-*[]?;", *p[0])) && - (i < ISDN_LMSNLEN - 1)) - m->lmsn[i++] = *p[0]++; - m->lmsn[i] = '\0'; - break; - case 'R': - /* &R - Set V.110 bitrate adaption */ - p[0]++; - i = isdn_getnum(p); - switch (i) { - case 0: - /* Switch off V.110, back to X.75 */ - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; - m->mdmreg[REG_SI2] = 0; - info->xmit_size = m->mdmreg[REG_PSIZE] * 16; - break; - case 9600: - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11096; - m->mdmreg[REG_SI2] = 197; - info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10; - break; - case 19200: - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11019; - m->mdmreg[REG_SI2] = 199; - info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10; - break; - case 38400: - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_V11038; - m->mdmreg[REG_SI2] = 198; /* no existing standard for this */ - info->xmit_size = m->mdmreg[REG_PSIZE] * 16 / 10; - break; - default: - PARSE_ERROR1; - } - /* Switch off T.70 */ - m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT); - /* Set Service 7 */ - m->mdmreg[REG_SI1] |= 4; - break; - case 'S': - /* &S - Set Windowsize */ - p[0]++; - i = isdn_getnum(p); - if ((i > 0) && (i < 9)) - m->mdmreg[REG_WSIZE] = i; - else - PARSE_ERROR1; - break; - case 'V': - /* &V - Show registers */ - p[0]++; - isdn_tty_at_cout("\r\n", info); - for (i = 0; i < ISDN_MODEM_NUMREG; i++) { - sprintf(rb, "S%02d=%03d%s", i, - m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n"); - isdn_tty_at_cout(rb, info); - } - sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n", - strlen(m->msn) ? m->msn : "None"); - isdn_tty_at_cout(rb, info); - if (strlen(m->lmsn)) { - isdn_tty_at_cout("\r\nListen: ", info); - isdn_tty_at_cout(m->lmsn, info); - isdn_tty_at_cout("\r\n", info); - } - break; - case 'W': - /* &W - Write Profile */ - p[0]++; - switch (*p[0]) { - case '0': - p[0]++; - modem_write_profile(m); - break; - default: - PARSE_ERROR1; - } - break; - case 'X': - /* &X - Switch to BTX-Mode and T.70 */ - p[0]++; - switch (isdn_getnum(p)) { - case 0: - m->mdmreg[REG_T70] &= ~(BIT_T70 | BIT_T70_EXT); - info->xmit_size = m->mdmreg[REG_PSIZE] * 16; - break; - case 1: - m->mdmreg[REG_T70] |= BIT_T70; - m->mdmreg[REG_T70] &= ~BIT_T70_EXT; - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; - info->xmit_size = 112; - m->mdmreg[REG_SI1] = 4; - m->mdmreg[REG_SI2] = 0; - break; - case 2: - m->mdmreg[REG_T70] |= (BIT_T70 | BIT_T70_EXT); - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; - info->xmit_size = 112; - m->mdmreg[REG_SI1] = 4; - m->mdmreg[REG_SI2] = 0; - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - return 0; -} - -static int -isdn_tty_check_ats(int mreg, int mval, modem_info *info, atemu *m) -{ - /* Some plausibility checks */ - switch (mreg) { - case REG_L2PROT: - if (mval > ISDN_PROTO_L2_MAX) - return 1; - break; - case REG_PSIZE: - if ((mval * 16) > ISDN_SERIAL_XMIT_MAX) - return 1; -#ifdef CONFIG_ISDN_AUDIO - if ((m->mdmreg[REG_SI1] & 1) && (mval > VBUFX)) - return 1; -#endif - info->xmit_size = mval * 16; - switch (m->mdmreg[REG_L2PROT]) { - case ISDN_PROTO_L2_V11096: - case ISDN_PROTO_L2_V11019: - case ISDN_PROTO_L2_V11038: - info->xmit_size /= 10; - } - break; - case REG_SI1I: - case REG_PLAN: - case REG_SCREEN: - /* readonly registers */ - return 1; - } - return 0; -} - -/* - * Perform ATS command - */ -static int -isdn_tty_cmd_ATS(char **p, modem_info *info) -{ - atemu *m = &info->emu; - int bitpos; - int mreg; - int mval; - int bval; - - mreg = isdn_getnum(p); - if (mreg < 0 || mreg >= ISDN_MODEM_NUMREG) - PARSE_ERROR1; - switch (*p[0]) { - case '=': - p[0]++; - mval = isdn_getnum(p); - if (mval < 0 || mval > 255) - PARSE_ERROR1; - if (isdn_tty_check_ats(mreg, mval, info, m)) - PARSE_ERROR1; - m->mdmreg[mreg] = mval; - break; - case '.': - /* Set/Clear a single bit */ - p[0]++; - bitpos = isdn_getnum(p); - if ((bitpos < 0) || (bitpos > 7)) - PARSE_ERROR1; - switch (*p[0]) { - case '=': - p[0]++; - bval = isdn_getnum(p); - if (bval < 0 || bval > 1) - PARSE_ERROR1; - if (bval) - mval = m->mdmreg[mreg] | (1 << bitpos); - else - mval = m->mdmreg[mreg] & ~(1 << bitpos); - if (isdn_tty_check_ats(mreg, mval, info, m)) - PARSE_ERROR1; - m->mdmreg[mreg] = mval; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout((m->mdmreg[mreg] & (1 << bitpos)) ? "1" : "0", - info); - break; - default: - PARSE_ERROR1; - } - break; - case '?': - p[0]++; - isdn_tty_show_profile(mreg, info); - break; - default: - PARSE_ERROR1; - break; - } - return 0; -} - -/* - * Perform ATA command - */ -static void -isdn_tty_cmd_ATA(modem_info *info) -{ - atemu *m = &info->emu; - isdn_ctrl cmd; - int l2; - - if (info->msr & UART_MSR_RI) { - /* Accept incoming call */ - info->last_dir = 0; - strcpy(info->last_num, dev->num[info->drv_index]); - m->mdmreg[REG_RINGCNT] = 0; - info->msr &= ~UART_MSR_RI; - l2 = m->mdmreg[REG_L2PROT]; -#ifdef CONFIG_ISDN_AUDIO - /* If more than one bit set in reg18, autoselect Layer2 */ - if ((m->mdmreg[REG_SI1] & m->mdmreg[REG_SI1I]) != m->mdmreg[REG_SI1]) { - if (m->mdmreg[REG_SI1I] == 1) { - if ((l2 != ISDN_PROTO_L2_MODEM) && (l2 != ISDN_PROTO_L2_FAX)) - l2 = ISDN_PROTO_L2_TRANS; - } else - l2 = ISDN_PROTO_L2_X75I; - } -#endif - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL2; - cmd.arg = info->isdn_channel + (l2 << 8); - info->last_l2 = l2; - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_SETL3; - cmd.arg = info->isdn_channel + (m->mdmreg[REG_L3PROT] << 8); -#ifdef CONFIG_ISDN_TTY_FAX - if (l2 == ISDN_PROTO_L2_FAX) { - cmd.parm.fax = info->fax; - info->fax->direction = ISDN_TTY_FAX_CONN_IN; - } -#endif - isdn_command(&cmd); - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_ACCEPTD; - info->dialing = 16; - info->emu.carrierwait = 0; - isdn_command(&cmd); - isdn_timer_ctrl(ISDN_TIMER_CARRIER, 1); - } else - isdn_tty_modem_result(RESULT_NO_ANSWER, info); -} - -#ifdef CONFIG_ISDN_AUDIO -/* - * Parse AT+F.. commands - */ -static int -isdn_tty_cmd_PLUSF(char **p, modem_info *info) -{ - atemu *m = &info->emu; - char rs[20]; - - if (!strncmp(p[0], "CLASS", 5)) { - p[0] += 5; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", - (m->mdmreg[REG_SI1] & 1) ? 8 : 0); -#ifdef CONFIG_ISDN_TTY_FAX - if (TTY_IS_FCLASS2(info)) - sprintf(rs, "\r\n2"); - else if (TTY_IS_FCLASS1(info)) - sprintf(rs, "\r\n1"); -#endif - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '0': - p[0]++; - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; - m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS; - m->mdmreg[REG_SI1] = 4; - info->xmit_size = - m->mdmreg[REG_PSIZE] * 16; - break; -#ifdef CONFIG_ISDN_TTY_FAX - case '1': - p[0]++; - if (!(dev->global_features & - ISDN_FEATURE_L3_FCLASS1)) - PARSE_ERROR1; - m->mdmreg[REG_SI1] = 1; - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX; - m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS1; - info->xmit_size = - m->mdmreg[REG_PSIZE] * 16; - break; - case '2': - p[0]++; - if (!(dev->global_features & - ISDN_FEATURE_L3_FCLASS2)) - PARSE_ERROR1; - m->mdmreg[REG_SI1] = 1; - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_FAX; - m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_FCLASS2; - info->xmit_size = - m->mdmreg[REG_PSIZE] * 16; - break; -#endif - case '8': - p[0]++; - /* L2 will change on dialout with si=1 */ - m->mdmreg[REG_L2PROT] = ISDN_PROTO_L2_X75I; - m->mdmreg[REG_L3PROT] = ISDN_PROTO_L3_TRANS; - m->mdmreg[REG_SI1] = 5; - info->xmit_size = VBUF; - break; - case '?': - p[0]++; - strcpy(rs, "\r\n0,"); -#ifdef CONFIG_ISDN_TTY_FAX - if (dev->global_features & - ISDN_FEATURE_L3_FCLASS1) - strcat(rs, "1,"); - if (dev->global_features & - ISDN_FEATURE_L3_FCLASS2) - strcat(rs, "2,"); -#endif - strcat(rs, "8"); - isdn_tty_at_cout(rs, info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - return 0; - } -#ifdef CONFIG_ISDN_TTY_FAX - return (isdn_tty_cmd_PLUSF_FAX(p, info)); -#else - PARSE_ERROR1; -#endif -} - -/* - * Parse AT+V.. commands - */ -static int -isdn_tty_cmd_PLUSV(char **p, modem_info *info) -{ - atemu *m = &info->emu; - isdn_ctrl cmd; - static char *vcmd[] = - {"NH", "IP", "LS", "RX", "SD", "SM", "TX", "DD", NULL}; - int i; - int par1; - int par2; - char rs[20]; - - i = 0; - while (vcmd[i]) { - if (!strncmp(vcmd[i], p[0], 2)) { - p[0] += 2; - break; - } - i++; - } - switch (i) { - case 0: - /* AT+VNH - Auto hangup feature */ - switch (*p[0]) { - case '?': - p[0]++; - isdn_tty_at_cout("\r\n1", info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '1': - p[0]++; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n1", info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - break; - case 1: - /* AT+VIP - Reset all voice parameters */ - isdn_tty_modem_reset_vpar(m); - break; - case 2: - /* AT+VLS - Select device, accept incoming call */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", m->vpar[0]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '0': - p[0]++; - m->vpar[0] = 0; - break; - case '2': - p[0]++; - m->vpar[0] = 2; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n0,2", info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - break; - case 3: - /* AT+VRX - Start recording */ - if (!m->vpar[0]) - PARSE_ERROR1; - if (info->online != 1) { - isdn_tty_modem_result(RESULT_NO_ANSWER, info); - return 1; - } - info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); - if (!info->dtmf_state) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); - PARSE_ERROR1; - } - info->silence_state = isdn_audio_silence_init(info->silence_state); - if (!info->silence_state) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc silence state\n"); - PARSE_ERROR1; - } - if (m->vpar[3] < 5) { - info->adpcmr = isdn_audio_adpcm_init(info->adpcmr, m->vpar[3]); - if (!info->adpcmr) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n"); - PARSE_ERROR1; - } - } -#ifdef ISDN_DEBUG_AT - printk(KERN_DEBUG "AT: +VRX\n"); -#endif - info->vonline |= 1; - isdn_tty_modem_result(RESULT_CONNECT, info); - return 0; - break; - case 4: - /* AT+VSD - Silence detection */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n<%d>,<%d>", - m->vpar[1], - m->vpar[2]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if ((*p[0] >= '0') && (*p[0] <= '9')) { - par1 = isdn_getnum(p); - if ((par1 < 0) || (par1 > 31)) - PARSE_ERROR1; - if (*p[0] != ',') - PARSE_ERROR1; - p[0]++; - par2 = isdn_getnum(p); - if ((par2 < 0) || (par2 > 255)) - PARSE_ERROR1; - m->vpar[1] = par1; - m->vpar[2] = par2; - break; - } else - if (*p[0] == '?') { - p[0]++; - isdn_tty_at_cout("\r\n<0-31>,<0-255>", - info); - break; - } else - PARSE_ERROR1; - break; - default: - PARSE_ERROR1; - } - break; - case 5: - /* AT+VSM - Select compression */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n<%d>,<%d><8000>", - m->vpar[3], - m->vpar[1]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - switch (*p[0]) { - case '2': - case '3': - case '4': - case '5': - case '6': - par1 = isdn_getnum(p); - if ((par1 < 2) || (par1 > 6)) - PARSE_ERROR1; - m->vpar[3] = par1; - break; - case '?': - p[0]++; - isdn_tty_at_cout("\r\n2;ADPCM;2;0;(8000)\r\n", - info); - isdn_tty_at_cout("3;ADPCM;3;0;(8000)\r\n", - info); - isdn_tty_at_cout("4;ADPCM;4;0;(8000)\r\n", - info); - isdn_tty_at_cout("5;ALAW;8;0;(8000)\r\n", - info); - isdn_tty_at_cout("6;ULAW;8;0;(8000)\r\n", - info); - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - break; - case 6: - /* AT+VTX - Start sending */ - if (!m->vpar[0]) - PARSE_ERROR1; - if (info->online != 1) { - isdn_tty_modem_result(RESULT_NO_ANSWER, info); - return 1; - } - info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); - if (!info->dtmf_state) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); - PARSE_ERROR1; - } - if (m->vpar[3] < 5) { - info->adpcms = isdn_audio_adpcm_init(info->adpcms, m->vpar[3]); - if (!info->adpcms) { - printk(KERN_WARNING "isdn_tty: Couldn't malloc adpcm state\n"); - PARSE_ERROR1; - } - } -#ifdef ISDN_DEBUG_AT - printk(KERN_DEBUG "AT: +VTX\n"); -#endif - m->lastDLE = 0; - info->vonline |= 2; - isdn_tty_modem_result(RESULT_CONNECT, info); - return 0; - break; - case 7: - /* AT+VDD - DTMF detection */ - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n<%d>,<%d>", - m->vpar[4], - m->vpar[5]); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if ((*p[0] >= '0') && (*p[0] <= '9')) { - if (info->online != 1) - PARSE_ERROR1; - par1 = isdn_getnum(p); - if ((par1 < 0) || (par1 > 15)) - PARSE_ERROR1; - if (*p[0] != ',') - PARSE_ERROR1; - p[0]++; - par2 = isdn_getnum(p); - if ((par2 < 0) || (par2 > 255)) - PARSE_ERROR1; - m->vpar[4] = par1; - m->vpar[5] = par2; - cmd.driver = info->isdn_driver; - cmd.command = ISDN_CMD_AUDIO; - cmd.arg = info->isdn_channel + (ISDN_AUDIO_SETDD << 8); - cmd.parm.num[0] = par1; - cmd.parm.num[1] = par2; - isdn_command(&cmd); - break; - } else - if (*p[0] == '?') { - p[0]++; - isdn_tty_at_cout("\r\n<0-15>,<0-255>", - info); - break; - } else - PARSE_ERROR1; - break; - default: - PARSE_ERROR1; - } - break; - default: - PARSE_ERROR1; - } - return 0; -} -#endif /* CONFIG_ISDN_AUDIO */ - -/* - * Parse and perform an AT-command-line. - */ -static void -isdn_tty_parse_at(modem_info *info) -{ - atemu *m = &info->emu; - char *p; - char ds[ISDN_MSNLEN]; - -#ifdef ISDN_DEBUG_AT - printk(KERN_DEBUG "AT: '%s'\n", m->mdmcmd); -#endif - for (p = &m->mdmcmd[2]; *p;) { - switch (*p) { - case ' ': - p++; - break; - case 'A': - /* A - Accept incoming call */ - p++; - isdn_tty_cmd_ATA(info); - return; - case 'D': - /* D - Dial */ - if (info->msr & UART_MSR_DCD) - PARSE_ERROR; - if (info->msr & UART_MSR_RI) { - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - return; - } - isdn_tty_getdial(++p, ds, sizeof ds); - p += strlen(p); - if (!strlen(m->msn)) - isdn_tty_modem_result(RESULT_NO_MSN_EAZ, info); - else if (strlen(ds)) - isdn_tty_dial(ds, info, m); - else - PARSE_ERROR; - return; - case 'E': - /* E - Turn Echo on/off */ - p++; - switch (isdn_getnum(&p)) { - case 0: - m->mdmreg[REG_ECHO] &= ~BIT_ECHO; - break; - case 1: - m->mdmreg[REG_ECHO] |= BIT_ECHO; - break; - default: - PARSE_ERROR; - } - break; - case 'H': - /* H - On/Off-hook */ - p++; - switch (*p) { - case '0': - p++; - isdn_tty_on_hook(info); - break; - case '1': - p++; - isdn_tty_off_hook(); - break; - default: - isdn_tty_on_hook(info); - break; - } - break; - case 'I': - /* I - Information */ - p++; - isdn_tty_at_cout("\r\nLinux ISDN", info); - switch (*p) { - case '0': - case '1': - p++; - break; - case '2': - p++; - isdn_tty_report(info); - break; - case '3': - p++; - snprintf(ds, sizeof(ds), "\r\n%d", info->emu.charge); - isdn_tty_at_cout(ds, info); - break; - default:; - } - break; -#ifdef DUMMY_HAYES_AT - case 'L': - case 'M': - /* only for be compilant with common scripts */ - /* no function */ - p++; - isdn_getnum(&p); - break; -#endif - case 'O': - /* O - Go online */ - p++; - if (info->msr & UART_MSR_DCD) - /* if B-Channel is up */ - isdn_tty_modem_result((m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM) ? RESULT_CONNECT : RESULT_CONNECT64000, info); - else - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - return; - case 'Q': - /* Q - Turn Emulator messages on/off */ - p++; - switch (isdn_getnum(&p)) { - case 0: - m->mdmreg[REG_RESP] |= BIT_RESP; - break; - case 1: - m->mdmreg[REG_RESP] &= ~BIT_RESP; - break; - default: - PARSE_ERROR; - } - break; - case 'S': - /* S - Set/Get Register */ - p++; - if (isdn_tty_cmd_ATS(&p, info)) - return; - break; - case 'V': - /* V - Numeric or ASCII Emulator-messages */ - p++; - switch (isdn_getnum(&p)) { - case 0: - m->mdmreg[REG_RESP] |= BIT_RESPNUM; - break; - case 1: - m->mdmreg[REG_RESP] &= ~BIT_RESPNUM; - break; - default: - PARSE_ERROR; - } - break; - case 'Z': - /* Z - Load Registers from Profile */ - p++; - if (info->msr & UART_MSR_DCD) { - info->online = 0; - isdn_tty_on_hook(info); - } - isdn_tty_modem_reset_regs(info, 1); - break; - case '+': - p++; - switch (*p) { -#ifdef CONFIG_ISDN_AUDIO - case 'F': - p++; - if (isdn_tty_cmd_PLUSF(&p, info)) - return; - break; - case 'V': - if ((!(m->mdmreg[REG_SI1] & 1)) || - (m->mdmreg[REG_L2PROT] == ISDN_PROTO_L2_MODEM)) - PARSE_ERROR; - p++; - if (isdn_tty_cmd_PLUSV(&p, info)) - return; - break; -#endif /* CONFIG_ISDN_AUDIO */ - case 'S': /* SUSPEND */ - p++; - isdn_tty_get_msnstr(ds, &p); - isdn_tty_suspend(ds, info, m); - break; - case 'R': /* RESUME */ - p++; - isdn_tty_get_msnstr(ds, &p); - isdn_tty_resume(ds, info, m); - break; - case 'M': /* MESSAGE */ - p++; - isdn_tty_send_msg(info, m, p); - break; - default: - PARSE_ERROR; - } - break; - case '&': - p++; - if (isdn_tty_cmd_ATand(&p, info)) - return; - break; - default: - PARSE_ERROR; - } - } -#ifdef CONFIG_ISDN_AUDIO - if (!info->vonline) -#endif - isdn_tty_modem_result(RESULT_OK, info); -} - -/* Need own toupper() because standard-toupper is not available - * within modules. - */ -#define my_toupper(c) (((c >= 'a') && (c <= 'z')) ? (c & 0xdf) : c) - -/* - * Perform line-editing of AT-commands - * - * Parameters: - * p inputbuffer - * count length of buffer - * channel index to line (minor-device) - */ -static int -isdn_tty_edit_at(const char *p, int count, modem_info *info) -{ - atemu *m = &info->emu; - int total = 0; - u_char c; - char eb[2]; - int cnt; - - for (cnt = count; cnt > 0; p++, cnt--) { - c = *p; - total++; - if (c == m->mdmreg[REG_CR] || c == m->mdmreg[REG_LF]) { - /* Separator (CR or LF) */ - m->mdmcmd[m->mdmcmdl] = 0; - if (m->mdmreg[REG_ECHO] & BIT_ECHO) { - eb[0] = c; - eb[1] = 0; - isdn_tty_at_cout(eb, info); - } - if ((m->mdmcmdl >= 2) && (!(strncmp(m->mdmcmd, "AT", 2)))) - isdn_tty_parse_at(info); - m->mdmcmdl = 0; - continue; - } - if (c == m->mdmreg[REG_BS] && m->mdmreg[REG_BS] < 128) { - /* Backspace-Function */ - if ((m->mdmcmdl > 2) || (!m->mdmcmdl)) { - if (m->mdmcmdl) - m->mdmcmdl--; - if (m->mdmreg[REG_ECHO] & BIT_ECHO) - isdn_tty_at_cout("\b", info); - } - continue; - } - if (cmdchar(c)) { - if (m->mdmreg[REG_ECHO] & BIT_ECHO) { - eb[0] = c; - eb[1] = 0; - isdn_tty_at_cout(eb, info); - } - if (m->mdmcmdl < 255) { - c = my_toupper(c); - switch (m->mdmcmdl) { - case 1: - if (c == 'T') { - m->mdmcmd[m->mdmcmdl] = c; - m->mdmcmd[++m->mdmcmdl] = 0; - break; - } else - m->mdmcmdl = 0; - /* Fall through - check for 'A' */ - case 0: - if (c == 'A') { - m->mdmcmd[m->mdmcmdl] = c; - m->mdmcmd[++m->mdmcmdl] = 0; - } - break; - default: - m->mdmcmd[m->mdmcmdl] = c; - m->mdmcmd[++m->mdmcmdl] = 0; - } - } - } - } - return total; -} - -/* - * Switch all modem-channels who are online and got a valid - * escape-sequence 1.5 seconds ago, to command-mode. - * This function is called every second via timer-interrupt from within - * timer-dispatcher isdn_timer_function() - */ -void -isdn_tty_modem_escape(void) -{ - int ton = 0; - int i; - int midx; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) - if (USG_MODEM(dev->usage[i]) && (midx = dev->m_idx[i]) >= 0) { - modem_info *info = &dev->mdm.info[midx]; - if (info->online) { - ton = 1; - if ((info->emu.pluscount == 3) && - time_after(jiffies, - info->emu.lastplus + PLUSWAIT2)) { - info->emu.pluscount = 0; - info->online = 0; - isdn_tty_modem_result(RESULT_OK, info); - } - } - } - isdn_timer_ctrl(ISDN_TIMER_MODEMPLUS, ton); -} - -/* - * Put a RING-message to all modem-channels who have the RI-bit set. - * This function is called every second via timer-interrupt from within - * timer-dispatcher isdn_timer_function() - */ -void -isdn_tty_modem_ring(void) -{ - int ton = 0; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - if (info->msr & UART_MSR_RI) { - ton = 1; - isdn_tty_modem_result(RESULT_RING, info); - } - } - isdn_timer_ctrl(ISDN_TIMER_MODEMRING, ton); -} - -/* - * For all online tty's, try sending data to - * the lower levels. - */ -void -isdn_tty_modem_xmit(void) -{ - int ton = 1; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - if (info->online) { - ton = 1; - isdn_tty_senddown(info); - isdn_tty_tint(info); - } - } - isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, ton); -} - -/* - * Check all channels if we have a 'no carrier' timeout. - * Timeout value is set by Register S7. - */ -void -isdn_tty_carrier_timeout(void) -{ - int ton = 0; - int i; - - for (i = 0; i < ISDN_MAX_CHANNELS; i++) { - modem_info *info = &dev->mdm.info[i]; - if (!info->dialing) - continue; - if (info->emu.carrierwait++ > info->emu.mdmreg[REG_WAITC]) { - info->dialing = 0; - isdn_tty_modem_result(RESULT_NO_CARRIER, info); - isdn_tty_modem_hup(info, 1); - } else - ton = 1; - } - isdn_timer_ctrl(ISDN_TIMER_CARRIER, ton); -} diff --git a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h deleted file mode 100644 index a6f801d2263b..000000000000 --- a/drivers/isdn/i4l/isdn_tty.h +++ /dev/null @@ -1,120 +0,0 @@ -/* $Id: isdn_tty.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem, tty related functions (linklevel). - * - * Copyright 1994-1999 by Fritz Elfert (fritz@isdn4linux.de) - * Copyright 1995,96 by Thinking Objects Software GmbH Wuerzburg - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#define DLE 0x10 -#define ETX 0x03 -#define DC4 0x14 - - -/* - * Definition of some special Registers of AT-Emulator - */ -#define REG_RINGATA 0 -#define REG_RINGCNT 1 /* ring counter register */ -#define REG_ESC 2 -#define REG_CR 3 -#define REG_LF 4 -#define REG_BS 5 - -#define REG_WAITC 7 - -#define REG_RESP 12 /* show response messages register */ -#define BIT_RESP 1 /* show response messages bit */ -#define REG_RESPNUM 12 /* show numeric responses register */ -#define BIT_RESPNUM 2 /* show numeric responses bit */ -#define REG_ECHO 12 -#define BIT_ECHO 4 -#define REG_DCD 12 -#define BIT_DCD 8 -#define REG_CTS 12 -#define BIT_CTS 16 -#define REG_DTRR 12 -#define BIT_DTRR 32 -#define REG_DSR 12 -#define BIT_DSR 64 -#define REG_CPPP 12 -#define BIT_CPPP 128 - -#define REG_DXMT 13 -#define BIT_DXMT 1 -#define REG_T70 13 -#define BIT_T70 2 -#define BIT_T70_EXT 32 -#define REG_DTRHUP 13 -#define BIT_DTRHUP 4 -#define REG_RESPXT 13 -#define BIT_RESPXT 8 -#define REG_CIDONCE 13 -#define BIT_CIDONCE 16 -#define REG_RUNG 13 /* show RUNG message register */ -#define BIT_RUNG 64 /* show RUNG message bit */ -#define REG_DISPLAY 13 -#define BIT_DISPLAY 128 - -#define REG_L2PROT 14 -#define REG_L3PROT 15 -#define REG_PSIZE 16 -#define REG_WSIZE 17 -#define REG_SI1 18 -#define REG_SI2 19 -#define REG_SI1I 20 -#define REG_PLAN 21 -#define REG_SCREEN 22 - -#define REG_CPN 23 -#define BIT_CPN 1 -#define REG_CPNFCON 23 -#define BIT_CPNFCON 2 -#define REG_CDN 23 -#define BIT_CDN 4 - -/* defines for result codes */ -#define RESULT_OK 0 -#define RESULT_CONNECT 1 -#define RESULT_RING 2 -#define RESULT_NO_CARRIER 3 -#define RESULT_ERROR 4 -#define RESULT_CONNECT64000 5 -#define RESULT_NO_DIALTONE 6 -#define RESULT_BUSY 7 -#define RESULT_NO_ANSWER 8 -#define RESULT_RINGING 9 -#define RESULT_NO_MSN_EAZ 10 -#define RESULT_VCON 11 -#define RESULT_RUNG 12 - -#define TTY_IS_FCLASS1(info) \ - ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \ - (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS1)) -#define TTY_IS_FCLASS2(info) \ - ((info->emu.mdmreg[REG_L2PROT] == ISDN_PROTO_L2_FAX) && \ - (info->emu.mdmreg[REG_L3PROT] == ISDN_PROTO_L3_FCLASS2)) - -extern void isdn_tty_modem_escape(void); -extern void isdn_tty_modem_ring(void); -extern void isdn_tty_carrier_timeout(void); -extern void isdn_tty_modem_xmit(void); -extern int isdn_tty_modem_init(void); -extern void isdn_tty_exit(void); -extern void isdn_tty_readmodem(void); -extern int isdn_tty_find_icall(int, int, setup_parm *); -extern int isdn_tty_stat_callback(int, isdn_ctrl *); -extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *); -extern int isdn_tty_capi_facility(capi_msg *cm); -extern void isdn_tty_at_cout(char *, modem_info *); -extern void isdn_tty_modem_hup(modem_info *, int); -#ifdef CONFIG_ISDN_TTY_FAX -extern int isdn_tty_cmd_PLUSF_FAX(char **, modem_info *); -extern int isdn_tty_fax_command(modem_info *, isdn_ctrl *); -extern void isdn_tty_fax_bitorder(modem_info *, struct sk_buff *); -#endif diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c deleted file mode 100644 index 47aae4916730..000000000000 --- a/drivers/isdn/i4l/isdn_ttyfax.c +++ /dev/null @@ -1,1123 +0,0 @@ -/* $Id: isdn_ttyfax.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel). - * - * Copyright 1999 by Armin Schindler (mac@melware.de) - * Copyright 1999 by Ralf Spachmann (mel@melware.de) - * Copyright 1999 by Cytronics & Melware - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#undef ISDN_TTY_FAX_STAT_DEBUG -#undef ISDN_TTY_FAX_CMD_DEBUG - -#include <linux/isdn.h> -#include "isdn_common.h" -#include "isdn_tty.h" -#include "isdn_ttyfax.h" - - -static char *isdn_tty_fax_revision = "$Revision: 1.1.2.2 $"; - -#define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; } - -static char * -isdn_getrev(const char *revision) -{ - char *rev; - char *p; - - if ((p = strchr(revision, ':'))) { - rev = p + 2; - p = strchr(rev, '$'); - *--p = 0; - } else - rev = "???"; - return rev; -} - -/* - * Fax Class 2 Modem results - * - */ - -static void -isdn_tty_fax_modem_result(int code, modem_info *info) -{ - atemu *m = &info->emu; - T30_s *f = info->fax; - char rs[50]; - char rss[50]; - char *rp; - int i; - static char *msg[] = - {"OK", "ERROR", "+FCON", "+FCSI:", "+FDIS:", - "+FHNG:", "+FDCS:", "CONNECT", "+FTSI:", - "+FCFR", "+FPTS:", "+FET:"}; - - - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout(msg[code], info); - -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax send %s on ttyI%d\n", - msg[code], info->line); -#endif - switch (code) { - case 0: /* OK */ - break; - case 1: /* ERROR */ - break; - case 2: /* +FCON */ - /* Append CPN, if enabled */ - if ((m->mdmreg[REG_CPNFCON] & BIT_CPNFCON) && - (!(dev->usage[info->isdn_channel] & ISDN_USAGE_OUTGOING))) { - sprintf(rs, "/%s", m->cpn); - isdn_tty_at_cout(rs, info); - } - info->online = 1; - f->fet = 0; - if (f->phase == ISDN_FAX_PHASE_A) - f->phase = ISDN_FAX_PHASE_B; - break; - case 3: /* +FCSI */ - case 8: /* +FTSI */ - sprintf(rs, "\"%s\"", f->r_id); - isdn_tty_at_cout(rs, info); - break; - case 4: /* +FDIS */ - rs[0] = 0; - rp = &f->r_resolution; - for (i = 0; i < 8; i++) { - sprintf(rss, "%c%s", rp[i] + 48, - (i < 7) ? "," : ""); - strcat(rs, rss); - } - isdn_tty_at_cout(rs, info); -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax DIS=%s on ttyI%d\n", - rs, info->line); -#endif - break; - case 5: /* +FHNG */ - sprintf(rs, "%d", f->code); - isdn_tty_at_cout(rs, info); - info->faxonline = 0; - break; - case 6: /* +FDCS */ - rs[0] = 0; - rp = &f->r_resolution; - for (i = 0; i < 8; i++) { - sprintf(rss, "%c%s", rp[i] + 48, - (i < 7) ? "," : ""); - strcat(rs, rss); - } - isdn_tty_at_cout(rs, info); -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax DCS=%s on ttyI%d\n", - rs, info->line); -#endif - break; - case 7: /* CONNECT */ - info->faxonline |= 2; - break; - case 9: /* FCFR */ - break; - case 10: /* FPTS */ - isdn_tty_at_cout("1", info); - break; - case 11: /* FET */ - sprintf(rs, "%d", f->fet); - isdn_tty_at_cout(rs, info); - break; - } - - isdn_tty_at_cout("\r\n", info); - - switch (code) { - case 7: /* CONNECT */ - info->online = 2; - if (info->faxonline & 1) { - sprintf(rs, "%c", XON); - isdn_tty_at_cout(rs, info); - } - break; - } -} - -static int -isdn_tty_fax_command1(modem_info *info, isdn_ctrl *c) -{ - static char *msg[] = - {"OK", "CONNECT", "NO CARRIER", "ERROR", "FCERROR"}; - -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty: FCLASS1 cmd(%d)\n", c->parm.aux.cmd); -#endif - if (c->parm.aux.cmd < ISDN_FAX_CLASS1_QUERY) { - if (info->online) - info->online = 1; - isdn_tty_at_cout("\r\n", info); - isdn_tty_at_cout(msg[c->parm.aux.cmd], info); - isdn_tty_at_cout("\r\n", info); - } - switch (c->parm.aux.cmd) { - case ISDN_FAX_CLASS1_CONNECT: - info->online = 2; - break; - case ISDN_FAX_CLASS1_OK: - case ISDN_FAX_CLASS1_FCERROR: - case ISDN_FAX_CLASS1_ERROR: - case ISDN_FAX_CLASS1_NOCARR: - break; - case ISDN_FAX_CLASS1_QUERY: - isdn_tty_at_cout("\r\n", info); - if (!c->parm.aux.para[0]) { - isdn_tty_at_cout(msg[ISDN_FAX_CLASS1_ERROR], info); - isdn_tty_at_cout("\r\n", info); - } else { - isdn_tty_at_cout(c->parm.aux.para, info); - isdn_tty_at_cout("\r\nOK\r\n", info); - } - break; - } - return (0); -} - -int -isdn_tty_fax_command(modem_info *info, isdn_ctrl *c) -{ - T30_s *f = info->fax; - char rs[10]; - - if (TTY_IS_FCLASS1(info)) - return (isdn_tty_fax_command1(info, c)); - -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax cmd %d on ttyI%d\n", - f->r_code, info->line); -#endif - switch (f->r_code) { - case ISDN_TTY_FAX_FCON: - info->faxonline = 1; - isdn_tty_fax_modem_result(2, info); /* +FCON */ - return (0); - case ISDN_TTY_FAX_FCON_I: - info->faxonline = 16; - isdn_tty_fax_modem_result(2, info); /* +FCON */ - return (0); - case ISDN_TTY_FAX_RID: - if (info->faxonline & 1) - isdn_tty_fax_modem_result(3, info); /* +FCSI */ - if (info->faxonline & 16) - isdn_tty_fax_modem_result(8, info); /* +FTSI */ - return (0); - case ISDN_TTY_FAX_DIS: - isdn_tty_fax_modem_result(4, info); /* +FDIS */ - return (0); - case ISDN_TTY_FAX_HNG: - if (f->phase == ISDN_FAX_PHASE_C) { - if (f->direction == ISDN_TTY_FAX_CONN_IN) { - sprintf(rs, "%c%c", DLE, ETX); - isdn_tty_at_cout(rs, info); - } else { - sprintf(rs, "%c", 0x18); - isdn_tty_at_cout(rs, info); - } - info->faxonline &= ~2; /* leave data mode */ - info->online = 1; - } - f->phase = ISDN_FAX_PHASE_E; - isdn_tty_fax_modem_result(5, info); /* +FHNG */ - isdn_tty_fax_modem_result(0, info); /* OK */ - return (0); - case ISDN_TTY_FAX_DCS: - isdn_tty_fax_modem_result(6, info); /* +FDCS */ - isdn_tty_fax_modem_result(7, info); /* CONNECT */ - f->phase = ISDN_FAX_PHASE_C; - return (0); - case ISDN_TTY_FAX_TRAIN_OK: - isdn_tty_fax_modem_result(6, info); /* +FDCS */ - isdn_tty_fax_modem_result(0, info); /* OK */ - return (0); - case ISDN_TTY_FAX_SENT: - isdn_tty_fax_modem_result(0, info); /* OK */ - return (0); - case ISDN_TTY_FAX_CFR: - isdn_tty_fax_modem_result(9, info); /* +FCFR */ - return (0); - case ISDN_TTY_FAX_ET: - sprintf(rs, "%c%c", DLE, ETX); - isdn_tty_at_cout(rs, info); - isdn_tty_fax_modem_result(10, info); /* +FPTS */ - isdn_tty_fax_modem_result(11, info); /* +FET */ - isdn_tty_fax_modem_result(0, info); /* OK */ - info->faxonline &= ~2; /* leave data mode */ - info->online = 1; - f->phase = ISDN_FAX_PHASE_D; - return (0); - case ISDN_TTY_FAX_PTS: - isdn_tty_fax_modem_result(10, info); /* +FPTS */ - if (f->direction == ISDN_TTY_FAX_CONN_OUT) { - if (f->fet == 1) - f->phase = ISDN_FAX_PHASE_B; - if (f->fet == 0) - isdn_tty_fax_modem_result(0, info); /* OK */ - } - return (0); - case ISDN_TTY_FAX_EOP: - info->faxonline &= ~2; /* leave data mode */ - info->online = 1; - f->phase = ISDN_FAX_PHASE_D; - return (0); - - } - return (-1); -} - - -void -isdn_tty_fax_bitorder(modem_info *info, struct sk_buff *skb) -{ - __u8 LeftMask; - __u8 RightMask; - __u8 fBit; - __u8 Data; - int i; - - if (!info->fax->bor) { - for (i = 0; i < skb->len; i++) { - Data = skb->data[i]; - for ( - LeftMask = 0x80, RightMask = 0x01; - LeftMask > RightMask; - LeftMask >>= 1, RightMask <<= 1 - ) { - fBit = (Data & LeftMask); - if (Data & RightMask) - Data |= LeftMask; - else - Data &= ~LeftMask; - if (fBit) - Data |= RightMask; - else - Data &= ~RightMask; - - } - skb->data[i] = Data; - } - } -} - -/* - * Parse AT+F.. FAX class 1 commands - */ - -static int -isdn_tty_cmd_FCLASS1(char **p, modem_info *info) -{ - static char *cmd[] = - {"AE", "TS", "RS", "TM", "RM", "TH", "RH"}; - isdn_ctrl c; - int par, i; - u_long flags; - - for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++) - if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2)) - break; - -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 (%s,%d)\n", p[0], c.parm.aux.cmd); -#endif - if (c.parm.aux.cmd == 7) - PARSE_ERROR1; - - p[0] += 2; - switch (*p[0]) { - case '?': - p[0]++; - c.parm.aux.subcmd = AT_QUERY; - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - c.parm.aux.subcmd = AT_EQ_QUERY; - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - c.parm.aux.subcmd = AT_EQ_VALUE; - c.parm.aux.para[0] = par; - } - break; - case 0: - c.parm.aux.subcmd = AT_COMMAND; - break; - default: - PARSE_ERROR1; - } - c.command = ISDN_CMD_FAXCMD; -#ifdef ISDN_TTY_FAX_CMD_DEBUG - printk(KERN_DEBUG "isdn_tty_cmd_FCLASS1 %d/%d/%d)\n", - c.parm.aux.cmd, c.parm.aux.subcmd, c.parm.aux.para[0]); -#endif - if (info->isdn_driver < 0) { - if ((c.parm.aux.subcmd == AT_EQ_VALUE) || - (c.parm.aux.subcmd == AT_COMMAND)) { - PARSE_ERROR1; - } - spin_lock_irqsave(&dev->lock, flags); - /* get a temporary connection to the first free fax driver */ - i = isdn_get_free_channel(ISDN_USAGE_FAX, ISDN_PROTO_L2_FAX, - ISDN_PROTO_L3_FCLASS1, -1, -1, "00"); - if (i < 0) { - spin_unlock_irqrestore(&dev->lock, flags); - PARSE_ERROR1; - } - info->isdn_driver = dev->drvmap[i]; - info->isdn_channel = dev->chanmap[i]; - info->drv_index = i; - dev->m_idx[i] = info->line; - spin_unlock_irqrestore(&dev->lock, flags); - c.driver = info->isdn_driver; - c.arg = info->isdn_channel; - isdn_command(&c); - spin_lock_irqsave(&dev->lock, flags); - isdn_free_channel(info->isdn_driver, info->isdn_channel, - ISDN_USAGE_FAX); - info->isdn_driver = -1; - info->isdn_channel = -1; - if (info->drv_index >= 0) { - dev->m_idx[info->drv_index] = -1; - info->drv_index = -1; - } - spin_unlock_irqrestore(&dev->lock, flags); - } else { - c.driver = info->isdn_driver; - c.arg = info->isdn_channel; - isdn_command(&c); - } - return 1; -} - -/* - * Parse AT+F.. FAX class 2 commands - */ - -static int -isdn_tty_cmd_FCLASS2(char **p, modem_info *info) -{ - atemu *m = &info->emu; - T30_s *f = info->fax; - isdn_ctrl cmd; - int par; - char rs[50]; - char rss[50]; - int maxdccval[] = - {1, 5, 2, 2, 3, 2, 0, 7}; - - /* FAA still unchanged */ - if (!strncmp(p[0], "AA", 2)) { /* TODO */ - p[0] += 2; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", 0); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* BADLIN=value - dummy 0=disable errorchk disabled, 1-255 nr. of lines for making page bad */ - if (!strncmp(p[0], "BADLIN", 6)) { - p[0] += 6; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->badlin); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->badlin = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBADLIN=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* BADMUL=value - dummy 0=disable errorchk disabled (threshold multiplier) */ - if (!strncmp(p[0], "BADMUL", 6)) { - p[0] += 6; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->badmul); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->badmul = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBADMUL=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* BOR=n - Phase C bit order, 0=direct, 1=reverse */ - if (!strncmp(p[0], "BOR", 3)) { - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->bor); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,1"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->bor = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBOR=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* NBC=n - No Best Capabilities */ - if (!strncmp(p[0], "NBC", 3)) { - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->nbc); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,1"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->nbc = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FNBC=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* BUF? - Readonly buffersize readout */ - if (!strncmp(p[0], "BUF?", 4)) { - p[0] += 4; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FBUF? (%d) \n", (16 * m->mdmreg[REG_PSIZE])); -#endif - p[0]++; - sprintf(rs, "\r\n %d ", (16 * m->mdmreg[REG_PSIZE])); - isdn_tty_at_cout(rs, info); - return 0; - } - /* CIG=string - local fax station id string for polling rx */ - if (!strncmp(p[0], "CIG", 3)) { - int i, r; - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n\"%s\"", f->pollid); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n\"STRING\""); - isdn_tty_at_cout(rs, info); - } else { - if (*p[0] == '"') - p[0]++; - for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) { - f->pollid[i] = *p[0]++; - } - if (*p[0] == '"') - p[0]++; - for (r = i; r < FAXIDLEN; r++) { - f->pollid[r] = 32; - } - f->pollid[FAXIDLEN - 1] = 0; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax local poll ID rx \"%s\"\n", f->pollid); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* CQ=n - copy qlty chk, 0= no chk, 1=only 1D chk, 2=1D+2D chk */ - if (!strncmp(p[0], "CQ", 2)) { - p[0] += 2; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->cq); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,1,2"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 2)) - PARSE_ERROR1; - f->cq = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FCQ=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* CR=n - can receive? 0= no data rx or poll remote dev, 1=do receive data or poll remote dev */ - if (!strncmp(p[0], "CR", 2)) { - p[0] += 2; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->cr); /* read actual value from struct and print */ - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,1"); /* display online help */ - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->cr = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FCR=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* CTCRTY=value - ECM retry count */ - if (!strncmp(p[0], "CTCRTY", 6)) { - p[0] += 6; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->ctcrty); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->ctcrty = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FCTCRTY=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* DCC=vr,br,wd,ln,df,ec,bf,st - DCE capabilities parms */ - if (!strncmp(p[0], "DCC", 3)) { - char *rp = &f->resolution; - int i; - - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - strcpy(rs, "\r\n"); - for (i = 0; i < 8; i++) { - sprintf(rss, "%c%s", rp[i] + 48, - (i < 7) ? "," : ""); - strcat(rs, rss); - } - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info); - p[0]++; - } else { - for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) { - if (*p[0] != ',') { - if ((*p[0] - 48) > maxdccval[i]) { - PARSE_ERROR1; - } - rp[i] = *p[0] - 48; - p[0]++; - if (*p[0] == ',') - p[0]++; - } else - p[0]++; - } -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FDCC capabilities DCE=%d,%d,%d,%d,%d,%d,%d,%d\n", - rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* DIS=vr,br,wd,ln,df,ec,bf,st - current session parms */ - if (!strncmp(p[0], "DIS", 3)) { - char *rp = &f->resolution; - int i; - - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - strcpy(rs, "\r\n"); - for (i = 0; i < 8; i++) { - sprintf(rss, "%c%s", rp[i] + 48, - (i < 7) ? "," : ""); - strcat(rs, rss); - } - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - isdn_tty_at_cout("\r\n(0,1),(0-5),(0-2),(0-2),(0-3),(0-2),(0),(0-7)", info); - p[0]++; - } else { - for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 8); i++) { - if (*p[0] != ',') { - if ((*p[0] - 48) > maxdccval[i]) { - PARSE_ERROR1; - } - rp[i] = *p[0] - 48; - p[0]++; - if (*p[0] == ',') - p[0]++; - } else - p[0]++; - } -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FDIS session parms=%d,%d,%d,%d,%d,%d,%d,%d\n", - rp[0], rp[1], rp[2], rp[3], rp[4], rp[5], rp[6], rp[7]); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* DR - Receive Phase C data command, initiates document reception */ - if (!strncmp(p[0], "DR", 2)) { - p[0] += 2; - if ((info->faxonline & 16) && /* incoming connection */ - ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D))) { -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FDR\n"); -#endif - f->code = ISDN_TTY_FAX_DR; - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_FAXCMD; - isdn_command(&cmd); - if (f->phase == ISDN_FAX_PHASE_B) { - f->phase = ISDN_FAX_PHASE_C; - } else if (f->phase == ISDN_FAX_PHASE_D) { - switch (f->fet) { - case 0: /* next page will be received */ - f->phase = ISDN_FAX_PHASE_C; - isdn_tty_fax_modem_result(7, info); /* CONNECT */ - break; - case 1: /* next doc will be received */ - f->phase = ISDN_FAX_PHASE_B; - break; - case 2: /* fax session is terminating */ - f->phase = ISDN_FAX_PHASE_E; - break; - default: - PARSE_ERROR1; - } - } - } else { - PARSE_ERROR1; - } - return 1; - } - /* DT=df,vr,wd,ln - TX phase C data command (release DCE to proceed with negotiation) */ - if (!strncmp(p[0], "DT", 2)) { - int i, val[] = - {4, 0, 2, 3}; - char *rp = &f->resolution; - - p[0] += 2; - if (!(info->faxonline & 1)) /* not outgoing connection */ - PARSE_ERROR1; - - for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) { - if (*p[0] != ',') { - if ((*p[0] - 48) > maxdccval[val[i]]) { - PARSE_ERROR1; - } - rp[val[i]] = *p[0] - 48; - p[0]++; - if (*p[0] == ',') - p[0]++; - } else - p[0]++; - } -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FDT tx data command parms=%d,%d,%d,%d\n", - rp[4], rp[0], rp[2], rp[3]); -#endif - if ((f->phase == ISDN_FAX_PHASE_B) || (f->phase == ISDN_FAX_PHASE_D)) { - f->code = ISDN_TTY_FAX_DT; - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_FAXCMD; - isdn_command(&cmd); - if (f->phase == ISDN_FAX_PHASE_D) { - f->phase = ISDN_FAX_PHASE_C; - isdn_tty_fax_modem_result(7, info); /* CONNECT */ - } - } else { - PARSE_ERROR1; - } - return 1; - } - /* ECM=n - Error mode control 0=disabled, 2=enabled, handled by DCE alone incl. buff of partial pages */ - if (!strncmp(p[0], "ECM", 3)) { - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->ecm); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,2"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par != 0) && (par != 2)) - PARSE_ERROR1; - f->ecm = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FECM=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* ET=n - End of page or document */ - if (!strncmp(p[0], "ET=", 3)) { - p[0] += 3; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-2"); - isdn_tty_at_cout(rs, info); - } else { - if ((f->phase != ISDN_FAX_PHASE_D) || - (!(info->faxonline & 1))) - PARSE_ERROR1; - par = isdn_getnum(p); - if ((par < 0) || (par > 2)) - PARSE_ERROR1; - f->fet = par; - f->code = ISDN_TTY_FAX_ET; - cmd.driver = info->isdn_driver; - cmd.arg = info->isdn_channel; - cmd.command = ISDN_CMD_FAXCMD; - isdn_command(&cmd); -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FET=%d\n", par); -#endif - return 1; - } - return 0; - } - /* K - terminate */ - if (!strncmp(p[0], "K", 1)) { - p[0] += 1; - if ((f->phase == ISDN_FAX_PHASE_IDLE) || (f->phase == ISDN_FAX_PHASE_E)) - PARSE_ERROR1; - isdn_tty_modem_hup(info, 1); - return 1; - } - /* LID=string - local fax ID */ - if (!strncmp(p[0], "LID", 3)) { - int i, r; - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n\"%s\"", f->id); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n\"STRING\""); - isdn_tty_at_cout(rs, info); - } else { - if (*p[0] == '"') - p[0]++; - for (i = 0; (*p[0]) && i < (FAXIDLEN - 1) && (*p[0] != '"'); i++) { - f->id[i] = *p[0]++; - } - if (*p[0] == '"') - p[0]++; - for (r = i; r < FAXIDLEN; r++) { - f->id[r] = 32; - } - f->id[FAXIDLEN - 1] = 0; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax local ID \"%s\"\n", f->id); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - - /* MDL? - DCE Model */ - if (!strncmp(p[0], "MDL?", 4)) { - p[0] += 4; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: FMDL?\n"); -#endif - isdn_tty_at_cout("\r\nisdn4linux", info); - return 0; - } - /* MFR? - DCE Manufacturer */ - if (!strncmp(p[0], "MFR?", 4)) { - p[0] += 4; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: FMFR?\n"); -#endif - isdn_tty_at_cout("\r\nisdn4linux", info); - return 0; - } - /* MINSP=n - Minimum Speed for Phase C */ - if (!strncmp(p[0], "MINSP", 5)) { - p[0] += 5; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->minsp); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-5"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 5)) - PARSE_ERROR1; - f->minsp = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FMINSP=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* PHCTO=value - DTE phase C timeout */ - if (!strncmp(p[0], "PHCTO", 5)) { - p[0] += 5; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->phcto); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0-255"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 255)) - PARSE_ERROR1; - f->phcto = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FPHCTO=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - - /* REL=n - Phase C received EOL alignment */ - if (!strncmp(p[0], "REL", 3)) { - p[0] += 3; - switch (*p[0]) { - case '?': - p[0]++; - sprintf(rs, "\r\n%d", f->rel); - isdn_tty_at_cout(rs, info); - break; - case '=': - p[0]++; - if (*p[0] == '?') { - p[0]++; - sprintf(rs, "\r\n0,1"); - isdn_tty_at_cout(rs, info); - } else { - par = isdn_getnum(p); - if ((par < 0) || (par > 1)) - PARSE_ERROR1; - f->rel = par; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FREL=%d\n", par); -#endif - } - break; - default: - PARSE_ERROR1; - } - return 0; - } - /* REV? - DCE Revision */ - if (!strncmp(p[0], "REV?", 4)) { - p[0] += 4; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: FREV?\n"); -#endif - strcpy(rss, isdn_tty_fax_revision); - sprintf(rs, "\r\nRev: %s", isdn_getrev(rss)); - isdn_tty_at_cout(rs, info); - return 0; - } - - /* Phase C Transmit Data Block Size */ - if (!strncmp(p[0], "TBC=", 4)) { /* dummy, not used */ - p[0] += 4; -#ifdef ISDN_TTY_FAX_STAT_DEBUG - printk(KERN_DEBUG "isdn_tty: Fax FTBC=%c\n", *p[0]); -#endif - switch (*p[0]) { - case '0': - p[0]++; - break; - default: - PARSE_ERROR1; - } - return 0; - } - printk(KERN_DEBUG "isdn_tty: unknown token=>AT+F%s<\n", p[0]); - PARSE_ERROR1; -} - -int -isdn_tty_cmd_PLUSF_FAX(char **p, modem_info *info) -{ - if (TTY_IS_FCLASS2(info)) - return (isdn_tty_cmd_FCLASS2(p, info)); - else if (TTY_IS_FCLASS1(info)) - return (isdn_tty_cmd_FCLASS1(p, info)); - PARSE_ERROR1; -} diff --git a/drivers/isdn/i4l/isdn_ttyfax.h b/drivers/isdn/i4l/isdn_ttyfax.h deleted file mode 100644 index ccda4fcf8f7b..000000000000 --- a/drivers/isdn/i4l/isdn_ttyfax.h +++ /dev/null @@ -1,17 +0,0 @@ -/* $Id: isdn_ttyfax.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem, tty_fax related functions (linklevel). - * - * Copyright 1999 by Armin Schindler (mac@melware.de) - * Copyright 1999 by Ralf Spachmann (mel@melware.de) - * Copyright 1999 by Cytronics & Melware - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - - -#define XON 0x11 -#define XOFF 0x13 -#define DC2 0x12 diff --git a/drivers/isdn/i4l/isdn_v110.c b/drivers/isdn/i4l/isdn_v110.c deleted file mode 100644 index d11fe76f138f..000000000000 --- a/drivers/isdn/i4l/isdn_v110.c +++ /dev/null @@ -1,625 +0,0 @@ -/* $Id: isdn_v110.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, V.110 related functions (linklevel). - * - * Copyright by Thomas Pfeiffer (pfeiffer@pds.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/delay.h> - -#include <linux/isdn.h> -#include "isdn_v110.h" - -#undef ISDN_V110_DEBUG - -char *isdn_v110_revision = "$Revision: 1.1.2.2 $"; - -#define V110_38400 255 -#define V110_19200 15 -#define V110_9600 3 - -/* - * The following data are precoded matrices, online and offline matrix - * for 9600, 19200 und 38400, respectively - */ -static unsigned char V110_OnMatrix_9600[] = -{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, - 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, - 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xfd}; - -static unsigned char V110_OffMatrix_9600[] = -{0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -static unsigned char V110_OnMatrix_19200[] = -{0xf0, 0xf0, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, - 0xfd, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7, 0xff, 0xf7}; - -static unsigned char V110_OffMatrix_19200[] = -{0xf0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -static unsigned char V110_OnMatrix_38400[] = -{0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0xfd, 0x7f, 0x7f, 0x7f, 0x7f}; - -static unsigned char V110_OffMatrix_38400[] = -{0x00, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff}; - -/* - * FlipBits reorders sequences of keylen bits in one byte. - * E.g. source order 7654321 will be converted to 45670123 when keylen = 4, - * and to 67452301 when keylen = 2. This is necessary because ordering on - * the isdn line is the other way. - */ -static inline unsigned char -FlipBits(unsigned char c, int keylen) -{ - unsigned char b = c; - unsigned char bit = 128; - int i; - int j; - int hunks = (8 / keylen); - - c = 0; - for (i = 0; i < hunks; i++) { - for (j = 0; j < keylen; j++) { - if (b & (bit >> j)) - c |= bit >> (keylen - j - 1); - } - bit >>= keylen; - } - return c; -} - - -/* isdn_v110_open allocates and initializes private V.110 data - * structures and returns a pointer to these. - */ -static isdn_v110_stream * -isdn_v110_open(unsigned char key, int hdrlen, int maxsize) -{ - int i; - isdn_v110_stream *v; - - if ((v = kzalloc(sizeof(isdn_v110_stream), GFP_ATOMIC)) == NULL) - return NULL; - v->key = key; - v->nbits = 0; - for (i = 0; key & (1 << i); i++) - v->nbits++; - - v->nbytes = 8 / v->nbits; - v->decodelen = 0; - - switch (key) { - case V110_38400: - v->OnlineFrame = V110_OnMatrix_38400; - v->OfflineFrame = V110_OffMatrix_38400; - break; - case V110_19200: - v->OnlineFrame = V110_OnMatrix_19200; - v->OfflineFrame = V110_OffMatrix_19200; - break; - default: - v->OnlineFrame = V110_OnMatrix_9600; - v->OfflineFrame = V110_OffMatrix_9600; - break; - } - v->framelen = v->nbytes * 10; - v->SyncInit = 5; - v->introducer = 0; - v->dbit = 1; - v->b = 0; - v->skbres = hdrlen; - v->maxsize = maxsize - hdrlen; - if ((v->encodebuf = kmalloc(maxsize, GFP_ATOMIC)) == NULL) { - kfree(v); - return NULL; - } - return v; -} - -/* isdn_v110_close frees private V.110 data structures */ -void -isdn_v110_close(isdn_v110_stream *v) -{ - if (v == NULL) - return; -#ifdef ISDN_V110_DEBUG - printk(KERN_DEBUG "v110 close\n"); -#endif - kfree(v->encodebuf); - kfree(v); -} - - -/* - * ValidHeaderBytes return the number of valid bytes in v->decodebuf - */ -static int -ValidHeaderBytes(isdn_v110_stream *v) -{ - int i; - for (i = 0; (i < v->decodelen) && (i < v->nbytes); i++) - if ((v->decodebuf[i] & v->key) != 0) - break; - return i; -} - -/* - * SyncHeader moves the decodebuf ptr to the next valid header - */ -static void -SyncHeader(isdn_v110_stream *v) -{ - unsigned char *rbuf = v->decodebuf; - int len = v->decodelen; - - if (len == 0) - return; - for (rbuf++, len--; len > 0; len--, rbuf++) /* such den SyncHeader in buf ! */ - if ((*rbuf & v->key) == 0) /* erstes byte gefunden ? */ - break; /* jupp! */ - if (len) - memcpy(v->decodebuf, rbuf, len); - - v->decodelen = len; -#ifdef ISDN_V110_DEBUG - printk(KERN_DEBUG "isdn_v110: Header resync\n"); -#endif -} - -/* DecodeMatrix takes n (n>=1) matrices (v110 frames, 10 bytes) where - len is the number of matrix-lines. len must be a multiple of 10, i.e. - only complete matices must be given. - From these, netto data is extracted and returned in buf. The return-value - is the bytecount of the decoded data. -*/ -static int -DecodeMatrix(isdn_v110_stream *v, unsigned char *m, int len, unsigned char *buf) -{ - int line = 0; - int buflen = 0; - int mbit = 64; - int introducer = v->introducer; - int dbit = v->dbit; - unsigned char b = v->b; - - while (line < len) { /* Are we done with all lines of the matrix? */ - if ((line % 10) == 0) { /* the 0. line of the matrix is always 0 ! */ - if (m[line] != 0x00) { /* not 0 ? -> error! */ -#ifdef ISDN_V110_DEBUG - printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad Header\n"); - /* returning now is not the right thing, though :-( */ -#endif - } - line++; /* next line of matrix */ - continue; - } else if ((line % 10) == 5) { /* in line 5 there's only e-bits ! */ - if ((m[line] & 0x70) != 0x30) { /* 011 has to be at the beginning! */ -#ifdef ISDN_V110_DEBUG - printk(KERN_DEBUG "isdn_v110: DecodeMatrix, V110 Bad 5th line\n"); - /* returning now is not the right thing, though :-( */ -#endif - } - line++; /* next line */ - continue; - } else if (!introducer) { /* every byte starts with 10 (stopbit, startbit) */ - introducer = (m[line] & mbit) ? 0 : 1; /* current bit of the matrix */ - next_byte: - if (mbit > 2) { /* was it the last bit in this line ? */ - mbit >>= 1; /* no -> take next */ - continue; - } /* otherwise start with leftmost bit in the next line */ - mbit = 64; - line++; - continue; - } else { /* otherwise we need to set a data bit */ - if (m[line] & mbit) /* was that bit set in the matrix ? */ - b |= dbit; /* yes -> set it in the data byte */ - else - b &= dbit - 1; /* no -> clear it in the data byte */ - if (dbit < 128) /* is that data byte done ? */ - dbit <<= 1; /* no, got the next bit */ - else { /* data byte is done */ - buf[buflen++] = b; /* copy byte into the output buffer */ - introducer = b = 0; /* init of the intro sequence and of the data byte */ - dbit = 1; /* next we look for the 0th bit */ - } - goto next_byte; /* look for next bit in the matrix */ - } - } - v->introducer = introducer; - v->dbit = dbit; - v->b = b; - return buflen; /* return number of bytes in the output buffer */ -} - -/* - * DecodeStream receives V.110 coded data from the input stream. It recovers the - * original frames. - * The input stream doesn't need to be framed - */ -struct sk_buff * -isdn_v110_decode(isdn_v110_stream *v, struct sk_buff *skb) -{ - int i; - int j; - int len; - unsigned char *v110_buf; - unsigned char *rbuf; - - if (!skb) { - printk(KERN_WARNING "isdn_v110_decode called with NULL skb!\n"); - return NULL; - } - rbuf = skb->data; - len = skb->len; - if (v == NULL) { - /* invalid handle, no chance to proceed */ - printk(KERN_WARNING "isdn_v110_decode called with NULL stream!\n"); - dev_kfree_skb(skb); - return NULL; - } - if (v->decodelen == 0) /* cache empty? */ - for (; len > 0; len--, rbuf++) /* scan for SyncHeader in buf */ - if ((*rbuf & v->key) == 0) - break; /* found first byte */ - if (len == 0) { - dev_kfree_skb(skb); - return NULL; - } - /* copy new data to decode-buffer */ - memcpy(&(v->decodebuf[v->decodelen]), rbuf, len); - v->decodelen += len; -ReSync: - if (v->decodelen < v->nbytes) { /* got a new header ? */ - dev_kfree_skb(skb); - return NULL; /* no, try later */ - } - if (ValidHeaderBytes(v) != v->nbytes) { /* is that a valid header? */ - SyncHeader(v); /* no -> look for header */ - goto ReSync; - } - len = (v->decodelen - (v->decodelen % (10 * v->nbytes))) / v->nbytes; - if ((v110_buf = kmalloc(len, GFP_ATOMIC)) == NULL) { - printk(KERN_WARNING "isdn_v110_decode: Couldn't allocate v110_buf\n"); - dev_kfree_skb(skb); - return NULL; - } - for (i = 0; i < len; i++) { - v110_buf[i] = 0; - for (j = 0; j < v->nbytes; j++) - v110_buf[i] |= (v->decodebuf[(i * v->nbytes) + j] & v->key) << (8 - ((j + 1) * v->nbits)); - v110_buf[i] = FlipBits(v110_buf[i], v->nbits); - } - v->decodelen = (v->decodelen % (10 * v->nbytes)); - memcpy(v->decodebuf, &(v->decodebuf[len * v->nbytes]), v->decodelen); - - skb_trim(skb, DecodeMatrix(v, v110_buf, len, skb->data)); - kfree(v110_buf); - if (skb->len) - return skb; - else { - kfree_skb(skb); - return NULL; - } -} - -/* EncodeMatrix takes input data in buf, len is the bytecount. - Data is encoded into v110 frames in m. Return value is the number of - matrix-lines generated. -*/ -static int -EncodeMatrix(unsigned char *buf, int len, unsigned char *m, int mlen) -{ - int line = 0; - int i = 0; - int mbit = 128; - int dbit = 1; - int introducer = 3; - int ibit[] = {0, 1, 1}; - - while ((i < len) && (line < mlen)) { /* while we still have input data */ - switch (line % 10) { /* in which line of the matrix are we? */ - case 0: - m[line++] = 0x00; /* line 0 is always 0 */ - mbit = 128; /* go on with the 7th bit */ - break; - case 5: - m[line++] = 0xbf; /* line 5 is always 10111111 */ - mbit = 128; /* go on with the 7th bit */ - break; - } - if (line >= mlen) { - printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n"); - return line; - } - next_bit: - switch (mbit) { /* leftmost or rightmost bit ? */ - case 1: - line++; /* rightmost -> go to next line */ - if (line >= mlen) { - printk(KERN_WARNING "isdn_v110 (EncodeMatrix): buffer full!\n"); - return line; - } - /* fall through */ - case 128: - m[line] = 128; /* leftmost -> set byte to 1000000 */ - mbit = 64; /* current bit in the matrix line */ - continue; - } - if (introducer) { /* set 110 sequence ? */ - introducer--; /* set on digit less */ - m[line] |= ibit[introducer] ? mbit : 0; /* set corresponding bit */ - mbit >>= 1; /* bit of matrix line >> 1 */ - goto next_bit; /* and go on there */ - } /* else push data bits into the matrix! */ - m[line] |= (buf[i] & dbit) ? mbit : 0; /* set data bit in matrix */ - if (dbit == 128) { /* was it the last one? */ - dbit = 1; /* then go on with first bit of */ - i++; /* next byte in input buffer */ - if (i < len) /* input buffer done ? */ - introducer = 3; /* no, write introducer 110 */ - else { /* input buffer done ! */ - m[line] |= (mbit - 1) & 0xfe; /* set remaining bits in line to 1 */ - break; - } - } else /* not the last data bit */ - dbit <<= 1; /* then go to next data bit */ - mbit >>= 1; /* go to next bit of matrix */ - goto next_bit; - - } - /* if necessary, generate remaining lines of the matrix... */ - if ((line) && ((line + 10) < mlen)) - switch (++line % 10) { - case 1: - m[line++] = 0xfe; - /* fall through */ - case 2: - m[line++] = 0xfe; - /* fall through */ - case 3: - m[line++] = 0xfe; - /* fall through */ - case 4: - m[line++] = 0xfe; - /* fall through */ - case 5: - m[line++] = 0xbf; - /* fall through */ - case 6: - m[line++] = 0xfe; - /* fall through */ - case 7: - m[line++] = 0xfe; - /* fall through */ - case 8: - m[line++] = 0xfe; - /* fall through */ - case 9: - m[line++] = 0xfe; - } - return line; /* that's how many lines we have */ -} - -/* - * Build a sync frame. - */ -static struct sk_buff * -isdn_v110_sync(isdn_v110_stream *v) -{ - struct sk_buff *skb; - - if (v == NULL) { - /* invalid handle, no chance to proceed */ - printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n"); - return NULL; - } - if ((skb = dev_alloc_skb(v->framelen + v->skbres))) { - skb_reserve(skb, v->skbres); - skb_put_data(skb, v->OfflineFrame, v->framelen); - } - return skb; -} - -/* - * Build an idle frame. - */ -static struct sk_buff * -isdn_v110_idle(isdn_v110_stream *v) -{ - struct sk_buff *skb; - - if (v == NULL) { - /* invalid handle, no chance to proceed */ - printk(KERN_WARNING "isdn_v110_sync called with NULL stream!\n"); - return NULL; - } - if ((skb = dev_alloc_skb(v->framelen + v->skbres))) { - skb_reserve(skb, v->skbres); - skb_put_data(skb, v->OnlineFrame, v->framelen); - } - return skb; -} - -struct sk_buff * -isdn_v110_encode(isdn_v110_stream *v, struct sk_buff *skb) -{ - int i; - int j; - int rlen; - int mlen; - int olen; - int size; - int sval1; - int sval2; - int nframes; - unsigned char *v110buf; - unsigned char *rbuf; - struct sk_buff *nskb; - - if (v == NULL) { - /* invalid handle, no chance to proceed */ - printk(KERN_WARNING "isdn_v110_encode called with NULL stream!\n"); - return NULL; - } - if (!skb) { - /* invalid skb, no chance to proceed */ - printk(KERN_WARNING "isdn_v110_encode called with NULL skb!\n"); - return NULL; - } - rlen = skb->len; - nframes = (rlen + 3) / 4; - v110buf = v->encodebuf; - if ((nframes * 40) > v->maxsize) { - size = v->maxsize; - rlen = v->maxsize / 40; - } else - size = nframes * 40; - if (!(nskb = dev_alloc_skb(size + v->skbres + sizeof(int)))) { - printk(KERN_WARNING "isdn_v110_encode: Couldn't alloc skb\n"); - return NULL; - } - skb_reserve(nskb, v->skbres + sizeof(int)); - if (skb->len == 0) { - skb_put_data(nskb, v->OnlineFrame, v->framelen); - *((int *)skb_push(nskb, sizeof(int))) = 0; - return nskb; - } - mlen = EncodeMatrix(skb->data, rlen, v110buf, size); - /* now distribute 2 or 4 bits each to the output stream! */ - rbuf = skb_put(nskb, size); - olen = 0; - sval1 = 8 - v->nbits; - sval2 = v->key << sval1; - for (i = 0; i < mlen; i++) { - v110buf[i] = FlipBits(v110buf[i], v->nbits); - for (j = 0; j < v->nbytes; j++) { - if (size--) - *rbuf++ = ~v->key | (((v110buf[i] << (j * v->nbits)) & sval2) >> sval1); - else { - printk(KERN_WARNING "isdn_v110_encode: buffers full!\n"); - goto buffer_full; - } - olen++; - } - } -buffer_full: - skb_trim(nskb, olen); - *((int *)skb_push(nskb, sizeof(int))) = rlen; - return nskb; -} - -int -isdn_v110_stat_callback(int idx, isdn_ctrl *c) -{ - isdn_v110_stream *v = NULL; - int i; - int ret = 0; - - if (idx < 0) - return 0; - switch (c->command) { - case ISDN_STAT_BSENT: - /* Keep the send-queue of the driver filled - * with frames: - * If number of outstanding frames < 3, - * send down an Idle-Frame (or an Sync-Frame, if - * v->SyncInit != 0). - */ - if (!(v = dev->v110[idx])) - return 0; - atomic_inc(&dev->v110use[idx]); - for (i = 0; i * v->framelen < c->parm.length; i++) { - if (v->skbidle > 0) { - v->skbidle--; - ret = 1; - } else { - if (v->skbuser > 0) - v->skbuser--; - ret = 0; - } - } - for (i = v->skbuser + v->skbidle; i < 2; i++) { - struct sk_buff *skb; - if (v->SyncInit > 0) - skb = isdn_v110_sync(v); - else - skb = isdn_v110_idle(v); - if (skb) { - if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) { - dev_kfree_skb(skb); - break; - } else { - if (v->SyncInit) - v->SyncInit--; - v->skbidle++; - } - } else - break; - } - atomic_dec(&dev->v110use[idx]); - return ret; - case ISDN_STAT_DHUP: - case ISDN_STAT_BHUP: - while (1) { - atomic_inc(&dev->v110use[idx]); - if (atomic_dec_and_test(&dev->v110use[idx])) { - isdn_v110_close(dev->v110[idx]); - dev->v110[idx] = NULL; - break; - } - mdelay(1); - } - break; - case ISDN_STAT_BCONN: - if (dev->v110emu[idx] && (dev->v110[idx] == NULL)) { - int hdrlen = dev->drv[c->driver]->interface->hl_hdrlen; - int maxsize = dev->drv[c->driver]->interface->maxbufsize; - atomic_inc(&dev->v110use[idx]); - switch (dev->v110emu[idx]) { - case ISDN_PROTO_L2_V11096: - dev->v110[idx] = isdn_v110_open(V110_9600, hdrlen, maxsize); - break; - case ISDN_PROTO_L2_V11019: - dev->v110[idx] = isdn_v110_open(V110_19200, hdrlen, maxsize); - break; - case ISDN_PROTO_L2_V11038: - dev->v110[idx] = isdn_v110_open(V110_38400, hdrlen, maxsize); - break; - default:; - } - if ((v = dev->v110[idx])) { - while (v->SyncInit) { - struct sk_buff *skb = isdn_v110_sync(v); - if (dev->drv[c->driver]->interface->writebuf_skb(c->driver, c->arg, 1, skb) <= 0) { - dev_kfree_skb(skb); - /* Unable to send, try later */ - break; - } - v->SyncInit--; - v->skbidle++; - } - } else - printk(KERN_WARNING "isdn_v110: Couldn't open stream for chan %d\n", idx); - atomic_dec(&dev->v110use[idx]); - } - break; - default: - return 0; - } - return 0; -} diff --git a/drivers/isdn/i4l/isdn_v110.h b/drivers/isdn/i4l/isdn_v110.h deleted file mode 100644 index de774ab598c9..000000000000 --- a/drivers/isdn/i4l/isdn_v110.h +++ /dev/null @@ -1,29 +0,0 @@ -/* $Id: isdn_v110.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, V.110 related functions (linklevel). - * - * Copyright by Thomas Pfeiffer (pfeiffer@pds.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef _isdn_v110_h_ -#define _isdn_v110_h_ - -/* - * isdn_v110_encode will take raw data and encode it using V.110 - */ -extern struct sk_buff *isdn_v110_encode(isdn_v110_stream *, struct sk_buff *); - -/* - * isdn_v110_decode receives V.110 coded data from the stream and rebuilds - * frames from them. The source stream doesn't need to be framed. - */ -extern struct sk_buff *isdn_v110_decode(isdn_v110_stream *, struct sk_buff *); - -extern int isdn_v110_stat_callback(int, isdn_ctrl *); -extern void isdn_v110_close(isdn_v110_stream *v); - -#endif diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c deleted file mode 100644 index 48bfbcb4a09d..000000000000 --- a/drivers/isdn/i4l/isdn_x25iface.c +++ /dev/null @@ -1,332 +0,0 @@ -/* $Id: isdn_x25iface.c,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * Linux ISDN subsystem, X.25 related functions - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * stuff needed to support the Linux X.25 PLP code on top of devices that - * can provide a lab_b service using the concap_proto mechanism. - * This module supports a network interface which provides lapb_sematics - * -- as defined in Documentation/networking/x25-iface.txt -- to - * the upper layer and assumes that the lower layer provides a reliable - * data link service by means of the concap_device_ops callbacks. - * - * Only protocol specific stuff goes here. Device specific stuff - * goes to another -- device related -- concap_proto support source file. - * - */ - -/* #include <linux/isdn.h> */ -#include <linux/netdevice.h> -#include <linux/concap.h> -#include <linux/slab.h> -#include <linux/wanrouter.h> -#include <net/x25device.h> -#include "isdn_x25iface.h" - -/* for debugging messages not to cause an oops when device pointer is NULL*/ -#define MY_DEVNAME(dev) ((dev) ? (dev)->name : "DEVICE UNSPECIFIED") - - -typedef struct isdn_x25iface_proto_data { - int magic; - enum wan_states state; - /* Private stuff, not to be accessed via proto_data. We provide the - other storage for the concap_proto instance here as well, - enabling us to allocate both with just one kmalloc(): */ - struct concap_proto priv; -} ix25_pdata_t; - - - -/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */ -static void isdn_x25iface_proto_del(struct concap_proto *); -static int isdn_x25iface_proto_close(struct concap_proto *); -static int isdn_x25iface_proto_restart(struct concap_proto *, - struct net_device *, - struct concap_device_ops *); -static int isdn_x25iface_xmit(struct concap_proto *, struct sk_buff *); -static int isdn_x25iface_receive(struct concap_proto *, struct sk_buff *); -static int isdn_x25iface_connect_ind(struct concap_proto *); -static int isdn_x25iface_disconn_ind(struct concap_proto *); - - -static struct concap_proto_ops ix25_pops = { - .proto_new = &isdn_x25iface_proto_new, - .proto_del = &isdn_x25iface_proto_del, - .restart = &isdn_x25iface_proto_restart, - .close = &isdn_x25iface_proto_close, - .encap_and_xmit = &isdn_x25iface_xmit, - .data_ind = &isdn_x25iface_receive, - .connect_ind = &isdn_x25iface_connect_ind, - .disconn_ind = &isdn_x25iface_disconn_ind -}; - -/* error message helper function */ -static void illegal_state_warn(unsigned state, unsigned char firstbyte) -{ - printk(KERN_WARNING "isdn_x25iface: firstbyte %x illegal in" - "current state %d\n", firstbyte, state); -} - -/* check protocol data field for consistency */ -static int pdata_is_bad(ix25_pdata_t *pda) { - - if (pda && pda->magic == ISDN_X25IFACE_MAGIC) return 0; - printk(KERN_WARNING - "isdn_x25iface_xxx: illegal pointer to proto data\n"); - return 1; -} - -/* create a new x25 interface protocol instance - */ -struct concap_proto *isdn_x25iface_proto_new(void) -{ - ix25_pdata_t *tmp = kmalloc(sizeof(ix25_pdata_t), GFP_KERNEL); - IX25DEBUG("isdn_x25iface_proto_new\n"); - if (tmp) { - tmp->magic = ISDN_X25IFACE_MAGIC; - tmp->state = WAN_UNCONFIGURED; - /* private data space used to hold the concap_proto data. - Only to be accessed via the returned pointer */ - spin_lock_init(&tmp->priv.lock); - tmp->priv.dops = NULL; - tmp->priv.net_dev = NULL; - tmp->priv.pops = &ix25_pops; - tmp->priv.flags = 0; - tmp->priv.proto_data = tmp; - return (&(tmp->priv)); - } - return NULL; -}; - -/* close the x25iface encapsulation protocol - */ -static int isdn_x25iface_proto_close(struct concap_proto *cprot) { - - ix25_pdata_t *tmp; - int ret = 0; - ulong flags; - - if (!cprot) { - printk(KERN_ERR "isdn_x25iface_proto_close: " - "invalid concap_proto pointer\n"); - return -1; - } - IX25DEBUG("isdn_x25iface_proto_close %s \n", MY_DEVNAME(cprot->net_dev)); - spin_lock_irqsave(&cprot->lock, flags); - cprot->dops = NULL; - cprot->net_dev = NULL; - tmp = cprot->proto_data; - if (pdata_is_bad(tmp)) { - ret = -1; - } else { - tmp->state = WAN_UNCONFIGURED; - } - spin_unlock_irqrestore(&cprot->lock, flags); - return ret; -} - -/* Delete the x25iface encapsulation protocol instance - */ -static void isdn_x25iface_proto_del(struct concap_proto *cprot) { - - ix25_pdata_t *tmp; - - IX25DEBUG("isdn_x25iface_proto_del \n"); - if (!cprot) { - printk(KERN_ERR "isdn_x25iface_proto_del: " - "concap_proto pointer is NULL\n"); - return; - } - tmp = cprot->proto_data; - if (tmp == NULL) { - printk(KERN_ERR "isdn_x25iface_proto_del: inconsistent " - "proto_data pointer (maybe already deleted?)\n"); - return; - } - /* close if the protocol is still open */ - if (cprot->dops) isdn_x25iface_proto_close(cprot); - /* freeing the storage should be sufficient now. But some additional - settings might help to catch wild pointer bugs */ - tmp->magic = 0; - cprot->proto_data = NULL; - - kfree(tmp); - return; -} - -/* (re-)initialize the data structures for x25iface encapsulation - */ -static int isdn_x25iface_proto_restart(struct concap_proto *cprot, - struct net_device *ndev, - struct concap_device_ops *dops) -{ - ix25_pdata_t *pda = cprot->proto_data; - ulong flags; - - IX25DEBUG("isdn_x25iface_proto_restart %s \n", MY_DEVNAME(ndev)); - - if (pdata_is_bad(pda)) return -1; - - if (!(dops && dops->data_req && dops->connect_req - && dops->disconn_req)) { - printk(KERN_WARNING "isdn_x25iface_restart: required dops" - " missing\n"); - isdn_x25iface_proto_close(cprot); - return -1; - } - spin_lock_irqsave(&cprot->lock, flags); - cprot->net_dev = ndev; - cprot->pops = &ix25_pops; - cprot->dops = dops; - pda->state = WAN_DISCONNECTED; - spin_unlock_irqrestore(&cprot->lock, flags); - return 0; -} - -/* deliver a dl_data frame received from i4l HL driver to the network layer - */ -static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb) -{ - IX25DEBUG("isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev)); - if (((ix25_pdata_t *)(cprot->proto_data)) - ->state == WAN_CONNECTED) { - if (skb_push(skb, 1)) { - skb->data[0] = X25_IFACE_DATA; - skb->protocol = x25_type_trans(skb, cprot->net_dev); - netif_rx(skb); - return 0; - } - } - printk(KERN_WARNING "isdn_x25iface_receive %s: not connected, skb dropped\n", MY_DEVNAME(cprot->net_dev)); - dev_kfree_skb(skb); - return -1; -} - -/* a connection set up is indicated by lower layer - */ -static int isdn_x25iface_connect_ind(struct concap_proto *cprot) -{ - struct sk_buff *skb; - enum wan_states *state_p - = &(((ix25_pdata_t *)(cprot->proto_data))->state); - IX25DEBUG("isdn_x25iface_connect_ind %s \n" - , MY_DEVNAME(cprot->net_dev)); - if (*state_p == WAN_UNCONFIGURED) { - printk(KERN_WARNING - "isdn_x25iface_connect_ind while unconfigured %s\n" - , MY_DEVNAME(cprot->net_dev)); - return -1; - } - *state_p = WAN_CONNECTED; - - skb = dev_alloc_skb(1); - if (skb) { - skb_put_u8(skb, X25_IFACE_CONNECT); - skb->protocol = x25_type_trans(skb, cprot->net_dev); - netif_rx(skb); - return 0; - } else { - printk(KERN_WARNING "isdn_x25iface_connect_ind: " - " out of memory -- disconnecting\n"); - cprot->dops->disconn_req(cprot); - return -1; - } -} - -/* a disconnect is indicated by lower layer - */ -static int isdn_x25iface_disconn_ind(struct concap_proto *cprot) -{ - struct sk_buff *skb; - enum wan_states *state_p - = &(((ix25_pdata_t *)(cprot->proto_data))->state); - IX25DEBUG("isdn_x25iface_disconn_ind %s \n", MY_DEVNAME(cprot->net_dev)); - if (*state_p == WAN_UNCONFIGURED) { - printk(KERN_WARNING - "isdn_x25iface_disconn_ind while unconfigured\n"); - return -1; - } - if (!cprot->net_dev) return -1; - *state_p = WAN_DISCONNECTED; - skb = dev_alloc_skb(1); - if (skb) { - skb_put_u8(skb, X25_IFACE_DISCONNECT); - skb->protocol = x25_type_trans(skb, cprot->net_dev); - netif_rx(skb); - return 0; - } else { - printk(KERN_WARNING "isdn_x25iface_disconn_ind:" - " out of memory\n"); - return -1; - } -} - -/* process a frame handed over to us from linux network layer. First byte - semantics as defined in Documentation/networking/x25-iface.txt -*/ -static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb) -{ - unsigned char firstbyte = skb->data[0]; - enum wan_states *state = &((ix25_pdata_t *)cprot->proto_data)->state; - int ret = 0; - IX25DEBUG("isdn_x25iface_xmit: %s first=%x state=%d\n", - MY_DEVNAME(cprot->net_dev), firstbyte, *state); - switch (firstbyte) { - case X25_IFACE_DATA: - if (*state == WAN_CONNECTED) { - skb_pull(skb, 1); - netif_trans_update(cprot->net_dev); - ret = (cprot->dops->data_req(cprot, skb)); - /* prepare for future retransmissions */ - if (ret) skb_push(skb, 1); - return ret; - } - illegal_state_warn(*state, firstbyte); - break; - case X25_IFACE_CONNECT: - if (*state == WAN_DISCONNECTED) { - *state = WAN_CONNECTING; - ret = cprot->dops->connect_req(cprot); - if (ret) { - /* reset state and notify upper layer about - * immidiatly failed attempts */ - isdn_x25iface_disconn_ind(cprot); - } - } else { - illegal_state_warn(*state, firstbyte); - } - break; - case X25_IFACE_DISCONNECT: - switch (*state) { - case WAN_DISCONNECTED: - /* Should not happen. However, give upper layer a - chance to recover from inconstistency but don't - trust the lower layer sending the disconn_confirm - when already disconnected */ - printk(KERN_WARNING "isdn_x25iface_xmit: disconnect " - " requested while disconnected\n"); - isdn_x25iface_disconn_ind(cprot); - break; /* prevent infinite loops */ - case WAN_CONNECTING: - case WAN_CONNECTED: - *state = WAN_DISCONNECTED; - cprot->dops->disconn_req(cprot); - break; - default: - illegal_state_warn(*state, firstbyte); - } - break; - case X25_IFACE_PARAMS: - printk(KERN_WARNING "isdn_x25iface_xmit: setting of lapb" - " options not yet supported\n"); - break; - default: - printk(KERN_WARNING "isdn_x25iface_xmit: frame with illegal" - " first byte %x ignored:\n", firstbyte); - } - dev_kfree_skb(skb); - return 0; -} diff --git a/drivers/isdn/i4l/isdn_x25iface.h b/drivers/isdn/i4l/isdn_x25iface.h deleted file mode 100644 index ca08e082cf7c..000000000000 --- a/drivers/isdn/i4l/isdn_x25iface.h +++ /dev/null @@ -1,30 +0,0 @@ -/* $Id: isdn_x25iface.h,v 1.1.2.2 2004/01/12 22:37:19 keil Exp $ - * - * header for Linux ISDN subsystem, x.25 related functions - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef _LINUX_ISDN_X25IFACE_H -#define _LINUX_ISDN_X25IFACE_H - -#define ISDN_X25IFACE_MAGIC 0x1e75a2b9 -/* #define DEBUG_ISDN_X25 if you want isdn_x25 debugging messages */ -#ifdef DEBUG_ISDN_X25 -# define IX25DEBUG(fmt, args...) printk(KERN_DEBUG fmt, ##args) -#else -# define IX25DEBUG(fmt, args...) -#endif - -#include <linux/skbuff.h> -#include <linux/isdn.h> -#include <linux/concap.h> - -extern struct concap_proto_ops *isdn_x25iface_concap_proto_ops_pt; -extern struct concap_proto *isdn_x25iface_proto_new(void); - - - -#endif diff --git a/drivers/isdn/isdnloop/Makefile b/drivers/isdn/isdnloop/Makefile deleted file mode 100644 index 5ff4c0e09768..000000000000 --- a/drivers/isdn/isdnloop/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# Makefile for the isdnloop ISDN device driver - -# Each configuration option enables a list of files. - -obj-$(CONFIG_ISDN_DRV_LOOP) += isdnloop.o diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c deleted file mode 100644 index 755c6bbc9553..000000000000 --- a/drivers/isdn/isdnloop/isdnloop.c +++ /dev/null @@ -1,1528 +0,0 @@ -/* $Id: isdnloop.c,v 1.11.6.7 2001/11/11 19:54:31 kai Exp $ - * - * ISDN low-level module implementing a dummy loop driver. - * - * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/sched.h> -#include "isdnloop.h" - -static char *isdnloop_id = "loop0"; - -MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card"); -MODULE_AUTHOR("Fritz Elfert"); -MODULE_LICENSE("GPL"); -module_param(isdnloop_id, charp, 0); -MODULE_PARM_DESC(isdnloop_id, "ID-String of first card"); - -static int isdnloop_addcard(char *); - -/* - * Free queue completely. - * - * Parameter: - * card = pointer to card struct - * channel = channel number - */ -static void -isdnloop_free_queue(isdnloop_card *card, int channel) -{ - struct sk_buff_head *queue = &card->bqueue[channel]; - - skb_queue_purge(queue); - card->sndcount[channel] = 0; -} - -/* - * Send B-Channel data to another virtual card. - * This routine is called via timer-callback from isdnloop_pollbchan(). - * - * Parameter: - * card = pointer to card struct. - * ch = channel number (0-based) - */ -static void -isdnloop_bchan_send(isdnloop_card *card, int ch) -{ - isdnloop_card *rcard = card->rcard[ch]; - int rch = card->rch[ch], len, ack; - struct sk_buff *skb; - isdn_ctrl cmd; - - while (card->sndcount[ch]) { - skb = skb_dequeue(&card->bqueue[ch]); - if (skb) { - len = skb->len; - card->sndcount[ch] -= len; - ack = *(skb->head); /* used as scratch area */ - cmd.driver = card->myid; - cmd.arg = ch; - if (rcard) { - rcard->interface.rcvcallb_skb(rcard->myid, rch, skb); - } else { - printk(KERN_WARNING "isdnloop: no rcard, skb dropped\n"); - dev_kfree_skb(skb); - - } - cmd.command = ISDN_STAT_BSENT; - cmd.parm.length = len; - card->interface.statcallb(&cmd); - } else - card->sndcount[ch] = 0; - } -} - -/* - * Send/Receive Data to/from the B-Channel. - * This routine is called via timer-callback. - * It schedules itself while any B-Channel is open. - * - * Parameter: - * data = pointer to card struct, set by kernel timer.data - */ -static void -isdnloop_pollbchan(struct timer_list *t) -{ - isdnloop_card *card = from_timer(card, t, rb_timer); - unsigned long flags; - - if (card->flags & ISDNLOOP_FLAGS_B1ACTIVE) - isdnloop_bchan_send(card, 0); - if (card->flags & ISDNLOOP_FLAGS_B2ACTIVE) - isdnloop_bchan_send(card, 1); - if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) { - /* schedule b-channel polling again */ - spin_lock_irqsave(&card->isdnloop_lock, flags); - card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD; - add_timer(&card->rb_timer); - card->flags |= ISDNLOOP_FLAGS_RBTIMER; - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - } else - card->flags &= ~ISDNLOOP_FLAGS_RBTIMER; -} - -/* - * Parse ICN-type setup string and fill fields of setup-struct - * with parsed data. - * - * Parameter: - * setup = setup string, format: [caller-id],si1,si2,[called-id] - * cmd = pointer to struct to be filled. - */ -static void -isdnloop_parse_setup(char *setup, isdn_ctrl *cmd) -{ - char *t = setup; - char *s = strchr(t, ','); - - *s++ = '\0'; - strlcpy(cmd->parm.setup.phone, t, sizeof(cmd->parm.setup.phone)); - s = strchr(t = s, ','); - *s++ = '\0'; - if (!strlen(t)) - cmd->parm.setup.si1 = 0; - else - cmd->parm.setup.si1 = simple_strtoul(t, NULL, 10); - s = strchr(t = s, ','); - *s++ = '\0'; - if (!strlen(t)) - cmd->parm.setup.si2 = 0; - else - cmd->parm.setup.si2 = - simple_strtoul(t, NULL, 10); - strlcpy(cmd->parm.setup.eazmsn, s, sizeof(cmd->parm.setup.eazmsn)); - cmd->parm.setup.plan = 0; - cmd->parm.setup.screen = 0; -} - -typedef struct isdnloop_stat { - char *statstr; - int command; - int action; -} isdnloop_stat; -/* *INDENT-OFF* */ -static isdnloop_stat isdnloop_stat_table[] = { - {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */ - {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */ - {"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */ - {"DDIS_", ISDN_STAT_DHUP, 0}, /* D-Channel disconnected */ - {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */ - {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */ - {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */ - {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */ - {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */ - {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */ - {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */ - {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */ - {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */ - {"E_L1: ACTIVATION FAILED", - ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */ - {NULL, 0, -1} -}; -/* *INDENT-ON* */ - - -/* - * Parse Status message-strings from virtual card. - * Depending on status, call statcallb for sending messages to upper - * levels. Also set/reset B-Channel active-flags. - * - * Parameter: - * status = status string to parse. - * channel = channel where message comes from. - * card = card where message comes from. - */ -static void -isdnloop_parse_status(u_char *status, int channel, isdnloop_card *card) -{ - isdnloop_stat *s = isdnloop_stat_table; - int action = -1; - isdn_ctrl cmd; - - while (s->statstr) { - if (!strncmp(status, s->statstr, strlen(s->statstr))) { - cmd.command = s->command; - action = s->action; - break; - } - s++; - } - if (action == -1) - return; - cmd.driver = card->myid; - cmd.arg = channel; - switch (action) { - case 1: - /* BCON_x */ - card->flags |= (channel) ? - ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE; - break; - case 2: - /* BDIS_x */ - card->flags &= ~((channel) ? - ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE); - isdnloop_free_queue(card, channel); - break; - case 3: - /* DCAL_I and DSCA_I */ - isdnloop_parse_setup(status + 6, &cmd); - break; - case 4: - /* FCALL */ - sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid); - sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1); - cmd.parm.setup.si1 = 7; - cmd.parm.setup.si2 = 0; - cmd.parm.setup.plan = 0; - cmd.parm.setup.screen = 0; - break; - case 5: - /* CIF */ - strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num)); - break; - case 6: - /* AOC */ - snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d", - (int) simple_strtoul(status + 7, NULL, 16)); - break; - case 7: - /* CAU */ - status += 3; - if (strlen(status) == 4) - snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c", - status + 2, *status, *(status + 1)); - else - strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num)); - break; - case 8: - /* Misc Errors on L1 and L2 */ - card->flags &= ~ISDNLOOP_FLAGS_B1ACTIVE; - isdnloop_free_queue(card, 0); - cmd.arg = 0; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - cmd.command = ISDN_STAT_DHUP; - cmd.arg = 0; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - cmd.command = ISDN_STAT_BHUP; - card->flags &= ~ISDNLOOP_FLAGS_B2ACTIVE; - isdnloop_free_queue(card, 1); - cmd.arg = 1; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - cmd.command = ISDN_STAT_DHUP; - cmd.arg = 1; - cmd.driver = card->myid; - break; - } - card->interface.statcallb(&cmd); -} - -/* - * Store a cwcharacter into ringbuffer for reading from /dev/isdnctrl - * - * Parameter: - * card = pointer to card struct. - * c = char to store. - */ -static void -isdnloop_putmsg(isdnloop_card *card, unsigned char c) -{ - ulong flags; - - spin_lock_irqsave(&card->isdnloop_lock, flags); - *card->msg_buf_write++ = (c == 0xff) ? '\n' : c; - if (card->msg_buf_write == card->msg_buf_read) { - if (++card->msg_buf_read > card->msg_buf_end) - card->msg_buf_read = card->msg_buf; - } - if (card->msg_buf_write > card->msg_buf_end) - card->msg_buf_write = card->msg_buf; - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -/* - * Poll a virtual cards message queue. - * If there are new status-replies from the card, copy them to - * ringbuffer for reading on /dev/isdnctrl and call - * isdnloop_parse_status() for processing them. Watch for special - * Firmware bootmessage and parse it, to get the D-Channel protocol. - * If there are B-Channels open, initiate a timer-callback to - * isdnloop_pollbchan(). - * This routine is called periodically via timer interrupt. - * - * Parameter: - * data = pointer to card struct - */ -static void -isdnloop_polldchan(struct timer_list *t) -{ - isdnloop_card *card = from_timer(card, t, st_timer); - struct sk_buff *skb; - int avail; - int left; - u_char c; - int ch; - unsigned long flags; - u_char *p; - isdn_ctrl cmd; - - skb = skb_dequeue(&card->dqueue); - if (skb) - avail = skb->len; - else - avail = 0; - for (left = avail; left > 0; left--) { - c = *skb->data; - skb_pull(skb, 1); - isdnloop_putmsg(card, c); - card->imsg[card->iptr] = c; - if (card->iptr < 59) - card->iptr++; - if (!skb->len) { - avail++; - isdnloop_putmsg(card, '\n'); - card->imsg[card->iptr] = 0; - card->iptr = 0; - if (card->imsg[0] == '0' && card->imsg[1] >= '0' && - card->imsg[1] <= '2' && card->imsg[2] == ';') { - ch = (card->imsg[1] - '0') - 1; - p = &card->imsg[3]; - isdnloop_parse_status(p, ch, card); - } else { - p = card->imsg; - if (!strncmp(p, "DRV1.", 5)) { - printk(KERN_INFO "isdnloop: (%s) %s\n", CID, p); - if (!strncmp(p + 7, "TC", 2)) { - card->ptype = ISDN_PTYPE_1TR6; - card->interface.features |= ISDN_FEATURE_P_1TR6; - printk(KERN_INFO - "isdnloop: (%s) 1TR6-Protocol loaded and running\n", CID); - } - if (!strncmp(p + 7, "EC", 2)) { - card->ptype = ISDN_PTYPE_EURO; - card->interface.features |= ISDN_FEATURE_P_EURO; - printk(KERN_INFO - "isdnloop: (%s) Euro-Protocol loaded and running\n", CID); - } - continue; - - } - } - } - } - if (avail) { - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = avail; - card->interface.statcallb(&cmd); - } - if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) - if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) { - /* schedule b-channel polling */ - card->flags |= ISDNLOOP_FLAGS_RBTIMER; - spin_lock_irqsave(&card->isdnloop_lock, flags); - del_timer(&card->rb_timer); - card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD; - add_timer(&card->rb_timer); - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - } - /* schedule again */ - spin_lock_irqsave(&card->isdnloop_lock, flags); - card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD; - add_timer(&card->st_timer); - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -/* - * Append a packet to the transmit buffer-queue. - * - * Parameter: - * channel = Number of B-channel - * skb = packet to send. - * card = pointer to card-struct - * Return: - * Number of bytes transferred, -E??? on error - */ -static int -isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card *card) -{ - int len = skb->len; - unsigned long flags; - struct sk_buff *nskb; - - if (len > 4000) { - printk(KERN_WARNING - "isdnloop: Send packet too large\n"); - return -EINVAL; - } - if (len) { - if (!(card->flags & (channel ? ISDNLOOP_FLAGS_B2ACTIVE : ISDNLOOP_FLAGS_B1ACTIVE))) - return 0; - if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE) - return 0; - spin_lock_irqsave(&card->isdnloop_lock, flags); - nskb = dev_alloc_skb(skb->len); - if (nskb) { - skb_copy_from_linear_data(skb, - skb_put(nskb, len), len); - skb_queue_tail(&card->bqueue[channel], nskb); - dev_kfree_skb(skb); - } else - len = 0; - card->sndcount[channel] += len; - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - } - return len; -} - -/* - * Read the messages from the card's ringbuffer - * - * Parameter: - * buf = pointer to buffer. - * len = number of bytes to read. - * user = flag, 1: called from userlevel 0: called from kernel. - * card = pointer to card struct. - * Return: - * number of bytes actually transferred. - */ -static int -isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card *card) -{ - int count; - u_char __user *p; - - for (p = buf, count = 0; count < len; p++, count++) { - if (card->msg_buf_read == card->msg_buf_write) - return count; - if (put_user(*card->msg_buf_read++, p)) - return -EFAULT; - if (card->msg_buf_read > card->msg_buf_end) - card->msg_buf_read = card->msg_buf; - } - return count; -} - -/* - * Simulate a card's response by appending it to the cards - * message queue. - * - * Parameter: - * card = pointer to card struct. - * s = pointer to message-string. - * ch = channel: 0 = generic messages, 1 and 2 = D-channel messages. - * Return: - * 0 on success, 1 on memory squeeze. - */ -static int -isdnloop_fake(isdnloop_card *card, char *s, int ch) -{ - struct sk_buff *skb; - int len = strlen(s) + ((ch >= 0) ? 3 : 0); - skb = dev_alloc_skb(len); - if (!skb) { - printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_fake\n"); - return 1; - } - if (ch >= 0) - sprintf(skb_put(skb, 3), "%02d;", ch); - skb_put_data(skb, s, strlen(s)); - skb_queue_tail(&card->dqueue, skb); - return 0; -} -/* *INDENT-OFF* */ -static isdnloop_stat isdnloop_cmd_table[] = { - {"BCON_R", 0, 1}, /* B-Channel connect */ - {"BCON_I", 0, 17}, /* B-Channel connect ind */ - {"BDIS_R", 0, 2}, /* B-Channel disconnect */ - {"DDIS_R", 0, 3}, /* D-Channel disconnect */ - {"DCON_R", 0, 16}, /* D-Channel connect */ - {"DSCA_R", 0, 4}, /* Dial 1TR6-SPV */ - {"DCAL_R", 0, 5}, /* Dial */ - {"EAZC", 0, 6}, /* Clear EAZ listener */ - {"EAZ", 0, 7}, /* Set EAZ listener */ - {"SEEAZ", 0, 8}, /* Get EAZ listener */ - {"MSN", 0, 9}, /* Set/Clear MSN listener */ - {"MSALL", 0, 10}, /* Set multi MSN listeners */ - {"SETSIL", 0, 11}, /* Set SI list */ - {"SEESIL", 0, 12}, /* Get SI list */ - {"SILC", 0, 13}, /* Clear SI list */ - {"LOCK", 0, -1}, /* LOCK channel */ - {"UNLOCK", 0, -1}, /* UNLOCK channel */ - {"FV2ON", 1, 14}, /* Leased mode on */ - {"FV2OFF", 1, 15}, /* Leased mode off */ - {NULL, 0, -1} -}; -/* *INDENT-ON* */ - - -/* - * Simulate an error-response from a card. - * - * Parameter: - * card = pointer to card struct. - */ -static void -isdnloop_fake_err(isdnloop_card *card) -{ - char buf[64]; - - snprintf(buf, sizeof(buf), "E%s", card->omsg); - isdnloop_fake(card, buf, -1); - isdnloop_fake(card, "NAK", -1); -} - -static u_char ctable_eu[] = {0x00, 0x11, 0x01, 0x12}; -static u_char ctable_1t[] = {0x00, 0x3b, 0x01, 0x3a}; - -/* - * Assemble a simplified cause message depending on the - * D-channel protocol used. - * - * Parameter: - * card = pointer to card struct. - * loc = location: 0 = local, 1 = remote. - * cau = cause: 1 = busy, 2 = nonexistent callerid, 3 = no user responding. - * Return: - * Pointer to buffer containing the assembled message. - */ -static char * -isdnloop_unicause(isdnloop_card *card, int loc, int cau) -{ - static char buf[6]; - - switch (card->ptype) { - case ISDN_PTYPE_EURO: - sprintf(buf, "E%02X%02X", (loc) ? 4 : 2, ctable_eu[cau]); - break; - case ISDN_PTYPE_1TR6: - sprintf(buf, "%02X44", ctable_1t[cau]); - break; - default: - return "0000"; - } - return buf; -} - -/* - * Release a virtual connection. Called from timer interrupt, when - * called party did not respond. - * - * Parameter: - * card = pointer to card struct. - * ch = channel (0-based) - */ -static void -isdnloop_atimeout(isdnloop_card *card, int ch) -{ - unsigned long flags; - char buf[60]; - - spin_lock_irqsave(&card->isdnloop_lock, flags); - if (card->rcard[ch]) { - isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1); - card->rcard[ch]->rcard[card->rch[ch]] = NULL; - card->rcard[ch] = NULL; - } - isdnloop_fake(card, "DDIS_I", ch + 1); - /* No user responding */ - sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3)); - isdnloop_fake(card, buf, ch + 1); - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -/* - * Wrapper for isdnloop_atimeout(). - */ -static void -isdnloop_atimeout0(struct timer_list *t) -{ - isdnloop_card *card = from_timer(card, t, c_timer[0]); - - isdnloop_atimeout(card, 0); -} - -/* - * Wrapper for isdnloop_atimeout(). - */ -static void -isdnloop_atimeout1(struct timer_list *t) -{ - isdnloop_card *card = from_timer(card, t, c_timer[1]); - - isdnloop_atimeout(card, 1); -} - -/* - * Install a watchdog for a user, not responding. - * - * Parameter: - * card = pointer to card struct. - * ch = channel to watch for. - */ -static void -isdnloop_start_ctimer(isdnloop_card *card, int ch) -{ - unsigned long flags; - - spin_lock_irqsave(&card->isdnloop_lock, flags); - timer_setup(&card->c_timer[ch], ch ? isdnloop_atimeout1 - : isdnloop_atimeout0, 0); - card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT; - add_timer(&card->c_timer[ch]); - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -/* - * Kill a pending channel watchdog. - * - * Parameter: - * card = pointer to card struct. - * ch = channel (0-based). - */ -static void -isdnloop_kill_ctimer(isdnloop_card *card, int ch) -{ - unsigned long flags; - - spin_lock_irqsave(&card->isdnloop_lock, flags); - del_timer(&card->c_timer[ch]); - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -static u_char si2bit[] = {0, 1, 0, 0, 0, 2, 0, 4, 0, 0}; -static u_char bit2si[] = {1, 5, 7}; - -/* - * Try finding a listener for an outgoing call. - * - * Parameter: - * card = pointer to calling card. - * p = pointer to ICN-type setup-string. - * lch = channel of calling card. - * cmd = pointer to struct to be filled when parsing setup. - * Return: - * 0 = found match, alerting should happen. - * 1 = found matching number but it is busy. - * 2 = no matching listener. - * 3 = found matching number but SI does not match. - */ -static int -isdnloop_try_call(isdnloop_card *card, char *p, int lch, isdn_ctrl *cmd) -{ - isdnloop_card *cc = cards; - unsigned long flags; - int ch; - int num_match; - int i; - char *e; - char nbuf[32]; - - isdnloop_parse_setup(p, cmd); - while (cc) { - for (ch = 0; ch < 2; ch++) { - /* Exclude ourself */ - if ((cc == card) && (ch == lch)) - continue; - num_match = 0; - switch (cc->ptype) { - case ISDN_PTYPE_EURO: - for (i = 0; i < 3; i++) - if (!(strcmp(cc->s0num[i], cmd->parm.setup.phone))) - num_match = 1; - break; - case ISDN_PTYPE_1TR6: - e = cc->eazlist[ch]; - while (*e) { - sprintf(nbuf, "%s%c", cc->s0num[0], *e); - if (!(strcmp(nbuf, cmd->parm.setup.phone))) - num_match = 1; - e++; - } - } - if (num_match) { - spin_lock_irqsave(&card->isdnloop_lock, flags); - /* channel idle? */ - if (!(cc->rcard[ch])) { - /* Check SI */ - if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return 3; - } - /* ch is idle, si and number matches */ - cc->rcard[ch] = card; - cc->rch[ch] = lch; - card->rcard[lch] = cc; - card->rch[lch] = ch; - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return 0; - } else { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - /* num matches, but busy */ - if (ch == 1) - return 1; - } - } - } - cc = cc->next; - } - return 2; -} - -/* - * Depending on D-channel protocol and caller/called, modify - * phone number. - * - * Parameter: - * card = pointer to card struct. - * phone = pointer phone number. - * caller = flag: 1 = caller, 0 = called. - * Return: - * pointer to new phone number. - */ -static char * -isdnloop_vstphone(isdnloop_card *card, char *phone, int caller) -{ - int i; - static char nphone[30]; - - if (!card) { - printk("BUG!!!\n"); - return ""; - } - switch (card->ptype) { - case ISDN_PTYPE_EURO: - if (caller) { - for (i = 0; i < 2; i++) - if (!(strcmp(card->s0num[i], phone))) - return phone; - return card->s0num[0]; - } - return phone; - break; - case ISDN_PTYPE_1TR6: - if (caller) { - sprintf(nphone, "%s%c", card->s0num[0], phone[0]); - return nphone; - } else - return &phone[strlen(phone) - 1]; - break; - } - return ""; -} - -/* - * Parse an ICN-type command string sent to the 'card'. - * Perform misc. actions depending on the command. - * - * Parameter: - * card = pointer to card struct. - */ -static void -isdnloop_parse_cmd(isdnloop_card *card) -{ - char *p = card->omsg; - isdn_ctrl cmd; - char buf[60]; - isdnloop_stat *s = isdnloop_cmd_table; - int action = -1; - int i; - int ch; - - if ((card->omsg[0] != '0') && (card->omsg[2] != ';')) { - isdnloop_fake_err(card); - return; - } - ch = card->omsg[1] - '0'; - if ((ch < 0) || (ch > 2)) { - isdnloop_fake_err(card); - return; - } - p += 3; - while (s->statstr) { - if (!strncmp(p, s->statstr, strlen(s->statstr))) { - action = s->action; - if (s->command && (ch != 0)) { - isdnloop_fake_err(card); - return; - } - break; - } - s++; - } - if (action == -1) - return; - switch (action) { - case 1: - /* 0x;BCON_R */ - if (card->rcard[ch - 1]) { - isdnloop_fake(card->rcard[ch - 1], "BCON_I", - card->rch[ch - 1] + 1); - isdnloop_fake(card, "BCON_C", ch); - } - break; - case 17: - /* 0x;BCON_I */ - if (card->rcard[ch - 1]) { - isdnloop_fake(card->rcard[ch - 1], "BCON_C", - card->rch[ch - 1] + 1); - } - break; - case 2: - /* 0x;BDIS_R */ - isdnloop_fake(card, "BDIS_C", ch); - if (card->rcard[ch - 1]) { - isdnloop_fake(card->rcard[ch - 1], "BDIS_I", - card->rch[ch - 1] + 1); - } - break; - case 16: - /* 0x;DCON_R */ - isdnloop_kill_ctimer(card, ch - 1); - if (card->rcard[ch - 1]) { - isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]); - isdnloop_fake(card->rcard[ch - 1], "DCON_C", - card->rch[ch - 1] + 1); - isdnloop_fake(card, "DCON_C", ch); - } - break; - case 3: - /* 0x;DDIS_R */ - isdnloop_kill_ctimer(card, ch - 1); - if (card->rcard[ch - 1]) { - isdnloop_kill_ctimer(card->rcard[ch - 1], card->rch[ch - 1]); - isdnloop_fake(card->rcard[ch - 1], "DDIS_I", - card->rch[ch - 1] + 1); - card->rcard[ch - 1] = NULL; - } - isdnloop_fake(card, "DDIS_C", ch); - break; - case 4: - /* 0x;DSCA_Rdd,yy,zz,oo */ - if (card->ptype != ISDN_PTYPE_1TR6) { - isdnloop_fake_err(card); - return; - } - /* Fall through */ - case 5: - /* 0x;DCAL_Rdd,yy,zz,oo */ - p += 6; - switch (isdnloop_try_call(card, p, ch - 1, &cmd)) { - case 0: - /* Alerting */ - sprintf(buf, "D%s_I%s,%02d,%02d,%s", - (action == 4) ? "SCA" : "CAL", - isdnloop_vstphone(card, cmd.parm.setup.eazmsn, 1), - cmd.parm.setup.si1, - cmd.parm.setup.si2, - isdnloop_vstphone(card->rcard[ch - 1], - cmd.parm.setup.phone, 0)); - isdnloop_fake(card->rcard[ch - 1], buf, card->rch[ch - 1] + 1); - /* Fall through */ - case 3: - /* si1 does not match, don't alert but start timer */ - isdnloop_start_ctimer(card, ch - 1); - break; - case 1: - /* Remote busy */ - isdnloop_fake(card, "DDIS_I", ch); - sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 1)); - isdnloop_fake(card, buf, ch); - break; - case 2: - /* No such user */ - isdnloop_fake(card, "DDIS_I", ch); - sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 2)); - isdnloop_fake(card, buf, ch); - break; - } - break; - case 6: - /* 0x;EAZC */ - card->eazlist[ch - 1][0] = '\0'; - break; - case 7: - /* 0x;EAZ */ - p += 3; - if (strlen(p) >= sizeof(card->eazlist[0])) - break; - strcpy(card->eazlist[ch - 1], p); - break; - case 8: - /* 0x;SEEAZ */ - sprintf(buf, "EAZ-LIST: %s", card->eazlist[ch - 1]); - isdnloop_fake(card, buf, ch + 1); - break; - case 9: - /* 0x;MSN */ - break; - case 10: - /* 0x;MSNALL */ - break; - case 11: - /* 0x;SETSIL */ - p += 6; - i = 0; - while (strchr("0157", *p)) { - if (i) - card->sil[ch - 1] |= si2bit[*p - '0']; - i = (*p++ == '0'); - } - if (*p) - isdnloop_fake_err(card); - break; - case 12: - /* 0x;SEESIL */ - sprintf(buf, "SIN-LIST: "); - p = buf + 10; - for (i = 0; i < 3; i++) - if (card->sil[ch - 1] & (1 << i)) - p += sprintf(p, "%02d", bit2si[i]); - isdnloop_fake(card, buf, ch + 1); - break; - case 13: - /* 0x;SILC */ - card->sil[ch - 1] = 0; - break; - case 14: - /* 00;FV2ON */ - break; - case 15: - /* 00;FV2OFF */ - break; - } -} - -/* - * Put command-strings into the of the 'card'. In reality, execute them - * right in place by calling isdnloop_parse_cmd(). Also copy every - * command to the read message ringbuffer, preceding it with a '>'. - * These mesagges can be read at /dev/isdnctrl. - * - * Parameter: - * buf = pointer to command buffer. - * len = length of buffer data. - * user = flag: 1 = called form userlevel, 0 called from kernel. - * card = pointer to card struct. - * Return: - * number of bytes transferred (currently always equals len). - */ -static int -isdnloop_writecmd(const u_char *buf, int len, int user, isdnloop_card *card) -{ - int xcount = 0; - int ocount = 1; - isdn_ctrl cmd; - - while (len) { - int count = len; - u_char *p; - u_char msg[0x100]; - - if (count > 255) - count = 255; - if (user) { - if (copy_from_user(msg, buf, count)) - return -EFAULT; - } else - memcpy(msg, buf, count); - isdnloop_putmsg(card, '>'); - for (p = msg; count > 0; count--, p++) { - len--; - xcount++; - isdnloop_putmsg(card, *p); - card->omsg[card->optr] = *p; - if (*p == '\n') { - card->omsg[card->optr] = '\0'; - card->optr = 0; - isdnloop_parse_cmd(card); - if (len) { - isdnloop_putmsg(card, '>'); - ocount++; - } - } else { - if (card->optr < 59) - card->optr++; - } - ocount++; - } - } - cmd.command = ISDN_STAT_STAVAIL; - cmd.driver = card->myid; - cmd.arg = ocount; - card->interface.statcallb(&cmd); - return xcount; -} - -/* - * Delete card's pending timers, send STOP to linklevel - */ -static void -isdnloop_stopcard(isdnloop_card *card) -{ - unsigned long flags; - isdn_ctrl cmd; - - spin_lock_irqsave(&card->isdnloop_lock, flags); - if (card->flags & ISDNLOOP_FLAGS_RUNNING) { - card->flags &= ~ISDNLOOP_FLAGS_RUNNING; - del_timer(&card->st_timer); - del_timer(&card->rb_timer); - del_timer(&card->c_timer[0]); - del_timer(&card->c_timer[1]); - cmd.command = ISDN_STAT_STOP; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - } - spin_unlock_irqrestore(&card->isdnloop_lock, flags); -} - -/* - * Stop all cards before unload. - */ -static void -isdnloop_stopallcards(void) -{ - isdnloop_card *p = cards; - - while (p) { - isdnloop_stopcard(p); - p = p->next; - } -} - -/* - * Start a 'card'. Simulate card's boot message and set the phone - * number(s) of the virtual 'S0-Interface'. Install D-channel - * poll timer. - * - * Parameter: - * card = pointer to card struct. - * sdefp = pointer to struct holding ioctl parameters. - * Return: - * 0 on success, -E??? otherwise. - */ -static int -isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp) -{ - unsigned long flags; - isdnloop_sdef sdef; - int i; - - if (card->flags & ISDNLOOP_FLAGS_RUNNING) - return -EBUSY; - if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef))) - return -EFAULT; - - for (i = 0; i < 3; i++) { - if (!memchr(sdef.num[i], 0, sizeof(sdef.num[i]))) - return -EINVAL; - } - - spin_lock_irqsave(&card->isdnloop_lock, flags); - switch (sdef.ptype) { - case ISDN_PTYPE_EURO: - if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96", - -1)) { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return -ENOMEM; - } - card->sil[0] = card->sil[1] = 4; - if (isdnloop_fake(card, "TEI OK", 0)) { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return -ENOMEM; - } - for (i = 0; i < 3; i++) { - strlcpy(card->s0num[i], sdef.num[i], - sizeof(card->s0num[0])); - } - break; - case ISDN_PTYPE_1TR6: - if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95", - -1)) { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return -ENOMEM; - } - card->sil[0] = card->sil[1] = 4; - if (isdnloop_fake(card, "TEI OK", 0)) { - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return -ENOMEM; - } - strlcpy(card->s0num[0], sdef.num[0], sizeof(card->s0num[0])); - card->s0num[1][0] = '\0'; - card->s0num[2][0] = '\0'; - break; - default: - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n", - sdef.ptype); - return -EINVAL; - } - timer_setup(&card->rb_timer, isdnloop_pollbchan, 0); - timer_setup(&card->st_timer, isdnloop_polldchan, 0); - card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD; - add_timer(&card->st_timer); - card->flags |= ISDNLOOP_FLAGS_RUNNING; - spin_unlock_irqrestore(&card->isdnloop_lock, flags); - return 0; -} - -/* - * Main handler for commands sent by linklevel. - */ -static int -isdnloop_command(isdn_ctrl *c, isdnloop_card *card) -{ - ulong a; - int i; - char cbuf[80]; - isdn_ctrl cmd; - isdnloop_cdef cdef; - - switch (c->command) { - case ISDN_CMD_IOCTL: - memcpy(&a, c->parm.num, sizeof(ulong)); - switch (c->arg) { - case ISDNLOOP_IOCTL_DEBUGVAR: - return (ulong) card; - case ISDNLOOP_IOCTL_STARTUP: - return isdnloop_start(card, (isdnloop_sdef *) a); - break; - case ISDNLOOP_IOCTL_ADDCARD: - if (copy_from_user((char *)&cdef, - (char *)a, - sizeof(cdef))) - return -EFAULT; - return isdnloop_addcard(cdef.id1); - break; - case ISDNLOOP_IOCTL_LEASEDCFG: - if (a) { - if (!card->leased) { - card->leased = 1; - while (card->ptype == ISDN_PTYPE_UNKNOWN) - schedule_timeout_interruptible(10); - schedule_timeout_interruptible(10); - sprintf(cbuf, "00;FV2ON\n01;EAZ1\n02;EAZ2\n"); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - printk(KERN_INFO - "isdnloop: (%s) Leased-line mode enabled\n", - CID); - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - } else { - if (card->leased) { - card->leased = 0; - sprintf(cbuf, "00;FV2OFF\n"); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - printk(KERN_INFO - "isdnloop: (%s) Leased-line mode disabled\n", - CID); - cmd.command = ISDN_STAT_RUN; - cmd.driver = card->myid; - cmd.arg = 0; - card->interface.statcallb(&cmd); - } - } - return 0; - default: - return -EINVAL; - } - break; - case ISDN_CMD_DIAL: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (card->leased) - break; - if ((c->arg & 255) < ISDNLOOP_BCH) { - char *p; - char dcode[4]; - - a = c->arg; - p = c->parm.setup.phone; - if (*p == 's' || *p == 'S') { - /* Dial for SPV */ - p++; - strcpy(dcode, "SCA"); - } else - /* Normal Dial */ - strcpy(dcode, "CAL"); - snprintf(cbuf, sizeof(cbuf), - "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), - dcode, p, c->parm.setup.si1, - c->parm.setup.si2, c->parm.setup.eazmsn); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - } - break; - case ISDN_CMD_ACCEPTD: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (c->arg < ISDNLOOP_BCH) { - a = c->arg + 1; - cbuf[0] = 0; - switch (card->l2_proto[a - 1]) { - case ISDN_PROTO_L2_X75I: - sprintf(cbuf, "%02d;BX75\n", (int) a); - break; -#ifdef CONFIG_ISDN_X25 - case ISDN_PROTO_L2_X25DTE: - sprintf(cbuf, "%02d;BX2T\n", (int) a); - break; - case ISDN_PROTO_L2_X25DCE: - sprintf(cbuf, "%02d;BX2C\n", (int) a); - break; -#endif - case ISDN_PROTO_L2_HDLC: - sprintf(cbuf, "%02d;BTRA\n", (int) a); - break; - } - if (strlen(cbuf)) - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - sprintf(cbuf, "%02d;DCON_R\n", (int) a); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - } - break; - case ISDN_CMD_ACCEPTB: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (c->arg < ISDNLOOP_BCH) { - a = c->arg + 1; - switch (card->l2_proto[a - 1]) { - case ISDN_PROTO_L2_X75I: - sprintf(cbuf, "%02d;BCON_R,BX75\n", (int) a); - break; -#ifdef CONFIG_ISDN_X25 - case ISDN_PROTO_L2_X25DTE: - sprintf(cbuf, "%02d;BCON_R,BX2T\n", (int) a); - break; - case ISDN_PROTO_L2_X25DCE: - sprintf(cbuf, "%02d;BCON_R,BX2C\n", (int) a); - break; -#endif - case ISDN_PROTO_L2_HDLC: - sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int) a); - break; - default: - sprintf(cbuf, "%02d;BCON_R\n", (int) a); - } - printk(KERN_DEBUG "isdnloop writecmd '%s'\n", cbuf); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - break; - case ISDN_CMD_HANGUP: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (c->arg < ISDNLOOP_BCH) { - a = c->arg + 1; - sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int) a, (int) a); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - } - break; - case ISDN_CMD_SETEAZ: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (card->leased) - break; - if (c->arg < ISDNLOOP_BCH) { - a = c->arg + 1; - if (card->ptype == ISDN_PTYPE_EURO) { - sprintf(cbuf, "%02d;MS%s%s\n", (int) a, - c->parm.num[0] ? "N" : "ALL", c->parm.num); - } else - sprintf(cbuf, "%02d;EAZ%s\n", (int) a, - c->parm.num[0] ? c->parm.num : (u_char *) "0123456789"); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - } - break; - case ISDN_CMD_CLREAZ: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if (card->leased) - break; - if (c->arg < ISDNLOOP_BCH) { - a = c->arg + 1; - if (card->ptype == ISDN_PTYPE_EURO) - sprintf(cbuf, "%02d;MSNC\n", (int) a); - else - sprintf(cbuf, "%02d;EAZC\n", (int) a); - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - } - break; - case ISDN_CMD_SETL2: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - if ((c->arg & 255) < ISDNLOOP_BCH) { - a = c->arg; - switch (a >> 8) { - case ISDN_PROTO_L2_X75I: - sprintf(cbuf, "%02d;BX75\n", (int) (a & 255) + 1); - break; -#ifdef CONFIG_ISDN_X25 - case ISDN_PROTO_L2_X25DTE: - sprintf(cbuf, "%02d;BX2T\n", (int) (a & 255) + 1); - break; - case ISDN_PROTO_L2_X25DCE: - sprintf(cbuf, "%02d;BX2C\n", (int) (a & 255) + 1); - break; -#endif - case ISDN_PROTO_L2_HDLC: - sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1); - break; - case ISDN_PROTO_L2_TRANS: - sprintf(cbuf, "%02d;BTRA\n", (int) (a & 255) + 1); - break; - default: - return -EINVAL; - } - i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); - card->l2_proto[a & 255] = (a >> 8); - } - break; - case ISDN_CMD_SETL3: - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - return 0; - default: - return -EINVAL; - } - } - return 0; -} - -/* - * Find card with given driverId - */ -static inline isdnloop_card * -isdnloop_findcard(int driverid) -{ - isdnloop_card *p = cards; - - while (p) { - if (p->myid == driverid) - return p; - p = p->next; - } - return (isdnloop_card *) 0; -} - -/* - * Wrapper functions for interface to linklevel - */ -static int -if_command(isdn_ctrl *c) -{ - isdnloop_card *card = isdnloop_findcard(c->driver); - - if (card) - return isdnloop_command(c, card); - printk(KERN_ERR - "isdnloop: if_command called with invalid driverId!\n"); - return -ENODEV; -} - -static int -if_writecmd(const u_char __user *buf, int len, int id, int channel) -{ - isdnloop_card *card = isdnloop_findcard(id); - - if (card) { - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - return isdnloop_writecmd(buf, len, 1, card); - } - printk(KERN_ERR - "isdnloop: if_writecmd called with invalid driverId!\n"); - return -ENODEV; -} - -static int -if_readstatus(u_char __user *buf, int len, int id, int channel) -{ - isdnloop_card *card = isdnloop_findcard(id); - - if (card) { - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - return isdnloop_readstatus(buf, len, card); - } - printk(KERN_ERR - "isdnloop: if_readstatus called with invalid driverId!\n"); - return -ENODEV; -} - -static int -if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) -{ - isdnloop_card *card = isdnloop_findcard(id); - - if (card) { - if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) - return -ENODEV; - /* ack request stored in skb scratch area */ - *(skb->head) = ack; - return isdnloop_sendbuf(channel, skb, card); - } - printk(KERN_ERR - "isdnloop: if_sendbuf called with invalid driverId!\n"); - return -ENODEV; -} - -/* - * Allocate a new card-struct, initialize it - * link it into cards-list and register it at linklevel. - */ -static isdnloop_card * -isdnloop_initcard(char *id) -{ - isdnloop_card *card; - int i; - card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL); - if (!card) { - printk(KERN_WARNING - "isdnloop: (%s) Could not allocate card-struct.\n", id); - return (isdnloop_card *) 0; - } - card->interface.owner = THIS_MODULE; - card->interface.channels = ISDNLOOP_BCH; - card->interface.hl_hdrlen = 1; /* scratch area for storing ack flag*/ - card->interface.maxbufsize = 4000; - card->interface.command = if_command; - card->interface.writebuf_skb = if_sendbuf; - card->interface.writecmd = if_writecmd; - card->interface.readstat = if_readstatus; - card->interface.features = ISDN_FEATURE_L2_X75I | -#ifdef CONFIG_ISDN_X25 - ISDN_FEATURE_L2_X25DTE | - ISDN_FEATURE_L2_X25DCE | -#endif - ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_P_UNKNOWN; - card->ptype = ISDN_PTYPE_UNKNOWN; - strlcpy(card->interface.id, id, sizeof(card->interface.id)); - card->msg_buf_write = card->msg_buf; - card->msg_buf_read = card->msg_buf; - card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1]; - for (i = 0; i < ISDNLOOP_BCH; i++) { - card->l2_proto[i] = ISDN_PROTO_L2_X75I; - skb_queue_head_init(&card->bqueue[i]); - } - skb_queue_head_init(&card->dqueue); - spin_lock_init(&card->isdnloop_lock); - card->next = cards; - cards = card; - if (!register_isdn(&card->interface)) { - cards = cards->next; - printk(KERN_WARNING - "isdnloop: Unable to register %s\n", id); - kfree(card); - return (isdnloop_card *) 0; - } - card->myid = card->interface.channels; - return card; -} - -static int -isdnloop_addcard(char *id1) -{ - isdnloop_card *card; - card = isdnloop_initcard(id1); - if (!card) { - return -EIO; - } - printk(KERN_INFO - "isdnloop: (%s) virtual card added\n", - card->interface.id); - return 0; -} - -static int __init -isdnloop_init(void) -{ - if (isdnloop_id) - return isdnloop_addcard(isdnloop_id); - - return 0; -} - -static void __exit -isdnloop_exit(void) -{ - isdn_ctrl cmd; - isdnloop_card *card = cards; - isdnloop_card *last; - int i; - - isdnloop_stopallcards(); - while (card) { - cmd.command = ISDN_STAT_UNLOAD; - cmd.driver = card->myid; - card->interface.statcallb(&cmd); - for (i = 0; i < ISDNLOOP_BCH; i++) - isdnloop_free_queue(card, i); - card = card->next; - } - card = cards; - while (card) { - last = card; - skb_queue_purge(&card->dqueue); - card = card->next; - kfree(last); - } - printk(KERN_NOTICE "isdnloop-ISDN-driver unloaded\n"); -} - -module_init(isdnloop_init); -module_exit(isdnloop_exit); diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h deleted file mode 100644 index e9e035552bb4..000000000000 --- a/drivers/isdn/isdnloop/isdnloop.h +++ /dev/null @@ -1,112 +0,0 @@ -/* $Id: isdnloop.h,v 1.5.6.3 2001/09/23 22:24:56 kai Exp $ - * - * Loopback lowlevel module for testing of linklevel. - * - * Copyright 1997 by Fritz Elfert (fritz@isdn4linux.de) - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - */ - -#ifndef isdnloop_h -#define isdnloop_h - -#define ISDNLOOP_IOCTL_DEBUGVAR 0 -#define ISDNLOOP_IOCTL_ADDCARD 1 -#define ISDNLOOP_IOCTL_LEASEDCFG 2 -#define ISDNLOOP_IOCTL_STARTUP 3 - -/* Struct for adding new cards */ -typedef struct isdnloop_cdef { - char id1[10]; -} isdnloop_cdef; - -/* Struct for configuring cards */ -typedef struct isdnloop_sdef { - int ptype; - char num[3][20]; -} isdnloop_sdef; - -#if defined(__KERNEL__) || defined(__DEBUGVAR__) - -#ifdef __KERNEL__ -/* Kernel includes */ - -#include <linux/errno.h> -#include <linux/fs.h> -#include <linux/major.h> -#include <asm/io.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/slab.h> -#include <linux/mm.h> -#include <linux/mman.h> -#include <linux/ioport.h> -#include <linux/timer.h> -#include <linux/wait.h> -#include <linux/isdnif.h> - -#endif /* __KERNEL__ */ - -#define ISDNLOOP_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */ -#define ISDNLOOP_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */ -#define ISDNLOOP_FLAGS_RUNNING 4 /* Cards driver activated */ -#define ISDNLOOP_FLAGS_RBTIMER 8 /* scheduling of B-Channel-poll */ -#define ISDNLOOP_TIMER_BCREAD 1 /* B-Channel poll-cycle */ -#define ISDNLOOP_TIMER_DCREAD (HZ/2) /* D-Channel poll-cycle */ -#define ISDNLOOP_TIMER_ALERTWAIT (10 * HZ) /* Alert timeout */ -#define ISDNLOOP_MAX_SQUEUE 65536 /* Max. outstanding send-data */ -#define ISDNLOOP_BCH 2 /* channels per card */ - -/* - * Per card driver data - */ -typedef struct isdnloop_card { - struct isdnloop_card *next; /* Pointer to next device struct */ - struct isdnloop_card - *rcard[ISDNLOOP_BCH]; /* Pointer to 'remote' card */ - int rch[ISDNLOOP_BCH]; /* 'remote' channel */ - int myid; /* Driver-Nr. assigned by linklevel */ - int leased; /* Flag: This Adapter is connected */ - /* to a leased line */ - int sil[ISDNLOOP_BCH]; /* SI's to listen for */ - char eazlist[ISDNLOOP_BCH][11]; - /* EAZ's to listen for */ - char s0num[3][20]; /* 1TR6 base-number or MSN's */ - unsigned short flags; /* Statusflags */ - int ptype; /* Protocol type (1TR6 or Euro) */ - struct timer_list st_timer; /* Timer for Status-Polls */ - struct timer_list rb_timer; /* Timer for B-Channel-Polls */ - struct timer_list - c_timer[ISDNLOOP_BCH]; /* Timer for Alerting */ - int l2_proto[ISDNLOOP_BCH]; /* Current layer-2-protocol */ - isdn_if interface; /* Interface to upper layer */ - int iptr; /* Index to imsg-buffer */ - char imsg[60]; /* Internal buf for status-parsing */ - int optr; /* Index to omsg-buffer */ - char omsg[60]; /* Internal buf for cmd-parsing */ - char msg_buf[2048]; /* Buffer for status-messages */ - char *msg_buf_write; /* Writepointer for statusbuffer */ - char *msg_buf_read; /* Readpointer for statusbuffer */ - char *msg_buf_end; /* Pointer to end of statusbuffer */ - int sndcount[ISDNLOOP_BCH]; /* Byte-counters for B-Ch.-send */ - struct sk_buff_head - bqueue[ISDNLOOP_BCH]; /* B-Channel queues */ - struct sk_buff_head dqueue; /* D-Channel queue */ - spinlock_t isdnloop_lock; -} isdnloop_card; - -/* - * Main driver data - */ -#ifdef __KERNEL__ -static isdnloop_card *cards = (isdnloop_card *) 0; -#endif /* __KERNEL__ */ - -/* Utility-Macros */ - -#define CID (card->interface.id) - -#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */ -#endif /* isdnloop_h */ diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index cd036e87335a..038e72a84b33 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -4,8 +4,6 @@ * Karsten Keil (keil@isdn4linux.de) * * This file is (c) under GNU PUBLIC LICENSE - * For changes and modifications please read - * ../../../Documentation/isdn/mISDN.cert * * Thanks to Karsten Keil (great drivers) * Cologne Chip (great chips) |