diff options
Diffstat (limited to 'drivers/isdn')
46 files changed, 22 insertions, 22765 deletions
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index 6e3bf833c67e..be8387c0eeef 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig @@ -21,33 +21,8 @@ menuconfig ISDN if ISDN -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" endif # ISDN diff --git a/drivers/isdn/Makefile b/drivers/isdn/Makefile index f2a529c5a511..63baf27a2c79 100644 --- a/drivers/isdn/Makefile +++ b/drivers/isdn/Makefile @@ -6,5 +6,3 @@ obj-$(CONFIG_ISDN_CAPI) += capi/ obj-$(CONFIG_MISDN) += mISDN/ obj-$(CONFIG_ISDN) += hardware/ -obj-$(CONFIG_HYSDN) += hysdn/ -obj-$(CONFIG_ISDN_DRV_GIGASET) += gigaset/ diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig index 089dbee18f36..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 @@ -34,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/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig deleted file mode 100644 index c593105b3600..000000000000 --- a/drivers/isdn/gigaset/Kconfig +++ /dev/null @@ -1,62 +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_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 9c010891dcd7..000000000000 --- a/drivers/isdn/gigaset/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -gigaset-y := common.o interface.o proc.o ev-layer.o asyncdata.o - -ifdef CONFIG_GIGASET_CAPI -gigaset-y += capi.o -else -gigaset-y += dummyll.o -endif - -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 c0cbee06bc21..000000000000 --- a/drivers/isdn/gigaset/asyncdata.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - * 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. - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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 149b1aca52a2..000000000000 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ /dev/null @@ -1,2675 +0,0 @@ -/* - * 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. - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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 9cb2ab57fa4a..000000000000 --- a/drivers/isdn/gigaset/capi.c +++ /dev/null @@ -1,2520 +0,0 @@ -/* - * Kernel CAPI interface for the Gigaset driver - * - * Copyright (c) 2009 by Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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 76b5407b5277..000000000000 --- a/drivers/isdn/gigaset/common.c +++ /dev/null @@ -1,1156 +0,0 @@ -/* - * Stuff used by all variants of the driver - * - * Copyright (c) 2001 by Stefan Eilers, - * Hansjoerg Lipp <hjlipp@web.de>, - * Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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 570c2d53b84e..000000000000 --- a/drivers/isdn/gigaset/dummyll.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Dummy LL interface for the Gigaset driver - * - * Copyright (c) 2009 by Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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 182826e9d07c..000000000000 --- a/drivers/isdn/gigaset/ev-layer.c +++ /dev/null @@ -1,1913 +0,0 @@ -/* - * Stuff used by all variants of the driver - * - * Copyright (c) 2001 by Stefan Eilers, - * Hansjoerg Lipp <hjlipp@web.de>, - * Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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 166537e2dfca..000000000000 --- a/drivers/isdn/gigaset/gigaset.h +++ /dev/null @@ -1,830 +0,0 @@ -/* - * Siemens Gigaset 307x driver - * Common header file for all connection variants - * - * Written by Stefan Eilers - * and Hansjoerg Lipp <hjlipp@web.de> - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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/interface.c b/drivers/isdn/gigaset/interface.c deleted file mode 100644 index d9a578ac32cd..000000000000 --- a/drivers/isdn/gigaset/interface.c +++ /dev/null @@ -1,616 +0,0 @@ -/* - * interface to user space for the gigaset driver - * - * Copyright (c) 2004 by Hansjoerg Lipp <hjlipp@web.de> - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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 f9264ba0fe77..000000000000 --- a/drivers/isdn/gigaset/isocdata.c +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * Common data handling layer for bas_gigaset - * - * Copyright (c) 2005 by Tilman Schmidt <tilman@imap.cc>, - * Hansjoerg Lipp <hjlipp@web.de>. - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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 e3f9d0f089fa..000000000000 --- a/drivers/isdn/gigaset/proc.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Stuff used by all variants of the driver - * - * Copyright (c) 2001 by Stefan Eilers, - * Hansjoerg Lipp <hjlipp@web.de>, - * Tilman Schmidt <tilman@imap.cc>. - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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 e1de8b1a1001..000000000000 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ /dev/null @@ -1,799 +0,0 @@ -/* 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. - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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 eade36dafa34..000000000000 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ /dev/null @@ -1,949 +0,0 @@ -/* - * 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> - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * ===================================================================== - */ - -#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/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__ */ |